繁体   English   中英

查找两个 CGPoints 之间的点

[英]Find points between two CGPoints

试图找到起点和终点之间最近的点。

点阵:

let pointsArray = [(10.0, 10.0), (70.0, 10.0), (10.0, 200.0), (70.0, 200.0), (73.0, 10.0), (133.0, 10.0), (73.0, 200.0), (133.0, 200.0), (135.5, 10.0), (195.5, 10.0), (135.5, 200.0), (195.5, 200.0), (198.5, 10.0), (258.5, 10.0), (198.5, 200.0), (258.5, 200.0), (261.5, 10.0), (321.5, 10.0), (261.5, 200.0), (321.5, 200.0), (324.0, 10.0), (384.0, 10.0), (324.0, 200.0), (384.0, 200.0), (387.0, 10.0), (447.0, 10.0), (387.0, 200.0), (447.0, 200.0), (450.0, 10.0), (510.0, 10.0), (450.0, 200.0), (510.0, 200.0), (512.5, 10.0), (572.5, 10.0), (512.5, 200.0), (572.5, 200.0), (575.5, 10.0), (635.5, 10.0), (575.5, 200.0), (635.5, 200.0), (638.5, 10.0), (698.5, 10.0), (638.5, 200.0), (698.5, 200.0), (701.0, 10.0), (761.0, 10.0), (701.0, 200.0), (761.0, 200.0), (764.0, 10.0), (824.0, 10.0), (764.0, 200.0), (824.0, 200.0), (10.0, 390.0), (70.0, 390.0), (73.0, 390.0), (133.0, 390.0), (135.5, 390.0), (195.5, 390.0), (198.5, 390.0), (258.5, 390.0), (261.5, 390.0), (321.5, 390.0), (324.0, 390.0), (384.0, 390.0), (387.0, 390.0), (447.0, 390.0), (450.0, 390.0), (510.0, 390.0), (512.5, 390.0), (572.5, 390.0), (575.5, 390.0), (635.5, 390.0), (638.5, 390.0), (698.5, 390.0), (701.0, 390.0), (761.0, 390.0), (764.0, 390.0), (824.0, 390.0), (10.0, 580.0), (70.0, 580.0), (73.0, 580.0), (133.0, 580.0), (135.5, 580.0), (195.5, 580.0), (198.5, 580.0), (258.5, 580.0)]

let startPoint = CGPoint(x: 80, y: 20)
let endPoint = CGPoint(x: 170, y: 440)

在这里,我试图从现有的点数组中找到起点和终点之间的点。

使用以下从特定点开始的延伸距离,但我无法仅获得 startPoint 和 Endpoint 之间的特定点

extension CGPoint {
    func distance(to point: CGPoint) -> CGFloat {
        return sqrt(pow(x - point.x, 2) + pow(y - point.y, 2))
    }
}

这绝不是唯一的解决方案,但这是我会采取的一种方法。

1. 从数组中检索有效点

我们只想从位于起点和终点之间的数组中获取有效点。 所以为了形象化它,我假设:

CGPoint 定义一个区域,在 2 个点之间最近

我假设

  • 开始 x 和开始 y 将是 <= 结束 x 和结束 y。
  • 起点和终点可以是一条直线
  • 起点和终点可以是同一个点
  • 但 end 不能在 start 的下方或左侧

因此,为了支持这一点,我添加到您的 CGPoint 扩展中以检查该点是否存在于该区域中

