检测多边形与n边的自相交?

时间:2016-12-05 21:50:04

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

我使用Google Maps SDK允许用户通过点击在地图上绘制多边形。一切运作完美是用户在路径后绘制多边形并在该路径上继续而不越过线。如果发生这种情况,则会产生以下结果:Done properly Example。然而。如果用户要出错并跨越或改变其“点击”路径的方向,则会发生这种情况:Error Example 我需要  A)提醒用户他们已经创建了无效的多边形,并且必须撤消该操作,或者 B)校正多边形形状以形成完整的多边形。

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

我已经做过研究并找到了检测线交叉的算法和公式,但是我还没有在Swift中找到任何一个解决方案,以识别多边形是否基于点自相交(在这种情况下,纬度和经度) )。我不需要知道这一点,对于这个问题,“这个多边形是否会自相交?”这个问题是正确的还是错误的?多边形通常少于20个边。

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

2 个答案:

答案 0 :(得分: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 3更新。

答案 1 :(得分:0)

这似乎对我需要的东西很有效。摘自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)")


                }
            }
        }
    }