4

我有一个带有坐标(x,y)的列表点的mysql数据库表

我想找到落在矩形内的点列表。如果矩形的任何一侧平行或垂直于任何轴对齐,这将很简单。但不是。这意味着矩形被旋转。我还必须找到一个圆圈内的点。

矩形的已知数据 - 所有四个点的坐标 圆形的已知数据 - 中心和半径的坐标。

如何查询 mysql 表以找到落在矩形和圆形中的点?

如果这很重要,那么我使用的前端是 PHP。

4

2 回答 2

2

一个矩形可以由代表相对角的两个点来定义,例如:A(x,y) 和 B(x,y)。如果您要测试一个点 C(x,y) 以查看它是否在矩形内,则:

IF( (Cx BETWEEN Ax AND Bx) AND (Cy BETWEEN Ay AND By) ) THEN
  point C is in the rectangle defined by points A and B
ELSE
  nope
ENDIF

圆可以由单个点 C(x,y) 和半径 R 定义。如果圆心与点 P(x,y) 之间的距离 D 小于半径 R,则它在圆内:

你当然记得勾股定理,对吧?

C² = A² + B² SO C = SQRT(A² + B²)

所以:

D = SQRT( ABS(Cx - Px)² + ABS(Cy - Py)²)

IF( D <= R ) THEN
  point P is inside the circle with center C and radius R
ELSE
  nope
ENDIF

编辑:

检查一个点是否在多边形内的算法比我希望在 SQL 查询或存储过程中编写的算法复杂一些,但这是完全可能的。值得注意的是,它以恒定时间运行并且非常轻量级。[对于 poly 中的每个点大约需要 6 个算术运算,并且可能需要 2 或 3 个逻辑运算]

要减少所需的数字计算,您可以简单地编写您的选择以在粗略的边界框中获取点,然后再进一步处理它们:

WHERE
  x BETWEEN MIN(x1,x2,x3,x4) AND MAX(x1,x2,x3,x4)
  AND
  y BETWEEN MIN(y1,y2,y3,y4) AND MAX(y1,y2,y3,y4)

假设对包含 x 和 y 值的列进行了索引,这可能会比简单地进行数学运算使用更少的 CPU 周期,但这是值得商榷的,我倾向于称之为洗牌。

至于圈子,你不可能比

WHERE
  SQRT( POW(ABS($Cx - x),2) + POW(ABS($Cy - y),2) ) < $radius

您太关心这些计算的感知成本,只需编写代码并使其工作即可。这不是执行这种琐碎优化的阶段。

于 2013-04-05T16:09:09.383 回答
1

要添加到@Sammitch 的答案的一件事是,如果您正在查看世界地图上的纬度和经度,计算半正弦距离(球面上的距离计算,因为地球是一个球体;) https://en.wikipedia.org/维基/Haversine_formula )

这是一个用于计算的普通 Javascript 示例:

          function calculateHaversineDistance(lat1x, lon1, lat2x, lon2) {
            var R = 6371; // km
            var dLat = toRad(lat2x-lat1x);
            var dLon = toRad(lon2-lon1);
            var lat1 = toRad(lat1x);
            var lat2 = toRad(lat2x);
            var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                    Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
            var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            return R * c;
          }
          function toRad(x) {
             return x * Math.PI / 180;
          }

编辑->

这是我写的一个php版本:

function toRad($x) {
 return $x * pi() / 180;
}

function calculateHaversineDistance($lat1, $lon1, $lat2, $lon2) {

    $R = 6371; // km
    $dLat = $this->toRad($lat2-$lat1);

    $dLon = $this->toRad($lon2-$lon1);

    $lat1 = $this->toRad($lat1);

    $lat2 = $this->toRad($lat2);


    $a = sin($dLat/2) * sin($dLat/2) +
            sin($dLon/2) * sin($dLon/2) * cos($lat1) * cos($lat2);

    $c = 2 * atan2(sqrt($a), sqrt(1-$a));

    return $R * $c;
}
于 2017-02-07T10:08:28.813 回答