Grafische Datenverarbeitung

3 2D-Graphik: Transformationen, Clipping

Verarbeitungsschritte von der Szene zum Bild

Mögliche Transformationen
 Verschiebung
 Skalierung
 Spiegelung an x und y oder am Ursprung
 Drehung
 Scherung in x und y

Verkettung von Transformationen
Werden zwei Transformationen in unterschiedlicher Reihenfolge ausgeführt, ergeben sich im allgemeinen unterschiedliche Ergebnisse.

Affine Abbildung
Eine einfache Möglichkeit, solche Modellierungs-Transformationen mathematisch zu beschreiben bzw. vom Rechner ausführen zu lassen, sind sog. affine Abbildungen.
Eigenschaften
 Ein Punkt mit endlichen Koordinaten wird auf einen Punkt mit endlichen Koordinaten abgebildet.
 linientreu: das Bild einer Gerade ist eine Gerade
 parallelentreu: das Bild zweier parallelen Geraden sind zwei parallele Geraden
 Affine Abbildungen, die nur aus Verschiebungen, Rotationen und Spiegelungen bestehen sind längen- und winkeltreu.
Konsequenzen
Aufgrund der Linien- und Parallelentreue müssen bei geometrischen Grundobjekten, die durch Punkte und Strecken definiert sind, nur die Punkte transformiert werden.

Homogene Darstellung affiner Abbildungen
(Skalierung, Rotation, Spiegelung und Scherung) = Matrix-Vektor-Multiplikation.
(Transformationen)=Multiplikation von Matrizen
(Verschiebung)=Vektor-Addition
Vereinheitlichung der Berechnung, so dass sich alle Transformationen mit Hilfe einer Matrix-Vektor-Multiplikation berechnen lassen.
3D-Graphik: Transformationen

Algorithmus von (Cohen-)Sutherland-Hodgman
Das Clip-Rechteck besitze die extremen Koordinaten xmin, xmax, ymin und ymax
Codierung:
Bit 1: links des Rechtecks
Bit 2: rechts des Rechtecks
Bit 3: unter dem Recheck
Bit 4: über dem Rechteck



 

1. Ist die Oder-Verknüpfung der Codes der beiden Endpunkte gleich 0000, ist die Strecke vollständig im Clip-Rechteck enthalten
2. Ist die Und-Verknüpfung der Codes der beiden Endpunkte ungleich 0000, liegt die Strecke sicher außerhalb des Clip-Rechtecks
3 Ansonsten: weitere Untersuchung nötig

BEGIN
 j:=0;
 IF (n>2) THEN
  i:=1;
  pn+1:=p1;
  WHILE (i<=n) DO
   r:=pi;
   IF (IstAufSichtbarerSeite(r,g)) THEN
    j:=j+1; qj:=r;
    i:=i+1;
    s:=Schnitt(r,pi,g);
    IF (s != unendlich) THEN
     j:=j+1; qj:=s;
 m:=j;
END

 

OpenGL- 2D Viewport Transformation
Viewport-Transformation Ausschnitt
void gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
Beschreibung
Erzeugt eine Matrix M für die Projektion zweidimensionaler Koordinaten auf den Bildschirm und multipliziert die aktuelle Projektionsmatrix mit M. Das Clip-Rechteck besitzt die extremen Eckpunkte (left, bottom)T und (right,top)T.
Beispiel
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 10.0, 0.0, 10.0);

Viewport-Transformation Viewport
void glViewport(GLint x, GLint y, Glsizei width, GLsizei height)
Beschreibung
Definiert die linke untere Ecke sowie die Breite und Höhe des aktuellen Viewports.

Ergenzender Code:
 

/****************************************************************************************/
/*                 Clippen von Linien an einem Fenster nach Cohen-Sutherland            */
/****************************************************************************************/
private static final byte EMPTY  = 0;
private static final byte LEFT   = 1;
private static final byte RIGHT  = 2;           // 4-Bit-Bereichscodes
private static final byte BOTTOM = 4;
private static final byte TOP    = 8;

private int xmin, xmax, ymin, ymax;             // Clip-Fensterraender

private byte region_code(                       // liefert den region-code
                          Point P )             // fuer den Punkt P 
{
        byte c;

        c = EMPTY;
        if (P.x < xmin) c = LEFT; else
        if (P.x > xmax) c = RIGHT;
        if (P.y < ymin) c |= BOTTOM; else
        if (P.y > ymax) c |= TOP;
        return(c);
}


private void set_clip_window(         // setzt die Variablen xmin, ymin, xmax, ymax 
                Point P,              // anhand des Ursprungs P des Clip-Fensters
                Point delta )         // und anhand seiner Breite/Hoehe delta
        {
                xmin = P.x; xmax = P.x + delta.x;
                ymin = P.y; ymax = P.y + delta.y;
        }


private boolean cohen_sutherland(     // liefert true,
                Point p1, Point p2,   // falls die Gerade p1-p2 sichtbar ist 
                Point Q1, Point Q2)   // liefert ggf. sichtbaren Teil Q1-Q2 zurueck
{
        boolean finite_slope;         // true falls Gerade p1-p2 nicht senkrecht laeuft
        double slope = 0.0;           // Steigung der Geraden p1-p2
        byte C, C1, C2;               // 4-Bit-Bereichs-Code
        Point Q = new Point();        // zu berechnender Schnittpunkt mit Gerade

        Point P1 = new Point(p1);     // lokale
        Point P2 = new Point(p2);     // Variablen
        finite_slope = (P1.x != P2.x);
        if (finite_slope) slope = (double)(P2.y-P1.y)/(double)(P2.x-P1.x);
        C1 = region_code(P1);
        C2 = region_code(P2);

        while ((C1 != EMPTY) || (C2 != EMPTY))  { // mind. ein Endpunkt noch ausserhalb

            if ((C1&C2) != EMPTY) return(false);  // beide auf derselben Seite ausserhalb
            else 
            {
                if (C1 == EMPTY) C = C2; else C = C1; // C ist ausserhalb. Berechne
                                                      // einen Schnittpunkt mit den
                                                      // verlaengerten Fensterkanten
       
                if ((C & LEFT) != EMPTY) {         // schneide mit linker Fenster-Kante
                        Q.x = xmin; 
                        Q.y = (int)((Q.x-P1.x)*slope + P1.y);
                        } else

                if ((C & RIGHT) != EMPTY){        // schneide mit rechter Fenster-Kante
                        Q.x = xmax; 
                        Q.y = (int)((Q.x-P1.x)*slope + P1.y);
                        } else

                if ((C & BOTTOM) != EMPTY) {      // schneide mit unterer Fenster-Kante
                        Q.y = ymin; 
                        if (finite_slope) 
                                Q.x = (int)((Q.y-P1.y)/slope + P1.x); else 
                                Q.x = P1.x;
                        }else

                if ((C & TOP) != EMPTY) {         // schneide mit oberer Fenster-Kante
                        Q.y = ymax;
                        if (finite_slope)
                                Q.x = (int)((Q.y-P1.y)/slope + P1.x); else 
                                Q.x = P1.x;
                        }

                if (C==C1) {
                        P1.x = Q.x; P1.y = Q.y; C1 = region_code (P1);
                } else {
                        P2.x = Q.x; P2.y = Q.y; C2 = region_code (P2);
                }
            }

        }
        // uebergib Anfang und Ende des sichtbaren Teils
        Q1.x=P1.x; Q1.y=P1.y;
        Q2.x=P2.x; Q2.y=P2.y;

        return(true);        
}