extension CGPoint
{
    func distance(to point: CGPoint) -> CGFloat
    {
        return sqrt(pow(x - point.x, 2) + pow(y - point.y, 2))
    }
    
    
    /// Checks if the current point exists in a region. The x and y coordinate of
    /// `regionStart` has  to be less than or equal to `regionEnd` for a
    /// valid check to occur.
    /// - Parameters:
    ///   - regionStart: The bottom left of the region
    ///   - regionEnd: The top right of the region
    /// - Returns: True if the current point falls within the region
    func doesExistInRegion(regionStart: CGPoint, regionEnd: CGPoint) -> Bool
    {
        // Check if we have an invalid region
        if regionStart.x > regionEnd.x || regionStart.y > regionEnd.y
        {
            return false
        }
        
        // Check if the current point is outside the region
        if x < regionStart.x ||
            y < regionStart.y ||
            x > regionEnd.x ||
            y > regionEnd.y
        {
            return false
        }
        
        // The point is within the region
        return true
    }
}

然后我使用这样的扩展名仅提取有效点:

let pointsArray = [(10.0, 10.0), (70.0, 10.0), (10.0, 200.0), (70.0, 200.0), (73.0, 10.0), (133.0, 10.0), (73.0, 200.0), (133.0, 200.0), (135.5, 10.0), (195.5, 10.0), (135.5, 200.0), (195.5, 200.0), (198.5, 10.0), (258.5, 10.0), (198.5, 200.0), (258.5, 200.0), (261.5, 10.0), (321.5, 10.0), (261.5, 200.0), (321.5, 200.0), (324.0, 10.0), (384.0, 10.0), (324.0, 200.0), (384.0, 200.0), (387.0, 10.0), (447.0, 10.0), (387.0, 200.0), (447.0, 200.0), (450.0, 10.0), (510.0, 10.0), (450.0, 200.0), (510.0, 200.0), (512.5, 10.0), (572.5, 10.0), (512.5, 200.0), (572.5, 200.0), (575.5, 10.0), (635.5, 10.0), (575.5, 200.0), (635.5, 200.0), (638.5, 10.0), (698.5, 10.0), (638.5, 200.0), (698.5, 200.0), (701.0, 10.0), (761.0, 10.0), (701.0, 200.0), (761.0, 200.0), (764.0, 10.0), (824.0, 10.0), (764.0, 200.0), (824.0, 200.0), (10.0, 390.0), (70.0, 390.0), (73.0, 390.0), (133.0, 390.0), (135.5, 390.0), (195.5, 390.0), (198.5, 390.0), (258.5, 390.0), (261.5, 390.0), (321.5, 390.0), (324.0, 390.0), (384.0, 390.0), (387.0, 390.0), (447.0, 390.0), (450.0, 390.0), (510.0, 390.0), (512.5, 390.0), (572.5, 390.0), (575.5, 390.0), (635.5, 390.0), (638.5, 390.0), (698.5, 390.0), (701.0, 390.0), (761.0, 390.0), (764.0, 390.0), (824.0, 390.0), (10.0, 580.0), (70.0, 580.0), (73.0, 580.0), (133.0, 580.0), (135.5, 580.0), (195.5, 580.0), (198.5, 580.0), (258.5, 580.0)]

let startPoint = CGPoint(x: 80, y: 20)
let endPoint = CGPoint(x: 170, y: 440)

let validPoints = extractValidPoints()

private func extractValidPoints() -> [CGPoint]
{
    var validPoints: [CGPoint] = []
    
    for point in pointsArray
    {
        let coordinate = CGPoint(x: point.0, y: point.1)
        
        if coordinate.doesExistInRegion(regionStart: startPoint, regionEnd: endPoint)
        {
            validPoints.append(coordinate)
        }
    }
    
    return validPoints
}

2.找到对之间的最短距离

从上面的数组中,我得到了该区域内的 4 个有效坐标,它们存储在validPoints数组中:

(133.0, 200.0)
(135.5, 200.0)
(133.0, 390.0)
(135.5, 390.0)

现在我们可以遍历这些点来获得距离。 首先,我创建了一个方便的结构来更好地组织事物

struct PointPair: Comparable, Hashable
{
    private(set) var startPoint = CGPoint.zero
    private(set) var endPoint = CGPoint.zero
    private(set) var distance = CGFloat.zero
    
