【问题标题】:How to tell if a circle is encompassed by several others如何判断一个圆圈是否被其他几个圆圈包围
【发布时间】:2015-10-08 17:12:02
【问题描述】:

我正在构建一个与 Google Places API 交互的程序,以识别美国县内给定类型的所有机构。谷歌接受半径形式的搜索——所以为了覆盖整个区域,我正在按顺序构建我的搜索半径。但是,此算法会创建很多我想过滤掉的重叠圆圈。所以:

给定一个圆列表,每个圆的中心和半径,我如何判断一个圆是否被其他圆的任意组合完全覆盖?

我已经可以判断一个圆圈是否被另一个圆圈包围 - 我的问题是它们中的很多都被其他几个圆圈包围。

有人询问我现有的代码——我目前有测试一个圆圈是否与另一个圆圈完全重叠的代码——而不是它们的组合。但这就是我所拥有的。您可以看到,如果它与其他 20 个圆圈重叠,我排除了当前问题的近似值,此时它可能已包含在内:

def radiusIsInsidePreviousQuery(self, testQuery):
    newSearchCoordinates = (testQuery['center']['lat'], testQuery['center']['lng'])
    alreadyBeenSearched = False

    numberOfIntersectingCircles = 0

    for queryNumber in self.results.keys():
        previousQuery = self.results[queryNumber]
        previousSearchCoordinates = (previousQuery['center']['lat'], 
                                     previousQuery['center']['lng'])

        centroidDistance = VincentyDistance(newSearchCoordinates, 
                                            previousSearchCoordinates)

        centroidDistanceMeters = centroidDistance.meters
        newQueryRadius = testQuery['radius']
        fullSearchDistance = centroidDistanceMeters + newQueryRadius

        #If the full search distance (the sum of the distance between
        #the two searches' centroids and the new search's radius) is less
        #than the previous search's radius, then the new search is encompassed
        #entirely by the old search.
        previousQueryRadius = previousQuery['radius']
        if fullSearchDistance <= previousQueryRadius:
            print "Search area encompassed"
            alreadyBeenSearched = True
        elif centroidDistanceMeters < newQueryRadius + previousQueryRadius:
            numberOfIntersectingCircles += 1
        elif self.queriesAreEqual(testQuery, previousQuery):
            print "found duplicate"
            alreadyBeenSearched = True   

    #If it intersects with 20 other circles, it's not doing any more good.
    if numberOfIntersectingCircles > 20:
        alreadyBeenSearched = True    

    return alreadyBeenSearched 

【问题讨论】:

  • 请贴出你目前开发的代码
  • 刚刚做了,谢谢@il_raffa。当前问题的进展并不大。

标签: python geometry geopy


【解决方案1】:

您可以将此作为磁盘联合问题来解决。此问题与Alpha shapes 的理论有关,可以通过构造weighted (additive) Voronoi diagram 来解决,对于n 磁盘可以及时执行O(n Log(n))

您可以按如下方式使用此构造:计算列表中磁盘的并集。然后将单个磁盘添加到此联合中。如果没有变化,则包含单个磁盘。

您将不得不使用 CGAL 等高级软件包,因为该算法远非简单。


如果您可以使用近似解决方案并且旨在简化编程,只需以合适的分辨率将磁盘绘制在空白图像中即可。然后检查绘制单个磁盘是否达到新的像素。

这种方法成本很高,因为您需要处理的像素数量等于磁盘的总面积。


混合解决方案也可以作为难度和效率之间的折衷。

选择一个垂直分辨率并用等距的水平线对平面进行交叉影线。它们将沿线段与每个磁盘相交。为每个水平保留一个段列表并在添加新磁盘时执行段的联合是一件容易的事。 (n 段的并集很容易通过对重叠的排序和计数来执行。)

【讨论】:

  • 感谢您的创意!如果我要追求绝对准确性,我肯定会选择你的第一个想法 - 但是,我愿意接受一些近似值,所以我喜欢你的后者,但恐怕我错过了一些术语。您介意详细说明一下垂直分辨率和交叉影线的重要性吗?
  • 平行线。这是一种扫描线方法。
  • 哦,我想我明白了。因此,用交叉影线平行线覆盖平面,并保留一个已被圆圈覆盖的立方体列表。如果新圈子只覆盖以前的圈子,那是多余的吗?
  • 好吧,如果你创建两个平行线平面 - 一个垂直和一个水平 - 你将创建一个由立方体组成的矩阵,对吧?
  • 在第三种方法中,没有正方形,只有线段。只有一个扫描方向,这使得它成为一种有吸引力的解决方案(更快的计算)。
【解决方案2】:

让我们考虑要测试的圆A。

我不知道您的计算需要多精确,但我们假设用 100 个点表示 A 的周长就足够了。

导入数学

#Circle to be tested

Circle_A = (3,2,1)
resolution = 100

circumference_A = []
for t in xrange(resolution):
    step = (2*math.pi)/resolution 
    x = Circle_A[0]
    y = Circle_A[1]
    r = Circle_A[2]
    circumference_A.append((x+(r*math.cos(t*step)),y+(r*math.sin(t*step))))

# Given list of circles (we need to know center and radius of each).
# Put them in a list of tuples like this (x,y,r)

ListOfCircles=[(5,2,2),(2,4,2),(2,2,1),(3,1,1)]

# Test:Check if all the points of circumference A are not < r from each one of the circles in the list.

overlap_count = 0
for p in circumference_A:
    print('testing p:',p)
    for c in ListOfCircles:
        distance = math.sqrt(math.pow(p[0]-c[0],2) + math.pow(p[1]-c[1],2))
        if distance < c[2]:
            overlap_count += 1
            print('overlap found with circle',c)
            break
        else:
            print('distance:',str(distance))
            print('origin:',c)



if overlap_count == resolution:
    print("Circle A is completely overlapped by the ListOfCircles")
else:
    print(str(overlap_count)+" points out of "+ str(resolution) + " overlapped with the composed area")

【讨论】:

  • 我真的很想知道为什么这个答案被否决了。答案准确地解释了 OP 需要知道的内容。 TL;DR : 测试圆周的任何点是否在给定的圆列表的每个区域内。
  • 非常感谢您的帮助!所以,也许我误读了你的代码,如果我是的话,我很抱歉。但是假设您正在测试的圆圈列表恰好都是同一个圆圈的三个实例 - 如果它们的重叠计数之和等于分辨率,这不是说圆圈被完全包围了,即使它只是圆圈的同一部分被多次覆盖,部分仍然暴露在外?
  • 这就是为什么 break 语句很重要。一旦一个点在里面,它就会停止测试它,所以它不会给你误报。您可以按原样运行脚本并开始使用它。 break 语句也使它非常快 => resolution*log(n) 是你正在测试的圈数。它也使用 std 库,仅此而已。
猜你喜欢
  • 1970-01-01
  • 2018-12-15
  • 2021-06-24
  • 1970-01-01
  • 1970-01-01
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 2019-04-25
相关资源
最近更新 更多