search_intersect

Werbung
Search and Intersection
 Schnitt zweier Segmente
 Schnitt von Segment und Dreieck
 Punkt im Polygon
 Schnitt konvexer Polygone
Schnitt zweier Segmente - Grundlagen
A
a
b
Lab
p(1/2)
Segment
Menge 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. 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]
d
a
c
b
Schnittpunkt der Segmente
Der Schnittpunkt der Segmente ab und cd wird durch diejenigen Werte von s und t
spezifiziert, 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)] / D
t = – [ax(cy – by) + bx(ay – cy ) + cx(by – ay)] / D
D = ax(dy – cy) + bx(cy – dy) + dx(by – ay) + cx(ay – by)
D=0

Segmente sind parallel
Schnitt zweier Segmente - Quellcode
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;
#define X 0
#define Y 1
typedef enum {FALSE, TRUE} bool;
#define DIM 2
typedef int tPointi[DIM];
typedef double tPointd[DIM];
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;
bool SegSegInt( tPointi a, tPointi b, tPointi c, tPointi d,
tPointd p ) {
double s, t;
double num, denom;
p[X] = a[X] + s * ( b[X] – a[X] );
p[Y] = a[Y] + s * ( b[Y] – a[Y] );
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 ( ( 0.0 <= s ) && ( s <= 1.0) &&
( 0.0 <= t) && ( t <<= 1.0) )
return TRUE;
else
return FALSE;
if ( denom == 0.0 ) return FALSE;
}
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 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);
Bei parallelen Segmenten:
// num bestimmen für s
if ( num == 0.0 || num == denom) code = ‘v‘;
s = num / denom;
Sonderbehandlung durch Funktion
ParallelInt(…)
// 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;
}
Anwendung:
- Schnitt konvexer Polygone
(später)
Schnitt Segment / Dreieck - Grundlagen
Anwendung: Ray – Tracing
Gegeben sei ein Segment qr und ein Dreieck T = abc.
1. Schritt : Bestimmung des Schnittpunktes von qr mit der Ebene π,
die T enthält.
π
N = (A,B,C)
p = (x,y,z)
Ebenengleichung:
π : Ax + By + Cz = D
bzw. als Punktprodukt geschrieben:
π : (x, y ,z) * (A, B, C) = D
N = (A, B, C) ist Normalenvektor
der Ebene π.
D/ |N|
(0,0,0)
Schnitt Segment / Dreieck – Schnitt Segment/Ebene
Wie auch im Zweidimensionalen kann jeder Punkt p auf dem Segment qr
durch 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) = D
genügen muss, gilt:
p (t )  ( A, B, C )  D
 p (t )  N D
 [ q  t ( r  q )]  N D
 q  N  t (r  q)  N  D
t 
D qN
(r  q)  N
Gilt t  [0,1], dann schneidet
Das Segment qr die Ebene π.
 t eingesetzt in p(t) liefert
die Koordinaten des Schnittpunktes von qr mit π
Schnitt 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.
r
π
p
Projektion : Streichen einer Koordinate
in T =  abc und in p.
Problem : Was, wenn π z.B. vertikal
zur xy – Ebene liegt ?
q
 Streichen derjenigen Koordinate,
die im Normalenvektor N der Ebene
π am größten ist.
p‘
z
y
x
Schnitt 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‘ :
Deutung:
+--
+-+
2
--+
Alle 3 areas positiv oder negativ:
 p‘ ist streng innerhalb von T‘
1
2 areas „0“:
 p‘ liegt auf Eckpunkt
+++
++-
-++
0
-+-
1 area „0“:
 p‘ liegt auf Kante, falls die beiden
anderen areas die gleichen
Vorzeichen haben
Punkt 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 Crossings
bis zu 20mal schneller.
Punkt im Polygon – Winding number
p
q
P
Idee:
Man steht auf Punkt q und betrachtet
Punkt p, der einmal auf dem Rand des
Polygons entgegen dem Uhrzeigersinn
entlangläuft, bis er wieder seine Ursprungsposition erreicht hat.
Beobachtung:
q ∉ P : totale Drehung 0
q  P : totale Drehung 2π
(Drehung gegen Uhrzeigersinn: positiv!)
Punkt 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 Winkeldrehung 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 Crossings
25
Idee:
16
20
15
21
22
18
q1
23
19
14
17
q2
Ist diese Zahl ungerade, liegt q innerhalb
von P, sonst nicht.
P
26
12
10
24
8
27
6
q3
9
Beispiele:
q1 : 3 Schnitte => q1  P
q2 : 2 Schnitte => q2  P
2
7
4
3
0
13
Ziehe von q aus einen Strahl in beliebige
(z.B. x- ) Richtung und zähle die Schnitte
mit dem Rand von P.
5
11
Aber: Betrachte q3!
1
Was, wenn der Strahl eine Ecke trifft,
oder kollinear mit einer Kante verläuft?
Punkt 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 Regel
aufstellt:
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 Crossings
Unter Beachtung der eben genannten Regel, ergibt sich nun folgende Situation:
25
16
20
15
22
21
23
18
14
13
 Problem für Punkte gelöst, die
