Betrachten drei Clipping-Algorithmen:
clipcsIdee:
Formulieren wir einige benötigte einfache Funktionen:
int Encode(point p) {
return
( ( ( ( ( (p.x > y_max)
<< 1
) | (p.x < y_min)
) << 1
) | (p.x < x_min)
) << 1
) | (p.x > x_max);
}
wobei x_min, x_max, y_min, und y_max die Fensterkoordinaten sind.
Algorithmus:
(als C++-Programmgerüst, welches das Segment zeichnet und leicht
als Übung vervollständigt werden kann.)
void ClipCohenSutherland(
point p, point q
) {
enum State { NOTDONE, ACCEPT, REJECT };
State done(NOTDONE);
while(done != ACCEPT && done != REJECT ) {
code_p = Encode(p);
code_q = Encode(q);
if ( Accept(code_p,code_q) ) done = ACCEPT;
else {
if ( Reject(code_p,code_q) ) done = REJECT;
else {
if ( Inside(code_p) ) {
Swap(&p,&q);
Swap(&code_p,&code_q);
}
if (code_p&LEFT) {
p = Intersect(p,q,left_border);
else if (code_p&RIGHT) {
p = Intersect(p,q,right_border);
}
else ...
}
}
}
if (done == ACCEPT) DrawLine(p,q,color);
}
cliplbIdee:
Betrachten parametrisierte Form des Segmentes
Dieses muss innerhalb des Fensters liegen. Wir erhalten also die Bedingungen:
Dies sind vier Ungleichungen der Form:
Nämlich
Bemerkung: die Ausdrücke für und ergeben sich auch aus der secintersectSchnittpunktberechnung zwischen Segmenten, wenn man berückschtigt, dass die Fensterbegrenzungen horizontal bzw. vertikal verlaufen und damit in den Determinanten Nullen auftauchen.
Idee des Verfahrens:
Sofern die Differenz für nicht Null ist, können wir jeweils durch eine Division berechnen:
Ist ein , so verläuft das Segment parallel zu einer der Fensterseiten, ist dann , so liegt es auserhalb.
Ist ein , so läuft man bzgl. der parametrisierten Gleichung von Außen nach Innen, also verschieben wir .
Ist ein , so läuft man bzgl. der parametrisierten Gleichung von Innen nach ßen, also verschieben wir .
Es muss natürlich stets gelten: , da wir uns entlang des Segmentes bewegen.
Algorithmus:
(als C++-Programmgerüst, welches zeichnet und leicht
als Übung vervollständigt/modifiziert werden kann.)
Die Funktion ClipTest() testet jeweils für eine der Ungleichungen, d.h. Fensterbegrenzung, und aktualisiert gegebenenfalls die Parameter:
bool ClipTest(
double p, double q,
double& t0, double& t1
) {
if( p < 0 ) {
double t(q/p);
if( t > t1 ) return false;
t0 = Max(t0,t);
}
else if( p > 0 ) {
double t(q/p);
if( t < t0 ) return false;
t1 = Min(t1,t);
}
else if( q < 0 ) return false;
return true;
}
Hauptfunktion:
void ClipLiangBarsky(
point P, point Q
) {
double t0(0.0);
double t1(1.0);
double Dx(q.x-p.x);
if( ClipTest(-Dx, P.x-xwmin, t0, t1) ) {
if( ClipTest(Dx, xwmax-P.x, t0, t1) ) {
double Dy(Q.y-P.y);
if( ClipTest(-Dy, P.y-ywmin, t0, t1) ) {
if( ClipTest(Dy, ywmax-P.y, t0, t1) ) {
if( t0 > 0 ) {
P.x = P.x + t0*Dx;
P.y = P.y + t0*Dy;
}
if( t1 < 1) {
Q.x = P.x + t1*Dx;
Q.y = P.y + t1*Dy;
}
DrawLine(P,Q,color);
}
}
}
}
}
Liang-Barsky Clipping kommt mit einer Division pro Fensterseite als arithmetischer Operation aus, womit er u.U. effizienter als der Cohen-Sutherland-Algorithmus zu implementieren ist. Auch kommen im Mittel weniger Schnittpunktberechnungen mit den Fensterbegrenzungen vor (hier sind die Aussagen in der Literatur aber uneinheitlich).
clipnlnHier werden die eventuell unnötigen Schnittpunktberechnungen der anderen Algorithmen eliminiert, indem das Gebiet in weitere Regionen unterteilt wird, in denen sich die Endpunkte befinden können. Damit erreicht man, dass nur genau mit den Fensterbegrenzungen ein Schnittpunkt berechnet wird, wo wirklich ein Schnittpunkt mit dem Fenster auftritt.
(Tafelerklärung, wird noch ergänzt)
Der NLN-Algorithmus ist nicht leicht auf 3 Dimensionen zu erweitern, was ein Vorteil der anderen beiden Verfahren ist (wir sehen es wieder wenn wir rayboxinterStrahl-Box-Schnittpunkte im RayTracing-Algorithmus untersuchen). NLN kommt im Mittel aber mit weniger arithmetischen Operationen aus.
Beachte: Heute sollte man jedoch weniger die Anzahl der arithmetischen Operationen vergleichen, als vielmehr die Möglichkeiten einer parallelen oder gepipelineten Ausführung der Operationen, sowie die Sprungstruktur zwischen den Basisblöcken des Programmcodes (viele ifs sind u.U. weniger effizient als einige Divisionen).
Folgende Tabelle zeigt einige Laufzeitmessungen und auch einen Vergleich mit einer geschickten Implementierung des Clippings, welche Festkommazahlen benutzt und weitere Optimierungen verwendet (der Artikel spezifiziert den tatsächlichen Algorithmus allerdings nicht ?!)
LB steht für Liang-Barsky, CS für Cohen-Sutherland, FPC für die neue? Methode in verschiedenen Variationen (siehe Originalartikel).
Interessant wäre z.B. eine MMX/SSE-Implementierung oder was immer die CPU/GPU zur Verfügung stellt, bei der man alle -Werte für die Schnittpunkte mit den vier Fensterbegrenzungen parallel berechnet und dann anschließend geschickt auswählt und berechnet.