【问题标题】:Finding Points in a Rectangle or Circle with mysql使用 mysql 在矩形或圆形中查找点
【发布时间】:2013-03-28 03:02:08
【问题描述】:

我有一个 mysql 数据库表,其中包含一个列表点及其坐标 (x,y)

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

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

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

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

【问题讨论】:

  • 我不想调用所有点并分析每个点,因为点列表很广泛,是否可以通过其他方式完成?

标签: php mysql geometry cartesian


【解决方案1】:

一个矩形可以由代表对角的两个点来定义,例如: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 查询或存储过程中编写的算法复杂一些,但这是完全可能的。值得注意的是,它以恒定时间运行并且非常轻量级。 [对于多边形中的每个点大约需要 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

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

【讨论】:

  • 我知道公式,但我需要知道的是,我可以编写存储过程或查询,通过它传递已知参数并获取落在该区域内的点列表。用php+mysql可以吗。
  • 他的矩形显然是旋转的,所以你的 inRectangle 代码不起作用。必须旋转它使其与 Y 轴垂直,这将是非常痛苦的。
  • 我不想调用所有点并分析每个点,因为点列表很广泛。
  • @Vishak 很好,除非您想到的圆形和矩形总是相同,您可以预先计算并存储结果,否则无法做到神奇地知道。您可以通过过滤掉距离任何测试点超过 X 个单位的点来减少实际处理的点数,其中 X 足够大,但这可能需要与实际处理它们一样多的数学运算,这不是那么多。数学是计算机的全部工作,他们非常擅长。
  • 谢谢。编辑有帮助。我也是这么想的。我计划从矩形顶点中获取最大 x、最大 y、最小 x 和最小 y,以创建另一个围绕所需矩形的矩形,并获取主矩形内的所有点,然后仅在这些返回的点上运行该函数,从而消除休息。通过具有 max x、min x、min y 和 maxy 四个条件的查询,获取主矩形中的点将非常简单。对于一个圆圈,我想以同样的方式围绕它创建一个正方形。
【解决方案2】:

要添加到@Sammitch 的答案的一件事是,如果您在世界地图上查看纬度和经度,则计算半正弦距离(球面上的距离计算,因为地球是一个球体;)https://en.wikipedia.org/wiki/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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-07
    • 2012-03-28
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多