    init(withStartPoint start: CGPoint, andEndPoint end: CGPoint)
    {
        startPoint = start
        endPoint = end
        distance = startPoint.distance(to: endPoint)
        
        // Just for convenience
        display()
    }
    
    func display()
    {
        print("Distance (\(startPoint.x), \(startPoint.y)) and (\(endPoint.x), \(endPoint.y)): \(distance)")
    }
    
    // Needed to implement this so that we conform to Comparable and
    // can compare 2 points
    static func < (lhs: PointPair, rhs: PointPair) -> Bool
    {
        return lhs.distance < rhs.distance
    }
    
    // Need to implement this to conform to Hashable so we can insert a PointPair
    // into dictionaries and data strcutures that work with Hashable types
    func hash(into hasher: inout Hasher)
    {
        hasher.combine(startPoint.x)
        hasher.combine(startPoint.y)
        hasher.combine(endPoint.x)
        hasher.combine(endPoint.y)
    }
}

现在我可以遍历validPoints数组并检查这样的对:

if let nearestPoint = retrieveClosestPairUsingSort(fromPoints: validPoints)
{
    print("The nearest pair using sort O(n log n) is")
    print(nearestPoint.display())
}

private func retrieveClosestPairUsingSort(fromPoints points: [CGPoint]) -> PointPair?
{
    var pairs: [PointPair] = []
    
    // Loop through all the points
    for index in 0 ..< points.count
    {
        for secondIndex in index + 1 ..< points.count
        {
            let pointPair = PointPair(withStartPoint: points[index],
                                      andEndPoint: points[secondIndex])
            
            pairs.append(pointPair)
        }
    }
    
    return pairs.sorted().first
}

为此的output如下:

Distance (133.0, 200.0) and (135.5, 200.0): 2.5
Distance (133.0, 200.0) and (133.0, 390.0): 190.0
Distance (133.0, 200.0) and (135.5, 390.0): 190.01644665659865
Distance (135.5, 200.0) and (133.0, 390.0): 190.01644665659865
Distance (135.5, 200.0) and (135.5, 390.0): 190.0
Distance (133.0, 390.0) and (135.5, 390.0): 2.5
The nearest pair using sort O(n log n) is
Distance (133.0, 200.0) and (135.5, 200.0): 2.5

3. 更进一步

如果您有大量过滤点,您可以考虑将坐标放入最小堆中以检索 O(n) 中最近的对 - 我在这里有一个实现

if let nearestPoint = retrieveClosestPairUsingHeap(fromPoints: validPoints)
{
    print("The nearest pair using heap O(n) is")
    print(nearestPoint.display())
}

private func retrieveClosestPairUsingHeap(fromPoints points: [CGPoint]) -> PointPair?
{
    // Instantiate a min heap so the root will be the closest pair
    var heap = Heap<PointPair>(withProperty: .min)
    
    // Loop through all the points
    for index in 0 ..< points.count
    {
        for secondIndex in index + 1 ..< points.count
        {
            let pointPair = PointPair(withStartPoint: points[index],
                                      andEndPoint: points[secondIndex])
            
            heap.insert(pointPair)
        }
    }
    
    return heap.peek()
}

这也给出了相同的 output:

Distance (133.0, 200.0) and (135.5, 200.0): 2.5
Distance (133.0, 200.0) and (133.0, 390.0): 190.0
Distance (133.0, 200.0) and (135.5, 390.0): 190.01644665659865
Distance (135.5, 200.0) and (133.0, 390.0): 190.01644665659865
Distance (135.5, 200.0) and (135.5, 390.0): 190.0
Distance (133.0, 390.0) and (135.5, 390.0): 2.5
The nearest pair using heap O(n) is
Distance (133.0, 390.0) and (135.5, 390.0): 2.5

我创建了一个示例,所有这些代码作为一个简单的控制台应用程序一起工作以进行测试 -你可以从这里获取它。

我希望这回答了你的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM