1 /*---------------------------------------------------------------------------*\
2 * OpenSG NURBS Library *
5 * Copyright (C) 2001-2006 by the University of Bonn, Computer Graphics Group*
7 * http://cg.cs.uni-bonn.de/ *
9 * contact: edhellon@cs.uni-bonn.de, guthe@cs.uni-bonn.de, rk@cs.uni-bonn.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
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. *
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. *
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. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 # pragma warning (disable : 985)
46 #include "OSGSimplePolygon.h"
47 #include "OSGpredicates.h"
52 # define M_PI 3.14159265358979323846
55 # define M_PI_2 (M_PI * 0.5)
61 static char THIS_FILE
[] = __FILE__
;
66 * Converted to use robust predicates, see `predicates.c' and
69 * FIXME: may have some license issues, also must run at first
70 * compilation the `predicates_init' calculator, may have trouble
78 // default constructor
79 SimplePolygon::SimplePolygon() :
92 //! Triangulates the polygon, using RK's constrained method.
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
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() )
120 polylist
.push_back(*this);
125 unsigned int ui_prev
;
127 unsigned int ui_next
;
128 const unsigned int cui_vertex_cnt
= UInt32(vertices
.size());
129 SimplePolygon cl_poly
;
133 for(ui_prev
= 1; ui_prev
< cui_vertex_cnt
; ++ui_prev
)
135 if(globalverts
[vertices
[ui_prev
]][1] < globalverts
[vertices
[ui_mid
]][1])
139 else if( (globalverts
[vertices
[ui_prev
]][1] == globalverts
[vertices
[ui_mid
]][1]) &&
140 (globalverts
[vertices
[ui_prev
]][0] < globalverts
[vertices
[ui_mid
]][0]) )
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
;
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
;
185 // std::cerr << " triangulate in, size: " << vertices.size() << std::endl;
186 switch(vertices
.size() )
194 polylist
.push_back(*this);
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;
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();
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;
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
);
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;
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
);
297 // recalc valid third points!
299 validThirdPoints
.resize(vertices
.size() );
302 int i2
, i3
; // this is an index into the vertices[] vector
304 DCTPivector verts
; //p1verts, p2verts, p3verts;
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 ];
323 i2
= i
+ 1; //v2 = vertices[ i + 1 ];
324 err
= findThirdPoint(globalverts
, i
, i2
, i3
);
334 // std::cerr << " k: " << k;
335 verts
.push_back(vertices
[k
]);
336 k
++; if(k
== int(vertices
.size()) )
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
);
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
);
361 verts
.push_back(vertices
[k
]);
362 k
++; if(k
== int(vertices
.size()) )
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
);
372 // std::cerr << "triangulate out!!!" << std::endl;
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;
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
)
416 // std::cerr << "no delauney check" << std::endl;
417 i3
= getThirdPoint(globalverts
, i1
, i2
, 0);
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
);
431 // std::cerr << "no third points left." << std::endl;
434 if(isDelaunay(globalverts
, i1
, i2
, i3
) == 0)
436 // std::cerr << "third point found: " << i3 << std::endl;
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 ) {
450 // std::cerr << "Third point for " << i1 << " " << i2 << " is: " << i3 << std::endl;
457 // std::cerr << "No third point for " << i1 << " " << i2 << " ." << std::endl;
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>
474 * and a negative value if an error happened.
476 int SimplePolygon::isInsidePolygon(DCTPVec2dvector
&globalverts
, int i1
, int i2
, int i3
) const
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];
498 dres
= orient2d(p3
, p2
, pn
);
499 // std::cerr << "next edge test: " << dres << std::endl;
505 // the third (i3) point must also lie to the left of the edge (prev, i1)
506 // (NOT! on the edge) to be inside
508 pp
[0] = globalverts
[prev
][0];
509 pp
[1] = globalverts
[prev
][1];
510 p1
[0] = globalverts
[vi1
][0];
511 p1
[1] = globalverts
[vi1
][1];
515 dres
= orient2d(p3
, pp
, p1
);
516 // std::cerr << "prev edge test: " << dres << std::endl;
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;
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
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
]];
564 if(pj
[0] - max
[0] > DCTP_EPS
)
566 if(min
[0] - pj
[0] > DCTP_EPS
)
568 if(pj
[1] - max
[1] > DCTP_EPS
)
570 if(min
[1] - pj
[1] > DCTP_EPS
)
573 for(int i
= 0; i
< size
; i
++)
577 const Vec2d
&pi
= globalverts
[vertices
[i
]];
578 if(pi
[0] - max
[0] > DCTP_EPS
)
580 if(min
[0] - pi
[0] > DCTP_EPS
)
582 if(pi
[1] - max
[1] > DCTP_EPS
)
584 if(min
[1] - pi
[1] > DCTP_EPS
)
586 if( (test
& ptest
) == 0)
588 // std::cerr << "checking: " << v1 << " " << v3 << " and i: " << i << std::endl;
589 res
= doIntersect(globalverts
, i1
, i3
, j
, i
);
591 return res
; // either intersection or error
592 res
= doIntersect(globalverts
, i2
, i3
, j
, i
);
594 return res
; // see above
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
610 * \param p1 the second polyline
613 * \return 0 if they don't intersect <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
)
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) )
646 if( (r1
> 0.0) && (r2
> 0.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) )
657 if( (r3
> 0.0) && (r4
> 0.0) )
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
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;
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
684 * \return 0 if not 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
);
702 if(order
< 0.0) // clockwise order -> change order
703 dres
= incircle(pa
, pc
, pb
, pd
);
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
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
)
734 const unsigned int vsize
= UInt32(vertices
.size());
736 for(i
= 0; i
< vsize
; ++i
)
738 v4
= getThirdPoint(globalverts
, v1
, v2
, i
);
745 ret
= isInsideCircumCircle(globalverts
, v1
, v2
, v3
, v4
);
746 // std::cerr << "Inside circle test " << v1 << "," << v2 << "," << v3 << "," << v4 << " = " << ret << std::endl;
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 ) )
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
)
784 if(getMinMax(globalverts
, min
, max
) )
786 // std::cerr << "Ignoring degenerate polygon..." << std::endl;
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
);
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());
818 DCTPivector
newPoints(oldNum
); // waste some memory to have linear time
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
];
845 double d1
[2], d2
[2], d3
[2];
852 if(orient2d(d1
, d2
, d3
) != 0)
854 newPoints
[newNum
] = vertices
[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;
871 // std::cerr << newNum << " points left." << std::endl;
876 vertices
.resize(newNum
);
878 for(i
= 0; i
< newNum
; ++i
)
880 vertices
[i
] = newPoints
[i
];
889 int SimplePolygon::splitPolygon(DCTPVec2dvector
&globalverts
, simplepolygonvector
&polylist
, const Vec2d min
, const Vec2d max
)
892 std::pair
<DCTPVec2dset::iterator
, bool> siv
;
893 int oldNum
= UInt32(vertices
.size());
896 // std::cerr << "Removing double vertices... " << oldNum << std::endl;
898 for(i1
= 0; i1
< oldNum
; ++i1
)
900 siv
= vset
.insert(globalverts
[vertices
[i1
]]);
903 // here we need to split the polygon and start with the new ones again.
905 DCTPivector
newPoints(oldNum
); // waste some memory to have nlogn time
910 // copy points before first intersection
911 while(DCTPVecIsNotEqual(globalverts
[vertices
[i2
]], globalverts
[vertices
[i1
]]) )
913 newPoints
[i2
] = vertices
[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
];
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;
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
973 // polygon had no double vertices so we are finished
977 int SimplePolygon::intersectPolygon(DCTPVec2dvector
&globalverts
, simplepolygonvector
&polylist
)
979 int oldNum
= UInt32(vertices
.size());
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
]];
995 else if(max
[0] < p2
[0])
999 else if(max
[1] < p2
[1])
1002 const unsigned int start
= (i2
== oldNum
- 1) ? 1 : 0;
1004 p4
= globalverts
[vertices
[start
]];
1006 if(p4
[0] - max
[0] > DCTP_EPS
)
1008 if(min
[0] - p4
[0] > DCTP_EPS
)
1010 if(p4
[1] - max
[1] > DCTP_EPS
)
1012 if(min
[1] - p4
[1] > DCTP_EPS
)
1015 for(i1
= start
; i1
< i2
- 1; ++i1
)
1018 p4
= globalverts
[vertices
[i1
+ 1]];
1021 if(p4
[0] - max
[0] > DCTP_EPS
)
1023 if(min
[0] - p4
[0] > DCTP_EPS
)
1025 if(p4
[1] - max
[1] > DCTP_EPS
)
1027 if(min
[1] - p4
[1] > DCTP_EPS
)
1029 if( (test
& ptest
) == 0)
1031 // std::cerr << i1 << "," << i1 + 1 << " overlaps " << i2 << "," << i2 + 1 << std::endl;
1032 // the bounding boxes overlap
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
1048 if(doIntersect(globalverts
, i1
, i1
+ 1, i2
, (i2
+ 1) % oldNum
) )
1050 // the lines intersect => ... p1 ip p4 ... ; ip p2 ... p3
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
) )
1062 else if(DCTPVecIsEqual(ip
, p2
) )
1064 iip
= vertices
[i1
+ 1];
1066 else if(DCTPVecIsEqual(ip
, p3
) )
1070 else if(DCTPVecIsEqual(ip
, p4
) )
1072 iip
= vertices
[(i2
+ 1) % oldNum
];
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;
1091 DCTPivector
newPoints(oldNum
);
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
];
1107 if( (iip
!= vertices
[i1
]) &&
1108 (iip
!= vertices
[(i2
+ 1) % oldNum
]) )
1110 newPoints
[newNum
] = iip
;
1113 if( (iip
!= vertices
[i2
]) &&
1114 (iip
!= vertices
[i1
+ 1]) )
1116 poly
.vertices
.resize(i2
+ 1 - i1
);
1117 poly
.vertices
[i2
- i1
] = iip
;
1121 poly
.vertices
.resize(i2
- i1
);
1126 poly
.vertices
.resize(i2
- i1
);
1130 for(i
= 0; i
< i2
- i1
; ++i
)
1132 poly
.vertices
[i
] = vertices
[i1
+ i
+ 1];
1136 for(i
= i2
+ 1; i
< oldNum
; ++i
)
1138 newPoints
[newNum
] = vertices
[i
];
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;
1162 // Ok, we have a valid polygon, so triangulate it.
1163 poly
.triangulate(globalverts
, polylist
);
1166 // check if there are other intersections
1173 // polygon had no intersections so we are finished
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());
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());
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;
1246 // std::cerr << "convex" << std::endl;
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
;
1259 return osgATan(dir
[1] / dir
[0]);
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)
1274 min
= max
= globalverts
[vertices
[0]];
1276 for(unsigned int i
= 1; i
< vertices
.size(); ++i
)
1278 Vec2d p
= globalverts
[vertices
[i
]];
1283 else if(max
[0] < p
[0])
1291 else if(max
[1] < p
[1])