| Code Coverage | ||||||||||
| Classes and Traits | Functions and Methods | Lines | ||||||||
| Total |  | 0.00% | 0 / 1 |  | 88.89% | 8 / 9 | CRAP |  | 93.62% | 88 / 94 | 
| Calculator |  | 0.00% | 0 / 1 |  | 88.89% | 8 / 9 | 25.16 |  | 93.62% | 88 / 94 | 
| distanceBetweenCoordinates($coord1, $coord2) |  | 100.00% | 1 / 1 | 1 |  | 100.00% | 5 / 5 | |||
| getFirstCoordinate($track) |  | 0.00% | 0 / 1 | 12 |  | 0.00% | 0 / 6 | |||
| distVincenty($lat1, $lon1, $lat2, $lon2) |  | 100.00% | 1 / 1 | 6 |  | 100.00% | 37 / 37 | |||
| trackDistance($track) |  | 100.00% | 1 / 1 | 5 |  | 100.00% | 15 / 15 | |||
| elevationChangeBetweenCoordinates($point1, $point2) |  | 100.00% | 1 / 1 | 1 |  | 100.00% | 2 / 2 | |||
| totalTrackElevation($track) |  | 100.00% | 1 / 1 | 3 |  | 100.00% | 9 / 9 | |||
| timePassedBetweenCoordinates($point1, $point2) |  | 100.00% | 1 / 1 | 2 |  | 100.00% | 4 / 4 | |||
| totalTrackTime($track) |  | 100.00% | 1 / 1 | 3 |  | 100.00% | 12 / 12 | |||
| averageTrackSpeed($track) |  | 100.00% | 1 / 1 | 1 |  | 100.00% | 4 / 4 | |||
| <?php | |
| /** | |
| * | |
| */ | |
| namespace aae\geo { | |
| /** | |
| * @author Axel Ancona Esselmann | |
| * @package aae\geo | |
| */ | |
| class Calculator { | |
| /** | |
| * Calculates geodetic distance between two Points specified by latitude/longitude using | |
| * Vincenty inverse formula for ellipsoids | |
| * | |
| * @param [type] $coord1 [description] | |
| * @param [type] $coord2 [description] | |
| * @return [type] [description] | |
| */ | |
| public static function distanceBetweenCoordinates($coord1, $coord2) { | |
| $lat1 = $coord1->lat; | |
| $lon1 = $coord1->lon; | |
| $lat2 = $coord2->lat; | |
| $lon2 = $coord2->lon; | |
| return self::distVincenty($lat1, $lon1, $lat2, $lon2); | |
| } | |
| public static function getFirstCoordinate($track) { | |
| foreach ($track as $element) { | |
| if ($element instanceof \aae\math\geospatial\Point) { | |
| return $element; | |
| } else { | |
| return Calculator::getFirstCoordinate($element); | |
| } | |
| } | |
| } | |
| /* Calculates geodetic distance between two points specified by latitude/longitude using | |
| * Vincenty inverse formula for ellipsoids | |
| * | |
| * | |
| * Vincenty Inverse Solution of Geodesics on the Ellipsoid | |
| * Adapted from a version created by Chris Veness | |
| * | |
| * from: Vincenty inverse formula - T Vincenty, | |
| * "Direct and Inverse Solutions of Geodesics on the Ellipsoid with | |
| * application of nested equations", Survey Review, vol XXII no 176, 1975 | |
| * http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf | |
| * | |
| * @param float lat1, lon1: first point in decimal degrees | |
| * @param float lat2, lon2: second point in decimal degrees | |
| * @returns float distance in km between points | |
| */ | |
| public static function distVincenty($lat1, $lon1, $lat2, $lon2) { | |
| // WGS-84 ellipsoid params | |
| $a = 6378137; | |
| $b = 6356752.314245; | |
| $f = 1/298.257223563; | |
| $L = deg2rad(($lon2-$lon1)); | |
| $U1 = atan((1-$f) * tan(deg2rad($lat1))); | |
| $U2 = atan((1-$f) * tan(deg2rad($lat2))); | |
| $sinU1 = sin($U1); | |
| $cosU1 = cos($U1); | |
| $sinU2 = sin($U2); | |
| $cosU2 = cos($U2); | |
| $lambda = $L; | |
| $iterLimit = 100; | |
| do { | |
| $sinLambda = sin($lambda); | |
| $cosLambda = cos($lambda); | |
| $sinSigma = sqrt(($cosU2*$sinLambda) * ($cosU2*$sinLambda) + | |
| ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda) * | |
| ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda)); | |
| if ($sinSigma==0) return 0; // co-incident points | |
| $cosSigma = $sinU1*$sinU2 + $cosU1*$cosU2*$cosLambda; | |
| $sigma = atan2($sinSigma, $cosSigma); | |
| $sinAlpha = $cosU1 * $cosU2 * $sinLambda / $sinSigma; | |
| $cosSqAlpha = 1 - $sinAlpha*$sinAlpha; | |
| $cos2SigmaM = $cosSigma - 2*$sinU1*$sinU2/$cosSqAlpha; | |
| if ($cos2SigmaM == NAN) $cos2SigmaM = 0; // equatorial line: $cosSqAlpha=0 (§6) | |
| $C = $f/16*$cosSqAlpha*(4+$f*(4-3*$cosSqAlpha)); | |
| $lambdaP = $lambda; | |
| $lambda = $L + (1-$C) * $f * $sinAlpha * | |
| ($sigma + $C*$sinSigma*($cos2SigmaM+$C*$cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM))); | |
| } while (abs($lambda-$lambdaP) > 1e-12 && --$iterLimit>0); | |
| if ($iterLimit==0) return NAN; // formula failed to converge | |
| $uSq = $cosSqAlpha * ($a*$a - $b*$b) / ($b*$b); | |
| $A = 1 + $uSq/16384*(4096+$uSq*(-768+$uSq*(320-175*$uSq))); | |
| $B = $uSq/1024 * (256+$uSq*(-128+$uSq*(74-47*$uSq))); | |
| $deltaSigma = $B*$sinSigma*($cos2SigmaM+$B/4*($cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM) - | |
| $B/6*$cos2SigmaM*(-3+4*$sinSigma*$sinSigma)*(-3+4*$cos2SigmaM*$cos2SigmaM))); | |
| $s = $b*$A*($sigma-$deltaSigma); | |
| //$s = round($s, 3); // round to 1mm precision | |
| return $s/1000.0; | |
| // note: to return initial/final bearings in addition to distance, use something like: | |
| /* | |
| $fwdAz = atan2($cosU2*$sinLambda, $cosU1*$sinU2-$sinU1*$cosU2*$cosLambda); | |
| $revAz = atan2($cosU1*$sinLambda, -$sinU1*$cosU2+$cosU1*$sinU2*$cosLambda); | |
| return { $distance: $s, $initialBearing: deg2rad($fwdAz), $finalBearing: deg2rad($revAz) };*/ | |
| } | |
| /** | |
| * [trackDistance description] | |
| * @param [type] $track [description] | |
| * @return [type] [description] | |
| */ | |
| public static function trackDistance($track) { | |
| $total = 0; | |
| $paused = 0; | |
| for ($i=1; $i < count($track->segmentStarts); $i++) { | |
| $distance = self::distanceBetweenCoordinates($track[$track->segmentStarts[$i]], $track[$track->segmentStarts[$i]-1]); | |
| if ($distance > 0) { | |
| $paused += $distance; | |
| } | |
| } | |
| for ($i=0; $i < count($track) - 1; $i++) { | |
| $distance = self::distanceBetweenCoordinates($track[$i], $track[$i+1]); | |
| if ($distance > 0) { | |
| $total += $distance; | |
| } | |
| } | |
| return $total - $paused; | |
| } | |
| /** | |
| * [elevationChangeBetweenCoordinates description] | |
| * @param [type] $point1 [description] | |
| * @param [type] $point2 [description] | |
| * @return [type] [description] | |
| */ | |
| public static function elevationChangeBetweenCoordinates($point1, $point2) { | |
| $result = $point2->ele - $point1->ele; | |
| return $result; | |
| } | |
| /** | |
| * [trackElevation description] | |
| * @param [type] $track [description] | |
| * @return [type] [description] | |
| */ | |
| public static function totalTrackElevation($track) { | |
| $result = array("elevGain" => 0, "elevLoss" => 0); | |
| for ($i=0; $i < count($track) - 1; $i++) { | |
| $elevation = self::elevationChangeBetweenCoordinates($track[$i], $track[$i+1]); | |
| if ($elevation > 0) { | |
| $result["elevGain"] += $elevation; | |
| } else { | |
| $result["elevLoss"] += $elevation; | |
| } | |
| } | |
| return $result; | |
| } | |
| /** | |
| * Returns the amount of time passed from point1 to point2. Throws an exception when | |
| * point2 has an earlier time than point1. | |
| * | |
| * @param Point __parameterDescription__ | |
| * @param Point __parameterDescription__ | |
| */ | |
| public static function timePassedBetweenCoordinates($point1, $point2) { | |
| $result = $point2->time - $point1->time; | |
| if ($result < 0) { | |
| throw new \Exception("point2 has an earlier time than point1", 1); | |
| } | |
| return $result; | |
| } | |
| /** | |
| * __functionDescription__ | |
| * @param __type__ __parameterDescription__ | |
| */ | |
| public static function totalTrackTime($track) { | |
| $timePaused = 0; | |
| foreach ($track->segmentStarts as $segmentStart) { | |
| if ($segmentStart > 0) { | |
| $lastPoint = $track[$segmentStart]; | |
| $firstPoint = $track[$segmentStart-1]; | |
| $timePaused += self::timePassedBetweenCoordinates($firstPoint, $lastPoint); | |
| } | |
| } | |
| $lastPoint = $track[count($track)-1]; | |
| $firstPoint = $track[0]; | |
| $total = self::timePassedBetweenCoordinates($firstPoint, $lastPoint) - $timePaused; | |
| return $total; | |
| } | |
| /** | |
| * Returns the average speed in km/h | |
| * @param __type__ __parameterDescription__ | |
| */ | |
| public static function averageTrackSpeed($track) { | |
| $distance = self::trackDistance($track); | |
| $time = self::totalTrackTime($track) / (60 * 60); | |
| $result = $distance / ($time); | |
| return $result; | |
| } | |
| } | |
| } |