Geometry 计算由一个圆重叠的多个正方形面积的分数

Geometry 计算由一个圆重叠的多个正方形面积的分数,geometry,Geometry,这是一个基于编程问题的几何问题。基本上,我有一个MySQL数据库,其中充满了纬度和经度点,彼此间隔1公里,对应于每个点周围平方公里范围内的人口。然后我想知道每个网格的相对分数,这些网格被一个任意大小的圆圈所占据,这个圆圈与这些网格重叠,这样我就可以计算出大概有多少人生活在一个给定的圆圈内 下面是一个问题形式的实际示例(距离不按比例): 我感兴趣的是了解X点半径范围内的人口。我的数据库计算出,a点和B点的条目与X点足够接近,因此相关。本例中的A点类似于40.7458,-74.0375,B点类似于

这是一个基于编程问题的几何问题。基本上,我有一个MySQL数据库,其中充满了纬度和经度点,彼此间隔1公里,对应于每个点周围平方公里范围内的人口。然后我想知道每个网格的相对分数,这些网格被一个任意大小的圆圈所占据,这个圆圈与这些网格重叠,这样我就可以计算出大概有多少人生活在一个给定的圆圈内

下面是一个问题形式的实际示例(距离不按比例):

我感兴趣的是了解X点半径范围内的人口。我的数据库计算出,a点和B点的条目与X点足够接近,因此相关。本例中的A点类似于40.7458,-74.0375,B点类似于40.7458,-74.0292。从A和B到其栅格边缘的每条绿线表示0.5公里,因此围绕A和B的灰色圆圈分别表示1公里^2

点X位于大约40.744,-74.032处,半径(紫色)为0.05公里

现在,我可以使用地理三角函数轻松计算显示的红线。所以我知道AX线大约是.504公里,BX线的距离大约是.309公里,不管我得到什么

所以我的问题是:计算网格a的分数和网格B的分数的可靠方法是什么?网格B的分数被X周围的紫色圆圈占据

最终,我将计算人口总数并乘以这个分数。所以在这个例子中,1公里2的网格对应9561人,B的网格对应10763人。因此,如果我知道(只是假设)X周围的半径覆盖了A面积的1%和B面积的3%,我可以通过将A和B的总体乘以它们各自的分数并求和,对该圆覆盖的总人口做出合理的背面估计

我只使用了上面的两个正方形,但是根据半径的大小(可以是任意的),可能会有很多可能的正方形,就像这样,这使它成为一个更普遍的问题:

在某些情况下,很容易计算出所讨论的方格线100%被半径包围,这在原则上相当容易(例如,如果AX之间的距离小于X周围的半径,我知道我不需要做任何进一步的数学计算)

现在,确定哪些点在圆的范围内是很容易的。但我有点执着于找出它们对应区域的分数


感谢您的帮助。

通过足够的分类(如下图所示),所有计算都可以简化为原始计算,即提供图像中所示橙色区域的角度区域的计算

如上所示,当
y0>0
时,无论
x0
是正还是负,橙色区域都可以精确计算为
sqrt(r^2-y^2)
减去矩形区域
(x1-x0)*(y1-y0)的
x0
x1
的积分.
积分有一个众所周知的闭合表达式,因此无需使用任何数值算法进行计算

圆和正方形之间的其他交点可以减少为矩形和直角形状的组合,如上面用橙色绘制的那样。例如,下图中由水平和垂直橙色光线分隔的交点可以通过将红色矩形的面积加上两个角形(蓝色和绿色)来表示

蓝色区域是直接应用上面确定的基本情况的结果(下面的矩形折叠为零)。绿色区域也可以用同样的方法测量,一旦负
y
坐标被其绝对值替换(另一个
y
0

运用这些观点,我们可以列举所有的案例。基本上,应该考虑的情况下,只有一个,两个,三个或四个角落的广场躺在圆圈内,而其余的(如果有的话)落在外面。枚举本身就是一个问题,但至少在理论上可以通过考虑相对较少的“典型”配置来解决

对于如上所述列举的每种情况,必须计算一些矩形和角度区域上的分解,并将部分相加(或减去),如上述三色示例所示。每个零件的面积将减少到矩形或原始角度区域


要将这条攻击线转化为有效的算法,需要做大量的工作。更深层次的分析可以为如何最小化“典型”配置的数量提供一些启示。如果不是,我认为要考虑的组合数量,无论多么大,都应该是可管理的。 如果你的问题得到了一个近似的答案,那么你可以使用另一种编程简单得多的技术。这个问题的整个思想简化为计算正方形和圆形相交的面积。我没有在我的另一个答案中解释这一点,但是找到可能拦截圆的正方形应该不是问题,否则,让我们知道

计算交叉点的近似面积的想法非常简单。在正方形中随机生成足够多的点,并检查其中有多少点属于圆。圆中点的数量与正方形中随机点的总数之间的比率将给出交点相对于正方形面积的比例

现在,假设你必须对围绕圆的所有正方形重复相同的程序(即,正方形w)
//$p is an array of latitude, longitude, value, and distance from the centerpoint 
//$cx,$cy are the lat/lon of the center point, $cr is the radius of the circle
//$pdist is the distance from each node to its edge (in this case, .5 km, since it is a 1km x 1km grid)

function sum_circle($p, $cx, $cy, $cr, $pdist) {
    $total = 0; //initialize the total
    $hyp = sqrt(($pdist*$pdist)+($pdist*$pdist)); //hypotenuse of distance

    for($i=0; $i<count($p); $i++) { //cycle over all points
        $px = $p[$i][0];    //x value of point
        $py = $p[$i][1];    //y value of point
        $pv = $p[$i][2];    //associated value of point (e.g. population)
        $dist = $p[$i][3];  //calculated distance of point coordinate to centerpoint

        //first, the easy case — items that are well outside the maximum distance
        if($dist>$cr+$hyp) { //if the distance is greater than circle radius plus the hypoteneuse
            $per = 0; //then use 0% of its associated value
        } else if($dist+$hyp<=$cr) { //other easy case - completely inside circle (distance + hypotenuse <= radius)
            $per = 1; //then use 100% of its associated value
        } else { //the edge cases
            $mx = ($cx-$px); $my = ($cy-$py); //calculate the angle of the difference
            $theta = abs(rad2deg(atan2($my,$mx)));
            $theta = abs((($theta + 89) % 90 + 90) % 90 - 89); //reduce it to a positive degree between 0 and 90
            $tf = abs(1-($theta/45)); //this basically makes it so that if the angle is close to 45, it returns 0, 
                                      //if it is close to 0 or 90, it returns 1
            $hyp_adjust = ($hyp*(1-$tf)+($pdist*$tf)); //now we create a mixed value that is weighted by whether the
                                                        //hypotenuse or the distance between cells should be used                                                   

            $per = ($cr-$dist+$hyp_adjust)/100; //lastly, we use the above numbers to estimate what percentage of 
                                                //the square associated with the centerpoint is covered
            if($per>1) $per = 1; //normalize for over 100% or under 0%
            if($per<0) $per = 0; 
        }
        $total+=$per*$pv;   //add the value multiplied by the percentage to the total
    }  
    return $total;
}