search and intersection schnitt zweier segmente schnitt von segment und dreieck punkt im polygon...
TRANSCRIPT
Search and IntersectionSearch and Intersection
Schnitt zweier Segmente Schnitt von Segment und Dreieck Punkt im Polygon Schnitt konvexer Polygone
Schnitt zweier Segmente - GrundlagenSchnitt zweier Segmente - Grundlagen
Lab
A
a
b
p(1/2)
SegmentMenge aller Punkte auf einer Geraden zwischen zwei Punkten a und b
Darstellung eines Segmentes ?Sei A = b – a. Jeder Punkt auf Lab kann durch die Vektorsumme
p(s) = a + sA dargestellt werden.
Beispiele: p(0) = a p(1) = a + A = a + b – a = b p(1/2) = (a + b)/2
=> p(s) für s [0,1] repräsentiert alle Punkte auf dem Segment ab
Schnitt zweier Segmente - math. UmsetzungSchnitt zweier Segmente - math. Umsetzung
Gegeben seien nun zwei Segmente
ab : p(s) = a + sA für s [0,1] cd : q(t) = c + tC für t [0,1]
a
bc
d
Schnittpunkt der SegmenteDer Schnittpunkt der Segmente ab und cd wird durch diejenigen Werte von s und tspezifiziert, für die p(s) = q(t) gilt:
a + sA = c + tC
Diese Vektorgleichung beinhaltet zwei Gleichungen mit zwei Unbekannten,nämlich die x- und y-Gleichungen, mit jeweils s und t als Unbekannte.Als Lösung dieses Gleichungssystems ergibt sich:
s = [ax(dy – cy) + cx(ay – dy) + dx(cy – ay)] / Dt = – [ax(cy – by) + bx(ay – cy ) + cx(by – ay)] / DD = ax(dy – cy) + bx(cy – dy) + dx(by – ay) + cx(ay – by)
D = 0 Segmente sind parallel
Schnitt zweier Segmente - QuellcodeSchnitt zweier Segmente - Quellcode
#define X 0#define Y 1typedef enum {FALSE, TRUE} bool;#define DIM 2typedef int tPointi[DIM];typedef double tPointd[DIM];
bool SegSegInt( tPointi a, tPointi b, tPointi c, tPointi d, tPointd p ) { double s, t; double num, denom;
denom = a[X] * (double) ( d[Y] – c[Y] ) + b[X] * (double) ( c[Y] – d[Y] ) + d[X] * (double) ( b[Y] – a[Y] ) +
c[x] * (double) ( a[Y] – b[Y] ) ;
if ( denom == 0.0 ) return FALSE;
num = a[X] * (double) ( d[Y] – c[Y] ) + c[X] * (double) ( a[Y] – d[Y] ) + d[X] * (double) ( c[Y] – a[Y] ); s = num / denom;
num = - ( a[X] * (double) ( c[Y] – b[Y] ) + b[X] * (double) ( a[Y] – c[Y] ) + c[X] * (double) ( b[Y] – a[Y] ) ); t = num / denom;
p[X] = a[X] + s * ( b[X] – a[X] ); p[Y] = a[Y] + s * ( b[Y] – a[Y] );
if ( ( 0.0 <= s ) && ( s <= 1.0) && ( 0.0 <= t) && ( t <<= 1.0) ) return TRUE; else return FALSE;}
Schnitt zweier Segmente Schnitt zweier Segmente
Schwächen des Quellcodes:
1. Bei parallelen Segmenten wird standardmäßig „FALSE“ zurückgegeben, obwohl auch diese sich schneiden (überlappen) können.
2. Da viele Anwendungen zwischen echtem („proper“) und entartetem („improper“) Schnitt unterscheiden müssen, wäre es sinnvoll, diese Information, z.B. codiert als Character-Wert, zurückzuliefern.
Beispiel:„e“ : Segmente überlappen kollinear, teilen mindestens einen Punkt ( e = „edge“)„v“ : Endpunkt des einen Segmentes ist auf dem anderen Segment, aber „e“ trifft nicht zu ( v = „vertex“)„1“ : Schnitt ist „proper“; Segmente teilen einen Punkt und weder „e“, noch „v“ treffen zu„0“ : Segmente schneiden sich nicht
Schnitt zweier Segmente – verbesserter QuellcodeSchnitt zweier Segmente – verbesserter Quellcode
char SegSegInt( tPointi a, tPointi b, tPointi c, tPointi d, tPointd p ) {
double s, t; double num, denom; char code; // denom bestimmen if ( denom == 0.0 ) return ParallelInt(a,b,c,d,p);
// num bestimmen für s if ( num == 0.0 || num == denom) code = ‘v‘; s = num / denom;
// num bestimmen für t if ( num == 0.0 || num == denom) code = ‘v‘; t = num / denom; // p[X] und p[Y] bestimmen if ( ( 0.0 <= s ) && ( s <= 1.0) && ( 0.0 <= t) && ( t <<= 1.0) ) code = ‘1‘; else if ( ( 0.0 > s ) || ( s > 1.0) || ( 0.0 > t) || ( t > 1.0) ) code = ‘0‘; return code; }
Bei parallelen Segmenten:
Sonderbehandlung durch FunktionParallelInt(…)
Anwendung: - Schnitt konvexer Polygone (später)
Schnitt Segment / Dreieck - GrundlagenSchnitt Segment / Dreieck - Grundlagen
Gegeben sei ein Segment qr und ein Dreieck T = abc.
1. Schritt : Bestimmung des Schnittpunktes von qr mit der Ebene π, die T enthält.
π
p = (x,y,z)
(0,0,0)
N = (A,B,C)
D/ |N|
Ebenengleichung:π : Ax + By + Cz = D
bzw. als Punktprodukt geschrieben:π : (x, y ,z) * (A, B, C) = D
N = (A, B, C) ist Normalenvektorder Ebene π.
Anwendung: Ray – Tracing
Schnitt Segment / Dreieck – Schnitt Segment/EbeneSchnitt Segment / Dreieck – Schnitt Segment/Ebene
Wie auch im Zweidimensionalen kann jeder Punkt p auf dem Segment qrdurch die Gleichung p(t) = q + t * (r – q) ( t [0,1]) dargestellt werden.
Gesucht ist nun ein Wert für den Parameter t, so dass p(t) auf der Ebeneπ liegt.
Da jeder Punkt p = (x,y,z) auf π der Ebenengleichung (x,y,z) * (A,B,C) = Dgenügen muss, gilt:
Nqr
NqDt
DNqrtNq
DNqrtq
DNtp
DCBAtp
)(
)(
)]([
)(
),,()( Gilt t [0,1], dann schneidetDas Segment qr die Ebene π.
t eingesetzt in p(t) liefert die Koordinaten des Schnitt- punktes von qr mit π
Schnitt Segment / Dreieck – Projektion in 2DSchnitt Segment / Dreieck – Projektion in 2D
2. Schritt : Liegt der Schnittpunkt p von Segment qr und Ebene π innerhalb von T = abc?
Beobachtung : Eigentlich zweidimensionales Problem!
Lösung : Projektion des Dreiecks abc und p auf zwei Dimensionen.
xy
z
π
q
r
p
p‘
Projektion : Streichen einer Koordinate in T = abc und in p.
Problem : Was, wenn π z.B. vertikal zur xy – Ebene liegt ?
Streichen derjenigen Koordinate, die im Normalenvektor N der Ebene π am größten ist.
Schnitt Segment / Dreieck – signed areasSchnitt Segment / Dreieck – signed areas
Es gilt : p liegt in T, falls der projizierte Punkt p‘ innerhalb des projizierten Dreiecks T‘ liegt.
Wie stellt man die Lage von p‘ zu T‘ fest?
=> Berechnung von ‘signed areas‘ bezüglich p‘ :
1
2
0
+++
-++
--+
-+-
++-
+-++--
Deutung:
Alle 3 areas positiv oder negativ: p‘ ist streng innerhalb von T‘
2 areas „0“: p‘ liegt auf Eckpunkt
1 area „0“: p‘ liegt auf Kante, falls die beiden anderen areas die gleichen Vorzeichen haben
Punkt im PolygonPunkt im Polygon
Gegeben ist ein fixes Polygon P und ein Punkt q.
Dieser Abschnitt beschäftigt sich mit Möglichkeiten, herauszufinden, ob q in P liegt oder nicht.
2 Fälle:
1. Polygon konvex: LeftOn – Test für jede Kante des Polygons
2. Polygon nicht konvex:
- Winding Number - Ray Crossings
Anmerkung:Obwohl beide Algorithmen in O(n) arbeiten, ist die Methode der Ray Crossingsbis zu 20mal schneller.
Punkt im Polygon – Winding numberPunkt im Polygon – Winding number
q
P
p
Idee:Man steht auf Punkt q und betrachtetPunkt p, der einmal auf dem Rand desPolygons entgegen dem Uhrzeigersinnentlangläuft, bis er wieder seine Ursprungs-position erreicht hat.
Beobachtung:q P : totale Drehung 0∉q P : totale Drehung 2π
(Drehung gegen Uhrzeigersinn: positiv!)
Punkt im Polygon – Winding numberPunkt im Polygon – Winding number
Winding Number:
Die Winding Number von q bezüglich P ist die Anzahl der Umdrehungen die ein,auf dem Rand von P entlanglaufender Punkt p um q macht:
Die totale Winkeldrehung geteilt durch 2π
( da man am Ende wieder die Ausgangsorientierung erreicht hat, ist die totale Winkel- drehung ein Vielfaches von 2π und also die Winding Number eine ganze Zahl )
Problem des Algorithmus:Abhängigkeit von Fließpunkt-Berechnungen ( speziell: trigonometrische Berech. )
=> bis zu 20mal langsamer als Ray – Crossings – Algorithmus
Punkt im Polygon – Ray CrossingsPunkt im Polygon – Ray Crossings
Idee:Ziehe von q aus einen Strahl in beliebige(z.B. x- ) Richtung und zähle die Schnittemit dem Rand von P.
Ist diese Zahl ungerade, liegt q innerhalbvon P, sonst nicht.
Beispiele:q1 : 3 Schnitte => q1 Pq2 : 2 Schnitte => q2 P
Aber: Betrachte q3!
Was, wenn der Strahl eine Ecke trifft, oder kollinear mit einer Kante verläuft?
q1
q2
q3
P
0 1
2
3
4 5
6
7
8
9
10
11
12
1314
15
16
17
18
19
20
2122
23
24
25
26
27
Punkt im Polygon – Ray CrossingsPunkt im Polygon – Ray Crossings
Problem:Der von q ausgehende Strahl R trifft Ecke von P oder verläuft kollinear zu einer Kante von P.
Beobachtung:Die meisten Schwierigkeiten kann man umgehen, indem man folgende Regelaufstellt: Damit eine Kante e von P als Schnitt zählt, muss folgendes gelten:
1. Einer von e‘s Endpunkten muss streng oberhalb von R liegen 2. Der zweite Endpunkt von e muss auf oder unterhalb von R liegen 3. Die x-Koordinate des Schnittpunktes muss echt größer als die von q sein.
( => keine Kante, die kollinear mit R verläuft kann als Schnitt zählen )
Punkt im Polygon – Ray CrossingsPunkt im Polygon – Ray Crossings
Unter Beachtung der eben genannten Regel, ergibt sich nun folgende Situation:
P
0 1
2
3
45
6
7
8
9
10
11
12
1314
15
16
17
18
19
20
2122
23
24
25
26
27
Dicke Kanten und schwarze Eckengelten als „innerhalb von P“ , dünne Kanten und weiße EckenGelten als „außerhalb von P“.
Problem für Punkte gelöst, die echt innerhalb von P liegen.
Aber: Inkonsistente Behandlung für Punkte,die auf dem Rand von P liegen!
( P ist geschlossenes Gebilde => Punkte auf dem Rand von P sollen als „innerhalb“ gelten )
Punkt im Polygon – Ray CrossingsPunkt im Polygon – Ray Crossings
Lösung:Ziehe von q ausgehend zusätzlich einen Strahl in (–x) – Richtung.Für Kanten e von P gelten hierbei umgekehrte Voraussetzungen um als Schnittzu zählen:
1. Einer von e‘s Endpunkten muss streng unterhalb von R liegen 2. Der zweite Endpunkt von e muss auf oder oberhalb von R liegen 3. Die x-Koordinate des Schnittpunktes muss echt kleiner als die von q sein.
Ergeben sich nun unterschiedliche Ergebnisse für die entgegengesetzten Strahlen,so gilt q P.
Aber:Diese Methode funktioniert nur für Punkte, die innerhalb einer Kante von P liegen, nicht jedoch für die Ecken von P !
=> Zu Beginn des Algorithmus einfachen Test durchführen, ob q Kante ist.
Punkt im Polygon – Ray Crossings – Quellcode Punkt im Polygon – Ray Crossings – Quellcode
char InPoly( tPointi q, tPolygoni P, int n) { int i, i1; //point index int d; //dimension index double x; //x intersection of e with ray int RCross = 0; //number of right edge/ray crossings int LCross = 0; //number of left edge/ray crossings bool RStrad, LStrad; //flags indicating the edge strads //the x - axis //Shift so that q is the origin. Note this destroys polygon for( i = 0; i < n; i++ ) { for( d = 0; d < DIM; d++ ) P[i][d] = P[i][d] - q[d]; } //For each edge e = (i-1,i), see if crosses ray for( i = 0; i < n; i++) { //first check if q = (0,0) is vertex if( P[i][X] == 0 && P[i][y] == 0) return 'v'; i1 = ( i + n - 1) % n; //Check if e straddles x axis, with bias above/below RStrad = ( P[i][Y] > 0 ) != ( P[i1][Y] > 0 ); LStrad = ( P[i][Y] < 0 ) != ( P[i1][Y] < 0 );
if(RStrad || LStrad) { //Compute intersection of e with x - axis x = ( P[i][X] * P[i1][Y] - P[i1][X] * P[i][Y]) / (double)(P[i1][Y] - P[i][Y]); if (RStrad && x > 0 ) RCross ++; if (LStrad && x < 0 ) LCross ++; } } //q on an edge if L/RCross counts are not the same parity if( ( RCross % 2) != ( LCross % 2) ) return 'e'; //q inside iff an odd number of crossings if ( RCross % 2) == 1) return 'i'; else return 'o'; }
‘i‘ : q liegt streng innerhalb von P‘o‘ : q liegt streng außerhalb von P‘e‘ : q liegt auf Kante, aber ist kein Endpunkt‘v‘ : q ist Ecke von P
Punkt im Polyeder Punkt im Polyeder
Methode:Ray Crossings
Funktioniert im Prinzip wie in 2D, aber: keine Sonderbehandlung für Spezialfälle,
sondern: Generierung eines Zufallsstrahls.
Schnitt konvexer Polygone Schnitt konvexer Polygone
Der Schnitt zweier beliebiger Polygone mit m und n Ecken kann die quadratischeKomplexität Ω(nm) haben :
Beschränkt man sich jedoch auf konvexe Polygone, ergibt sich die lineareKomplexität O(n+m).
Der erste lineare Algorithmus wurde 1978 von Shamos gefunden.
Im Folgenden wird ein Algorithmus vorgestellt, der 1982 von O‘Rourke entwickelt wurde.
Schnitt konvexer Polygone – Algorithmus von O‘Rourke Schnitt konvexer Polygone – Algorithmus von O‘Rourke
Gegeben sind zwei konvexe Polygone, Q und P, deren Ränder gegen den Uhrzeigersinn orientiert sind.A und B sind gerichtete Kanten auf den Rändern von Q und P.
Grundsätzliche Idee:
A und B „jagen“ einander, d.h. sie durchlaufen die Kanten von Q und P gegenden Uhrzeigersinn und adjustieren ihre Geschwindigkeiten so, dass sie sich bei jedem Schnitt der Ränder von Q und P treffen:
Q
PA
B
Schnitt konvexer Polygone – Algorithmus von O‘Rourke Schnitt konvexer Polygone – Algorithmus von O‘Rourke
Grundstruktur des Algorithmus:
Algorithm: INTERSECTION OF CONVEX POLYGONSChoose A and B arbitrarily.repeat if A intersects B then Check for termination. Update an inside flag. Advance either A or B, depending on geometric conditions.until both A and B cycle their polygons.Handle P Q = and Q P and P Q cases.
Schwierigkeit des Algorithmus liegt darin, Regeln für das Weitersetzen von A und B zu finden!
Schnitt konvexer Polygone – Algorithmus von O‘Rourke Schnitt konvexer Polygone – Algorithmus von O‘Rourke
Idee:Wenn B auf die Gerade „zielt“, die A enthält, diese aber nicht schneidet,dann wird B weitergesetzt, um näheran einen möglichen Schnittpunkt mitA zu gelangen.( alle durchgezogenen Linien in der Graphik)
Diese Situation kann folgendermaßenbeschrieben werden:
- Sei H(A) die offene Halbebene auf der linken Seite von A.
- „A x B > 0“ soll bedeuten, dass die z-Koordinate des Kreuzproduktes > 0 ist. ( => die kürzeste Drehung von A nach B ist gegen den Uhrzeigersinn )
Schnitt konvexer Polygone – Algorithmus von O‘Rourke Schnitt konvexer Polygone – Algorithmus von O‘Rourke
falls A x B > 0 und b H(A), oderfalls A x B < 0 und b H(A), => B wird weitergesetzt
falls A x B < 0 und a H(B), oderfalls A x B > 0 und a H(B), => A wird weitergesetzt
( B x A = - A x B )
A x B Halfplane Condition Advance Rule > 0 b H(A) A > 0 b H(A) B . < 0 a H(B) B < 0 a H(B) A
Schnitt konvexer Polygone – Details des AlgorithmusSchnitt konvexer Polygone – Details des Algorithmus
Polygone Q und P sind Arrays von Eckpunkten, die über die Variablen a und b indiziert werden. a1 und b1 indizieren jeweils die Eckpunkte, die eine Position vor a und b liegen.
a1 ist Anfangspunkt von A, a Endpunkt von A ( Entsprechendes für B )
Q
PA
B
0
1
2
3
4
5
6
1
2
3
4
5
0
a
a1
b
b1
Schnitt konvexer Polygone – Details des AlgorithmusSchnitt konvexer Polygone – Details des Algorithmus
Q
PA
B
0
1
2
3
4
5
6
1
2
3
4
5
0
a
a1
b
b1Am Anfang des Algorithmus ist das inside-flag auf „unknown“gesetzt.
Die Kanten A und B laufen nunsolange weiter (entsprechend dengeometrischen Vorraussetzungen),bis sie sich zum ersten Malschneiden.
Dieser Schnittpunkt ist der erste Eckpunkt des Schnittpolygons S. Außerdem wird nundas inside-flag auf „Pin“ oder „Qin“ gesetzt.
Solange nun „Qin“ gilt, gehören die Kanten von A zu S, bei „Pin“ die von B.
Bei jedem Schnittpunkt von A und B kann sich der Wert des inside-flags ändern!Außerdem gehört jeder Schnittpunkt von A und B zu S.
S
Schnitt konvexer Polygone – Details des AlgorithmusSchnitt konvexer Polygone – Details des Algorithmus
Abbruchbedingung:
Der Algorithmus ist fertig, wenn A und B ihre Polygone einmal umlaufen haben.
Jedoch gibt es mögliche Fälle, in denen eine der beiden Kanten nie nie weitergesetztwird.
Die Hauptschleife des Algorithmus bricht ab, wenn:
- A und B ihre Polygone einmal umlaufen haben, oder - eine der beiden Kanten ihr Polygon zweimal umlaufen hat
Anmerkung:Ist die inside – Flag nach Beendigung der Hauptschleife noch immer auf „unknown“gesetzt, weiß man, dass sich die Polygone nicht geschnitten haben!
Schnitt konvexer Polygone – Algorithmus / SonderfälleSchnitt konvexer Polygone – Algorithmus / Sonderfälle
1. A und B überlappen und sind entgegengesetzt orientiert => Die Kante der Überlappung ist der gesamte Schnitt der beiden Polygone
2. A und B sind parallel ( A x B = 0) und a ist rechts von B, sowie b rechts von A => P Q =
Q
P
AB
a
b
QP
A B
Search and Intersection - AusblickSearch and Intersection - Ausblick
Weitere Themen, die unter „Search and Intersection“ fallen, aberaufgrund ihres Umfangs in diesem Vortrag nicht mehr behandeltwerden können, sind z.B.:
- der Schnitt von nicht-konvexen Polygonen - Extrempunkte von Polygonen - Extrempunkte von Polytopen - Lage eines Punktes in der Ebene