echt innerhalb von P liegen.
19
17
P
12
26
8
10
24
27
6
2
7
5
3
1
Aber:
Inkonsistente Behandlung für Punkte,
die auf dem Rand von P liegen!
9
4
0
Dicke Kanten und schwarze Ecken
gelten als „innerhalb von P“ ,
dünne Kanten und weiße Ecken
Gelten als „außerhalb von P“.
11
( P ist geschlossenes Gebilde
=> Punkte auf dem Rand von P
sollen als „innerhalb“ gelten )
Punkt 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 Schnitt
zu 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
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
Methode:
Ray Crossings
Funktioniert im Prinzip wie in 2D, aber:
keine Sonderbehandlung für Spezialfälle,
sondern:
Generierung eines Zufallsstrahls.
Schnitt konvexer Polygone
Der Schnitt zweier beliebiger
Polygone mit m und n Ecken
kann die quadratische
Komplexität Ω(nm) haben :
Beschränkt man sich jedoch auf konvexe Polygone, ergibt sich die lineare
Komplexitä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
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 gegen
den Uhrzeigersinn und adjustieren ihre Geschwindigkeiten so, dass sie sich
bei jedem Schnitt der Ränder von Q und P treffen:
A
B
Q
P
Schnitt konvexer Polygone – Algorithmus von O‘Rourke
Grundstruktur des Algorithmus:
Algorithm: INTERSECTION OF CONVEX POLYGONS
Choose 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
Idee:
Wenn B auf die Gerade „zielt“, die
A enthält, diese aber nicht schneidet,
dann wird B weitergesetzt, um näher
an einen möglichen Schnittpunkt mit
A zu gelangen.
( alle durchgezogenen Linien in
der Graphik)
Diese Situation kann folgendermaßen
beschrieben 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
falls A x B > 0 und b  H(A), oder
falls A x B < 0 und b  H(A),
=> B wird weitergesetzt
falls A x B < 0 und a  H(B), oder
falls A x B > 0 und a  H(B),
=> A wird weitergesetzt
( BxA= -Ax B)
AxB
>0
>0
<0
<0
Halfplane Condition
b  H(A)
b  H(A)
a  H(B)
a  H(B)
Advance Rule
A
B .
B
A
Schnitt 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 )
a1
A
b1
a
0
4
6
5
3
B
4
Q
b
P
5
0
2
1
3
2
1
Schnitt konvexer Polygone – Details des Algorithmus
a1
A
Am Anfang des Algorithmus ist
das inside-flag auf „unknown“
gesetzt.
b1
a
0
B
b
P
5
5
3
4
S
Q
Die Kanten A und B laufen nun
solange weiter (entsprechend den
geometrischen Vorraussetzungen),
bis sie sich zum ersten Mal
schneiden.
4
6
0
2
1
3
2
1
Dieser Schnittpunkt ist der erste Eckpunkt des Schnittpolygons S. Außerdem wird nun
das 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.
Schnitt 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 weitergesetzt
wird.
 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älle
1.
A und B überlappen und sind entgegengesetzt orientiert
=> Die Kante der Überlappung ist der gesamte Schnitt der beiden Polygone
P
Q
2.
A B
A und B sind parallel ( A x B = 0) und a ist rechts von B, sowie b rechts von A
=> P  Q = 
a
P
B
Q
A
b
Search and Intersection - Ausblick
Weitere Themen, die unter „Search and Intersection“ fallen, aber
aufgrund ihres Umfangs in diesem Vortrag nicht mehr behandelt
werden können, sind z.B.:
- der Schnitt von nicht-konvexen Polygonen
- Extrempunkte von Polygonen
- Extrempunkte von Polytopen
- Lage eines Punktes in der Ebene
Herunterladen