changed: gcc8 base update
[opensg.git] / Source / System / NodeCores / Drawables / Nurbs / Internal / OSGSimplePolygon.cpp
blob8a8cbbc68993c4f4d3791e10d167bb7f1777cb17
1 /*---------------------------------------------------------------------------*\
2 * OpenSG NURBS Library *
3 * *
4 * *
5 * Copyright (C) 2001-2006 by the University of Bonn, Computer Graphics Group*
6 * *
7 * http://cg.cs.uni-bonn.de/ *
8 * *
9 * contact: edhellon@cs.uni-bonn.de, guthe@cs.uni-bonn.de, rk@cs.uni-bonn.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
38 #ifdef WIN32
39 # pragma warning (disable : 985)
40 #endif
42 #include <stdio.h>
44 #include "OSGLog.h"
46 #include "OSGSimplePolygon.h"
47 #include "OSGpredicates.h"
49 OSG_USING_NAMESPACE
51 #ifndef M_PI
52 # define M_PI 3.14159265358979323846
53 #endif /* M_PI */
54 #ifndef M_PI_2
55 # define M_PI_2 (M_PI * 0.5)
56 #endif /* M_PI_2 */
58 #ifdef _DEBUG
59 #ifdef WIN32
60 #undef THIS_FILE
61 static char THIS_FILE[] = __FILE__;
62 #endif
63 #endif
66 * Converted to use robust predicates, see `predicates.c' and
67 * `predicates.h'
69 * FIXME: may have some license issues, also must run at first
70 * compilation the `predicates_init' calculator, may have trouble
71 * on Win32 systems.
75 * Public methods
78 // default constructor
79 SimplePolygon::SimplePolygon() :
80 vertices ( ),
81 is_marked ( 0),
82 validThirdPoints( ),
83 numThirdPoints ( 0),
84 maxCalculated ( 0),
85 v1tp ( -1),
86 v2tp ( -1),
87 m_bConvex (false)
92 //! Triangulates the polygon, using RK's constrained method.
93 /*!
94 * Note that the resulting triangulation will not necessarily be complex,
95 * since it's constrained by the polygon's edges.
97 * Besides triangulating the polygon this method also does:
98 * - insertion of the new polygons (triangles) at the end of
99 * the polygon list.
100 * - setting up marking information for the new polygons.
102 * \param polylist the global list of polygons
103 * \param selfindex the index of this polygon in the global list
104 * \return zero on success, and a negative integer if some error occured.
106 int SimplePolygon::triangulate(DCTPVec2dvector &globalverts, simplepolygonvector &polylist)
108 #ifdef OSG_TRIANGULATE_CONVEX
109 if( (!is_marked) && (m_bConvex) )
111 // std::cerr <<"triangulating convex: " <<vertices.size() << std::endl;
112 switch(vertices.size() )
114 case 0:
115 case 1:
116 case 2:
117 return 0;
118 case 3:
120 polylist.push_back(*this);
122 return 0;
125 unsigned int ui_prev;
126 unsigned int ui_mid;
127 unsigned int ui_next;
128 const unsigned int cui_vertex_cnt = UInt32(vertices.size());
129 SimplePolygon cl_poly;
131 ui_mid = 0;
133 for(ui_prev = 1; ui_prev < cui_vertex_cnt; ++ui_prev)
135 if(globalverts[vertices[ui_prev]][1] < globalverts[vertices[ui_mid]][1])
137 ui_mid = ui_prev;
139 else if( (globalverts[vertices[ui_prev]][1] == globalverts[vertices[ui_mid]][1]) &&
140 (globalverts[vertices[ui_prev]][0] < globalverts[vertices[ui_mid]][0]) )
142 ui_mid = ui_prev;
146 ui_prev = (ui_mid + cui_vertex_cnt - 1) % cui_vertex_cnt;
147 ui_next = (ui_mid + 1) % cui_vertex_cnt;
149 cl_poly.vertices.resize(3);
150 cl_poly.is_marked = is_marked;
151 cl_poly.vertices[0] = vertices[ui_mid];
152 cl_poly.vertices[1] = vertices[ui_next];
153 cl_poly.vertices[2] = vertices[ui_prev];
155 ui_prev = (ui_prev + cui_vertex_cnt - 1) % cui_vertex_cnt;
156 ui_next = (ui_next + 1) % cui_vertex_cnt;
158 while(cl_poly.vertices[1] != cl_poly.vertices[2])
160 polylist.push_back(cl_poly);
161 if(globalverts[vertices[ui_prev]][1] < globalverts[vertices[ui_next]][1])
163 cl_poly.vertices[0] = cl_poly.vertices[2];
164 cl_poly.vertices[2] = vertices[ui_prev];
165 ui_prev = (ui_prev + cui_vertex_cnt - 1) % cui_vertex_cnt;
167 else if( (globalverts[vertices[ui_prev]][1] == globalverts[vertices[ui_next]][1]) &&
168 (globalverts[vertices[ui_prev]][0] < globalverts[vertices[ui_next]][0]) )
170 cl_poly.vertices[0] = cl_poly.vertices[2];
171 cl_poly.vertices[2] = vertices[ui_prev];
172 ui_prev = (ui_prev + cui_vertex_cnt - 1) % cui_vertex_cnt;
174 else
176 cl_poly.vertices[0] = cl_poly.vertices[1];
177 cl_poly.vertices[1] = vertices[ui_next];
178 ui_next = (ui_next + 1) % cui_vertex_cnt;
181 return 0;
183 #endif
185 // std::cerr << " triangulate in, size: " << vertices.size() << std::endl;
186 switch(vertices.size() )
188 case 0:
189 case 1:
190 case 2:
191 return 0;
192 case 3:
194 polylist.push_back(*this);
195 // SimplePolygon p;
196 // p.vertices = vertices;
197 // p.is_marked = is_marked;
198 // std::cerr << "adding polygon of 3 vertices into the list..." << std::endl;
199 // polylist.push_back( p ); // FIXME, this is not too elegant
200 // std::cerr << "triangulate out!!!" << std::endl;
202 return 0;
203 case 4:
205 const int ci_v1 = vertices[0];
206 const int ci_v2 = vertices[1];
207 const int ci_v3 = vertices[2];
208 const int ci_v4 = vertices[3];
209 const double cd_sdist1 = (globalverts[ci_v1] - globalverts[ci_v3]).squareLength();
210 const double cd_sdist2 = (globalverts[ci_v2] - globalverts[ci_v4]).squareLength();
211 double ad_pa[2];
212 double ad_pb[2];
213 double ad_pc[2];
214 double ad_pd[2];
215 SimplePolygon p;
217 p.vertices.resize(3);
218 p.is_marked = is_marked;
220 ad_pa[0] = globalverts[ci_v1][0];
221 ad_pa[1] = globalverts[ci_v1][1];
222 ad_pb[0] = globalverts[ci_v2][0];
223 ad_pb[1] = globalverts[ci_v2][1];
224 ad_pc[0] = globalverts[ci_v3][0];
225 ad_pc[1] = globalverts[ci_v3][1];
226 ad_pd[0] = globalverts[ci_v4][0];
227 ad_pd[1] = globalverts[ci_v4][1];
229 if(cd_sdist1 - cd_sdist2 < DCTP_EPS)
231 /* const double cd_r1 = orient2d( ad_pa, ad_pb, ad_pc );
232 const double cd_r2 = orient2d( ad_pa, ad_pb, ad_pd );
233 if( ( ( cd_r1 <= 0.0 ) && ( cd_r2 <= 0.0 ) ) ||
234 ( ( cd_r1 >= 0.0 ) && ( cd_r2 >= 0.0 ) ) )*/
235 if( (orient2d(ad_pa, ad_pb, ad_pc) <= 0.0) ||
236 (orient2d(ad_pa, ad_pd, ad_pc) >= 0.0) ||
237 (incircle(ad_pa, ad_pb, ad_pc, ad_pd) > 0.0) )
239 p.vertices[0] = ci_v1;
240 p.vertices[1] = ci_v2;
241 p.vertices[2] = ci_v4;
242 polylist.push_back(p);
243 p.vertices[0] = ci_v2;
244 p.vertices[1] = ci_v3;
245 p.vertices[2] = ci_v4;
246 polylist.push_back(p);
247 // std::cerr << globalverts[ ci_v1 ] << globalverts[ ci_v2 ] << globalverts[ ci_v3 ] << globalverts[ ci_v4 ] << std::endl;
249 else
251 p.vertices[0] = ci_v1;
252 p.vertices[1] = ci_v2;
253 p.vertices[2] = ci_v3;
254 polylist.push_back(p);
255 p.vertices[0] = ci_v1;
256 p.vertices[1] = ci_v3;
257 p.vertices[2] = ci_v4;
258 polylist.push_back(p);
261 else
263 // const double cd_r1 = orient2d( ad_pc, ad_pd, ad_pa );
264 // const double cd_r2 = orient2d( ad_pc, ad_pd, ad_pb );
265 // if( ( ( cd_r1 <= 0.0 ) && ( cd_r2 <= 0.0 ) ) ||
266 // ( ( cd_r1 >= 0.0 ) && ( cd_r2 >= 0.0 ) ) )
267 if( (orient2d(ad_pb, ad_pc, ad_pd) <= 0.0) ||
268 (orient2d(ad_pb, ad_pa, ad_pd) >= 0.0) ||
269 (incircle(ad_pa, ad_pb, ad_pd, ad_pc) > 0.0) )
271 p.vertices[0] = ci_v1;
272 p.vertices[1] = ci_v2;
273 p.vertices[2] = ci_v3;
274 polylist.push_back(p);
275 p.vertices[0] = ci_v1;
276 p.vertices[1] = ci_v3;
277 p.vertices[2] = ci_v4;
278 polylist.push_back(p);
279 // std::cerr << globalverts[ ci_v1 ] << globalverts[ ci_v2 ] << globalverts[ ci_v3 ] << globalverts[ ci_v4 ] << std::endl;
281 else
283 p.vertices[0] = ci_v1;
284 p.vertices[1] = ci_v2;
285 p.vertices[2] = ci_v4;
286 polylist.push_back(p);
287 p.vertices[0] = ci_v2;
288 p.vertices[1] = ci_v3;
289 p.vertices[2] = ci_v4;
290 polylist.push_back(p);
294 return 0;
297 // recalc valid third points!
298 v1tp = -1;
299 validThirdPoints.resize(vertices.size() );
301 SimplePolygon poly;
302 int i2, i3; // this is an index into the vertices[] vector
303 int err;
304 DCTPivector verts; //p1verts, p2verts, p3verts;
305 int i;
306 int j;
307 // pseudo random (reproduces same triangulation)
308 int offs = (int( globalverts[vertices[0]][0] * vertices.size() ) ) % vertices.size();
310 /* for( i = 0; i < vertices.size( ); ++i )
312 std::cerr << globalverts[ vertices[ i ] ][0] << ",";
313 std::cerr << globalverts[ vertices[ i ] ][1] << std::endl;
316 for(j = 0; j < int(vertices.size()); j++)
318 i = (j + offs) % vertices.size();
319 // v1 = vertices[ i ];
320 if(i == int(vertices.size()) - 1)
321 i2 = 0; //v2 = vertices [ 0 ];
322 else
323 i2 = i + 1; //v2 = vertices[ i + 1 ];
324 err = findThirdPoint(globalverts, i, i2, i3);
325 if(err)
326 return err;
327 if(i3 >= 0)
329 // build p1
330 int k = i2; // !!!
331 verts.resize(0);
332 while(k != i3)
334 // std::cerr << " k: " << k;
335 verts.push_back(vertices[k]);
336 k++; if(k == int(vertices.size()) )
337 k = 0;
338 } // while k
339 verts.push_back(vertices[k]); // record the last one aswell
340 // std::cerr << " k: " << k << std::endl;
341 poly.vertices = verts;
342 poly.is_marked = is_marked;
343 // std::cerr << "calling p1... " << std::endl;
344 err = poly.triangulate(globalverts, polylist);
345 if(err)
346 return err;
347 // build p2
348 verts.resize(3);
349 verts[0] = vertices[i];
350 verts[1] = vertices[i2];
351 verts[2] = vertices[i3];
352 poly.vertices = verts;
353 poly.is_marked = is_marked;
354 // std::cerr << "adding p2 to the list..." << std::endl;
355 polylist.push_back(poly);
356 // build p3
357 k = i3;
358 verts.resize(0);
359 while(k != i)
361 verts.push_back(vertices[k]);
362 k++; if(k == int(vertices.size()) )
363 k = 0;
364 } // while k
365 verts.push_back(vertices[k]); // record the last one aswell
366 poly.vertices = verts;
367 poly.is_marked = is_marked;
368 // std::cerr << "calling p3... " << std::endl;
369 err = poly.triangulate(globalverts, polylist);
370 if(err)
371 return err;
372 // std::cerr << "triangulate out!!!" << std::endl;
373 return 0;
374 } // if
375 } // for i
377 /* SWARNING << "triangulate out WITH ERROR!!!" << endLog;
379 for( i = 0; i < vertices.size( ); ++i )
381 std::cerr << globalverts[ vertices[ i ] ][0] << ",";
382 std::cerr << globalverts[ vertices[ i ] ][1] << std::endl;
385 // char x[ 256 ];
386 // gets( x );
388 return -1;
392 * Protected methods.
395 //! Try to find a suitable third point for (i1, i2)
397 * `i1' and `i2' must already be an edge of the polygon, and the third point `i3'
398 * will be a point of the polygon which is different from `i1' and `i2'.
399 * The polygon's lines must not cross each other. These are actually all indices
400 * into the `globalverts' vector.
402 * \param globalverts global vertices vector
403 * \param i1 first point
404 * \param i2 second point (must form an edge with the first point)
405 * \param i3 suitable third point, or -1 if there's no suitable third point
406 * for (i1, i2 ) can't be found
407 * \return zero on success, and a negative integer if some error occured.
409 * FIXME: the semantics were changed so the above comments are not 100%
410 * FIXME: correct. TODO: Check with Michael. :)
412 int SimplePolygon::findThirdPoint(DCTPVec2dvector &globalverts, int i1, int i2, int &i3)
414 if(is_marked)
416 // std::cerr << "no delauney check" << std::endl;
417 i3 = getThirdPoint(globalverts, i1, i2, 0);
418 return 0;
421 unsigned int i;
422 const unsigned int vsize = UInt32(vertices.size());
424 // std::cerr << "searching third point for " << i1 << ", " << i2 << std::endl;
426 for(i = 0; i < vsize; ++i)
428 i3 = getThirdPoint(globalverts, i1, i2, i);
429 if(i3 == -1)
431 // std::cerr << "no third points left." << std::endl;
432 return 0;
434 if(isDelaunay(globalverts, i1, i2, i3) == 0)
436 // std::cerr << "third point found: " << i3 << std::endl;
437 return 0;
441 i3 = -1;
442 return 0;
444 /* i3 = -1;
445 for (int i = 0; i < (int) vertices.size(); i++ ) {
446 if ( ( i != i1 ) && ( i != i2 ) ) {
447 if ( isInsidePolygon( globalverts, i1, i2, i ) == 0 ) {
448 if ( isDelaunay( globalverts, i1, i2, i ) == 0 ) {
449 i3 = i;
450 // std::cerr << "Third point for " << i1 << " " << i2 << " is: " << i3 << std::endl;
451 return 0;
455 } //for i*/
457 // std::cerr << "No third point for " << i1 << " " << i2 << " ." << std::endl;
459 // return 0;
462 //! Is the triangle formed by the vertices (i1, i2, i3) inside the polygon ?
464 * `i1' and `i2' must already be an edge of the polygon, and the third point `i3'
465 * be a point of the polygon different from `i1' and `i2'. The polygon's lines
466 * must not cross each other.
468 * \param globalverts global vertices vector
469 * \param i1 first point
470 * \param i2 second point (must form an edge with the first point)
471 * \param i3 third point
472 * \return 1 if not inside <BR>
473 * 0 if inside <BR>
474 * and a negative value if an error happened.
476 int SimplePolygon::isInsidePolygon(DCTPVec2dvector &globalverts, int i1, int i2, int i3) const
478 double dres;
479 const int size = UInt32(vertices.size());
480 const int vi1 = vertices[i1];
481 const int vi2 = vertices[i2];
482 const int vi3 = vertices[i3];
483 const int prev = vertices[(size + i1 - 1) % size];
484 const int next = vertices[(i2 + 1) % size];
486 // the third (i3) point must lie to the left of the edge (i2, next)
487 // (NOT! on the edge) to be inside
488 double p2[2], p3[2], pn[2];
489 p3 [0] = globalverts[vi3][0];
490 p3 [1] = globalverts[vi3][1];
491 p2 [0] = globalverts[vi2][0];
492 p2 [1] = globalverts[vi2][1];
493 pn [0] = globalverts[next][0];
494 pn [1] = globalverts[next][1];
496 if(vi3 != next)
498 dres = orient2d(p3, p2, pn);
499 // std::cerr << "next edge test: " << dres << std::endl;
501 if(dres < 0.0)
502 return 1;
505 // the third (i3) point must also lie to the left of the edge (prev, i1)
506 // (NOT! on the edge) to be inside
507 double p1[2], pp[2];
508 pp [0] = globalverts[prev][0];
509 pp [1] = globalverts[prev][1];
510 p1 [0] = globalverts[vi1][0];
511 p1 [1] = globalverts[vi1][1];
513 if(vi3 != prev)
515 dres = orient2d(p3, pp, p1);
516 // std::cerr << "prev edge test: " << dres << std::endl;
518 if(dres < 0.0)
519 return 1;
522 // the third (i3) point must also lie to the left of the edge (i1, i2)
523 // (NOT! on the edge) to be inside
525 dres = orient2d(p3, p1, p2);
526 // std::cerr << "actual edge test: " << dres << std::endl;
528 if(dres <= 0.0)
529 return 1;
531 // if( m_bConvex ) return 0; // don't need intersection test for convex polygons
533 // the triangle is not completely outside the polygon, we have to
534 // go for the intersection test.
535 // FIXME/TODO: use bounding boxes to speed up testing:
536 // only test with those edges that are at least partially in the
537 // bounding box of the triangle to be tested
539 int res;
540 int j = size - 1;
541 Vec2d min, max;
542 unsigned char test, ptest;
544 min = max = globalverts[vi1];
545 if(min[0] > globalverts[vi2][0])
546 min[0] = globalverts[vi2][0];
547 else if(max[0] < globalverts[vi2][0])
548 max[0] = globalverts[vi2][0];
549 if(min[1] > globalverts[vi2][1])
550 min[1] = globalverts[vi2][1];
551 else if(max[1] < globalverts[vi2][1])
552 max[1] = globalverts[vi2][1];
553 if(min[0] > globalverts[vi3][0])
554 min[0] = globalverts[vi3][0];
555 else if(max[0] < globalverts[vi3][0])
556 max[0] = globalverts[vi3][0];
557 if(min[1] > globalverts[vi3][1])
558 min[1] = globalverts[vi3][1];
559 else if(max[1] < globalverts[vi3][1])
560 max[1] = globalverts[vi3][1];
562 const Vec2d &pj = globalverts[vertices[j]];
563 test = 0;
564 if(pj[0] - max[0] > DCTP_EPS)
565 test |= 0x01;
566 if(min[0] - pj[0] > DCTP_EPS)
567 test |= 0x02;
568 if(pj[1] - max[1] > DCTP_EPS)
569 test |= 0x04;
570 if(min[1] - pj[1] > DCTP_EPS)
571 test |= 0x08;
573 for(int i = 0; i < size; i++)
575 ptest = test;
576 test = 0;
577 const Vec2d &pi = globalverts[vertices[i]];
578 if(pi[0] - max[0] > DCTP_EPS)
579 test |= 0x01;
580 if(min[0] - pi[0] > DCTP_EPS)
581 test |= 0x02;
582 if(pi[1] - max[1] > DCTP_EPS)
583 test |= 0x04;
584 if(min[1] - pi[1] > DCTP_EPS)
585 test |= 0x08;
586 if( (test & ptest) == 0)
588 // std::cerr << "checking: " << v1 << " " << v3 << " and i: " << i << std::endl;
589 res = doIntersect(globalverts, i1, i3, j, i);
590 if(res)
591 return res; // either intersection or error
592 res = doIntersect(globalverts, i2, i3, j, i);
593 if(res)
594 return res; // see above
596 j = i;
599 return 0;
603 //! Do the two polylines (v1, v2) and (p1, p2) intersect (apart from the corners) ?
605 * The polylines must be different.
607 * \param globalverts global vertices vector
608 * \param v1 the first polyline
609 * \param v2
610 * \param p1 the second polyline
611 * \param p2
613 * \return 0 if they don't intersect <BR>
614 * 1 if they do <BR>
616 int SimplePolygon::doIntersect(DCTPVec2dvector &globalverts, int v1, int v2, int p1, int p2) const
618 // check if they share vertices
619 if(v1 == p1 || v1 == p2 || v2 == p1 || v2 == p2)
620 return 0;
622 double pa[2];
623 double pb[2];
624 double pc[2];
625 double pd[2];
626 const int vv1 = vertices[v1];
627 const int vv2 = vertices[v2];
628 const int vp1 = vertices[p1];
629 const int vp2 = vertices[p2];
631 pa[0] = globalverts[vv1][0];
632 pa[1] = globalverts[vv1][1];
633 pb[0] = globalverts[vv2][0];
634 pb[1] = globalverts[vv2][1];
635 pc[0] = globalverts[vp1][0];
636 pc[1] = globalverts[vp1][1];
637 pd[0] = globalverts[vp2][0];
638 pd[1] = globalverts[vp2][1];
640 const double r1 = orient2d(pa, pc, pd);
641 const double r2 = orient2d(pb, pc, pd);
642 if( (r1 < 0.0) && (r2 < 0.0) )
644 return 0;
646 if( (r1 > 0.0) && (r2 > 0.0) )
648 return 0;
651 const double r3 = orient2d(pc, pa, pb);
652 const double r4 = orient2d(pd, pa, pb);
653 if( (r3 < 0.0) && (r4 < 0.0) )
655 return 0;
657 if( (r3 > 0.0) && (r4 > 0.0) )
659 return 0;
661 return 1;
663 // do intersect??
665 * r1 and r2 must have different signs ( <0, >0, =0 ) AND
666 * r3 and r4 must also have different signs in suffice intersection of
667 * the two lines.
669 /* bool s1 = ( !(( r1 < 0 && r2 < 0 ) || ( r1 > 0 && r2 > 0 )) );
670 bool s2 = ( !(( r3 < 0 && r4 < 0 ) || ( r3 > 0 && r4 > 0 )) );
672 if ( s1 && s2 ) return 1;
673 else return 0;*/
677 //! Is the point `p' inside the circumcircle of the triangle (v1, v2, v3) ?
679 * \param globalverts global vertices vector
680 * \param v1 first vertex
681 * \param v2 second vertex
682 * \param v3 third vertex
683 * \param p the point
684 * \return 0 if not inside <BR>
685 * 1 if inside <BR>
687 int SimplePolygon::isInsideCircumCircle(DCTPVec2dvector &globalverts, int v1, int v2, int v3, int p) const
689 double pa[2], pb[2], pc[2], pd[2];
691 pa [0] = globalverts[vertices[v1]][0];
692 pa [1] = globalverts[vertices[v1]][1];
693 pb [0] = globalverts[vertices[v2]][0];
694 pb [1] = globalverts[vertices[v2]][1];
695 pc [0] = globalverts[vertices[v3]][0];
696 pc [1] = globalverts[vertices[v3]][1];
697 pd [0] = globalverts[vertices[p]][0];
698 pd [1] = globalverts[vertices[p]][1];
699 // check for order of (pa, pb, pc) they must be in counterclockwise order
700 double order = orient2d(pa, pb, pc);
701 double dres;
702 if(order < 0.0) // clockwise order -> change order
703 dres = incircle(pa, pc, pb, pd);
704 else
705 dres = incircle(pa, pb, pc, pd);
707 //std::cerr << pa[ 0 ] << "," << pa[ 1 ] << " ";
708 //std::cerr << pb[ 0 ] << "," << pb[ 1 ] << " ";
709 //std::cerr << pc[ 0 ] << "," << pc[ 1 ] << " ";
710 //std::cerr << pd[ 0 ] << "," << pd[ 1 ] << std::endl;
711 //std::cerr << "Inside Circumcircle: " << dres << std::endl; // >0 if inside
713 if(dres <= 0)
714 return 0;
715 else
716 return 1;
719 //! Is the triangle formed by the vertices (v1, v2, v3) a Delaunay triangle (with regard to this polygon ?
721 * \param globalverts global vertices vector
722 * \param v1 first vertex
723 * \param v2 second vertex
724 * \param v3 third vertex
726 * \return 0 if Delaunay <BR>
727 * 1 if not Delaunay <BR>
728 * and a negative value if an error happened.
730 int SimplePolygon::isDelaunay(DCTPVec2dvector &globalverts, int v1, int v2, int v3)
732 unsigned int i;
733 int v4, ret;
734 const unsigned int vsize = UInt32(vertices.size());
736 for(i = 0; i < vsize; ++i)
738 v4 = getThirdPoint(globalverts, v1, v2, i);
739 if(v4 == -1)
741 return 0;
743 if(v3 != v4)
745 ret = isInsideCircumCircle(globalverts, v1, v2, v3, v4);
746 // std::cerr << "Inside circle test " << v1 << "," << v2 << "," << v3 << "," << v4 << " = " << ret << std::endl;
747 if(ret)
749 return ret;
754 /* int res;
755 for( int i = 0; i < ( int ) vertices.size( ); ++i )
757 if( ( i != v1 ) && ( i != v2 ) && ( i != v3 ) )
759 // std::cerr << "check " << v1 << "," << v2 << "," << v3;
760 // std::cerr << " <-> " << v1 << "," << v2 << "," << i << std::endl;
761 res = isInsideCircumCircle( globalverts, v1, v2, v3, i );
762 // note: the Delaunay criterium is only for _visible_ vertices,
763 // we have to check that too.
764 if( ( res != 0 ) && ( isInsidePolygon( globalverts, v1, v2, i ) == 0 ) )
765 return res;
768 return 0;
771 //! Fixes the polygon (splits it if necessary) and call triangulation.
773 * Note that this has complexity O(n^2) but should not count since
774 * triangulation has O(n^3).
776 * \param globalverts the global vertices vector
777 * \param polylist the global list of polygons
778 * \return zero on success, and a negative integer if some error occured.
780 int SimplePolygon::fixAndTriangulate(DCTPVec2dvector &globalverts, simplepolygonvector &polylist)
782 Vec2d min, max;
784 if(getMinMax(globalverts, min, max) )
786 // std::cerr << "Ignoring degenerate polygon..." << std::endl;
787 return -1;
789 // while( removeLinearPoints( globalverts, min, max ) ) { }
790 while(splitPolygon(globalverts, polylist, min, max) )
793 while(intersectPolygon(globalverts, polylist) )
796 if(isReversed(globalverts) )
798 // std::cerr << "Ignoring reversed polygon." << std::endl;
799 return 0; // no error here...
802 // Ok, we have a valid polygon, so triangulate it.
803 triangulate(globalverts, polylist);
804 return 0;
807 //! Removes linear points from the polygon.
809 * Note that this has complexity O(n).
811 * \param globalverts the global vertices vector
812 * \return zero on success, and a negative integer if some error occured.
814 int SimplePolygon::removeLinearPoints(DCTPVec2dvector &globalverts, const Vec2d min, const Vec2d max)
816 int oldNum = UInt32(vertices.size());
817 int newNum = 0;
818 DCTPivector newPoints(oldNum); // waste some memory to have linear time
819 int i;
820 int last = oldNum - 1;
822 // std::cerr << "Removing linear points... " << oldNum << std::endl;
824 // insert nonlienaer points in new array
825 for(i = 0; i < oldNum; ++i)
827 Vec2d p = globalverts[vertices[i]];
828 // check for double vertices
829 if(DCTPVecIsNotEqual(p, globalverts[vertices[last]]) )
831 Vec2d pp = globalverts[vertices[last]];
832 Vec2d pn = globalverts[vertices[(i + 1) % oldNum]];
834 if( ( (p[0] - min[0] < DCTP_EPS) && (pn[0] - min[0] < DCTP_EPS) ) ||
835 ( (p[1] - min[1] < DCTP_EPS) && (pn[1] - min[1] < DCTP_EPS) ) ||
836 ( (max[0] - p[0] < DCTP_EPS) && (max[0] - pn[0] < DCTP_EPS) ) ||
837 ( (max[1] - p[1] < DCTP_EPS) && (max[1] - pn[1] < DCTP_EPS) ) )
839 newPoints[newNum] = vertices[i];
840 ++newNum;
841 last = i;
843 else
845 double d1[2], d2[2], d3[2];
846 d1[0] = pp[0];
847 d1[1] = pp[1];
848 d2[0] = p[0];
849 d2[1] = p[1];
850 d3[0] = pn[0];
851 d3[1] = pn[1];
852 if(orient2d(d1, d2, d3) != 0)
854 newPoints[newNum] = vertices[i];
855 ++newNum;
856 last = i;
858 /* else if( ( pp[1] != pn[1] ) && ( pp[0] != pn[0] ) )
860 std::cerr << "removing point " <<std::endl;
861 std::cerr << pp[0] << "," << pp[1] << std::endl;
862 std::cerr << "(" << p[0] << "," << p[1] << ")" << std::endl;
863 std::cerr << pn[0] << "," << pn[1] << std::endl;
864 char x[ 256 ];
865 gets( x );
871 // std::cerr << newNum << " points left." << std::endl;
873 // copy new points
874 if(newNum != oldNum)
876 vertices.resize(newNum);
878 for(i = 0; i < newNum; ++i)
880 vertices[i] = newPoints[i];
883 return 1;
886 return 0;
889 int SimplePolygon::splitPolygon(DCTPVec2dvector &globalverts, simplepolygonvector &polylist, const Vec2d min, const Vec2d max)
891 DCTPVec2dset vset;
892 std::pair<DCTPVec2dset::iterator, bool> siv;
893 int oldNum = UInt32(vertices.size());
894 int i1;
896 // std::cerr << "Removing double vertices... " << oldNum << std::endl;
898 for(i1 = 0; i1 < oldNum; ++i1)
900 siv = vset.insert(globalverts[vertices[i1]]);
901 if(!siv.second)
903 // here we need to split the polygon and start with the new ones again.
904 int i;
905 DCTPivector newPoints(oldNum); // waste some memory to have nlogn time
906 int newNum = 0;
907 int i2 = 0;
908 SimplePolygon poly;
910 // copy points before first intersection
911 while(DCTPVecIsNotEqual(globalverts[vertices[i2]], globalverts[vertices[i1]]) )
913 newPoints[i2] = vertices[i2];
914 ++i2;
916 newNum = i2;
918 // std::cerr << i2 << " = " << i1 << std::endl;
920 // construct new polygon
921 poly.vertices.resize(i1 - i2);
923 for(i = i2; i < i1; ++i)
925 poly.vertices[i - i2] = vertices[i];
926 // std::cerr << vertices[ i ] << " ";
929 // std::cerr << std::endl;
931 // copy points from second intersection to the end
932 for(i = i1; i < oldNum; ++i)
934 newPoints[newNum] = vertices[i];
935 ++newNum;
938 // copy new points back to polygon
939 vertices.resize(newNum);
941 for(i = 0; i < newNum; ++i)
943 vertices[i] = newPoints[i];
944 // std::cerr << vertices[ i ] << " ";
947 // std::cerr << std::endl;
949 // triangulate the new polygon
950 // std::cerr << oldNum << " split in " << vertices.size() << "," << poly.vertices.size() << std::endl;
951 // need to check for new liear points
952 // while( poly.removeLinearPoints( globalverts, min, max ) ) { }
953 while(poly.intersectPolygon(globalverts, polylist) )
956 if(poly.isReversed(globalverts) )
958 // std::cerr << "Ignoring reversed polygon." << std::endl;
960 else
962 // Ok, we have a valid polygon, so triangulate it.
963 poly.triangulate(globalverts, polylist);
966 // need to check for new liear points
967 // while( removeLinearPoints( globalverts, min, max ) ) { }
968 // check if there are other double vertices
969 return 1;
973 // polygon had no double vertices so we are finished
974 return 0;
977 int SimplePolygon::intersectPolygon(DCTPVec2dvector &globalverts, simplepolygonvector &polylist)
979 int oldNum = UInt32(vertices.size());
980 int i1, i2;
981 Vec2d min, max;
982 Vec2d p3, p4;
983 unsigned char test, ptest;
985 // std::cerr << "Removing intersections... " << oldNum << std::endl;
987 for(i2 = 2; i2 < oldNum; ++i2)
989 const Vec2d &p1 = globalverts[vertices[i2]];
990 const Vec2d &p2 = globalverts[vertices[(i2 + 1) % oldNum]];
992 min = max = p1;
993 if(min[0] > p2[0])
994 min[0] = p2[0];
995 else if(max[0] < p2[0])
996 max[0] = p2[0];
997 if(min[1] > p2[1])
998 min[1] = p2[1];
999 else if(max[1] < p2[1])
1000 max[1] = p2[1];
1002 const unsigned int start = (i2 == oldNum - 1) ? 1 : 0;
1004 p4 = globalverts[vertices[start]];
1005 test = 0;
1006 if(p4[0] - max[0] > DCTP_EPS)
1007 test |= 0x01;
1008 if(min[0] - p4[0] > DCTP_EPS)
1009 test |= 0x02;
1010 if(p4[1] - max[1] > DCTP_EPS)
1011 test |= 0x04;
1012 if(min[1] - p4[1] > DCTP_EPS)
1013 test |= 0x08;
1015 for(i1 = start; i1 < i2 - 1; ++i1)
1017 p3 = p4;
1018 p4 = globalverts[vertices[i1 + 1]];
1019 ptest = test;
1020 test = 0;
1021 if(p4[0] - max[0] > DCTP_EPS)
1022 test |= 0x01;
1023 if(min[0] - p4[0] > DCTP_EPS)
1024 test |= 0x02;
1025 if(p4[1] - max[1] > DCTP_EPS)
1026 test |= 0x04;
1027 if(min[1] - p4[1] > DCTP_EPS)
1028 test |= 0x08;
1029 if( (test & ptest) == 0)
1031 // std::cerr << i1 << "," << i1 + 1 << " overlaps " << i2 << "," << i2 + 1 << std::endl;
1032 // the bounding boxes overlap
1033 int iip = -1;
1034 bool intersect = false;
1035 double d1[2] = { p1[0], p1[1] };
1036 double d2[2] = { p2[0], p2[1] };
1037 double d3[2] = { p3[0], p3[1] };
1038 double d4[2] = { p4[0], p4[1] };
1040 if( (orient2d(d1, d2, d3) == 0.0) &&
1041 (orient2d(d1, d2, d4) == 0.0) )
1043 // the lines are colinear => ... p1 p4 ... ; p2 ... p3
1044 intersect = true;
1046 else
1048 if(doIntersect(globalverts, i1, i1 + 1, i2, (i2 + 1) % oldNum) )
1050 // the lines intersect => ... p1 ip p4 ... ; ip p2 ... p3
1051 Vec2d v1 = p2 - p1;
1052 Vec2d v2 = p4 - p3;
1053 Vec2d pp = p3 - p1;
1054 double a = pp[0] * v2[1] - pp[1] * v2[0];
1055 double b = v1[0] * v2[1] - v1[1] * v2[0];
1056 Vec2d ip = p1 + v1 * (a / b);
1058 if(DCTPVecIsEqual(ip, p1) )
1060 iip = vertices[i1];
1062 else if(DCTPVecIsEqual(ip, p2) )
1064 iip = vertices[i1 + 1];
1066 else if(DCTPVecIsEqual(ip, p3) )
1068 iip = vertices[i2];
1070 else if(DCTPVecIsEqual(ip, p4) )
1072 iip = vertices[(i2 + 1) % oldNum];
1074 else
1076 iip = UInt32(globalverts.size());
1077 globalverts.resize(iip + 1);
1078 globalverts[iip] = ip;
1081 // std::cerr << p1[0] << "," << p1[1] << " - " << p2[0] << "," << p2[1] << std::endl;
1082 // std::cerr << p3[0] << "," << p3[1] << " - " << p4[0] << "," << p4[1] << std::endl;
1083 // std::cerr << globalverts[ iip ][0] << "," << globalverts[ iip ][1] << " - " << std::endl;
1084 intersect = true;
1087 if(intersect)
1089 int i;
1090 int newNum;
1091 DCTPivector newPoints(oldNum);
1092 SimplePolygon poly;
1094 // std::cerr << i1 << "," << i1 + 1 << " intersects " << i2 << "," << i2 + 1 << std::endl;
1096 // copy points 0 ... i1
1097 for(i = 0; i <= i1; ++i)
1099 newPoints[i] = vertices[i];
1102 newNum = i;
1104 // copy iip's
1105 if(iip >= 0)
1107 if( (iip != vertices[i1]) &&
1108 (iip != vertices[(i2 + 1) % oldNum]) )
1110 newPoints[newNum] = iip;
1111 ++newNum;
1113 if( (iip != vertices[i2]) &&
1114 (iip != vertices[i1 + 1]) )
1116 poly.vertices.resize(i2 + 1 - i1);
1117 poly.vertices[i2 - i1] = iip;
1119 else
1121 poly.vertices.resize(i2 - i1);
1124 else
1126 poly.vertices.resize(i2 - i1);
1129 // copy i1+1 ... i2
1130 for(i = 0; i < i2 - i1; ++i)
1132 poly.vertices[i] = vertices[i1 + i + 1];
1135 // copy i2+1 ... n
1136 for(i = i2 + 1; i < oldNum; ++i)
1138 newPoints[newNum] = vertices[i];
1139 ++newNum;
1142 // copy new points back to polygon
1143 vertices.resize(newNum);
1145 for(i2 = 0; i2 < newNum; ++i2)
1147 vertices[i2] = newPoints[i2];
1150 // std::cerr << "split in " << newNum << "," << poly.vertices.size() << std::endl;
1152 // triangulate the new polygon
1153 while(poly.intersectPolygon(globalverts, polylist) )
1156 if(poly.isReversed(globalverts) )
1158 // std::cerr << "Ignoring reversed polygon." << std::endl;
1160 else
1162 // Ok, we have a valid polygon, so triangulate it.
1163 poly.triangulate(globalverts, polylist);
1166 // check if there are other intersections
1167 return 1;
1173 // polygon had no intersections so we are finished
1174 return 0;
1177 bool SimplePolygon::isReversed(DCTPVec2dvector &globalverts)
1179 unsigned int ui_vertex;
1180 unsigned int ui_upperleft;
1181 const unsigned int cui_vertex_cnt = UInt32(vertices.size());
1182 double ad_p[2];
1183 double ad_v[2];
1184 double ad_n[2];
1186 ui_upperleft = 0;
1188 for(ui_vertex = 1; ui_vertex < cui_vertex_cnt; ++ui_vertex)
1190 if(globalverts[vertices[ui_vertex]][1] < globalverts[vertices[ui_upperleft]][1])
1192 ui_upperleft = ui_vertex;
1194 else if( (globalverts[vertices[ui_vertex]][1] == globalverts[vertices[ui_upperleft]][1]) &&
1195 (globalverts[vertices[ui_vertex]][0] < globalverts[vertices[ui_upperleft]][0]) )
1197 ui_upperleft = ui_vertex;
1201 ad_p[0] = globalverts[vertices[(ui_upperleft + cui_vertex_cnt - 1) % cui_vertex_cnt]][0];
1202 ad_p[1] = globalverts[vertices[(ui_upperleft + cui_vertex_cnt - 1) % cui_vertex_cnt]][1];
1203 ad_v[0] = globalverts[vertices[ui_upperleft]][0];
1204 ad_v[1] = globalverts[vertices[ui_upperleft]][1];
1205 ad_n[0] = globalverts[vertices[(ui_upperleft + 1) % cui_vertex_cnt]][0];
1206 ad_n[1] = globalverts[vertices[(ui_upperleft + 1) % cui_vertex_cnt]][1];
1208 return (orient2d(ad_p, ad_v, ad_n) <= 0.0);
1211 bool SimplePolygon::isConvex(DCTPVec2dvector &globalverts)
1213 unsigned int ui_next;
1214 const unsigned int cui_vertex_cnt = UInt32(vertices.size());
1215 double ad_p[2];
1216 double ad_v[2];
1217 double ad_n[2];
1219 ad_p[0] = globalverts[vertices[cui_vertex_cnt - 2]][0];
1220 ad_p[1] = globalverts[vertices[cui_vertex_cnt - 2]][1];
1221 ad_v[0] = globalverts[vertices[cui_vertex_cnt - 1]][0];
1222 ad_v[1] = globalverts[vertices[cui_vertex_cnt - 1]][1];
1224 for(ui_next = 0; ui_next < cui_vertex_cnt; ++ui_next)
1226 // std::cerr <<"ui_next:" << ui_next << std::endl;
1227 ad_n[0] = globalverts[vertices[ui_next]][0];
1228 ad_n[1] = globalverts[vertices[ui_next]][1];
1229 // previous, current, and next vertices must be in
1230 // counterclockwise order for the polygon to be convex
1231 // (because our tessellator always gives CCW polygons)
1232 if(orient2d(ad_p, ad_v, ad_n) < 0.0)
1234 // std::cerr << ad_p[ 0 ] << " " << ad_p[ 1 ] << std::endl;
1235 // std::cerr << ad_v[ 0 ] << " " << ad_v[ 1 ] << std::endl;
1236 // std::cerr << ad_n[ 0 ] << " " << ad_n[ 1 ] << std::endl << std::endl;
1237 // not convex
1238 return false;
1240 ad_p[0] = ad_v[0];
1241 ad_p[1] = ad_v[1];
1242 ad_v[0] = ad_n[0];
1243 ad_v[1] = ad_n[1];
1246 // std::cerr << "convex" << std::endl;
1247 return true;
1250 // FIXME: should go to Vec2d
1251 double SimplePolygon::getAngle(Vec2d dir)
1253 if(osgAbs(dir[0]) < DCTP_EPS)
1255 return (dir[1] > 0.0) ? M_PI_2 : -M_PI_2;
1257 if(dir[0] > 0.0)
1259 return osgATan(dir[1] / dir[0]);
1261 else
1263 double ret = M_PI + osgATan(dir[1] / dir[0]);
1264 return (ret < M_PI) ? ret : (ret - 2.0 * M_PI);
1268 int SimplePolygon::getMinMax(DCTPVec2dvector &globalverts, Vec2d &min, Vec2d &max)
1270 if(vertices.size() == 0)
1272 return -1;
1274 min = max = globalverts[vertices[0]];
1276 for(unsigned int i = 1; i < vertices.size(); ++i)
1278 Vec2d p = globalverts[vertices[i]];
1279 if(min[0] > p[0])
1281 min[0] = p[0];
1283 else if(max[0] < p[0])
1285 max[0] = p[0];
1287 if(min[1] > p[1])
1289 min[1] = p[1];
1291 else if(max[1] < p[1])
1293 max[1] = p[1];
1297 return 0;