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; }