Ejemplo n.º 1
0
 /**
  * Returns the heading from one LatLng to another LatLng. Headings are
  * expressed in degrees clockwise from North within the range [-180,180).
  * @return The heading in degrees clockwise from north.
  */
 public static function computeHeading($from, $to)
 {
     // http://williams.best.vwh.net/avform.htm#Crs
     $fromLat = deg2rad($from['lat']);
     $fromLng = deg2rad($from['lng']);
     $toLat = deg2rad($to['lat']);
     $toLng = deg2rad($to['lng']);
     $dLng = $toLng - $fromLng;
     $heading = atan2(sin($dLng) * cos($toLat), cos($fromLat) * sin($toLat) - sin($fromLat) * cos($toLat) * cos($dLng));
     return MathUtil::wrap(rad2deg($heading), -180, 180);
 }
Ejemplo n.º 2
0
 private static function isLocationOnEdgeOrPath($point, $poly, $closed, $geodesic, $toleranceEarth)
 {
     $size = count($poly);
     if ($size == 0) {
         return false;
     }
     $tolerance = $toleranceEarth / MathUtil::EARTH_RADIUS;
     $havTolerance = MathUtil::hav($tolerance);
     $lat3 = deg2rad($point['lat']);
     $lng3 = deg2rad($point['lng']);
     $prev = !empty($closed) ? $poly[$size - 1] : 0;
     $lat1 = deg2rad($prev['lat']);
     $lng1 = deg2rad($prev['lng']);
     if ($geodesic) {
         foreach ($poly as $val) {
             $lat2 = deg2rad($val['lat']);
             $lng2 = deg2rad($val['lng']);
             if (self::isOnSegmentGC($lat1, $lng1, $lat2, $lng2, $lat3, $lng3, $havTolerance)) {
                 return true;
             }
             $lat1 = $lat2;
             $lng1 = $lng2;
         }
     } else {
         // We project the points to mercator space, where the Rhumb segment is a straight line,
         // and compute the geodesic distance between point3 and the closest point on the
         // segment. This method is an approximation, because it uses "closest" in mercator
         // space which is not "closest" on the sphere -- but the error is small because
         // "tolerance" is small.
         $minAcceptable = $lat3 - $tolerance;
         $maxAcceptable = $lat3 + $tolerance;
         $y1 = MathUtil::mercator($lat1);
         $y3 = MathUtil::mercator($lat3);
         $xTry = [];
         foreach ($poly as $val) {
             $lat2 = deg2rad($val['lat']);
             $y2 = MathUtil::mercator($lat2);
             $lng2 = deg2rad($val['lng']);
             if (max($lat1, $lat2) >= $minAcceptable && min($lat1, $lat2) <= $maxAcceptable) {
                 // We offset longitudes by -lng1; the implicit x1 is 0.
                 $x2 = MathUtil::wrap($lng2 - $lng1, -M_PI, M_PI);
                 $x3Base = MathUtil::wrap(lng3 - lng1, -M_PI, M_PI);
                 $xTry[0] = $x3Base;
                 // Also explore wrapping of x3Base around the world in both directions.
                 $xTry[1] = $x3Base + 2 * M_PI;
                 $xTry[2] = $x3Base - 2 * M_PI;
                 foreach ($xTry as $x3) {
                     $dy = $y2 - $y1;
                     $len2 = $x2 * $x2 + $dy * $dy;
                     $t = $len2 <= 0 ? 0 : MathUtil::clamp(($x3 * $x2 + ($y3 - $y1) * $dy) / $len2, 0, 1);
                     $xClosest = $t * $x2;
                     $yClosest = $y1 + $t * $dy;
                     $latClosest = MathUtil::inverseMercator($yClosest);
                     $havDist = MathUtil::havDistance($lat3, $latClosest, $x3 - $xClosest);
                     if ($havDist < $havTolerance) {
                         return true;
                     }
                 }
             }
             $lat1 = $lat2;
             $lng1 = $lng2;
             $y1 = $y2;
         }
     }
     return false;
 }