在折线中找到最接近latlng的点

我有一个由我从Google Maps Directions服务获得的latlng绘制的多义线。现在,我想在折线上找到最接近给定点的点。

(对我而言)最明显的方法是通过折线上的所有点进行循环并找到它们与给定点之间的距离,但是这种方法效率不高,因为折线上的点可能很大。

我很高兴听到这样做的其他选择。提前致谢。

回答:

它正在找到直线上最接近鼠标的点。另请注意,这是一个Google Maps API v2示例(但v3的原理是相同的)。

// Code to find the distance in metres between a lat/lng point and a polyline of lat/lng points

// All in WGS84. Free for any use.

//

// Bill Chadwick 2007

// updated to Google Maps API v3, Lawrence Ross 2014

// Construct a bdccGeo from its latitude and longitude in degrees

function bdccGeo(lat, lon)

{

var theta = (lon * Math.PI / 180.0);

var rlat = bdccGeoGeocentricLatitude(lat * Math.PI / 180.0);

var c = Math.cos(rlat);

this.x = c * Math.cos(theta);

this.y = c * Math.sin(theta);

this.z = Math.sin(rlat);

}

bdccGeo.prototype = new bdccGeo();

// internal helper functions =========================================

// Convert from geographic to geocentric latitude (radians).

function bdccGeoGeocentricLatitude(geographicLatitude)

{

var flattening = 1.0 / 298.257223563;//WGS84

var f = (1.0 - flattening) * (1.0 - flattening);

return Math.atan((Math.tan(geographicLatitude) * f));

}

// Returns the two antipodal points of intersection of two great

// circles defined by the arcs geo1 to geo2 and

// geo3 to geo4. Returns a point as a Geo, use .antipode to get the other point

function bdccGeoGetIntersection( geo1, geo2, geo3, geo4)

{

var geoCross1 = geo1.crossNormalize(geo2);

var geoCross2 = geo3.crossNormalize(geo4);

return geoCross1.crossNormalize(geoCross2);

}

//from Radians to Meters

function bdccGeoRadiansToMeters(rad)

{

return rad * 6378137.0; // WGS84 Equatorial Radius in Meters

}

//from Meters to Radians

function bdccGeoMetersToRadians(m)

{

return m / 6378137.0; // WGS84 Equatorial Radius in Meters

}

// properties =================================================

bdccGeo.prototype.getLatitudeRadians = function()

{

return (bdccGeoGeographicLatitude(Math.atan2(this.z,

Math.sqrt((this.x * this.x) + (this.y * this.y)))));

}

bdccGeo.prototype.getLongitudeRadians = function()

{

return (Math.atan2(this.y, this.x));

}

bdccGeo.prototype.getLatitude = function()

{

return this.getLatitudeRadians() * 180.0 / Math.PI;

}

bdccGeo.prototype.getLongitude = function()

{

return this.getLongitudeRadians() * 180.0 / Math.PI ;

}

// Methods =================================================

//Maths

bdccGeo.prototype.dot = function( b)

{

return ((this.x * b.x) + (this.y * b.y) + (this.z * b.z));

}

//More Maths

bdccGeo.prototype.crossLength = function( b)

{

var x = (this.y * b.z) - (this.z * b.y);

var y = (this.z * b.x) - (this.x * b.z);

var z = (this.x * b.y) - (this.y * b.x);

return Math.sqrt((x * x) + (y * y) + (z * z));

}

//More Maths

bdccGeo.prototype.scale = function( s)

{

var r = new bdccGeo(0,0);

r.x = this.x * s;

r.y = this.y * s;

r.z = this.z * s;

return r;

}

// More Maths

bdccGeo.prototype.crossNormalize = function( b)

{

var x = (this.y * b.z) - (this.z * b.y);

var y = (this.z * b.x) - (this.x * b.z);

var z = (this.x * b.y) - (this.y * b.x);

var L = Math.sqrt((x * x) + (y * y) + (z * z));

var r = new bdccGeo(0,0);

r.x = x / L;

r.y = y / L;

r.z = z / L;

return r;

}

// point on opposite side of the world to this point

bdccGeo.prototype.antipode = function()

{

return this.scale(-1.0);

}

//distance in radians from this point to point v2

bdccGeo.prototype.distance = function( v2)

{

return Math.atan2(v2.crossLength(this), v2.dot(this));

}

//returns in meters the minimum of the perpendicular distance of this point from the line segment geo1-geo2

//and the distance from this point to the line segment ends in geo1 and geo2

bdccGeo.prototype.distanceToLineSegMtrs = function(geo1, geo2)

{

//point on unit sphere above origin and normal to plane of geo1,geo2

//could be either side of the plane

var p2 = geo1.crossNormalize(geo2);

// intersection of GC normal to geo1/geo2 passing through p with GC geo1/geo2

var ip = bdccGeoGetIntersection(geo1,geo2,this,p2);

//need to check that ip or its antipode is between p1 and p2

var d = geo1.distance(geo2);

var d1p = geo1.distance(ip);

var d2p = geo2.distance(ip);

//window.status = d + ", " + d1p + ", " + d2p;

if ((d >= d1p) && (d >= d2p))

return bdccGeoRadiansToMeters(this.distance(ip));

else

{

ip = ip.antipode();

d1p = geo1.distance(ip);

d2p = geo2.distance(ip);

}

if ((d >= d1p) && (d >= d2p))

return bdccGeoRadiansToMeters(this.distance(ip));

else

return bdccGeoRadiansToMeters(Math.min(geo1.distance(this),geo2.distance(this)));

}

// distance in meters from GLatLng point to GPolyline or GPolygon poly

function bdccGeoDistanceToPolyMtrs(poly, point)

{

var d = 999999999;

var i;

var p = new bdccGeo(point.lat(),point.lng());

for(i=0; i<(poly.getPath().getLength()-1); i++)

{

var p1 = poly.getPath().getAt(i);

var l1 = new bdccGeo(p1.lat(),p1.lng());

var p2 = poly.getPath().getAt(i+1);

var l2 = new bdccGeo(p2.lat(),p2.lng());

var dp = p.distanceToLineSegMtrs(l1,l2);

if(dp < d)

d = dp;

}

return d;

}

// get a new GLatLng distanceMeters away on the compass bearing azimuthDegrees

// from the GLatLng point - accurate to better than 200m in 140km (20m in 14km) in the UK

function bdccGeoPointAtRangeAndBearing (point, distanceMeters, azimuthDegrees)

{

var latr = point.lat() * Math.PI / 180.0;

var lonr = point.lng() * Math.PI / 180.0;

var coslat = Math.cos(latr);

var sinlat = Math.sin(latr);

var az = azimuthDegrees* Math.PI / 180.0;

var cosaz = Math.cos(az);

var sinaz = Math.sin(az);

var dr = distanceMeters / 6378137.0; // distance in radians using WGS84 Equatorial Radius

var sind = Math.sin(dr);

var cosd = Math.cos(dr);

return new google.maps.LatLng(Math.asin((sinlat * cosd) + (coslat * sind * cosaz)) * 180.0 / Math.PI,

(Math.atan2((sind * sinaz), (coslat * cosd) - (sinlat * sind * cosaz)) + lonr) * 180.0 / Math.PI);

}

以上是 在折线中找到最接近latlng的点 的全部内容, 来源链接: utcz.com/qa/410716.html

回到顶部