• Keine Ergebnisse gefunden

(6) Polygon Clipping

N/A
N/A
Protected

Academic year: 2022

Aktie "(6) Polygon Clipping"

Copied!
39
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

U N I V E R S I T Ä T KOBLENZ · LANDAU

(6) Polygon Clipping

Vorlesung

„Computergraphik I“

S. Müller

(2)

Wiederholung I

 Clipping

 Berechnung eines Ausschnitts

 Test der Gültigkeit der Parameter bei Putpixel zu teuer, daher Clipping z.B. mit Bildschirmfenster

 2-Stufiges Vorgehen:

• Schneller Test, ob Linie innerhalb/außerhalb des Bildschirms liegt

• Berechnung des Schnittpunkts nur, wenn unbedingt nötig.

 Cohen-Sutherland

(3)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 3 -

Wiederholung II

Durch einfache Bit-Operationen (und, oder) lässt sich schnell

erkennen, ob eine Linie vollständig innerhalb bzw. außerhalb des

Bereichs liegt.

1.

2.

3.

4.

5.

0

& 2

1 c

c

0

| 2

1 c = = c

0000

0100 0110

0101

1001 1000 1010

0001 0010

Linie vollständig außerhalb, fertig.

Linie vollständig innerhalb, alles zeichnen.

Sonst: neue Punkte

bestimmen bis 3) erreicht ist

A B

C

D E

F

G

H

cut

c

G

| c

H 0110

c

G

&c

H 0000

draw

c

E

| c

F 0000

c

E

&c

F 0000

cut

c

C

| c

D 0100

c

C

&c

D 0000

ignore

c

A

&c

B 1000

(4)

Wiederholung III

