polygon.c++
7.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#include "polygon.h"
void polygon::_init_normal_(void) {
if(vl && count>0) {
for(unsigned i=0; i<count; i++) {
center[O_X]+=(*vl)[content[i]][O_X];
center[O_Y]+=(*vl)[content[i]][O_Y];
center[O_Z]+=(*vl)[content[i]][O_Z];
}
center[X]=center[O_X]/=count;
center[Y]=center[O_Y]/=count;
center[Z]=center[O_Z]/=count;
center[W]=center[O_W]=1;
normal=center+
(((*vl)[content[1]]-(*vl)[content[0]])|
((*vl)[content[count-1]]-(*vl)[content[0]])).norm();
}
else {
center=vertex();
normal=vertex();
}
}
void polygon::transform(const Mmn<double>& tm, int p) {
for(unsigned i=0; i<count; i++) {
(*vl)[content[i]].transform(tm, p);
}
transform_normal(tm, p);
}
void polygon::transform_normal(const Mmn<double>& tm, int p) {
center.transform(tm, p);
normal.transform(tm, p);
}
void polygon::reset(void) {
/* for(unsigned i=0; i<count; i++) {
(*vl)[content[i]].reset();
}*/
center.reset();
normal.reset();
}
/**
* \brief Clipping gegen eine vordere Z-Ebene
*
* Dieser Algorithmus clippt das polygon gegen eine vordere Z-Ebene
*
* \param this Das ungeclippte unprojezierte Polygon.
* \return ein geclipptes Polygon.
*/
polygon polygon::clip_front_z(double min_Z) const {
container<unsigned> clip;
polygon ret;
for(unsigned j=0; j<(*this).card(); j++) {
double x0=(*vl)[container<unsigned>::operator[](j)][X],
y0=(*vl)[container<unsigned>::operator[](j)][Y],
z0=(*vl)[container<unsigned>::operator[](j)][Z],
x1=(*vl)[container<unsigned>::operator[]((j+1)%(*this).card())][X],
y1=(*vl)[container<unsigned>::operator[]((j+1)%(*this).card())][Y],
z1=(*vl)[container<unsigned>::operator[]((j+1)%(*this).card())][Z];
// Wenn beide drin sind den zweiten übernehmen.
if(z0>min_Z && z1>min_Z)
// Nur P2 nach clip übernehmen
clip[clip.card()]=
container<unsigned>::operator[]((j+1)%(*this).card());
// Wenn nur P2 drin ist
if(z0<=min_Z && z1>min_Z) {
// Schnittpunkt berechnen und nach temp übernehmen
unsigned idx=(*vl).card();
double t=(min_Z-z0)/(z1-z0);
double x=x0+t*(x1-x0);
double y=y0+t*(y1-y0);
// neuen Vertex zur Vertexliste.
(*vl)[idx]=vertex(x, y, min_Z, COORD);
// und ins geclippte polygon
clip[clip.card()]=idx;
// und P2 ins geclippte polygon
clip[clip.card()]=
container<unsigned>::operator[]((j+1)%(*this).card());
}
// Wenn nur P1 drin ist
if(z0>min_Z && z1<=min_Z) {
// Schnittpunkt berechnen und nach temp übernehmen
unsigned idx=(*vl).card();
double t=(min_Z-z1)/(z0-z1);
double x=x1+t*(x0-x1);
double y=y1+t*(y0-y1);
// neuen Vertex zur Vertexliste.
(*vl)[idx]=vertex(x, y, min_Z, COORD);
// und ins geclippte polygon
clip[clip.card()]=idx;
}
}
// Das geclippte Polygon zurückliefern.
ret=polygon(clip, vl);
ret.set_id(id);
return ret;
}
/**
* \brief Clippings nach Sutherland-Hodgman
*
* Cliped das Polygon an dem Polygon p. Es wird ein neues Polygon
* erzeugt, das diesem Polygon innerhalb des Polygons p entspricht.
* Dieses neue Polygon nutzt die selbe Vertexliste.
*
* \param p Das Polygon an dem geclipped werden soll.
* \returns Ein in p passendes Polygon.
*/
polygon polygon::clip_2d(const polygon& p) const {
//! enthält während des clippings die aktuellen
//! Vertex_listen indizies.
container<unsigned> clip;
// Zuerst Origialdaten sichern.
clip=(container<unsigned>)*this;
// Solange unbearbeitete Kanten im Clippolygon sind...
for(unsigned i=0; i<p.card(); i++) {
//! enthält immer die neuen geclippten VL-Indizies
container<unsigned> temp;
//! Hole nächste Kante des Clippolygons und sichere sie als
//! Vektor. Diese ist definiert über die beiden Punkte
//! p[i] und p[(i+1)%p.card()]
double x0=p[i][X],
y0=p[i][Y],
x1=p[(i+1)%p.card()][X],
y1=p[(i+1)%p.card()][Y];
// Jetzt muss zunaechst ein Vektor erzeugt werden der senkrecht
// von der Kante ins Poligon zeigt
// chk=(X=P1.Y-P2.Y, Y=P2.X-P1.X, 0)
vertex chk(y0-y1, x1-x0, 0, VEKTOR);
// Solange Kanten nicht bearbeitet wurden
for(unsigned j=0; j<clip.card(); j++) {
//! hole nächste Kante aus clipped Prüfe ob Punkt1 und/oder
//! Punkt2 immerhalb des Clippolygons sind.
//! Kante ist (*vl)[clip[j]] und (*vl)[clip[(j+1)%clip.count]]
double x0s=(*vl)[clip[j]][X],
y0s=(*vl)[clip[j]][Y],
x1s=(*vl)[clip[(j+1)%clip.card()]][X],
y1s=(*vl)[clip[(j+1)%clip.card()]][Y];
//! Liegt der erste Punkt innerhalb des Clippolygons
//! chk%(P1 - clipP1) > 0.05 und/oder
double chk_p1=chk%((*vl)[clip[j]] - (*p.vl)[i]);
//! liegt der zweite Punkt innerhalb des Clippolygons
//! chk%(P2 - clipP1) > 0.05
double chk_p2=chk%((*vl)[clip[(j+1)%clip.card()]] -
(*p.vl)[i]);
// 0.05 ist ein Epsilon um Ungenauigkeiten auszugleichen und
// ganz sicher zu gehen das der Punkt wirklich innerhalb liegt.
// Wenn beide drin sind
if(chk_p1>0.05 && chk_p2>0.05)
// Nur P2 nach temp übernehmen
temp[temp.card()]=clip[(j+1)%clip.card()];
// Wenn nur P1 drin ist
if(chk_p1>0.05 && chk_p2<=0.05) {
// Schnittpunkt berechnen und nach temp übernehmen
unsigned idx=(*vl).card();
double x,y;
x=x0+((((x1s-x0s)*(y0-y0s))+((y1s-y0s)*(x0s-x0)))/
(((x1-x0)*(y1s-y0s))-((y1-y0)*(x1s-x0s))))*(x1-x0);
y=y0+((((x1s-x0s)*(y0-y0s))+((y1s-y0s)*(x0s-x0)))/
(((x1-x0)*(y1s-y0s))-((y1-y0)*(x1s-x0s))))*(y1-y0);
// neuen Vertex zur Vertexliste.
(*vl)[idx]=vertex(x, y, 0, COORD);
temp[temp.card()]=idx;
}
// Wenn nur P2 drin ist
if(chk_p1<=0.05 && chk_p2>0.05) {
// Schnittpunkt berechnen und nach temp übernehmen
unsigned idx=(*vl).card();
double x,y;
x=x0+((((x1s-x0s)*(y0-y0s))+((y1s-y0s)*(x0s-x0)))/
(((x1-x0)*(y1s-y0s))-((y1-y0)*(x1s-x0s))))*(x1-x0);
y=y0+((((x1s-x0s)*(y0-y0s))+((y1s-y0s)*(x0s-x0)))/
(((x1-x0)*(y1s-y0s))-((y1-y0)*(x1s-x0s))))*(y1-y0);
// neuen Vertex zur Vertexliste.
(*vl)[idx]=vertex(x, y, 0, COORD);
temp[temp.card()]=idx;
// P2 nach temp übernehmen
temp[temp.card()]=clip[(j+1)%clip.card()];
}
// Wenn keiner drin ist
// Nichts nach temp
}
// temp enthält jetzt die aktuellen Vertexindizies,
// für den nächsten durchlauf muß clip
// darauf gesetzt werden.
clip=temp;
}
// Das geclippte Polygon zurückliefern.
return polygon(clip, vl);
}
void polygon::project_2d(double lcx, double sw, double sh,
double ph_ar, double sy, int p) {
for(unsigned i=0; i<count; i++) {
(*vl)[content[i]].project_2d(lcx, sw, sh, ph_ar, sy, p);
}
}