【问题标题】:Detect self intersection of a polygon with n sides?检测具有n条边的多边形的自相交?
【发布时间】:2017-04-20 10:06:53
【问题描述】:

我正在使用 Google Maps SDK 允许用户通过点击在地图上绘制多边形。一切都很完美,用户要沿着一条路径绘制一个多边形,并在该路径上继续而不跨越线。如果发生这种情况,则会产生以下结果:。然而。如果用户犯了错误并跨越或改变他们的“点击”路径的方向,就会发生这种情况: 我需要要么 A) 提醒用户他们创建了一个无效的多边形,并且必须撤消该操作,或者 B) 修正多边形形状,形成一个完整的多边形。

根据我所做的研究,选项 A 似乎更加可行和简单,因为选项 B 需要重新排列多边形点的路径。

我已经完成研究并找到了检测线交点的算法和公式,但我还没有在 Swift 中找到任何解决方案来识别多边形是否基于点(在本例中为纬度和经度)自相交)。我不需要知道重点,只是对“这个多边形是否自相交”这个问题的真假。多边形的边通常少于 20 条。

也许 GoogleMaps SDK 内置了一个解决方案,但我还没有找到它。另外,我知道已经有针对此类问题的算法,我只是在将它们实现到 Swift 2 或 3 中时遇到了麻烦。感谢任何帮助,谢谢!

【问题讨论】:

  • 既然您已经找到了要使用的算法,那么您的实现有什么问题?
  • This answer 展示了如何在 swift 中进行线-线交叉。当用户添加新行时,只需测试新行与所有现有行的交集即可。
  • 这很简单。检查所有未连接的边(边),看看它们是否intersect
  • 你搞定了吗?我没有回复我的答案,因为我太忙了,它实际上会很大而且我不熟悉 google maps sdk,但可以将它编码为核心图形..
  • 是的,该解决方案看起来很实用。我发布了我的答案。它不会纠正多边形,但会提醒用户它是自相交的。

标签: swift algorithm google-maps polygon google-maps-sdk-ios


【解决方案1】:

我猜你是想在乌鸦飞过的时候想出最快的方式从一个点到另一个点。您可能还想考虑道路方向,我不会在这里。

这两种选择都是可能的。添加新行并确定它们是否已越过时,迭代每条现有行很容易。但是您的用户肯定不会被告知他们搞砸了,您的应用程序应该为他们修复它。这就是有趣的地方。

我确信存在一些算法可以找到包含所有点的最小多边形,但我没有查找它们,因为那里的乐趣在哪里。

我会这样做。在伪代码中:

if (line has intersected existing line)

find mean point (sum x sum y / n)

find nearest point to centre by:
taking min of: points.map(sqrt((x - centrex)^2 + (y-centrey)^2))

from the line between centre and nearest point, determine angle to every other line.

points.remove(nearest)

angles = points.map(cosine law(nearest to centre, centre, this point)) 
<- make sure to check if it crossed pi, at which point you must add pi.

sort angles so minimum is first.

starting at nearest point, add line to next point in the array of minimal angle points

对不起,我没有把它放到 swift 中。我明天会用适当的 Swift 3 更新。

【讨论】:

    【解决方案2】:

    这似乎很适合我的需要。来自Rob's answer here

     func intersectionBetweenSegmentsCL(p0: CLLocationCoordinate2D, _ p1: CLLocationCoordinate2D, _ p2: CLLocationCoordinate2D, _ p3: CLLocationCoordinate2D) -> CLLocationCoordinate2D? {
        var denominator = (p3.longitude - p2.longitude) * (p1.latitude - p0.latitude) - (p3.latitude - p2.latitude) * (p1.longitude - p0.longitude)
        var ua = (p3.latitude - p2.latitude) * (p0.longitude - p2.longitude) - (p3.longitude - p2.longitude) * (p0.latitude - p2.latitude)
        var ub = (p1.latitude - p0.latitude) * (p0.longitude - p2.longitude) - (p1.longitude - p0.longitude) * (p0.latitude - p2.latitude)
    
        if (denominator < 0) {
            ua = -ua; ub = -ub; denominator = -denominator
        }
    
        if ua >= 0.0 && ua <= denominator && ub >= 0.0 && ub <= denominator && denominator != 0 {
            print("INTERSECT")
            return CLLocationCoordinate2D(latitude: p0.latitude + ua / denominator * (p1.latitude - p0.latitude), longitude: p0.longitude + ua / denominator * (p1.longitude - p0.longitude))
        }
        return nil
    }
    

    然后我是这样实现的:

     if coordArray.count > 2 {
            let n = coordArray.count - 1
    
            for i in 1 ..< n {
                for j in 0 ..< i-1 {
                    if let intersection = intersectionBetweenSegmentsCL(coordArray[i], coordArray[i+1], coordArray[j], coordArray[j+1]) {
                        // do whatever you want with `intersection`
    
                        print("Error: Intersection @ \(intersection)")
    
    
                    }
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2013-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-20
      • 2016-05-19
      • 2016-11-18
      • 2011-10-31
      • 2015-10-22
      相关资源
      最近更新 更多