2016-09-19 11 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

、ガレス・リースは_」に定義さ:3

あなたが怒鳴るデモを実行することができます

更新処理を持ついくつかの問題があることに注意してください2次元ベクトルクロスプロダクト** v ** x ** w ** ** v ** x ** w ** y ** - ** ** v ** y ** w ** x "_ 。代わりに** + **を使用しています。 –

+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)

線分を含む行は、どこかにあなたがそう

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; 
    } 

のようなものを確認する線分の範囲に含まれていない交差しない場合は0

で割ることができませんあなたがのために上記の式を「引き出す」の粗製の方法をしたい場合は条件が

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

ようになるはずですxy 2つの線分の方程式で始まり、システムを解きます。

A1*x + B1*y = C1A2*x + B2*y = C2

バック右に左

x = (C1
-B1*y)/A1

プラグ上xため解くとy

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

について解きます

式は

A1

によって

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

乗算上部画分の底部のように見えるようにそしてx( "x = (C1
-B1*y)/A1")

ためバック上記の式に yプラグ

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

0123リンクに与えられた方程式を得るために、上から

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です。その答えは

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>