2017-02-09 40 views
1

給定CGRect並用2創建的線CGPoint是否有找到直線與直線相交的座標的方法?修剪CGRect中的直線(2 CGPoint)

enter image description here

從前面的圖像:我想要做到的,是替代點的矩形之外與相交的矩形邊框的紅點。

簡而言之,我正在尋找一種方法來修剪矩形內的一條線。

這是一個數學問題,但我想知道如何使用基礎解決這個問題,如果可能的話。

以下最新評論:似乎Core Graphics在這個過程中不能真正有用。我可以在Swift中轉換的任何其他提示或公式?

+0

你嘗試過什麼?你做了什麼研究?必須有無數的這樣做的例子。找到一些,做一些嘗試翻譯成你最喜歡的語言。 [編輯]你的問題到目前爲止你所嘗試過的。 – rmaddy

+0

其實我是在尋求幫助,因爲我找不到任何類似的東西(和我的問題中詳細說明的一樣),我正在尋求任何利用基礎和核心圖形的解決方案。 – MatterGoal

+1

您可能過度地限制自己,「利用基礎和核心圖形」。沒有具體的功能可以做到這一點。你需要做數學。你當然可以返回'CGPoint',這樣你就可以「利用核心圖形」。但是解決這個問題的方法就是求解一些線性方程組。如果你已經知道如何做到這一點,就完成了。核心圖形在這裏沒有提供任何東西,但有些類型可以使用(並且Foundation沒有真正提供任何對這個問題有用的東西)。您還需要定義如果線與矩形的多個邊相交會發生什麼情況。 –

回答

1

像這樣的東西(隨便測試),基於How do you detect where two line segments intersect?

import CoreGraphics 

let rect = CGRect(x: 10, y: 10, width: 100, height: 100) 

let point1 = CGPoint(x: 200, y: 200) 
let point2 = CGPoint(x: 20, y: 20) 

struct LineSegment { 
    var point1: CGPoint 
    var point2: CGPoint 

    func intersection(with line: LineSegment) -> CGPoint? { 
     // We'll use Gavin's interpretation of LeMothe: 
     // https://stackoverflow.com/a/1968345/97337 

     let p0_x = self.point1.x 
     let p0_y = self.point1.y 
     let p1_x = self.point2.x 
     let p1_y = self.point2.y 

     let p2_x = line.point1.x 
     let p2_y = line.point1.y 
     let p3_x = line.point2.x 
     let p3_y = line.point2.y 

     let s1_x = p1_x - p0_x 
     let s1_y = p1_y - p0_y 
     let s2_x = p3_x - p2_x 
     let s2_y = p3_y - p2_y 

     let denom = (-s2_x * s1_y + s1_x * s2_y) 

     // Make sure the lines aren't parallel 
     guard denom != 0 else { return nil } // parallel 

     let s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y))/denom 
     let t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x))/denom 

     // We've parameterized these lines as "origin + scale*vector" 
     // (s is the "scale" along one line, t is the "scale" along the other. 
     // At scale=0, we're at the origin at scale=1, we're at the terminus. 
     // Make sure we crossed between those. For more on what I mean by 
     // "parameterized" and why we go from 0 to 1, look up Bezier curves. 
     // We're just making a 1-dimentional Bezier here. 
     guard (0...1).contains(s) && (0...1).contains(t) else { return nil } 

     // Collision detected 
     return CGPoint(x: p0_x + (t * s1_x), y: p0_y + (t * s1_y)) 
    } 
} 

extension CGRect {  
    var edges: [LineSegment] { 
     return [ 
      LineSegment(point1: CGPoint(x: minX, y: minY), point2: CGPoint(x: minX, y: maxY)), 
      LineSegment(point1: CGPoint(x: minX, y: minY), point2: CGPoint(x: maxX, y: minY)), 
      LineSegment(point1: CGPoint(x: minX, y: maxY), point2: CGPoint(x: maxX, y: maxY)), 
      LineSegment(point1: CGPoint(x: maxX, y: minY), point2: CGPoint(x: maxX, y: maxY)), 
     ] 
    } 

    func intersection(with line: LineSegment) -> CGPoint? { 

    // Let's be super-simple here and require that one point be in the box and one point be outside, 
    // then we can ignore lots of corner cases 
     guard contains(line.point1) && !contains(line.point2) || 
      contains(line.point2) && !contains(line.point1) else { return nil } 

     // There are four edges. We might intersect with any of them (we know 
     // we intersect with exactly one, based on the previous guard. 
     // We could do a little math and figure out which one it has to be, 
     // but the `if` would be really tedious, so let's just check them all. 
     for edge in edges { 
      if let p = edge.intersection(with: line) { 
       return p 
      } 
     } 

     return nil 
    } 
} 

rect.intersection(with: LineSegment(point1: point1, point2: point2)) 
+0

它似乎與一個單一的交叉口,我試圖弄清楚如何使它的工作也與直線的兩條邊相交的線(我將通過一個完整的檢查明天)。 – MatterGoal

+0

主要問題將是定義你想要的答案。注意'CGRect.intersection'頂部的警戒聲明和註釋。目前它故意遺漏了這種情況。如果你想得到一個半任意交點,只需刪除guard語句。 –

+0

謝謝,這段代碼很完美。 而不是返回的交點,有幾個編輯我要返回一個線被修剪在矩形內: - 我保持守衛,當兩個點都包含在矩形中時返回原始線。 - 然後我選擇所有與行 相交的邊緣 - 根據我定義哪些點與替代計算出的交叉點的邊緣。 我會更新我的問題添加此代碼。 – MatterGoal