谷歌地图API v.3从一点到多点查找最近点 [英] Google map API v.3 find nearest point from one point to point on polyline

查看:155
本文介绍了谷歌地图API v.3从一点到多点查找最近点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一张折线地图。服务器将在地图上以LatLng点响应我。我需要检查位于多段线边缘的服务器的点。如果不是,我需要在多段线上找到最近的点,然后在多段线上最近的点放置一个标记。例如,如果服务器用A点回应我,我需要将一个标记放到B点。

stack.imgur.com/ib7BT.jpgrel =nofollow noreferrer>



我找到一个好的图书馆 http:/ /wtp2.appspot.com/cSnapToRouteDemo.html ,但该库适用于Google API版本。 2,我正在使用Google API版本。 3. Google API版本还有其他选择吗? 3? Google地图Javascript API有一个 / documentation / javascript / geometryrel =nofollow>几何库

几何库有一个 isLocationOnEdge 函数。请参阅文档


要确定点是否落在折线上或附近多边形上,或在多边形的边上或附近,请将该点,折线/多边形以及可选的公差值(以度为单位) google.maps.geometry.poly.isLocationOnEdge()。如果该点与线或边上最近点之间的距离在指定的容差范围内,该函数返回true。默认的容差值是10 -9 度。


您必须以这种方式包含库:

 < script type =text / javascript
src =https://maps.googleapis.com/maps / API / JS键= YOUR_API_KEY&安培;库=几何>
< / script>

如果您需要多个库,例如:

 < script type =text / javascript
src =https://maps.googleapis.com/maps/api/js?key= YOUR_API_KEY&安培;库=几何,地点>
< / script>

完整文档为 here




如果您需要查找点在Polyline上,你可以使用这个移植到你在你的问题中提到的库的v3版本:

  var mapRoute; 

var rtPoints;
var centerMAP = new google.maps.LatLng(-7.402438,110.446957);

函数gLatLngFromEN(e,n){
var ogbLL = NEtoLL(e,n);
var pc = OGBToWGS84(ogbLL.lat,ogbLL.lon,0);
返回新的google.maps.LatLng(pc.lat,pc.lon);


函数routeMap(){

mapRoute = new google.maps.Map(document.getElementById('mapRoute'),{
center :centerMAP,
zoom:14,
mapTypeId:google.maps.MapTypeId.SATELLITE
});
mapRoute.setCenter(gLatLngFromEN(469000,169000),13);

var rtPoints = new Array();
rtPoints.push(gLatLngFromEN(468000,168000));
rtPoints.push(gLatLngFromEN(468000,170000));
rtPoints.push(gLatLngFromEN(470000,170000));
rtPoints.push(gLatLngFromEN(470000,168000));
var rtPoly = new google.maps.Polyline({
路径:rtPoints,
strokeColor:#0000FF,
strokeWeight:3,
map:mapRoute
});
var container = document.createElement(div);
container.style.fontFamily ='Arial';
container.style.fontSize ='XX-Small';

var ptr = document.createElement(INPUT);
ptr.style.width =100px;
ptr.type =文字;
ptr.readOnly = true;
ptr.id =distPtr;
container.appendChild(ptr);

document.getElementById(control)。appendChild(container);


google.maps.event.addListener(mapRoute,'mousemove',function(point){
document.getElementById('distPtr')。value = Math.round bdccGeoDistanceToPolyMtrs(rtPoly,point.latLng));
});

}

google.maps.event.addDomListener(window,'load',routeMap);


//用于查找纬度/经度点与纬度/经度点间距离的代码
//全部用WGS84表示。免费用于任何用途。
//
// Bill Chadwick 2007
//更新为Google Maps API v3,Lawrence Ross 2014

//根据其经度和纬度构建bdccGeo度
函数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();

//内部帮助函数===================================== ====

//将地理转换为以地心为中心的纬度(弧度)。
函数bdccGeoGeocentricLatitude(geographicLatitude)
{
var flattening = 1.0 / 298.257223563; // WGS84
var f =(1.0 - flattening)*(1.0 - flattening);
return Math.atan((Math.tan(geographicLatitude)* f));
}

//从地心坐标转换为地理纬度(弧度)
函数bdccGeoGeographicLatitude(geocentricLatitude)
{
var flattening = 1.0 / 298.257223563; / / WGS84
var f =(1.0 - 展平)*(1.0 - 展平);
return Math.atan(Math.tan(geocentricLatitude)/ f);
}

//返回由圆弧geo1到geo2和
// geo3到geo4定义的两个很好的
//圆圈的两个对极点。返回一个点作为Geo,使用.antipode获取另一个点
函数bdccGeoGetIntersection(geo1,geo2,geo3,geo4)
{
var geoCross1 = geo1.crossNormalize(geo2);
var geoCross2 = geo3.crossNormalize(geo4);
返回geoCross1.crossNormalize(geoCross2);
}

//从Radians到Meters
函数bdccGeoRadiansToMeters(rad)
{
return rad * 6378137.0; // WGS84赤道半径(以米为单位)
}

//从米到弧度
函数bdccGeoMetersToRadians(m)
{
return m / 6378137.0; // WGS84赤道半径(以米为单位)
}

//属性=========================== ======================


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

//方法================================== ===============

//数学
bdccGeo.prototype.dot =函数(b)
{
返回((this.x * bx)+(this.y * by)+(this.z * bz));
}

//更多数学
bdccGeo.prototype.crossLength =函数(b)
{
var x =(this.y * bz) - (this.z * by);
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));
}

//更多数学
bdccGeo.prototype.scale =函数
{
var r = new bdccGeo(0,0) ;
r.x = this.x * s;
r.y = this.y * s;
r.z = this.z * s;
return r;


//更多数学
bdccGeo.prototype.crossNormalize =函数(b)
{
var x =(this.y * bz) - (this.z * by);
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;
}

//指向这个点的世界另一端
bdccGeo.prototype.antipode = function()
{
return this。规模(-1.0);
}






//以弧度为单位的距离,从这点到点v2
bdccGeo。 prototype.distance = function(v2)
{
return Math.atan2(v2.crossLength(this),v2.dot(this));
}

//以米为单位返回此点与线段geo1-geo2
//的垂直距离的最小值,以及此点到线段的距离在geo1和geo2中结束
bdccGeo.prototype.distanceToLineSegMtrs =函数(geo1,geo2)
{

//单位球体上方原点和法线到地平面的点geo1,geo2
//可以是飞机的任一侧
var p2 = geo1.crossNormalize(geo2);

//使用GC geo1 / geo2通过p传递给geo1 / geo2的GC法线交点
var ip = bdccGeoGetIntersection(geo1,geo2,this,p2);

//需要检查ip或其反对象在p1和p2之间
var d = geo1.distance(geo2);
var d1p = geo1.distance(ip);
var d2p = geo2.distance(ip);
//window.status = d +,+ d1p +,+ d2p; ((d> = d1p)&(d> = d2p))
返回bdccGeoRadiansToMeters(this.distance(ip));
else
{
ip = ip.antipode();
d1p = geo1.distance(ip);
d2p = geo2.distance(ip); ((d> = d1p)&&(d> = d2p))
返回bdccGeoRadiansToMeters(this.distance(ip));
}

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

//与GLatLng指向GPolyline或GPolygon的距离(单位:百万)b
bc函数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 = dp;
}
return d;
}

//获得一个新的GLatLng距离指南针距离GLatLng点的azimuthDegrees
//的距离 - 精确到140米(14米20米处)的200米以内英国

函数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; //使用WGS84的弧度距离Equalsial Radius
var sind = Math.sin(dr);
var cosd = Math.cos(dr); $(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);
}

致信Bill Chadwick 2007和Lawrence Ross 2014 v3版。和@geocodezip找到它。



JSFiddle演示


I`ve got a map with a polyline. The server will responds me with a LatLng point on a map. I need to check if the point from the server situated on a polyline edge. If not, i need to find the nearest point on the polyline and place a marker on the nearest point on the polyline. For example, if the server responds me with a point A, i need to place a marker to a point B.

I find a good library http://wtp2.appspot.com/cSnapToRouteDemo.html, but this library is for Google API ver. 2, and i'm using Google API ver. 3. Is there any alternative for Google API ver. 3 ? Thank's.

解决方案

The Google Maps Javascript API has a Geometry library.

The Geometry library has a isLocationOnEdge function. See the documentation.

To determine whether a point falls on or near a polyline, or on or near the edge of a polygon, pass the point, the polyline/polygon, and optionally a tolerance value in degrees to google.maps.geometry.poly.isLocationOnEdge(). The function returns true if the distance between the point and the closest point on the line or edge falls within the specified tolerance. The default tolerance value is 10-9 degrees.

You must include the library this way:

<script type="text/javascript"
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">
</script>

And if you need more than one library, for example:

<script type="text/javascript"
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry,places">
</script>

Full documentation is here.


If you need to find the point on the Polyline, you can use this ported to v3 version of the library you mentioned in your question:

var mapRoute;

var rtPoints;
var centerMAP = new google.maps.LatLng(-7.402438, 110.446957);

function gLatLngFromEN(e, n) {
    var ogbLL = NEtoLL(e, n);
    var pc = OGBToWGS84(ogbLL.lat, ogbLL.lon, 0);
    return new google.maps.LatLng(pc.lat, pc.lon);
}

function routeMap() {

    mapRoute = new google.maps.Map(document.getElementById('mapRoute'), {
        center: centerMAP,
        zoom: 14,
        mapTypeId: google.maps.MapTypeId.SATELLITE
    });
    mapRoute.setCenter(gLatLngFromEN(469000, 169000), 13);

    var rtPoints = new Array();
    rtPoints.push(gLatLngFromEN(468000, 168000));
    rtPoints.push(gLatLngFromEN(468000, 170000));
    rtPoints.push(gLatLngFromEN(470000, 170000));
    rtPoints.push(gLatLngFromEN(470000, 168000));
    var rtPoly = new google.maps.Polyline({
        path: rtPoints,
        strokeColor: "#0000FF",
        strokeWeight: 3,
        map: mapRoute
    });
    var container = document.createElement("div");
    container.style.fontFamily = 'Arial';
    container.style.fontSize = 'XX-Small';

    var ptr = document.createElement("INPUT");
    ptr.style.width = "100px";
    ptr.type = "Text";
    ptr.readOnly = true;
    ptr.id = "distPtr";
    container.appendChild(ptr);

    document.getElementById("control").appendChild(container);


    google.maps.event.addListener(mapRoute, 'mousemove', function (point) {
        document.getElementById('distPtr').value = Math.round(bdccGeoDistanceToPolyMtrs(rtPoly, point.latLng));
    });

}

google.maps.event.addDomListener(window, 'load', routeMap);


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

    // Convert from geocentric to geographic latitude (radians)
    function bdccGeoGeographicLatitude (geocentricLatitude) 
    {
      var flattening = 1.0 / 298.257223563;//WGS84
        var f = (1.0 - flattening) * (1.0 - flattening);
      return Math.atan(Math.tan(geocentricLatitude) / 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); 
        }

Credits to Bill Chadwick 2007 and Lawrence Ross 2014 for the v3 version. And @geocodezip for finding it.

JSFiddle demo

这篇关于谷歌地图API v.3从一点到多点查找最近点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