2016-09-19 68 views
2

我正試圖在Java中實現描述基於矢量的段交集算法here(最新推出的答案),但是因爲它通常與實現算法一起使用,所以您不能完全理解,所以我一直失敗。如果有人能校對我的代碼並告訴我我做錯了什麼,我將非常感激。段交集實現

boolean intersect(PVector p, PVector r, PVector q, PVector s){ 
    // r x s 
    double rxs = r.x*s.y + r.y*s.x; 
    //(q-p) x r 
    double qpxr = (q.x-p.x)*r.y + (q.y-p.y)*r.x; 

    PVector qp = q.sub(p).copy(); //q - p 
    //case one lines parallel might intersect: 
    if(rxs==0 && qpxr==0){ 
    println("case one: collinear might intersect"); 
    double t0 = qp.dot(r); 
    double t1 = qp.dot(r)/r.dot(r)+(s.dot(r)/r.dot(r)); 
    return max((float)t0 , 0.f) <= min((float)t1, 1.f);//if ranges intersect the segments intersect 
    }else if(rxs==0 && qpxr!=0){ 
    println("case two: parallel no intersect"); 
    return false; 
    }else if(rxs!=0){ 
    println("case three"); 
    double u = qpxr/rxs; 
    double t = (qp.x*r.y + qp.y*r.x)/rxs; 
    if((u>=0 && u<=1) && (t<=1 && t>=0)){ 
     PVector intersect = p.copy(); 
     intersect.add(r.copy().mult((float)t)); 
     point(intersect.x, intersect.y); 
     return true; 
    }else{ 
     println("no intersect"); 
     print(u); 
     print(" "); 
     println(t); 
    } 
    }else{ 
    println("case four no intersect"); 
    return false; 
    } 
    return false; 
} 

另外我試着用手工作一些答案,似乎仍然失敗,所以現在我有點失落。例如:

p=(0;0), r=(10;10) 
q=(10;0), s=(-10;10) 

r x s = 10*10 + (-10*10) = 0這會傳遞到其中假定並行性的第二情況下,即使各段都沒有。

P.S.有沒有辦法讓這段代碼更具可讀性?

+0

在這個問題的答案,加雷思·雷斯定義_「的二維矢量交叉乘積** v **×** w **是** ** ** ** ** ** ** ** ** ** ** ** ** **「**」 。您正在使用** + **。 –

+0

