【问题标题】:Area and perimeter of a figure made out of overlapping circles由重叠圆圈组成的图形的面积和周长
【发布时间】:2013-12-09 12:32:33
【问题描述】:

我计划用 python 编写这段代码,但这更像是一个一般的算法设计问题,而不是与任何特定语言有关的问题。我正在编写代码来模拟混合火箭发动机,长话短说,问题涉及找到由许多(可能数千个)重叠圆圈组成的图形的周长和面积。

我在 stackexchange 上看到了这个:

Combined area of overlapping circles

除了我还需要找到周长。该线程中有人提到了蒙特卡洛(随机点猜测)方法,但它可以用来找到周长和面积吗?

提前致谢。

【问题讨论】:

  • 面积的随机抽样方法效果很好,因为您只关心点进出形状的比例。同样的事情对周长不起作用,因为太少的点会恰好落在它上面,并且“周长的面积”没有意义。我认为您必须根据重叠点计算出周边弧的长度。
  • math.stackexchange.com 是您的网站!
  • 你看到this的问题了吗?它可能会为您指明正确的方向。

标签: python math geometry


【解决方案1】:

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

取 c1 并与其他圆相交。为 c1 初始化一个空的圆形扇区列表。

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

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

如果交点是两点,则将c1的不属于其他圆的扇区加入c1的圆扇区列表中。

c1的有效轮廓,是c1的扇区列表中所有扇区的交集长度。这种部门的交集可以由各种不相交的部门组成。

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

【讨论】:

  • 我正在做一个实现,但我的数学已经有点生疏了,所以可能需要一段时间。
  • 实施完毕,请看我的其他回答。
【解决方案2】:

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

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

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偷来的两个圆的交点计算公式。

【讨论】:

    猜你喜欢
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 2021-09-19
    • 2014-05-31
    • 1970-01-01
    • 2022-12-17
    • 1970-01-01
    相关资源
    最近更新 更多