如何检测一个点是否在圆内?

8

如何测试LatLng点是否在圆形范围内?(谷歌地图JavaScript v3)

getBounds()方法返回圆的边界框,也就是一个矩形,所以如果一个点在圆外但在边界框内,你会得到错误的答案。


请尝试我的解决方案:https://dev59.com/N2sz5IYBdhLWcg3wTl0T#46188650 - Nguyen Chi Thanh
6个回答

15

使用球面几何库(确保在API中包含它)

function pointInCircle(point, radius, center)
{
    return (google.maps.geometry.spherical.computeDistanceBetween(point, center) <= radius)
}

3
你可以手动进行距离比较,这是相当简单的。
(x1 - x2)^2 + (y1 - y2)^2 <= D^2 

1
请注意,这不考虑地球的球形映射。纬度/经度并不相等,因此在极点附近是错误的(但在赤道附近更准确)。 - toobulkeh
此外,这并未考虑地球曲率和使用的投影。 - m_x

2
你可以使用 Circle 对象来展示它;
new google.maps.Circle({
            map : map,
            center : new google.maps.LatLng(lat,lng),
            strokeColor:'#00FFCC',
            strokeWeight:2,
            fillOpacity:0,
            radius:radiusm
        });

并将勾股定理应用于坐标:但在这种情况下为了使它成为一个“真正”的圆,因为纬度和经度之间的比率在不同的纬度上是不同的, 你至少应该像这样进行调整:

var kmRadius = 100; //(radius of 100 km)
var lat_gap = kmRadius/111.1;
var lng_gap = lat_gap / Math.cos(lat / (Math.PI/180));

1

为什么不用毕达哥拉斯定理简单地计算一下呢?你知道a²+b²=c²。如果c小于r(半径),那么它就在内部。

var isInside=Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) >= r*r;

谢谢,这就是我最终采用的方法,使用API内置的函数。如果圆形对象有一个containsLocation()方法,那将会更容易。(我也希望有一个fitBounds()方法!)你可以在这里查看代码:Circle Selection for Google Maps - Michael Schade
2
请注意,这并没有考虑地球的球面映射。纬度/经度不相等,因此在极地附近是错误的(但在赤道附近更准确)。 - toobulkeh
此外,这并未考虑地球曲率和使用的投影。 - m_x

0

试试这个(Javascript):

const toRadians = (val) => {
   return val * Math.PI / 180;
}
const toDegrees = (val) => {
   return val * 180 / Math.PI;
}
// Calculate a point winthin a circle
// circle ={center:LatLong, radius: number} // in metres
const pointInsideCircle = (point, circle) => {
    let center = circle.center;
    let distance = distanceBetween(point, center);

    return distance < circle.radius; // Use '<=' if you want to get all points in the border
};

const distanceBetween = (point1, point2) => {
    var R = 6371e3; // metres
    var φ1 = toRadians(point1.latitude);
    var φ2 = toRadians(point2.latitude);
    var Δφ = toRadians(point2.latitude - point1.latitude);
    var Δλ = toRadians(point2.longitude - point1.longitude);

    var a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
            Math.cos1) * Math.cos2) *
            Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    return R * c;
}

参考文献: http://www.movable-type.co.uk/scripts/latlong.html

这个npm帮助模块执行相同的操作,并返回一个布尔值,用于判断该项是否在圆内。

https://www.npmjs.com/package/fencery


由于您使用的是es6: const toRadians = val => val * Math.PI / 180; const toDegrees = val => val * 180 / Math.PI; - pmrotule

0

类似这样的代码应该就能解决问题了(未经测试):

public boolean pointInCircle(Circle c, LatLng coord) {
  Rectangle r = c.getBounds();
  double rectX = r.getX();
  double rectY = r.getY();
  double rectWidth = r.getWidth();
  double rectHeight = r.getHeight();

  double circleCenterX = rectX + rectWidth/2;
  double circleCenterY = rectY + rectHeight/2;

  double lat = coord.getLatitude();
  double lon = coord.getLongitude();

  // Point in circle if (x−h)^2 + (y−k)^2 <= r^2
  double rSquared = Math.pow(rectWidth/2, 2);
  double point = Math.pow(lat - circleCenterX, 2) + Math.pow(lon - circleCenterY, 2);

  return (point <= rSquared) ? true : false;
}

2
请注意,这并没有考虑地球的球面映射。纬度/经度不相等,因此在极地附近是错误的(但在赤道附近更准确)。 - toobulkeh
此外,这并未考虑地球曲率和使用的投影。 - m_x

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接