[計算線段之間的交點]可能有重複(http://stackoverflow.com/questions/16314069/calculation-of-intersections-between-line-segments) –

回答

1

有關於topcoder的參考文獻,它描述瞭如何獲得2段相交的地方。如果你只是想知道,如果線相交,你是否A1*B2 - A2*B1 == 0給出:

A1 = y2-y1 B1 = x1-x2

A2 = y4-y3 B2 = x3-x4

了基本的直覺只是被你既然有地步方程段相交爲:

x = (C1*B2 - B1*C2)/(A1*B2 - A2*B1)

y = (A1*C2 - A2*C1)/(A1*B2 - A2*B1)

你不能用0

劃分如果包含該線段的線相交不要在某處的線段的範圍內不包含您檢查類似

boolean inRange(double x1,double y1,double x2,double y2,double x3,double y3){ 
     double dx = Math.abs(x3-x2); 
     double dy = Math.abs(y3-y2); 
     if (Math.abs(x3-x1)+Math.abs(x2-x1)==dx && 
      Math.abs(y3-y1)+Math.abs(y2-y1)==dy){ 
      return true; 
     } 
     return false; 
    } 

所以條件應該看起來像

if (!inRange(...) || (A1*B2 - A2*B1 == 0)) return false; 

如果你想粗略的方式「推導」上述方程xy你從2個線段的方程式開始並求解系統。

A1*x + B1*y = C1 A2*x + B2*y = C2

求解x左側

x = (C1
-B1*y)/A1

塞回權,解決y

A2*((C1
-B1*y)/A1) + B2*y = C2

y*(B2-(A2*B1/A1)) = C2 - (A2*C1/A1)

使方程看起來像

y = (A1*C2 - A2*C1)/(A1*B2-A2*B1)

乘法頂部和餾分的底部由A1

接着再將y回到上面的方程爲x( 「x = (C1
-B1*y)/A1」)

x = (C1/A1) - (B1*A1*C2-B1*A2*C1)/A1*(A1*B2 - A2*B1)

x = ((C1*A1*B2 - B1*A2*C1)-(B1*A1*C2 - B1*A2*C1))/A1*(A1*B2 - A2*B1)

從頂部

x = (C1*A1*B2 - B1*A1*C2)/A1*(A1*B2 - A2*B1)

劃分出A1得到方程中的鏈接給出:

x = (C1*B2 - B1*C2)/(A1*B2 - A2*B1)

1

此外,這裏使用奧拉夫Rabbachin C#版本Paul Bourke's Intersection point of two line segments in 2 dimensions算法的端口:

Line l1 = new Line(new PVector(10,10),new PVector(390,390)); 
Line l2 = new Line(new PVector(10,390),new PVector(390,10)); 

void setup(){ 
    size(400,400); 
    fill(0); 
} 
void draw(){ 
    //draw background and lines 
    background(255); 
    l1.draw(); 
    l2.draw(); 
    text("click and drag",10,15); 
    //check intersections (and draw) 
    PVector intersection = doLinesIntersect(l1,l2); 
    if(intersection != null){ 
    ellipse(intersection.x,intersection.y,15,15); 
    } 
} 

void mouseDragged(){ 
    l1.p1.x = mouseX; 
    l1.p1.y = mouseY; 
} 

class Line{ 
    PVector p1 = new PVector(); 
    PVector p2 = new PVector(); 

    Line(PVector start,PVector end){ 
    p1 = start; 
    p2 = end; 
    } 
    void draw(){ 
    line(p1.x,p1.y,p2.x,p2.y); 
    } 
} 
//port of http://paulbourke.net/geometry/pointlineplane/Helpers.cs 
PVector doLinesIntersect(Line l1, Line l2){ 
    // Denominator for ua and ub are the same, so store this calculation 
    float d = 
     (l2.p2.y - l2.p1.y) * (l1.p2.x - l1.p1.x) 
     - 
     (l2.p2.x - l2.p1.x) * (l1.p2.y - l1.p1.y); 

    //n_a and n_b are calculated as seperate values for readability 
    float n_a = 
     (l2.p2.x - l2.p1.x) * (l1.p1.y - l2.p1.y) 
     - 
     (l2.p2.y - l2.p1.y) * (l1.p1.x - l2.p1.x); 

    float n_b = 
     (l1.p2.x - l1.p1.x) * (l1.p1.y - l2.p1.y) 
     - 
     (l1.p2.y - l1.p1.y) * (l1.p1.x - l2.p1.x); 

    // Make sure there is not a division by zero - this also indicates that 
    // the lines are parallel. 
    // If n_a and n_b were both equal to zero the lines would be on top of each 
    // other (coincidental). This check is not done because it is not 
    // necessary for this implementation (the parallel check accounts for this). 
    if (d == 0) 
     return null; 

    // Calculate the intermediate fractional point that the lines potentially intersect. 
    float ua = n_a/d; 
    float ub = n_b/d; 

    // The fractional point will be between 0 and 1 inclusive if the lines 
    // intersect. If the fractional calculation is larger than 1 or smaller 
    // than 0 the lines would need to be longer to intersect. 
    if (ua >= 0d && ua <= 1d && ub >= 0d && ub <= 1d) 
    { 
     PVector intersection = new PVector(); 
     intersection.x = l1.p1.x + (ua * (l1.p2.x - l1.p1.x)); 
     intersection.y = l1.p1.y + (ua * (l1.p2.y - l1.p1.y)); 
     return intersection; 
    } 
    return null; 
} 

此外,您可能會發現toxiclibs有用,它是intersectLine Line2D functionality。要知道,有一些問題與處理3

更新

您可以運行波紋管演示:

var l1,l2; 
 

 
function setup() { 
 
    createCanvas(400,400); 
 
    fill(0); 
 
    
 
    l1 = new Line(); 
 
    l2 = new Line(); 
 
    
 
    l1.p1.x = l1.p1.y = 10; 
 
    l1.p2.x = l1.p2.y = 390; 
 
    
 
    l2.p1.x = 10; 
 
    l2.p1.y = 390; 
 
    l2.p2.x = 390; 
 
    l2.p2.y = 10; 
 
} 
 

 
function draw() { 
 
    //draw background and lines 
 
    background(255); 
 
    l1.draw(); 
 
    l2.draw(); 
 
    text("click and drag",10,15); 
 
    //check intersections (and draw) 
 
    var intersection = doLinesIntersect(l1,l2); 
 
    if(intersection != null){ 
 
    ellipse(intersection.x,intersection.y,15,15); 
 
    } 
 
} 
 

 
function mouseDragged(){ 
 
    l1.p1.x = mouseX || touchX; 
 
    l1.p1.y = mouseY || touchY; 
 
} 
 

 
//port of http://paulbourke.net/geometry/pointlineplane/Helpers.cs 
 
function doLinesIntersect(l1, l2){ 
 
    // Denominator for ua and ub are the same, so store this calculation 
 
    var d = 
 
     (l2.p2.y - l2.p1.y) * (l1.p2.x - l1.p1.x) 
 
     - 
 
     (l2.p2.x - l2.p1.x) * (l1.p2.y - l1.p1.y); 
 

 
    //n_a and n_b are calculated as seperate values for readability 
 
    var n_a = 
 
     (l2.p2.x - l2.p1.x) * (l1.p1.y - l2.p1.y) 
 
     - 
 
     (l2.p2.y - l2.p1.y) * (l1.p1.x - l2.p1.x); 
 

 
    var n_b = 
 
     (l1.p2.x - l1.p1.x) * (l1.p1.y - l2.p1.y) 
 
     - 
 
     (l1.p2.y - l1.p1.y) * (l1.p1.x - l2.p1.x); 
 

 
    // Make sure there is not a division by zero - this also indicates that 
 
    // the lines are parallel. 
 
    // If n_a and n_b were both equal to zero the lines would be on top of each 
 
    // other (coincidental). This check is not done because it is not 
 
    // necessary for this implementation (the parallel check accounts for this). 
 
    if (d == 0) 
 
     return null; 
 

 
    // Calculate the intermediate fractional point that the lines potentially intersect. 
 
    var ua = n_a/d; 
 
    var ub = n_b/d; 
 

 
    // The fractional point will be between 0 and 1 inclusive if the lines 
 
    // intersect. If the fractional calculation is larger than 1 or smaller 
 
    // than 0 the lines would need to be longer to intersect. 
 
    if (ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0) 
 
    { 
 
     var intersection = createVector(); 
 
     intersection.x = l1.p1.x + (ua * (l1.p2.x - l1.p1.x)); 
 
     intersection.y = l1.p1.y + (ua * (l1.p2.y - l1.p1.y)); 
 
     return intersection; 
 
    } 
 
    return null; 
 
} 
 

 
function Line(){ 
 
    this.p1 = createVector(); 
 
    this.p2 = createVector(); 
 
    
 
    this.draw = function(){ 
 
    line(this.p1.x,this.p1.y,this.p2.x,this.p2.y); 
 
    } 
 
    
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.3/p5.min.js"></script>