00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "eggPolygon.h"
00020 #include "eggGroupNode.h"
00021
00022 #include <indent.h>
00023
00024 #include <algorithm>
00025
00026 TypeHandle EggPolygon::_type_handle;
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 bool EggPolygon::
00039 cleanup() {
00040 remove_doubled_verts(true);
00041
00042
00043 Normald normal;
00044 return calculate_normal(normal);
00045 }
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 bool EggPolygon::
00060 calculate_normal(Normald &result, CoordinateSystem cs) const {
00061
00062 Vertexd v[3];
00063 int i = 0;
00064
00065 const_iterator vi = begin();
00066 while (vi != end()) {
00067 EggVertex *vertex = (*vi);
00068 v[i] = vertex->get_pos3();
00069
00070
00071 bool is_unique = true;
00072 for (int j = 0; j < i && is_unique; j++) {
00073 is_unique = !v[i].almost_equal(v[j]);
00074 }
00075
00076 if (is_unique) {
00077 if (i < 2) {
00078 i++;
00079
00080 } else {
00081
00082 LVector3d a = v[1] - v[0];
00083 LVector3d b = v[2] - v[0];
00084 LVector3d normal = a.cross(b);
00085
00086 if (normal.normalize()) {
00087
00088
00089 if (cs == CS_default) {
00090 cs = default_coordinate_system;
00091 }
00092 if (cs == CS_zup_left || cs == CS_yup_left) {
00093 normal = -normal;
00094 }
00095
00096 result = normal;
00097 return true;
00098 }
00099
00100
00101
00102 }
00103 }
00104 ++vi;
00105 }
00106
00107
00108
00109 return false;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 PT(EggPolygon) EggPolygon::
00127 triangulate_in_place(bool convex_also) {
00128 EggGroupNode *parent = get_parent();
00129 nassertr(parent != (EggGroupNode *)NULL, this);
00130
00131 PT(EggPolygon) save_me = this;
00132 parent->remove_child(this);
00133 triangulate_poly(parent, convex_also);
00134
00135 return save_me;
00136 }
00137
00138
00139
00140
00141
00142
00143
00144 void EggPolygon::
00145 write(ostream &out, int indent_level) const {
00146 write_header(out, indent_level, "<Polygon>");
00147 write_body(out, indent_level+2);
00148 indent(out, indent_level) << "}\n";
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158 bool EggPolygon::
00159 decomp_concave(EggGroupNode *container, int asum, int x, int y) const {
00160 #define VX(p, c) p->coord[c]
00161
00162 struct DecompVtx {
00163 int index;
00164 LPoint3d coord;
00165 struct DecompVtx *next;
00166 };
00167
00168 DecompVtx *p0, *p1, *p2, *t0, *vert;
00169 DecompVtx *m[3];
00170 double xmin, xmax, ymin, ymax;
00171 int i, init, csum, chek;
00172 double a[3], b[3], c[3], s[3];
00173
00174 int num_verts = size();
00175 nassertr(num_verts >= 3, false);
00176
00177
00178 vert = (DecompVtx *) alloca(sizeof(DecompVtx));
00179 vert->index = 0;
00180 vert->coord = get_vertex(0)->get_pos3();
00181 p1 = vert;
00182
00183 for (i = 1; i < num_verts; i++) {
00184 p0 = (DecompVtx *) alloca(sizeof(DecompVtx));
00185 p0->index = i;
00186 p0->coord = get_vertex(i)->get_pos3();
00187
00188
00189 if (!(p0->coord == p1->coord)) {
00190 p1->next = p0;
00191 p1 = p0;
00192 }
00193 }
00194 p1->next = vert;
00195
00196 p0 = vert;
00197 p1 = p0->next;
00198 p2 = p1->next;
00199 m[0] = p0;
00200 m[1] = p1;
00201 m[2] = p2;
00202 chek = 0;
00203
00204 while (p0 != p2->next) {
00205
00206 if (chek &&
00207 m[0] == p0 &&
00208 m[1] == p1 &&
00209 m[2] == p2) {
00210
00211 return false;
00212 }
00213
00214 chek = 1;
00215
00216 a[0] = VX(p1, y) - VX(p2, y);
00217 b[0] = VX(p2, x) - VX(p1, x);
00218 a[2] = VX(p0, y) - VX(p1, y);
00219 b[2] = VX(p1, x) - VX(p0, x);
00220
00221 csum = ((b[0] * a[2] - b[2] * a[0] >= 0.0) ? 1 : 0);
00222
00223 if (csum ^ asum) {
00224
00225 p0 = p1;
00226 p1 = p2;
00227 p2 = p2->next;
00228
00229 } else {
00230
00231 xmin = (VX(p0, x) < VX(p1, x)) ? VX(p0, x) : VX(p1, x);
00232 if (xmin > VX(p2, x))
00233 xmin = VX(p2, x);
00234
00235 xmax = (VX(p0, x) > VX(p1, x)) ? VX(p0, x) : VX(p1, x);
00236 if (xmax < VX(p2, x))
00237 xmax = VX(p2, x);
00238
00239 ymin = (VX(p0, y) < VX(p1, y)) ? VX(p0, y) : VX(p1, y);
00240 if (ymin > VX(p2, y))
00241 ymin = VX(p2, y);
00242
00243 ymax = (VX(p0, y) > VX(p1, y)) ? VX(p0, y) : VX(p1, y);
00244 if (ymax < VX(p2, y))
00245 ymax = VX(p2, y);
00246
00247 for (init = 1, t0 = p2->next; t0 != p0; t0 = t0->next) {
00248 if (VX(t0, x) >= xmin && VX(t0, x) <= xmax &&
00249 VX(t0, y) >= ymin && VX(t0, y) <= ymax) {
00250 if (init) {
00251 a[1] = VX(p2, y) - VX(p0, y);
00252 b[1] = VX(p0, x) - VX(p2, x);
00253 init = 0;
00254 c[0] = VX(p1, x) * VX(p2, y) - VX(p2, x) * VX(p1, y);
00255 c[1] = VX(p2, x) * VX(p0, y) - VX(p0, x) * VX(p2, y);
00256 c[2] = VX(p0, x) * VX(p1, y) - VX(p1, x) * VX(p0, y);
00257 }
00258
00259 s[0] = a[0] * VX(t0, x) + b[0] * VX(t0, y) + c[0];
00260 s[1] = a[1] * VX(t0, x) + b[1] * VX(t0, y) + c[1];
00261 s[2] = a[2] * VX(t0, x) + b[2] * VX(t0, y) + c[2];
00262
00263 if (asum) {
00264 if (s[0] >= 0.0 && s[1] >= 0.0 && s[2] >= 0.0)
00265 break;
00266 } else {
00267 if (s[0] <= 0.0 && s[1] <= 0.0 && s[2] <= 0.0)
00268 break;
00269 }
00270 }
00271 }
00272
00273 if (t0 != p0) {
00274 p0 = p1;
00275 p1 = p2;
00276 p2 = p2->next;
00277 } else {
00278
00279
00280 PT(EggPolygon) triangle = new EggPolygon(*this);
00281 triangle->clear();
00282 triangle->add_vertex(get_vertex(p0->index));
00283 triangle->add_vertex(get_vertex(p1->index));
00284 triangle->add_vertex(get_vertex(p2->index));
00285
00286 if (triangle->cleanup()) {
00287 container->add_child(triangle.p());
00288 }
00289
00290 p0->next = p1->next;
00291 p1 = p2;
00292 p2 = p2->next;
00293
00294 m[0] = p0;
00295 m[1] = p1;
00296 m[2] = p2;
00297 chek = 0;
00298 }
00299 }
00300 }
00301
00302
00303 PT(EggPolygon) triangle = new EggPolygon(*this);
00304 triangle->clear();
00305 triangle->add_vertex(get_vertex(p0->index));
00306 triangle->add_vertex(get_vertex(p1->index));
00307 triangle->add_vertex(get_vertex(p2->index));
00308
00309 if (triangle->cleanup()) {
00310 container->add_child(triangle.p());
00311 }
00312
00313 return true;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 bool EggPolygon::
00337 triangulate_poly(EggGroupNode *container, bool convex_also) {
00338 LPoint3d p0, p1, as;
00339 double dx1, dy1, dx2, dy2, max;
00340 int i, flag, asum, csum, index, x, y, v0, v1, v, even;
00341
00342 if (!cleanup()) {
00343 return false;
00344 }
00345
00346
00347 int num_verts = size();
00348 if (num_verts == 3) {
00349 container->add_child(this);
00350
00351 return true;
00352
00353 } else if (num_verts < 3) {
00354
00355 return false;
00356 }
00357
00358
00359 as[0] = 0.0;
00360 as[1] = 0.0;
00361 as[2] = 0.0;
00362
00363 for (i = 0; i < num_verts; i++) {
00364 p0 = get_vertex(i)->get_pos3();
00365 p1 = get_vertex((i + 1) % num_verts)->get_pos3();
00366 as[0] += p0[0] * p1[1] - p0[1] * p1[0];
00367 as[1] += p0[0] * p1[2] - p0[2] * p1[0];
00368 as[2] += p0[1] * p1[2] - p0[2] * p1[1];
00369 }
00370
00371
00372 max = 0.0;
00373 index = 0;
00374 flag = 0;
00375 for (i = 0; i < 3; i++) {
00376 if (as[i] >= 0.0) {
00377 if (as[i] > max) {
00378 max = as[i];
00379 index = i;
00380 flag = 1;
00381 }
00382 } else {
00383 as[i] = -as[i];
00384 if (as[i] > max) {
00385 max = as[i];
00386 index = i;
00387 flag = 0;
00388 }
00389 }
00390 }
00391
00392
00393 switch (index) {
00394 case 0:
00395 x = 0;
00396 y = 1;
00397 break;
00398
00399 case 1:
00400 x = 0;
00401 y = 2;
00402 break;
00403
00404 default:
00405 x = 1;
00406 y = 2;
00407 break;
00408 }
00409
00410
00411 p0 = get_vertex(0)->get_pos3();
00412 p1 = get_vertex(1)->get_pos3();
00413 dx1 = p1[x] - p0[x];
00414 dy1 = p1[y] - p0[y];
00415 p0 = p1;
00416 p1 = get_vertex(2)->get_pos3();
00417
00418 dx2 = p1[x] - p0[x];
00419 dy2 = p1[y] - p0[y];
00420 asum = ((dx1 * dy2 - dx2 * dy1 >= 0.0) ? 1 : 0);
00421
00422 for (i = 0; i < num_verts - 1; i++) {
00423 p0 = p1;
00424 p1 = get_vertex((i+3) % num_verts)->get_pos3();
00425
00426 dx1 = dx2;
00427 dy1 = dy2;
00428 dx2 = p1[x] - p0[x];
00429 dy2 = p1[y] - p0[y];
00430 csum = ((dx1 * dy2 - dx2 * dy1 >= 0.0) ? 1 : 0);
00431
00432 if (csum ^ asum) {
00433
00434 return decomp_concave(container, flag, x, y);
00435 }
00436 }
00437
00438
00439 if (!convex_also) {
00440 container->add_child(this);
00441
00442 return true;
00443 }
00444
00445 v0 = 0;
00446 v1 = 1;
00447 v = num_verts - 1;
00448
00449 even = 1;
00450
00451
00452
00453
00454
00455 for (i = 0; i < num_verts - 2; i++) {
00456 if (even) {
00457 PT(EggPolygon) triangle = new EggPolygon(*this);
00458 triangle->clear();
00459 triangle->add_vertex(get_vertex(v0));
00460 triangle->add_vertex(get_vertex(v1));
00461 triangle->add_vertex(get_vertex(v));
00462
00463 if (triangle->cleanup()) {
00464 container->add_child(triangle.p());
00465 }
00466
00467 v0 = v1;
00468 v1 = v;
00469 v = v0 + 1;
00470 } else {
00471 PT(EggPolygon) triangle = new EggPolygon(*this);
00472 triangle->clear();
00473 triangle->add_vertex(get_vertex(v1));
00474 triangle->add_vertex(get_vertex(v0));
00475 triangle->add_vertex(get_vertex(v));
00476
00477 if (triangle->cleanup()) {
00478 container->add_child(triangle.p());
00479 }
00480
00481 v0 = v1;
00482 v1 = v;
00483 v = v0 - 1;
00484 }
00485
00486 even = !even;
00487 }
00488
00489 return true;
00490 }