{

c1 = outcode( ax, ay);

c2 = outcode( bx, by);

while((c1 | c2) != 0) {

if ((c1 & c2) != 0) return ;

a = ay-by; b = bx-ax; d = ax*by-ay*bx;

if (c1 == 0) c = c2;

else c = c1;

if ((c & C_LEFT) != 0)

{ x = xmin; y = -(a*x+d)/b;}

else if ((c & C_RIGHT) != 0) { x = xmax; y = -(a*x+d)/b;}

else if ((c & C_TOP) != 0) { y = ymax; x = -(b*y+d)/a;}

else if ((c & C_BOTTOM) != 0) { y = ymin; x = -(b*y+d)/a;}

if (c == c1)

{ ax = x; ay = y; c1 = outcode(ax, ay);}

else

{ bx = x; by = y; c2 = outcode(bx, by);}

A (Oben, Links)

B (0000) A‘ (Oben)

A (Oben, Rechts)

B (0000) A‘ (0000) A‘‘ (0000)

A (Unten)

B (Rechts)

A‘ (Rechts)

(5)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 5 -

Wiederholung IV: Cohen-Sutherland

 Dieser Algorithmus arbeitet sehr effizient

 Er findet vor allem für Clipping an Bildschirmkanten Verwendung

 Nachteil: er funktioniert nur für rechteckige Ausschnitte

 für beliebige Ausschnittsfenster ist der Bereichscode so nicht mehr einsetzbar;

 das gleiche gilt für die einfache Berechnung der Schnittpunkte zwischen den Kanten der Ausschnittsfenster und den Linien

 Erweiterung für beliebige Ausschnittsfenster: Cyrus-

Beck

(6)

Wiederholung V: Cyrus-Beck

 Clipping von Linien, an beliebigen, konvexen Polygonzügen

 Eckpunkte des Clip-Objekts müssen gegen den

Uhrzeigersinn definiert werden („counterclockwise“)

 Degenerierte Kanten (identische Eckpunkte) müssen vorher

abgefangen werden

 Berechnung der Normalen auf die Kanten des Clip-Objekts, wobei Normalen nach außen zeigen

 Start- und Endpunkt der zu zeichnenden Linie werden für jede Kante mit Hilfe eines

In/Out-Tests klassifiziert

Skalarprodukt zwischen Normale und Verbindung Kante-Linienpunkt

Beiden innen: weitermachen ohne SP Berechnung

Beide außen: aufhören.

 Falls SP berechnet wird, wird

dieser ebenfalls als In/Out-

Punkt klassifiziert.

(7)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 7 -

Wiederholung VI: Cyrus-Beck

void clipAndDraw(Vector2D a, Vector2D b) {

Vector2D v,w0,w1,n;

float t, tIn, tOut, c0, c1, nenner;

int i;

v = b - a;

tIn = 0.0;

tOut = 1.0;

for (i=0; i<4; i++) {

int iNext = (i+1) % 4;

n.setX( clipPoints[iNext].y() - clipPoints[i].y() );

n.setY( - (clipPoints[iNext].x() - clipPoints[i].x()) );

w0 = a - clipPoints[i];

w1 = b - clipPoints[i];

c0 = dot(w0, n);

c1 = dot(w1, n);

if (c0 > 0 && c1 > 0)

// alles außerhalb, fertig return;

if (c0 <= 0 && c1 <= 0) // innerhalb, weitertesten

continue;

nenner = dot(v,n );

t = -c0/nenner;

if (nenner < 0 && t > tIn) tIn = t;

if (nenner > 0 && t < tOut) tOut = t;

}

if (tIn > tOut) return;

b = a + tOut * v;

a = a + tIn * v;

drawLine(a, b);

}

line_cyrus_beck.vcproj

(8)

Wiederholung VII: Cyrus-Beck

A

B In

Out

A

B

In In

Out

Out

Die klassifizierten Schnittpunkte (In/Out) werden entlang von t sortiert. Ist

t_in (t für äußersten In-Punkt) größer als t_out (t für innersten Out-Punkt),

dann liegt die Linie außerhalb und muss nicht gezeichnet werden.

(9)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Polygon Clipping

(10)

Ausgangspunkt

 Wir haben gesagt, dass die „Applikation“ sicherstellen muss, dass put_pixel(x,y) nur für gültige Pixel

aufgerufen wird.

 Bisher Clipping von Linien:

 Cohen-Sutherland: Clippen von Linien an rechteckigen Objekten mit Hilfe von Bereichscodes.

 Cyrus-Beck: Clippen von Linien an beliebigen, konvexen Polygonzügen

 Clipping von Polygon gegen Polygon:

 Sutherland-Hodgman

(11)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 11 -

Sutherland-Hodgman

 Clipping eines Polygonzugs gegen ein konvexes Clip- Polygon (z.B. Bildschirm); der Polygonzug darf konkav sein.

Bildschirm Polygonzug

(4 Punkte)

Ergebnis (9 Punkte)

(12)

Vorgehen

Der Polygonzug wird der Reihe nach an den Clip-Kanten geschnitten.

(13)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 13 -

Vorgehen

 Das Ergebnis muss wieder ein geschlossener Polygonzug sein.

 Als Eingabe dient die Liste der Eckpunkte in der richtigen Reihenfolge (gegen den Uhrzeigersinn).

 Die Routine gibt – nach dem Schnitt mit der jeweiligen Clip-Kante - eine neue Liste von Eckpunkten zurück.

 Wichtig: die Reihenfolge muss stimmen.

(14)

4 Fälle

A

B A

B

A B

A

B

Beide Punkte drinnen:

Output B

Annahme: der Startpunkt A wurde bereits behandelt

Linie „zeigt“ nach außen:

Output S

Linie „zeigt“ nach innen:

Output S, B

Beide Punkte draußen:

S

S

Output (nichts)

(15)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 15 -

Beispiel 1

A

B C

D

Input:

Output:

A B C D A B C S 2 S 1

S 2

S 1

Man beginnt mit der Kante letzter Punkt (D) – erster Punkt (A)

(16)

Beispiel 2

Input:

Output: S 1 A C

A

B C

S 2

S 1

S 4

S 5

S 6

S 3

S 4 S 5 S 6 S 3

A B C S 2

S 1

(17)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 17 -

PseudoCode

 Diese Routine wird der Reihe nach für jede Clip-Kante

aufgerufen.

 „Innerhalb/Außerhalb“: hier wird wieder die Normale auf die

Kante berechnet und mit Hilfe des Vorzeichens des

Skalarproduktes entschieden.

 „Output“: stellt ein neues

Polygon zusammen, das am Ende zurückgegeben wird.

 „Schnittpunkt“ berechnet den Schnittpunkt mit der Clipkante, wobei nur Punkte zw. A und B berechnet werden dürfen.

Polygon SutherlandHodgman(Polygon poly, Edge clipedge)

{

A ist letzter Punkt des Polygons;

Schleife über alle Ecken B des Polygons

{

Wenn B innerhalb von clipedge Wenn A innerhalb von clipedge Output (B);

else {

S = Schnittpunkt (A,B,edge);

Output(S), Output(B);

} else

Wenn A innerhalb von clipedge {

S = Schnittpunkt (A,B,edge);

Output(S);

} A = B;

}

Ergebnis von Output zurückgeben.

}

(18)

Beispiel

A

B C

D

Problem: unnötige Kanten mit Fläche Null…

(19)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 19 -

Sutherland-Hodgman

 Clipping eines Polygonzugs gegen ein konvexes Clip- Polygon (z.B. Bildschirm); der Polygonzug darf konkav sein.

 Problem: unnötige Kanten können am Rand

entstehen, was nicht unbedingt zu Fehlern führt; aus Effizienzgründen können diese nachträglich gelöscht werden.

 Lässt sich sehr gut als Pipeline in Hardware umsetzen.

 Erweiterung für konkave Clip-Polygone:

 Weiler-Atherton

(20)

Clippen von Texten und Bildern

 Schrift besteht aus Kurven für Umrisse der Buchstaben

 Diese werden in der Regel einmal gezeichnet und in verschiedenen Auflösungen als Pixelmuster/Bitmap

gespeichert

 Diese Bitmaps werden als Rechtecke betrachtet und gegen das Clip-Objekt geschnitten und nur der sichtbare Teil gezeichnet.

 Das gleiche gilt auch für Bilder.

a a

(21)

U N I V E R S I T Ä T KOBLENZ · LANDAU

Mausabfrage und

Polygon-Datenstruktur

(22)

Polygon

 Ein Polygon ist ein „n-Eck“ und setzt sich aus einer Reihe von zusammenhängenden Linien zusammen.

 Für eine korrekte Normalenberechnung wird vorausgesetzt, dass die Eckpunkte gegen den Uhrzeigersinn definiert sind.

 Datenstruktur für ein Polygon (2-dimensional), z.B.:

 Liste von Eckpunkten,

 Für jeden Eckpunkt x,y-Koordinate

(23)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 23 -

Polygon2D Klasse (Polygon2D.h)

# ifndef _POLYGON2D_H

#define _POLYGON2D_H

#include "Vector2D.h"

#include <vector>

using namespace std;

class Polygon2D { public:

Polygon2D();

~Polygon2D();

void addPoint(Vector2D point); // neuen Punkt anfuegen Vector2D getPoint(int i) const; // Punkt i zurueckliefern void deletePoints(); // alle Punkte loeschen int numPoints() const; // Anzahl Punkte

void draw() const; // Polygon zeichnen private:

vector<Vector2D> mPoints; // dyn. Array der Punkte };

#endif

(24)

Polygon2D Klasse (Polygon2D.cpp)

#include "Polygon2D.h"

#include <GL/glut.h>

Polygon2D::Polygon2D() {

}

Polygon2D::~Polygon2D() {

}

void Polygon2D::addPoint(Vector2D point) {

mPoints.push_back(point);

}

Vector2D Polygon2D::getPoint(int i) const {

return mPoints[i];

}

void Polygon2D::deletePoints() {

mPoints.clear();

}

int Polygon2D::numPoints() const {

return mPoints.size();

}

void Polygon2D::draw() const {

glBegin(GL_LINE_LOOP);

for (int i = 0 ; i < mPoints.size() ; i++) glVertex2f(mPoints[i].x(), mPoints[i].y());

glEnd();

}

(25)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 25 -

GLUT Funktion zur Mausabfrage

 GLUT stellt uns eine Callback-Funktion für die Maus zur Verfügung.

 Diese wird aufgerufen, wenn eine Maustaste gedrückt wird.

void mouse (int button, int state, int x, int y)

 Die Parameter:

 button : GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON (zeigt an, welche Knöpfe gedrückt wurden)

 state: GLUT_UP, GLUT_DOWN (zeigt an, ob die Taste gedrückt oder losgelassen wurde).

 x, y: Die Position des Mauszeigers beim Drücken der Taste

(gemessen von der linken oberen Ecke des Fenster !!!)

(26)

Beispielprogramm mit Mauseingabe

void mouse(int button, int state, int x, int y) {

Vector2D vertex( x, HOEHE - y);

if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) poly.addPoint ( vertex) ;

else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) poly.deletePoints();

glutPostRedisplay();

}

Wurde die linke Maustaste gedrückt, dann wird ein neuer Punkt zum Polygon hinzugefügt.

Wurde die rechte Maustaste gedrückt, so wird das Polygon gelöscht (genauer:

Liste auf Null Elemente zurückgesetzt).

Bildschirm x y

Maus x

y

(27)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 27 -

Beispielprogramm mit Mauseingabe

#include "Vector2D.h"

#include "Polygon2D.h"

#include <GL/glut.h>

#define BREITE 520

#define HOEHE 520 Polygon2D poly;

void display( void) {

glClear (GL_COLOR_BUFFER_BIT);

glColor3f( 0.0, 0.0, 1.0);

poly.draw();

glFlush ();

}

void init( void) {

glClearColor (1.0, 1.0, 1.0, 0.0);

glOrtho(0, BREITE, 0, HOEHE, -1, 1);

}

void mouse( int button, int state, int x, int y)

{

s. letzte Folie }

int main(int argc, char** argv) {

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);

glutInitWindowSize( BREITE, HOEHE);

glutInitWindowPosition (100, 100);

glutCreateWindow („Polygoneingabe");

init ();

glutMouseFunc(mouse);

glutDisplayFunc(display);

glutMainLoop();

return 0;

}

Poly_input.vcproj

(28)

Punkte und Linien in OpenGL

(29)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 29 -

Punkte, Linien, Flächen

 Alle bisher behandelten Algorithmen zum

 Zeichnen von Punkten

 Zeichnen von Linien (mit Clipping und linearer Interpolation von Eckpunktwerten z.B. Farbe)

 …

 … sind in OpenGL sehr effizient implementiert und auch entsprechend auf die Möglichkeiten der Graphik- Hardware abgebildet.

 OpenGL bietet uns daher eine wichtige Bibliothek zur Erstellung von graphischen Systemen (API:

application programming interface)

(30)

Namenstypisierung

 Funktionen mit verschiedenen Parametern tragen Typ und Dimension im Namen:

gl<FUNC>{1234}{b,ub,s,us,i,ui,f,d}[v](...)

 1,2,3,4: Dimension der Argumente

 b,ub,s,us,i,ui,f,d: Typ: GLbyte, GLubyte, etc. Sonderfall:

GLclampf, GLclampd

 optional können Parameter auch als Vektor übergeben

werden, gekennzeichnet durch das abschließende v

(31)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 31 -

Namenstypisierung

 Beispiel: glColor{34}{b,ub,s,us,i,ui,f,d}[v](...)

GLfloat f[3] = { 0.0, 0.5, 1.0 };

GLubyte b[4] = { 0, 127, 255, 255 };

glColor3f( 0.0, 0.5, 1.0 );

glColor3fv( f );

glColor4ubv( b );

(32)

OpenGL: Punkte

 OpenGL setzt Primitive aus einzelnen Eckpunkten zusammen

 Genereller Ablauf:

glBegin( GL_… );

glVertex...(...);

...

glEnd();

 Vorteil: keine eigenen Datenstrukturen nötig

(33)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 33 -

Beispiel: Eckpunkte

float fpos[3]={ 10, 0, 0 };

unsigned short sx=10,sy=0,sz=0;

glVertex2i( 10, 0 );

glVertex3s( sx, sy, sz );

glVertex3fv( fpos);

glVertex4d( 10.0, 0.0, 0.0, 1.0 );

 bestimmen alle den gleichen Punkt

 Homogene Koordinate wird von der Applikation in der

Regel nicht verwendet. Wenn sie weggelassen wird

(3D-Vektor) wird sie als 1 angenommen.

(34)

Primitivspezifische Einstellungen

 Punkte: Größe mittels

glPointSize( GLfloat size );

 nicht jede Größe unterstützt, über glGet() abzufragen

 Wenn Antialiasing abgeschaltet ist (default), dann ist der Punkt ein Quadrat von size*size Pixeln. Nicht-Integer Werte werden gerundet.

glDisable(GL_POINT_SMOOTH);

 Wenn Antialiasing eingeschaltet ist, dann wird ein Kreis gezeichnet. Nicht-Integer Werte für size werden hier nicht gerundet.

glEnable(GL_POINT_SMOOTH);

(35)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 35 -

Aktivieren / Inaktivieren

Viele Features müssen explizit aktiviert werden glEnable( GLenum feature );

zum Inaktivieren dient dann

glDisable( GLenum feature );

der Zustand kann abgefragt werden mittels glIsEnabled( GLenum feature );

die Konstanten können nicht verodert werden

(36)

Linien

 Linien: Breite mittels

glLineWidth( GLfloat width );

 ähnlich wie Punkte nicht jede Größe möglich

 Wenn Antialiasing abgeschaltet ist (default), dann ist width die Breite der Linie in Pixeln (also unabhängig von

Fenstergröße…). Nicht-Integer Werte werden gerundet.

glDisable(GL_LINE_SMOOTH);

 Wenn Antialiasing eingeschaltet ist, dann wird die Helligkeit der Pixel abhängig vom Bedeckungsgrad berechnet. Nicht- Integer Werte werden hier nicht gerundet.

glEnable(GL_LINE_SMOOTH);

(37)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 37 -

Strichelungen

 Gestrichelte Linien definierbar:

glLineStipple( GLint factor, GLushort pattern );

 Muster aus der Binärdarstellung von pattern 8 4 2 1 8 4 2 1 8 4 2 1 8 4 2 1

 0xaaaa

 0x1010

 factor vervielfacht die einzelnen Bits

 0xaaaa 1

 0xaaaa 3

 muß mit glEnable( GL_LINE_STIPPLE ); aktiviert werden

(38)

void display(void) {

int i;

glClear (GL_COLOR_BUFFER_BIT);

glColor3f (0.0, 0.0, 0.0);

/* 1. Zeile rechteckige Punkte */

for (i = -9; i < 10; i ++) {

glPointSize(10+i);

glBegin(GL_POINTS);

glVertex3f(i/10.0, 0.75,0);

glEnd();

}

/* 2. Zeile Anti-aliased Punkte */

glEnable(GL_POINT_SMOOTH);

for (i = -9; i < 10; i ++) {

glPointSize(10+i);

glBegin(GL_POINTS);

glVertex3f(i/10.0, 0.25,0);

glEnd();

}

/* 3. Zeile 2 Linien mit untersch. Stipple */

glEnable (GL_LINE_STIPPLE);

glLineWidth (1.0);

glLineStipple (1, 0x0101); /* dotted */

glBegin(GL_LINES);

glVertex3f(-0.75, -0.25, 0);

glVertex3f( 0, -0.25, 0);

glEnd();

glLineStipple (1, 0x00FF); /* dashed */

glBegin(GL_LINES);

glVertex3f( 0, -0.25, 0);

glVertex3f( 0.75, -0.25, 0);

glEnd();

/* 4. Zeile 2 dicke Lin. m. untersch. Stipple */

glLineWidth (5.0);

glLineStipple (1, 0x0101); /* dotted */

glBegin(GL_LINES);

glVertex3f(-0.75, -0.75, 0);

glVertex3f( 0, -0.75, 0);

glEnd();

glLineStipple (1, 0x00FF); /* dashed */

glBegin(GL_LINES);

glVertex3f( 0, -0.75, 0);

(39)

U N I V E R S I T Ä T

KOBLENZ · LANDAU S. Müller - 39 -

Beispiel

points_lines.c

points_lines.exe

Referenzen

ÄHNLICHE DOKUMENTE

[r]

[r]

Das Verfahren integrierte Planung im Dialog Die Vorgehensweise setzte auf ein integriertes, Ergebnis orientiertes Verfahren und knüpfte dabei an vorhandene Untersuchungen, Planungen

void glutSpaceballButtonFunc(void (*func)(int button, int state));. void glutButtonBoxFunc(void (*func)(int button,

Geschäftstätigkeit Ziel/Kompetenzen: Chancen und Risiken des Außenhandels einschätzen können, Vertragsbestandteile int. Verträge erläutern können, Abwicklung von

Eine selbstorganisierende Liste ist eine Liste, bei der kurz aufeinanderfolgende Zugriffe auf dieselben Elemente sehr effizient sind: Wird ein Element in der Liste gefunden,

Eine selbstorganisierende Liste ist eine Liste, bei der kurz aufeinanderfolgende Zugriffe auf dieselben Elemente sehr effizient sind: Wird ein Element in der Liste gefunden,

Hinweis: Die Methode equals(Struct other) der Klasse Struct wird nur von den JUnit-Testfällen verwendet und prüft nicht die korrekte