使用mysql在Rectangle或Circle中查找点

时间:2013-04-05 15:53:52

标签: php mysql geometry cartesian

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

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

矩形的已知数据 - 协调所有四点 圆的已知数据 -Co-纵坐标为中心和半径。

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

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

2 个答案:

答案 0 :(得分: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查询或存储过程中编写的算法要复杂一些,但这完全有可能。值得注意的是,它在恒定时间运行并且非常轻量级。 [需要大约6个算术运算,并且对于poly中的每个点可能需要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周期,但这是有争议的,我倾向于把它称为洗涤。 / p>

至于圆圈,你不可能比

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

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

答案 1 :(得分:0)

要添加到@ Sammitch的答案,有一点是,如果您在世界地图上查看纬度和经度,则计算半长距离(球面上的距离计算,因为地球是球体;)https://en.wikipedia.org/wiki/Haversine_formula)< / p>

这是一个用于计算的香草Javascript示例:

subject = subject.doOnUnsubscribe(() -> L.LOGD(TAG, "Unsubcribed from subject!"));

编辑 - &GT;

这是我写的php版本:

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