由重叠圆圈组成的图形的面积和周长

时间:2013-11-24 22:30:56

标签: python math geometry

我计划在python中编写这个代码,但这比一个特定语言更常见的算法设计问题。我正在编写代码来模拟混合火箭发动机,长话短说,问题在于找到由许多(可能是数千个)重叠圆组成的图形的周边和区域。

我在stackexchange上看到了这个:

Combined area of overlapping circles

除了我还需要找到周边。该线程中的某个人提到蒙特卡罗(随机点猜测)方法,但是可以用它来查找周长以及区域吗?

提前致谢。

2 个答案:

答案 0 :(得分:1)

假设你有圆圈c1,c2,...,cn。

取c1并将其与彼此相交。初始化c1的空扇区列表。

如果交点是零点或一点而c1在另一个圆之外,则在列表中添加一个360度扇区。

如果交点为零点或一点且c1在另一个圆内,则c1的有效轮廓为0,停止处理轮廓为0的c1并取下一个圆。

如果交点是两点,则将c1的扇区(不在另一个圆圈中)添加到c1的圆扇区列表中。

c1的有效轮廓是c1扇区列表中所有扇区的交叉长度。这个扇区的交叉点可以包含各种不相交的扇区。

冲洗并重复所有圆圈,然后总结结果值。

答案 1 :(得分:1)

我正在添加第二个答案而不是扩展第一个答案,因为我非常肯定其他答案是正确的,但我不确定这个答案是否正确。我做了一些简单的测试,似乎有效,但请指出我的错误。

这基本上是我之前所说的快速实施:

from math import atan2, pi

def intersectLine (a, b):
    s0, e0, s1, e1 = a [0], a [1], b [0], b [1]
    s = max (s0, s1)
    e = min (e0, e1)
    if e <= s: return (0, 0)
    return (s, e)

class SectorSet:
    def __init__ (self, sectors):
        self.sectors = sectors [:]

    def __repr__ (self):
        return repr (self.sectors)

    def __iadd__ (self, other):
        acc = []
        for mine in self.sectors:
            for others in other.sectors:
                acc.append (intersectLine (mine, others) )
        self.sectors = [x for x in acc if x [0] != x [1] ]
        return self

class Circle:
    CONTAINS = 0
    CONTAINED = 1
    DISJOINT = 2
    INTERSECT = 3

    def __init__ (self, x, y, r):
        self.x = float (x)
        self.y = float (y)
        self.r = float (r)

    def intersect (self, other):
        a, b, c, d, r0, r1 = self.x, self.y, other.x, other.y, self.r, other.r
        r0sq, r1sq = r0 ** 2, r1 ** 2
        Dsq = (c - a) ** 2 + (d - b) ** 2
        D = Dsq ** .5
        if D >= r0 + r1:
            return Circle.DISJOINT, None, None
        if D <= abs (r0 - r1):
            return Circle.CONTAINED if r0 < r1 else Circle.CONTAINS, None, None
        dd = .25 * ( (D + r0 + r1) * (D + r0 - r1) * (D - r0 + r1) * (-D + r0 + r1) ) ** .5
        x = (a + c) / 2. + (c - a) * (r0sq - r1sq) / 2. / Dsq
        x1 = x + 2 * (b - d) / Dsq * dd
        x2 = x - 2 * (b - d) / Dsq * dd
        y = (b + d) / 2. + (d - b) * (r0sq - r1sq) / 2. / Dsq
        y1 = y - 2 * (a - c) / Dsq * dd
        y2 = y + 2 * (a - c) / Dsq * dd
        return Circle.INTERSECT, (x1, y1), (x2, y2)

    def angle (self, point):
        x0, y0, x, y = self.x, self.y, point [0], point [1]
        a = atan2 (y - y0, x - x0) + 1.5 * pi
        if a >= 2 * pi: a -= 2 * pi
        return a / pi * 180

    def sector (self, other):
        typ, i1, i2 = self.intersect (other)
        if typ == Circle.DISJOINT: return SectorSet ( [ (0, 360) ] )
        if typ == Circle.CONTAINS: return SectorSet ( [ (0, 360) ] )
        if typ == Circle.CONTAINED: return SectorSet ( [] )
        a1 = self.angle (i1)
        a2 = self.angle (i2)
        if a1 > a2: return SectorSet ( [ (0, a2), (a1, 360) ] )
        return SectorSet ( [ (a1, a2) ] )

    def outline (self, others):
        sectors = SectorSet ( [ (0, 360) ] )
        for other in others:
            sectors += self.sector (other)
        u = 2 * self.r * pi
        total = 0
        for start, end in sectors.sectors:
            total += (end - start) / 360. * u
        return total

def outline (circles):
    total = 0
    for circle in circles:
        others = [other for other in circles if circle != other]
        total += circle.outline (others)
    return total

a = Circle (0, 0, 2)
b = Circle (-2, -1, 1)
c = Circle (2, -1, 1)
d = Circle (0, 2, 1)
print (outline ( [a, b, c, d] ) )

计算从here无耻地偷走的两个圆的交点的公式。