| 
									
										
										
										
											2021-01-12 13:45:31 -05:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2011-2021 Ivan Fratric and contributors.                */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "polypartition.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TPPLPoly::TPPLPoly() { | 
					
						
							|  |  |  |   hole = false; | 
					
						
							|  |  |  |   numpoints = 0; | 
					
						
							|  |  |  |   points = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TPPLPoly::~TPPLPoly() { | 
					
						
							|  |  |  |   if (points) { | 
					
						
							|  |  |  |     delete[] points; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPoly::Clear() { | 
					
						
							|  |  |  |   if (points) { | 
					
						
							|  |  |  |     delete[] points; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   hole = false; | 
					
						
							|  |  |  |   numpoints = 0; | 
					
						
							|  |  |  |   points = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPoly::Init(long numpoints) { | 
					
						
							|  |  |  |   Clear(); | 
					
						
							|  |  |  |   this->numpoints = numpoints; | 
					
						
							|  |  |  |   points = new TPPLPoint[numpoints]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPoly::Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3) { | 
					
						
							|  |  |  |   Init(3); | 
					
						
							|  |  |  |   points[0] = p1; | 
					
						
							|  |  |  |   points[1] = p2; | 
					
						
							|  |  |  |   points[2] = p3; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TPPLPoly::TPPLPoly(const TPPLPoly &src) : | 
					
						
							|  |  |  |         TPPLPoly() { | 
					
						
							|  |  |  |   hole = src.hole; | 
					
						
							|  |  |  |   numpoints = src.numpoints; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (numpoints > 0) { | 
					
						
							|  |  |  |     points = new TPPLPoint[numpoints]; | 
					
						
							|  |  |  |     memcpy(points, src.points, numpoints * sizeof(TPPLPoint)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TPPLPoly &TPPLPoly::operator=(const TPPLPoly &src) { | 
					
						
							|  |  |  |   Clear(); | 
					
						
							|  |  |  |   hole = src.hole; | 
					
						
							|  |  |  |   numpoints = src.numpoints; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (numpoints > 0) { | 
					
						
							|  |  |  |     points = new TPPLPoint[numpoints]; | 
					
						
							|  |  |  |     memcpy(points, src.points, numpoints * sizeof(TPPLPoint)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return *this; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TPPLOrientation TPPLPoly::GetOrientation() const { | 
					
						
							|  |  |  |   long i1, i2; | 
					
						
							|  |  |  |   tppl_float area = 0; | 
					
						
							|  |  |  |   for (i1 = 0; i1 < numpoints; i1++) { | 
					
						
							|  |  |  |     i2 = i1 + 1; | 
					
						
							|  |  |  |     if (i2 == numpoints) { | 
					
						
							|  |  |  |       i2 = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     area += points[i1].x * points[i2].y - points[i1].y * points[i2].x; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (area > 0) { | 
					
						
							|  |  |  |     return TPPL_ORIENTATION_CCW; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (area < 0) { | 
					
						
							|  |  |  |     return TPPL_ORIENTATION_CW; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return TPPL_ORIENTATION_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPoly::SetOrientation(TPPLOrientation orientation) { | 
					
						
							|  |  |  |   TPPLOrientation polyorientation = GetOrientation(); | 
					
						
							|  |  |  |   if (polyorientation != TPPL_ORIENTATION_NONE && polyorientation != orientation) { | 
					
						
							|  |  |  |     Invert(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPoly::Invert() { | 
					
						
							|  |  |  |   std::reverse(points, points + numpoints); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TPPLPartition::PartitionVertex::PartitionVertex() : | 
					
						
							|  |  |  |         previous(NULL), next(NULL) { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TPPLPoint TPPLPartition::Normalize(const TPPLPoint &p) { | 
					
						
							|  |  |  |   TPPLPoint r; | 
					
						
							|  |  |  |   tppl_float n = sqrt(p.x * p.x + p.y * p.y); | 
					
						
							|  |  |  |   if (n != 0) { | 
					
						
							|  |  |  |     r = p / n; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     r.x = 0; | 
					
						
							|  |  |  |     r.y = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return r; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | tppl_float TPPLPartition::Distance(const TPPLPoint &p1, const TPPLPoint &p2) { | 
					
						
							|  |  |  |   tppl_float dx, dy; | 
					
						
							|  |  |  |   dx = p2.x - p1.x; | 
					
						
							|  |  |  |   dy = p2.y - p1.y; | 
					
						
							|  |  |  |   return (sqrt(dx * dx + dy * dy)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Checks if two lines intersect.
 | 
					
						
							|  |  |  | int TPPLPartition::Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22) { | 
					
						
							|  |  |  |   if ((p11.x == p21.x) && (p11.y == p21.y)) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if ((p11.x == p22.x) && (p11.y == p22.y)) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if ((p12.x == p21.x) && (p12.y == p21.y)) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if ((p12.x == p22.x) && (p12.y == p22.y)) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   TPPLPoint v1ort, v2ort, v; | 
					
						
							|  |  |  |   tppl_float dot11, dot12, dot21, dot22; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v1ort.x = p12.y - p11.y; | 
					
						
							|  |  |  |   v1ort.y = p11.x - p12.x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v2ort.x = p22.y - p21.y; | 
					
						
							|  |  |  |   v2ort.y = p21.x - p22.x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v = p21 - p11; | 
					
						
							|  |  |  |   dot21 = v.x * v1ort.x + v.y * v1ort.y; | 
					
						
							|  |  |  |   v = p22 - p11; | 
					
						
							|  |  |  |   dot22 = v.x * v1ort.x + v.y * v1ort.y; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v = p11 - p21; | 
					
						
							|  |  |  |   dot11 = v.x * v2ort.x + v.y * v2ort.y; | 
					
						
							|  |  |  |   v = p12 - p21; | 
					
						
							|  |  |  |   dot12 = v.x * v2ort.x + v.y * v2ort.y; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (dot11 * dot12 > 0) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (dot21 * dot22 > 0) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Removes holes from inpolys by merging them with non-holes.
 | 
					
						
							|  |  |  | int TPPLPartition::RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys) { | 
					
						
							|  |  |  |   TPPLPolyList polys; | 
					
						
							|  |  |  |   TPPLPolyList::Element *holeiter, *polyiter, *iter, *iter2; | 
					
						
							|  |  |  |   long i, i2, holepointindex, polypointindex; | 
					
						
							|  |  |  |   TPPLPoint holepoint, polypoint, bestpolypoint; | 
					
						
							|  |  |  |   TPPLPoint linep1, linep2; | 
					
						
							|  |  |  |   TPPLPoint v1, v2; | 
					
						
							|  |  |  |   TPPLPoly newpoly; | 
					
						
							|  |  |  |   bool hasholes; | 
					
						
							|  |  |  |   bool pointvisible; | 
					
						
							|  |  |  |   bool pointfound; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Check for the trivial case of no holes.
 | 
					
						
							|  |  |  |   hasholes = false; | 
					
						
							|  |  |  |   for (iter = inpolys->front(); iter; iter = iter->next()) { | 
					
						
							|  |  |  |     if (iter->get().IsHole()) { | 
					
						
							|  |  |  |       hasholes = true; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!hasholes) { | 
					
						
							|  |  |  |     for (iter = inpolys->front(); iter; iter = iter->next()) { | 
					
						
							|  |  |  |       outpolys->push_back(iter->get()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   polys = *inpolys; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (1) { | 
					
						
							|  |  |  |     // Find the hole point with the largest x.
 | 
					
						
							|  |  |  |     hasholes = false; | 
					
						
							|  |  |  |     for (iter = polys.front(); iter; iter = iter->next()) { | 
					
						
							|  |  |  |       if (!iter->get().IsHole()) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!hasholes) { | 
					
						
							|  |  |  |         hasholes = true; | 
					
						
							|  |  |  |         holeiter = iter; | 
					
						
							|  |  |  |         holepointindex = 0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       for (i = 0; i < iter->get().GetNumPoints(); i++) { | 
					
						
							|  |  |  |         if (iter->get().GetPoint(i).x > holeiter->get().GetPoint(holepointindex).x) { | 
					
						
							|  |  |  |           holeiter = iter; | 
					
						
							|  |  |  |           holepointindex = i; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!hasholes) { | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     holepoint = holeiter->get().GetPoint(holepointindex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pointfound = false; | 
					
						
							|  |  |  |     for (iter = polys.front(); iter; iter = iter->next()) { | 
					
						
							|  |  |  |       if (iter->get().IsHole()) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       for (i = 0; i < iter->get().GetNumPoints(); i++) { | 
					
						
							|  |  |  |         if (iter->get().GetPoint(i).x <= holepoint.x) { | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!InCone(iter->get().GetPoint((i + iter->get().GetNumPoints() - 1) % (iter->get().GetNumPoints())), | 
					
						
							|  |  |  |                     iter->get().GetPoint(i), | 
					
						
							|  |  |  |                     iter->get().GetPoint((i + 1) % (iter->get().GetNumPoints())), | 
					
						
							|  |  |  |                     holepoint)) { | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         polypoint = iter->get().GetPoint(i); | 
					
						
							|  |  |  |         if (pointfound) { | 
					
						
							|  |  |  |           v1 = Normalize(polypoint - holepoint); | 
					
						
							|  |  |  |           v2 = Normalize(bestpolypoint - holepoint); | 
					
						
							|  |  |  |           if (v2.x > v1.x) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         pointvisible = true; | 
					
						
							|  |  |  |         for (iter2 = polys.front(); iter2; iter2->next()) { | 
					
						
							|  |  |  |           if (iter2->get().IsHole()) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           for (i2 = 0; i2 < iter2->get().GetNumPoints(); i2++) { | 
					
						
							|  |  |  |             linep1 = iter2->get().GetPoint(i2); | 
					
						
							|  |  |  |             linep2 = iter2->get().GetPoint((i2 + 1) % (iter2->get().GetNumPoints())); | 
					
						
							|  |  |  |             if (Intersects(holepoint, polypoint, linep1, linep2)) { | 
					
						
							|  |  |  |               pointvisible = false; | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (!pointvisible) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (pointvisible) { | 
					
						
							|  |  |  |           pointfound = true; | 
					
						
							|  |  |  |           bestpolypoint = polypoint; | 
					
						
							|  |  |  |           polyiter = iter; | 
					
						
							|  |  |  |           polypointindex = i; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!pointfound) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     newpoly.Init(holeiter->get().GetNumPoints() + polyiter->get().GetNumPoints() + 2); | 
					
						
							|  |  |  |     i2 = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= polypointindex; i++) { | 
					
						
							|  |  |  |       newpoly[i2] = polyiter->get().GetPoint(i); | 
					
						
							|  |  |  |       i2++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (i = 0; i <= holeiter->get().GetNumPoints(); i++) { | 
					
						
							|  |  |  |       newpoly[i2] = holeiter->get().GetPoint((i + holepointindex) % holeiter->get().GetNumPoints()); | 
					
						
							|  |  |  |       i2++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (i = polypointindex; i < polyiter->get().GetNumPoints(); i++) { | 
					
						
							|  |  |  |       newpoly[i2] = polyiter->get().GetPoint(i); | 
					
						
							|  |  |  |       i2++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     polys.erase(holeiter); | 
					
						
							|  |  |  |     polys.erase(polyiter); | 
					
						
							|  |  |  |     polys.push_back(newpoly); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (iter = polys.front(); iter; iter = iter->next()) { | 
					
						
							|  |  |  |     outpolys->push_back(iter->get()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TPPLPartition::IsConvex(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3) { | 
					
						
							|  |  |  |   tppl_float tmp; | 
					
						
							|  |  |  |   tmp = (p3.y - p1.y) * (p2.x - p1.x) - (p3.x - p1.x) * (p2.y - p1.y); | 
					
						
							|  |  |  |   if (tmp > 0) { | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TPPLPartition::IsReflex(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3) { | 
					
						
							|  |  |  |   tppl_float tmp; | 
					
						
							|  |  |  |   tmp = (p3.y - p1.y) * (p2.x - p1.x) - (p3.x - p1.x) * (p2.y - p1.y); | 
					
						
							|  |  |  |   if (tmp < 0) { | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TPPLPartition::IsInside(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p) { | 
					
						
							|  |  |  |   if (IsConvex(p1, p, p2)) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (IsConvex(p2, p, p3)) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (IsConvex(p3, p, p1)) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TPPLPartition::InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p) { | 
					
						
							|  |  |  |   bool convex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   convex = IsConvex(p1, p2, p3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (convex) { | 
					
						
							|  |  |  |     if (!IsConvex(p1, p2, p)) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!IsConvex(p2, p3, p)) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     if (IsConvex(p1, p2, p)) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (IsConvex(p2, p3, p)) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TPPLPartition::InCone(PartitionVertex *v, TPPLPoint &p) { | 
					
						
							|  |  |  |   TPPLPoint p1, p2, p3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   p1 = v->previous->p; | 
					
						
							|  |  |  |   p2 = v->p; | 
					
						
							|  |  |  |   p3 = v->next->p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return InCone(p1, p2, p3, p); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPartition::UpdateVertexReflexity(PartitionVertex *v) { | 
					
						
							|  |  |  |   PartitionVertex *v1 = NULL, *v3 = NULL; | 
					
						
							|  |  |  |   v1 = v->previous; | 
					
						
							|  |  |  |   v3 = v->next; | 
					
						
							|  |  |  |   v->isConvex = !IsReflex(v1->p, v->p, v3->p); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPartition::UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, long numvertices) { | 
					
						
							|  |  |  |   long i; | 
					
						
							|  |  |  |   PartitionVertex *v1 = NULL, *v3 = NULL; | 
					
						
							|  |  |  |   TPPLPoint vec1, vec3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v1 = v->previous; | 
					
						
							|  |  |  |   v3 = v->next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v->isConvex = IsConvex(v1->p, v->p, v3->p); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   vec1 = Normalize(v1->p - v->p); | 
					
						
							|  |  |  |   vec3 = Normalize(v3->p - v->p); | 
					
						
							|  |  |  |   v->angle = vec1.x * vec3.x + vec1.y * vec3.y; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (v->isConvex) { | 
					
						
							|  |  |  |     v->isEar = true; | 
					
						
							|  |  |  |     for (i = 0; i < numvertices; i++) { | 
					
						
							|  |  |  |       if ((vertices[i].p.x == v->p.x) && (vertices[i].p.y == v->p.y)) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if ((vertices[i].p.x == v1->p.x) && (vertices[i].p.y == v1->p.y)) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if ((vertices[i].p.x == v3->p.x) && (vertices[i].p.y == v3->p.y)) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (IsInside(v1->p, v->p, v3->p, vertices[i].p)) { | 
					
						
							|  |  |  |         v->isEar = false; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     v->isEar = false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Triangulation by ear removal.
 | 
					
						
							|  |  |  | int TPPLPartition::Triangulate_EC(TPPLPoly *poly, TPPLPolyList *triangles) { | 
					
						
							|  |  |  |   if (!poly->Valid()) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   long numvertices; | 
					
						
							|  |  |  |   PartitionVertex *vertices = NULL; | 
					
						
							|  |  |  |   PartitionVertex *ear = NULL; | 
					
						
							|  |  |  |   TPPLPoly triangle; | 
					
						
							|  |  |  |   long i, j; | 
					
						
							|  |  |  |   bool earfound; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (poly->GetNumPoints() < 3) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (poly->GetNumPoints() == 3) { | 
					
						
							|  |  |  |     triangles->push_back(*poly); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   numvertices = poly->GetNumPoints(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   vertices = new PartitionVertex[numvertices]; | 
					
						
							|  |  |  |   for (i = 0; i < numvertices; i++) { | 
					
						
							|  |  |  |     vertices[i].isActive = true; | 
					
						
							|  |  |  |     vertices[i].p = poly->GetPoint(i); | 
					
						
							|  |  |  |     if (i == (numvertices - 1)) { | 
					
						
							|  |  |  |       vertices[i].next = &(vertices[0]); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       vertices[i].next = &(vertices[i + 1]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (i == 0) { | 
					
						
							|  |  |  |       vertices[i].previous = &(vertices[numvertices - 1]); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       vertices[i].previous = &(vertices[i - 1]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (i = 0; i < numvertices; i++) { | 
					
						
							|  |  |  |     UpdateVertex(&vertices[i], vertices, numvertices); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < numvertices - 3; i++) { | 
					
						
							|  |  |  |     earfound = false; | 
					
						
							|  |  |  |     // Find the most extruded ear.
 | 
					
						
							|  |  |  |     for (j = 0; j < numvertices; j++) { | 
					
						
							|  |  |  |       if (!vertices[j].isActive) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!vertices[j].isEar) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!earfound) { | 
					
						
							|  |  |  |         earfound = true; | 
					
						
							|  |  |  |         ear = &(vertices[j]); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         if (vertices[j].angle > ear->angle) { | 
					
						
							|  |  |  |           ear = &(vertices[j]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!earfound) { | 
					
						
							|  |  |  |       delete[] vertices; | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     triangle.Triangle(ear->previous->p, ear->p, ear->next->p); | 
					
						
							|  |  |  |     triangles->push_back(triangle); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ear->isActive = false; | 
					
						
							|  |  |  |     ear->previous->next = ear->next; | 
					
						
							|  |  |  |     ear->next->previous = ear->previous; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (i == numvertices - 4) { | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     UpdateVertex(ear->previous, vertices, numvertices); | 
					
						
							|  |  |  |     UpdateVertex(ear->next, vertices, numvertices); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (i = 0; i < numvertices; i++) { | 
					
						
							|  |  |  |     if (vertices[i].isActive) { | 
					
						
							|  |  |  |       triangle.Triangle(vertices[i].previous->p, vertices[i].p, vertices[i].next->p); | 
					
						
							|  |  |  |       triangles->push_back(triangle); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   delete[] vertices; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) { | 
					
						
							|  |  |  |   TPPLPolyList outpolys; | 
					
						
							|  |  |  |   TPPLPolyList::Element *iter; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!RemoveHoles(inpolys, &outpolys)) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (iter = outpolys.front(); iter; iter = iter->next()) { | 
					
						
							|  |  |  |     if (!Triangulate_EC(&(iter->get()), triangles)) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, TPPLPolyList *parts) { | 
					
						
							|  |  |  |   if (!poly->Valid()) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   TPPLPolyList triangles; | 
					
						
							|  |  |  |   TPPLPolyList::Element *iter1, *iter2; | 
					
						
							|  |  |  |   TPPLPoly *poly1 = NULL, *poly2 = NULL; | 
					
						
							|  |  |  |   TPPLPoly newpoly; | 
					
						
							|  |  |  |   TPPLPoint d1, d2, p1, p2, p3; | 
					
						
							|  |  |  |   long i11, i12, i21, i22, i13, i23, j, k; | 
					
						
							|  |  |  |   bool isdiagonal; | 
					
						
							|  |  |  |   long numreflex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Check if the poly is already convex.
 | 
					
						
							|  |  |  |   numreflex = 0; | 
					
						
							|  |  |  |   for (i11 = 0; i11 < poly->GetNumPoints(); i11++) { | 
					
						
							|  |  |  |     if (i11 == 0) { | 
					
						
							|  |  |  |       i12 = poly->GetNumPoints() - 1; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       i12 = i11 - 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (i11 == (poly->GetNumPoints() - 1)) { | 
					
						
							|  |  |  |       i13 = 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       i13 = i11 + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (IsReflex(poly->GetPoint(i12), poly->GetPoint(i11), poly->GetPoint(i13))) { | 
					
						
							|  |  |  |       numreflex = 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (numreflex == 0) { | 
					
						
							|  |  |  |     parts->push_back(*poly); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!Triangulate_EC(poly, &triangles)) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (iter1 = triangles.front(); iter1; iter1 = iter1->next()) { | 
					
						
							|  |  |  |     poly1 = &(iter1->get()); | 
					
						
							|  |  |  |     for (i11 = 0; i11 < poly1->GetNumPoints(); i11++) { | 
					
						
							|  |  |  |       d1 = poly1->GetPoint(i11); | 
					
						
							|  |  |  |       i12 = (i11 + 1) % (poly1->GetNumPoints()); | 
					
						
							|  |  |  |       d2 = poly1->GetPoint(i12); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       isdiagonal = false; | 
					
						
							|  |  |  |       for (iter2 = iter1; iter2; iter2 = iter2->next()) { | 
					
						
							|  |  |  |         if (iter1 == iter2) { | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         poly2 = &(iter2->get()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (i21 = 0; i21 < poly2->GetNumPoints(); i21++) { | 
					
						
							|  |  |  |           if ((d2.x != poly2->GetPoint(i21).x) || (d2.y != poly2->GetPoint(i21).y)) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           i22 = (i21 + 1) % (poly2->GetNumPoints()); | 
					
						
							|  |  |  |           if ((d1.x != poly2->GetPoint(i22).x) || (d1.y != poly2->GetPoint(i22).y)) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           isdiagonal = true; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (isdiagonal) { | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!isdiagonal) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       p2 = poly1->GetPoint(i11); | 
					
						
							|  |  |  |       if (i11 == 0) { | 
					
						
							|  |  |  |         i13 = poly1->GetNumPoints() - 1; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         i13 = i11 - 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       p1 = poly1->GetPoint(i13); | 
					
						
							|  |  |  |       if (i22 == (poly2->GetNumPoints() - 1)) { | 
					
						
							|  |  |  |         i23 = 0; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         i23 = i22 + 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       p3 = poly2->GetPoint(i23); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!IsConvex(p1, p2, p3)) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       p2 = poly1->GetPoint(i12); | 
					
						
							|  |  |  |       if (i12 == (poly1->GetNumPoints() - 1)) { | 
					
						
							|  |  |  |         i13 = 0; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         i13 = i12 + 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       p3 = poly1->GetPoint(i13); | 
					
						
							|  |  |  |       if (i21 == 0) { | 
					
						
							|  |  |  |         i23 = poly2->GetNumPoints() - 1; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         i23 = i21 - 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       p1 = poly2->GetPoint(i23); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!IsConvex(p1, p2, p3)) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       newpoly.Init(poly1->GetNumPoints() + poly2->GetNumPoints() - 2); | 
					
						
							|  |  |  |       k = 0; | 
					
						
							|  |  |  |       for (j = i12; j != i11; j = (j + 1) % (poly1->GetNumPoints())) { | 
					
						
							|  |  |  |         newpoly[k] = poly1->GetPoint(j); | 
					
						
							|  |  |  |         k++; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       for (j = i22; j != i21; j = (j + 1) % (poly2->GetNumPoints())) { | 
					
						
							|  |  |  |         newpoly[k] = poly2->GetPoint(j); | 
					
						
							|  |  |  |         k++; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       triangles.erase(iter2); | 
					
						
							|  |  |  |       iter1->get() = newpoly; | 
					
						
							|  |  |  |       poly1 = &(iter1->get()); | 
					
						
							|  |  |  |       i11 = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (iter1 = triangles.front(); iter1; iter1 = iter1->next()) { | 
					
						
							|  |  |  |     parts->push_back(iter1->get()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TPPLPartition::ConvexPartition_HM(TPPLPolyList *inpolys, TPPLPolyList *parts) { | 
					
						
							|  |  |  |   TPPLPolyList outpolys; | 
					
						
							|  |  |  |   TPPLPolyList::Element *iter; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!RemoveHoles(inpolys, &outpolys)) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (iter = outpolys.front(); iter; iter = iter->next()) { | 
					
						
							|  |  |  |     if (!ConvexPartition_HM(&(iter->get()), parts)) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Minimum-weight polygon triangulation by dynamic programming.
 | 
					
						
							|  |  |  | // Time complexity: O(n^3)
 | 
					
						
							|  |  |  | // Space complexity: O(n^2)
 | 
					
						
							|  |  |  | int TPPLPartition::Triangulate_OPT(TPPLPoly *poly, TPPLPolyList *triangles) { | 
					
						
							|  |  |  |   if (!poly->Valid()) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   long i, j, k, gap, n; | 
					
						
							|  |  |  |   DPState **dpstates = NULL; | 
					
						
							|  |  |  |   TPPLPoint p1, p2, p3, p4; | 
					
						
							|  |  |  |   long bestvertex; | 
					
						
							|  |  |  |   tppl_float weight, minweight, d1, d2; | 
					
						
							|  |  |  |   Diagonal diagonal, newdiagonal; | 
					
						
							|  |  |  |   DiagonalList diagonals; | 
					
						
							|  |  |  |   TPPLPoly triangle; | 
					
						
							|  |  |  |   int ret = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   n = poly->GetNumPoints(); | 
					
						
							|  |  |  |   dpstates = new DPState *[n]; | 
					
						
							|  |  |  |   for (i = 1; i < n; i++) { | 
					
						
							|  |  |  |     dpstates[i] = new DPState[i]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Initialize states and visibility.
 | 
					
						
							|  |  |  |   for (i = 0; i < (n - 1); i++) { | 
					
						
							|  |  |  |     p1 = poly->GetPoint(i); | 
					
						
							|  |  |  |     for (j = i + 1; j < n; j++) { | 
					
						
							|  |  |  |       dpstates[j][i].visible = true; | 
					
						
							|  |  |  |       dpstates[j][i].weight = 0; | 
					
						
							|  |  |  |       dpstates[j][i].bestvertex = -1; | 
					
						
							|  |  |  |       if (j != (i + 1)) { | 
					
						
							|  |  |  |         p2 = poly->GetPoint(j); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Visibility check.
 | 
					
						
							|  |  |  |         if (i == 0) { | 
					
						
							|  |  |  |           p3 = poly->GetPoint(n - 1); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           p3 = poly->GetPoint(i - 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (i == (n - 1)) { | 
					
						
							|  |  |  |           p4 = poly->GetPoint(0); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           p4 = poly->GetPoint(i + 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!InCone(p3, p1, p4, p2)) { | 
					
						
							|  |  |  |           dpstates[j][i].visible = false; | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (j == 0) { | 
					
						
							|  |  |  |           p3 = poly->GetPoint(n - 1); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           p3 = poly->GetPoint(j - 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (j == (n - 1)) { | 
					
						
							|  |  |  |           p4 = poly->GetPoint(0); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           p4 = poly->GetPoint(j + 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!InCone(p3, p2, p4, p1)) { | 
					
						
							|  |  |  |           dpstates[j][i].visible = false; | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (k = 0; k < n; k++) { | 
					
						
							|  |  |  |           p3 = poly->GetPoint(k); | 
					
						
							|  |  |  |           if (k == (n - 1)) { | 
					
						
							|  |  |  |             p4 = poly->GetPoint(0); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             p4 = poly->GetPoint(k + 1); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (Intersects(p1, p2, p3, p4)) { | 
					
						
							|  |  |  |             dpstates[j][i].visible = false; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   dpstates[n - 1][0].visible = true; | 
					
						
							|  |  |  |   dpstates[n - 1][0].weight = 0; | 
					
						
							|  |  |  |   dpstates[n - 1][0].bestvertex = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (gap = 2; gap < n; gap++) { | 
					
						
							|  |  |  |     for (i = 0; i < (n - gap); i++) { | 
					
						
							|  |  |  |       j = i + gap; | 
					
						
							|  |  |  |       if (!dpstates[j][i].visible) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       bestvertex = -1; | 
					
						
							|  |  |  |       for (k = (i + 1); k < j; k++) { | 
					
						
							|  |  |  |         if (!dpstates[k][i].visible) { | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!dpstates[j][k].visible) { | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (k <= (i + 1)) { | 
					
						
							|  |  |  |           d1 = 0; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           d1 = Distance(poly->GetPoint(i), poly->GetPoint(k)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (j <= (k + 1)) { | 
					
						
							|  |  |  |           d2 = 0; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           d2 = Distance(poly->GetPoint(k), poly->GetPoint(j)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         weight = dpstates[k][i].weight + dpstates[j][k].weight + d1 + d2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((bestvertex == -1) || (weight < minweight)) { | 
					
						
							|  |  |  |           bestvertex = k; | 
					
						
							|  |  |  |           minweight = weight; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (bestvertex == -1) { | 
					
						
							|  |  |  |         for (i = 1; i < n; i++) { | 
					
						
							|  |  |  |           delete[] dpstates[i]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         delete[] dpstates; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dpstates[j][i].bestvertex = bestvertex; | 
					
						
							|  |  |  |       dpstates[j][i].weight = minweight; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   newdiagonal.index1 = 0; | 
					
						
							|  |  |  |   newdiagonal.index2 = n - 1; | 
					
						
							|  |  |  |   diagonals.push_back(newdiagonal); | 
					
						
							|  |  |  |   while (!diagonals.is_empty()) { | 
					
						
							|  |  |  |     diagonal = diagonals.front()->get(); | 
					
						
							|  |  |  |     diagonals.pop_front(); | 
					
						
							|  |  |  |     bestvertex = dpstates[diagonal.index2][diagonal.index1].bestvertex; | 
					
						
							|  |  |  |     if (bestvertex == -1) { | 
					
						
							|  |  |  |       ret = 0; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     triangle.Triangle(poly->GetPoint(diagonal.index1), poly->GetPoint(bestvertex), poly->GetPoint(diagonal.index2)); | 
					
						
							|  |  |  |     triangles->push_back(triangle); | 
					
						
							|  |  |  |     if (bestvertex > (diagonal.index1 + 1)) { | 
					
						
							|  |  |  |       newdiagonal.index1 = diagonal.index1; | 
					
						
							|  |  |  |       newdiagonal.index2 = bestvertex; | 
					
						
							|  |  |  |       diagonals.push_back(newdiagonal); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (diagonal.index2 > (bestvertex + 1)) { | 
					
						
							|  |  |  |       newdiagonal.index1 = bestvertex; | 
					
						
							|  |  |  |       newdiagonal.index2 = diagonal.index2; | 
					
						
							|  |  |  |       diagonals.push_back(newdiagonal); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 1; i < n; i++) { | 
					
						
							|  |  |  |     delete[] dpstates[i]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   delete[] dpstates; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPartition::UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates) { | 
					
						
							|  |  |  |   Diagonal newdiagonal; | 
					
						
							|  |  |  |   DiagonalList *pairs = NULL; | 
					
						
							|  |  |  |   long w2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   w2 = dpstates[a][b].weight; | 
					
						
							|  |  |  |   if (w > w2) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   pairs = &(dpstates[a][b].pairs); | 
					
						
							|  |  |  |   newdiagonal.index1 = i; | 
					
						
							|  |  |  |   newdiagonal.index2 = j; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (w < w2) { | 
					
						
							|  |  |  |     pairs->clear(); | 
					
						
							|  |  |  |     pairs->push_front(newdiagonal); | 
					
						
							|  |  |  |     dpstates[a][b].weight = w; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     if ((!pairs->is_empty()) && (i <= pairs->front()->get().index1)) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     while ((!pairs->is_empty()) && (pairs->front()->get().index2 >= j)) { | 
					
						
							|  |  |  |       pairs->pop_front(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     pairs->push_front(newdiagonal); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) { | 
					
						
							|  |  |  |   DiagonalList *pairs = NULL; | 
					
						
							|  |  |  |   DiagonalList::Element *iter, *lastiter; | 
					
						
							|  |  |  |   long top; | 
					
						
							|  |  |  |   long w; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!dpstates[i][j].visible) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   top = j; | 
					
						
							|  |  |  |   w = dpstates[i][j].weight; | 
					
						
							|  |  |  |   if (k - j > 1) { | 
					
						
							|  |  |  |     if (!dpstates[j][k].visible) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     w += dpstates[j][k].weight + 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (j - i > 1) { | 
					
						
							|  |  |  |     pairs = &(dpstates[i][j].pairs); | 
					
						
							|  |  |  |     iter = pairs->back(); | 
					
						
							|  |  |  |     lastiter = pairs->back(); | 
					
						
							|  |  |  |     while (iter != pairs->front()) { | 
					
						
							|  |  |  |       iter--; | 
					
						
							|  |  |  |       if (!IsReflex(vertices[iter->get().index2].p, vertices[j].p, vertices[k].p)) { | 
					
						
							|  |  |  |         lastiter = iter; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (lastiter == pairs->back()) { | 
					
						
							|  |  |  |       w++; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       if (IsReflex(vertices[k].p, vertices[i].p, vertices[lastiter->get().index1].p)) { | 
					
						
							|  |  |  |         w++; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         top = lastiter->get().index1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   UpdateState(i, k, w, top, j, dpstates); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TPPLPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) { | 
					
						
							|  |  |  |   DiagonalList *pairs = NULL; | 
					
						
							|  |  |  |   DiagonalList::Element *iter, *lastiter; | 
					
						
							|  |  |  |   long top; | 
					
						
							|  |  |  |   long w; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!dpstates[j][k].visible) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   top = j; | 
					
						
							|  |  |  |   w = dpstates[j][k].weight; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (j - i > 1) { | 
					
						
							|  |  |  |     if (!dpstates[i][j].visible) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     w += dpstates[i][j].weight + 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (k - j > 1) { | 
					
						
							|  |  |  |     pairs = &(dpstates[j][k].pairs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     iter = pairs->front(); | 
					
						
							|  |  |  |     if ((!pairs->is_empty()) && (!IsReflex(vertices[i].p, vertices[j].p, vertices[iter->get().index1].p))) { | 
					
						
							|  |  |  |       lastiter = iter; | 
					
						
							|  |  |  |       while (iter) { | 
					
						
							|  |  |  |         if (!IsReflex(vertices[i].p, vertices[j].p, vertices[iter->get().index1].p)) { | 
					
						
							|  |  |  |           lastiter = iter; | 
					
						
							|  |  |  |           iter = iter->next(); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (IsReflex(vertices[lastiter->get().index2].p, vertices[k].p, vertices[i].p)) { | 
					
						
							|  |  |  |         w++; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         top = lastiter->get().index2; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       w++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   UpdateState(i, k, w, j, top, dpstates); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, TPPLPolyList *parts) { | 
					
						
							|  |  |  |   if (!poly->Valid()) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   TPPLPoint p1, p2, p3, p4; | 
					
						
							|  |  |  |   PartitionVertex *vertices = NULL; | 
					
						
							|  |  |  |   DPState2 **dpstates = NULL; | 
					
						
							|  |  |  |   long i, j, k, n, gap; | 
					
						
							|  |  |  |   DiagonalList diagonals, diagonals2; | 
					
						
							|  |  |  |   Diagonal diagonal, newdiagonal; | 
					
						
							|  |  |  |   DiagonalList *pairs = NULL, *pairs2 = NULL; | 
					
						
							|  |  |  |   DiagonalList::Element *iter, *iter2; | 
					
						
							|  |  |  |   int ret; | 
					
						
							|  |  |  |   TPPLPoly newpoly; | 
					
						
							|  |  |  |   List<long> indices; | 
					
						
							|  |  |  |   List<long>::Element *iiter; | 
					
						
							|  |  |  |   bool ijreal, jkreal; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   n = poly->GetNumPoints(); | 
					
						
							|  |  |  |   vertices = new PartitionVertex[n]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dpstates = new DPState2 *[n]; | 
					
						
							|  |  |  |   for (i = 0; i < n; i++) { | 
					
						
							|  |  |  |     dpstates[i] = new DPState2[n]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Initialize vertex information.
 | 
					
						
							|  |  |  |   for (i = 0; i < n; i++) { | 
					
						
							|  |  |  |     vertices[i].p = poly->GetPoint(i); | 
					
						
							|  |  |  |     vertices[i].isActive = true; | 
					
						
							|  |  |  |     if (i == 0) { | 
					
						
							|  |  |  |       vertices[i].previous = &(vertices[n - 1]); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       vertices[i].previous = &(vertices[i - 1]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (i == (poly->GetNumPoints() - 1)) { | 
					
						
							|  |  |  |       vertices[i].next = &(vertices[0]); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       vertices[i].next = &(vertices[i + 1]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (i = 1; i < n; i++) { | 
					
						
							|  |  |  |     UpdateVertexReflexity(&(vertices[i])); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Initialize states and visibility.
 | 
					
						
							|  |  |  |   for (i = 0; i < (n - 1); i++) { | 
					
						
							|  |  |  |     p1 = poly->GetPoint(i); | 
					
						
							|  |  |  |     for (j = i + 1; j < n; j++) { | 
					
						
							|  |  |  |       dpstates[i][j].visible = true; | 
					
						
							|  |  |  |       if (j == i + 1) { | 
					
						
							|  |  |  |         dpstates[i][j].weight = 0; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         dpstates[i][j].weight = 2147483647; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (j != (i + 1)) { | 
					
						
							|  |  |  |         p2 = poly->GetPoint(j); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Visibility check.
 | 
					
						
							|  |  |  |         if (!InCone(&vertices[i], p2)) { | 
					
						
							|  |  |  |           dpstates[i][j].visible = false; | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!InCone(&vertices[j], p1)) { | 
					
						
							|  |  |  |           dpstates[i][j].visible = false; | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (k = 0; k < n; k++) { | 
					
						
							|  |  |  |           p3 = poly->GetPoint(k); | 
					
						
							|  |  |  |           if (k == (n - 1)) { | 
					
						
							|  |  |  |             p4 = poly->GetPoint(0); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             p4 = poly->GetPoint(k + 1); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (Intersects(p1, p2, p3, p4)) { | 
					
						
							|  |  |  |             dpstates[i][j].visible = false; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (i = 0; i < (n - 2); i++) { | 
					
						
							|  |  |  |     j = i + 2; | 
					
						
							|  |  |  |     if (dpstates[i][j].visible) { | 
					
						
							|  |  |  |       dpstates[i][j].weight = 0; | 
					
						
							|  |  |  |       newdiagonal.index1 = i + 1; | 
					
						
							|  |  |  |       newdiagonal.index2 = i + 1; | 
					
						
							|  |  |  |       dpstates[i][j].pairs.push_back(newdiagonal); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dpstates[0][n - 1].visible = true; | 
					
						
							|  |  |  |   vertices[0].isConvex = false; // By convention.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (gap = 3; gap < n; gap++) { | 
					
						
							|  |  |  |     for (i = 0; i < n - gap; i++) { | 
					
						
							|  |  |  |       if (vertices[i].isConvex) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       k = i + gap; | 
					
						
							|  |  |  |       if (dpstates[i][k].visible) { | 
					
						
							|  |  |  |         if (!vertices[k].isConvex) { | 
					
						
							|  |  |  |           for (j = i + 1; j < k; j++) { | 
					
						
							|  |  |  |             TypeA(i, j, k, vertices, dpstates); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           for (j = i + 1; j < (k - 1); j++) { | 
					
						
							|  |  |  |             if (vertices[j].isConvex) { | 
					
						
							|  |  |  |               continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             TypeA(i, j, k, vertices, dpstates); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           TypeA(i, k - 1, k, vertices, dpstates); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (k = gap; k < n; k++) { | 
					
						
							|  |  |  |       if (vertices[k].isConvex) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       i = k - gap; | 
					
						
							|  |  |  |       if ((vertices[i].isConvex) && (dpstates[i][k].visible)) { | 
					
						
							|  |  |  |         TypeB(i, i + 1, k, vertices, dpstates); | 
					
						
							|  |  |  |         for (j = i + 2; j < k; j++) { | 
					
						
							|  |  |  |           if (vertices[j].isConvex) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           TypeB(i, j, k, vertices, dpstates); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Recover solution.
 | 
					
						
							|  |  |  |   ret = 1; | 
					
						
							|  |  |  |   newdiagonal.index1 = 0; | 
					
						
							|  |  |  |   newdiagonal.index2 = n - 1; | 
					
						
							|  |  |  |   diagonals.push_front(newdiagonal); | 
					
						
							|  |  |  |   while (!diagonals.is_empty()) { | 
					
						
							|  |  |  |     diagonal = diagonals.front()->get(); | 
					
						
							|  |  |  |     diagonals.pop_front(); | 
					
						
							|  |  |  |     if ((diagonal.index2 - diagonal.index1) <= 1) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs); | 
					
						
							|  |  |  |     if (pairs->is_empty()) { | 
					
						
							|  |  |  |       ret = 0; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!vertices[diagonal.index1].isConvex) { | 
					
						
							|  |  |  |       iter = pairs->back(); | 
					
						
							|  |  |  |       iter--; | 
					
						
							|  |  |  |       j = iter->get().index2; | 
					
						
							|  |  |  |       newdiagonal.index1 = j; | 
					
						
							|  |  |  |       newdiagonal.index2 = diagonal.index2; | 
					
						
							|  |  |  |       diagonals.push_front(newdiagonal); | 
					
						
							|  |  |  |       if ((j - diagonal.index1) > 1) { | 
					
						
							|  |  |  |         if (iter->get().index1 != iter->get().index2) { | 
					
						
							|  |  |  |           pairs2 = &(dpstates[diagonal.index1][j].pairs); | 
					
						
							|  |  |  |           while (1) { | 
					
						
							|  |  |  |             if (pairs2->is_empty()) { | 
					
						
							|  |  |  |               ret = 0; | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             iter2 = pairs2->back(); | 
					
						
							|  |  |  |             iter2--; | 
					
						
							|  |  |  |             if (iter->get().index1 != iter2->get().index1) { | 
					
						
							|  |  |  |               pairs2->pop_back(); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (ret == 0) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         newdiagonal.index1 = diagonal.index1; | 
					
						
							|  |  |  |         newdiagonal.index2 = j; | 
					
						
							|  |  |  |         diagonals.push_front(newdiagonal); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       iter = pairs->front(); | 
					
						
							|  |  |  |       j = iter->get().index1; | 
					
						
							|  |  |  |       newdiagonal.index1 = diagonal.index1; | 
					
						
							|  |  |  |       newdiagonal.index2 = j; | 
					
						
							|  |  |  |       diagonals.push_front(newdiagonal); | 
					
						
							|  |  |  |       if ((diagonal.index2 - j) > 1) { | 
					
						
							|  |  |  |         if (iter->get().index1 != iter->get().index2) { | 
					
						
							|  |  |  |           pairs2 = &(dpstates[j][diagonal.index2].pairs); | 
					
						
							|  |  |  |           while (1) { | 
					
						
							|  |  |  |             if (pairs2->is_empty()) { | 
					
						
							|  |  |  |               ret = 0; | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             iter2 = pairs2->front(); | 
					
						
							|  |  |  |             if (iter->get().index2 != iter2->get().index2) { | 
					
						
							|  |  |  |               pairs2->pop_front(); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (ret == 0) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         newdiagonal.index1 = j; | 
					
						
							|  |  |  |         newdiagonal.index2 = diagonal.index2; | 
					
						
							|  |  |  |         diagonals.push_front(newdiagonal); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ret == 0) { | 
					
						
							|  |  |  |     for (i = 0; i < n; i++) { | 
					
						
							|  |  |  |       delete[] dpstates[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     delete[] dpstates; | 
					
						
							|  |  |  |     delete[] vertices; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   newdiagonal.index1 = 0; | 
					
						
							|  |  |  |   newdiagonal.index2 = n - 1; | 
					
						
							|  |  |  |   diagonals.push_front(newdiagonal); | 
					
						
							|  |  |  |   while (!diagonals.is_empty()) { | 
					
						
							|  |  |  |     diagonal = diagonals.front()->get(); | 
					
						
							|  |  |  |     diagonals.pop_front(); | 
					
						
							|  |  |  |     if ((diagonal.index2 - diagonal.index1) <= 1) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     indices.clear(); | 
					
						
							|  |  |  |     diagonals2.clear(); | 
					
						
							|  |  |  |     indices.push_back(diagonal.index1); | 
					
						
							|  |  |  |     indices.push_back(diagonal.index2); | 
					
						
							|  |  |  |     diagonals2.push_front(diagonal); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (!diagonals2.is_empty()) { | 
					
						
							|  |  |  |       diagonal = diagonals2.front()->get(); | 
					
						
							|  |  |  |       diagonals2.pop_front(); | 
					
						
							|  |  |  |       if ((diagonal.index2 - diagonal.index1) <= 1) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       ijreal = true; | 
					
						
							|  |  |  |       jkreal = true; | 
					
						
							|  |  |  |       pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs); | 
					
						
							|  |  |  |       if (!vertices[diagonal.index1].isConvex) { | 
					
						
							|  |  |  |         iter = pairs->back(); | 
					
						
							|  |  |  |         iter--; | 
					
						
							|  |  |  |         j = iter->get().index2; | 
					
						
							|  |  |  |         if (iter->get().index1 != iter->get().index2) { | 
					
						
							|  |  |  |           ijreal = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         iter = pairs->front(); | 
					
						
							|  |  |  |         j = iter->get().index1; | 
					
						
							|  |  |  |         if (iter->get().index1 != iter->get().index2) { | 
					
						
							|  |  |  |           jkreal = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       newdiagonal.index1 = diagonal.index1; | 
					
						
							|  |  |  |       newdiagonal.index2 = j; | 
					
						
							|  |  |  |       if (ijreal) { | 
					
						
							|  |  |  |         diagonals.push_back(newdiagonal); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         diagonals2.push_back(newdiagonal); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       newdiagonal.index1 = j; | 
					
						
							|  |  |  |       newdiagonal.index2 = diagonal.index2; | 
					
						
							|  |  |  |       if (jkreal) { | 
					
						
							|  |  |  |         diagonals.push_back(newdiagonal); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         diagonals2.push_back(newdiagonal); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       indices.push_back(j); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //std::sort(indices.begin(), indices.end());
 | 
					
						
							|  |  |  |     indices.sort(); | 
					
						
							|  |  |  |     newpoly.Init((long)indices.size()); | 
					
						
							|  |  |  |     k = 0; | 
					
						
							|  |  |  |     for (iiter = indices.front(); iiter != indices.back(); iiter = iiter->next()) { | 
					
						
							|  |  |  |       newpoly[k] = vertices[iiter->get()].p; | 
					
						
							|  |  |  |       k++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     parts->push_back(newpoly); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < n; i++) { | 
					
						
							|  |  |  |     delete[] dpstates[i]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   delete[] dpstates; | 
					
						
							|  |  |  |   delete[] vertices; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Creates a monotone partition of a list of polygons that
 | 
					
						
							|  |  |  | // can contain holes. Triangulates a set of polygons by
 | 
					
						
							|  |  |  | // first partitioning them into monotone polygons.
 | 
					
						
							|  |  |  | // Time complexity: O(n*log(n)), n is the number of vertices.
 | 
					
						
							|  |  |  | // Space complexity: O(n)
 | 
					
						
							|  |  |  | // The algorithm used here is outlined in the book
 | 
					
						
							|  |  |  | // "Computational Geometry: Algorithms and Applications"
 | 
					
						
							|  |  |  | // by Mark de Berg, Otfried Cheong, Marc van Kreveld, and Mark Overmars.
 | 
					
						
							|  |  |  | int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monotonePolys) { | 
					
						
							|  |  |  |   TPPLPolyList::Element *iter; | 
					
						
							|  |  |  |   MonotoneVertex *vertices = NULL; | 
					
						
							|  |  |  |   long i, numvertices, vindex, vindex2, newnumvertices, maxnumvertices; | 
					
						
							|  |  |  |   long polystartindex, polyendindex; | 
					
						
							|  |  |  |   TPPLPoly *poly = NULL; | 
					
						
							|  |  |  |   MonotoneVertex *v = NULL, *v2 = NULL, *vprev = NULL, *vnext = NULL; | 
					
						
							|  |  |  |   ScanLineEdge newedge; | 
					
						
							|  |  |  |   bool error = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   numvertices = 0; | 
					
						
							| 
									
										
										
										
											2021-05-21 17:12:13 +08:00
										 |  |  |   for (iter = inpolys->front(); iter; iter = iter->next()) { | 
					
						
							| 
									
										
										
										
											2021-01-12 13:45:31 -05:00
										 |  |  |     numvertices += iter->get().GetNumPoints(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   maxnumvertices = numvertices * 3; | 
					
						
							|  |  |  |   vertices = new MonotoneVertex[maxnumvertices]; | 
					
						
							|  |  |  |   newnumvertices = numvertices; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   polystartindex = 0; | 
					
						
							| 
									
										
										
										
											2021-05-21 17:12:13 +08:00
										 |  |  |   for (iter = inpolys->front(); iter; iter = iter->next()) { | 
					
						
							| 
									
										
										
										
											2021-01-12 13:45:31 -05:00
										 |  |  |     poly = &(iter->get()); | 
					
						
							|  |  |  |     polyendindex = polystartindex + poly->GetNumPoints() - 1; | 
					
						
							|  |  |  |     for (i = 0; i < poly->GetNumPoints(); i++) { | 
					
						
							|  |  |  |       vertices[i + polystartindex].p = poly->GetPoint(i); | 
					
						
							|  |  |  |       if (i == 0) { | 
					
						
							|  |  |  |         vertices[i + polystartindex].previous = polyendindex; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         vertices[i + polystartindex].previous = i + polystartindex - 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (i == (poly->GetNumPoints() - 1)) { | 
					
						
							|  |  |  |         vertices[i + polystartindex].next = polystartindex; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         vertices[i + polystartindex].next = i + polystartindex + 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     polystartindex = polyendindex + 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Construct the priority queue.
 | 
					
						
							|  |  |  |   long *priority = new long[numvertices]; | 
					
						
							|  |  |  |   for (i = 0; i < numvertices; i++) { | 
					
						
							|  |  |  |     priority[i] = i; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   std::sort(priority, &(priority[numvertices]), VertexSorter(vertices)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Determine vertex types.
 | 
					
						
							|  |  |  |   TPPLVertexType *vertextypes = new TPPLVertexType[maxnumvertices]; | 
					
						
							|  |  |  |   for (i = 0; i < numvertices; i++) { | 
					
						
							|  |  |  |     v = &(vertices[i]); | 
					
						
							|  |  |  |     vprev = &(vertices[v->previous]); | 
					
						
							|  |  |  |     vnext = &(vertices[v->next]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (Below(vprev->p, v->p) && Below(vnext->p, v->p)) { | 
					
						
							|  |  |  |       if (IsConvex(vnext->p, vprev->p, v->p)) { | 
					
						
							|  |  |  |         vertextypes[i] = TPPL_VERTEXTYPE_START; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         vertextypes[i] = TPPL_VERTEXTYPE_SPLIT; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else if (Below(v->p, vprev->p) && Below(v->p, vnext->p)) { | 
					
						
							|  |  |  |       if (IsConvex(vnext->p, vprev->p, v->p)) { | 
					
						
							|  |  |  |         vertextypes[i] = TPPL_VERTEXTYPE_END; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         vertextypes[i] = TPPL_VERTEXTYPE_MERGE; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       vertextypes[i] = TPPL_VERTEXTYPE_REGULAR; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Helpers.
 | 
					
						
							|  |  |  |   long *helpers = new long[maxnumvertices]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Binary search tree that holds edges intersecting the scanline.
 | 
					
						
							|  |  |  |   // Note that while set doesn't actually have to be implemented as
 | 
					
						
							|  |  |  |   // a tree, complexity requirements for operations are the same as
 | 
					
						
							|  |  |  |   // for the balanced binary search tree.
 | 
					
						
							|  |  |  |   Set<ScanLineEdge> edgeTree; | 
					
						
							|  |  |  |   // Store iterators to the edge tree elements.
 | 
					
						
							|  |  |  |   // This makes deleting existing edges much faster.
 | 
					
						
							|  |  |  |   Set<ScanLineEdge>::Element **edgeTreeIterators, *edgeIter; | 
					
						
							|  |  |  |   edgeTreeIterators = new Set<ScanLineEdge>::Element *[maxnumvertices]; | 
					
						
							|  |  |  |   //Pair<Set<ScanLineEdge>::iterator, bool> edgeTreeRet;
 | 
					
						
							|  |  |  |   for (i = 0; i < numvertices; i++) { | 
					
						
							|  |  |  |     edgeTreeIterators[i] = nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // For each vertex.
 | 
					
						
							|  |  |  |   for (i = 0; i < numvertices; i++) { | 
					
						
							|  |  |  |     vindex = priority[i]; | 
					
						
							|  |  |  |     v = &(vertices[vindex]); | 
					
						
							|  |  |  |     vindex2 = vindex; | 
					
						
							|  |  |  |     v2 = v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Depending on the vertex type, do the appropriate action.
 | 
					
						
							|  |  |  |     // Comments in the following sections are copied from
 | 
					
						
							|  |  |  |     // "Computational Geometry: Algorithms and Applications".
 | 
					
						
							|  |  |  |     // Notation: e_i = e subscript i, v_i = v subscript i, etc.
 | 
					
						
							|  |  |  |     switch (vertextypes[vindex]) { | 
					
						
							|  |  |  |       case TPPL_VERTEXTYPE_START: | 
					
						
							|  |  |  |         // Insert e_i in T and set helper(e_i) to v_i.
 | 
					
						
							|  |  |  |         newedge.p1 = v->p; | 
					
						
							|  |  |  |         newedge.p2 = vertices[v->next].p; | 
					
						
							|  |  |  |         newedge.index = vindex; | 
					
						
							|  |  |  |         //edgeTreeRet = edgeTree.insert(newedge);
 | 
					
						
							|  |  |  |         //edgeTreeIterators[vindex] = edgeTreeRet.first;
 | 
					
						
							|  |  |  |         edgeTreeIterators[vindex] = edgeTree.insert(newedge); | 
					
						
							|  |  |  |         helpers[vindex] = vindex; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case TPPL_VERTEXTYPE_END: | 
					
						
							|  |  |  |         if (edgeTreeIterators[v->previous] == edgeTree.back()) { | 
					
						
							|  |  |  |           error = true; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // If helper(e_i - 1) is a merge vertex
 | 
					
						
							|  |  |  |         if (vertextypes[helpers[v->previous]] == TPPL_VERTEXTYPE_MERGE) { | 
					
						
							|  |  |  |           // Insert the diagonal connecting vi to helper(e_i - 1) in D.
 | 
					
						
							|  |  |  |           AddDiagonal(vertices, &newnumvertices, vindex, helpers[v->previous], | 
					
						
							|  |  |  |                   vertextypes, edgeTreeIterators, &edgeTree, helpers); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Delete e_i - 1 from T
 | 
					
						
							|  |  |  |         edgeTree.erase(edgeTreeIterators[v->previous]); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case TPPL_VERTEXTYPE_SPLIT: | 
					
						
							|  |  |  |         // Search in T to find the edge e_j directly left of v_i.
 | 
					
						
							|  |  |  |         newedge.p1 = v->p; | 
					
						
							|  |  |  |         newedge.p2 = v->p; | 
					
						
							|  |  |  |         edgeIter = edgeTree.lower_bound(newedge); | 
					
						
							| 
									
										
										
										
											2021-05-21 17:12:13 +08:00
										 |  |  |         if (edgeIter == nullptr || edgeIter == edgeTree.front()) { | 
					
						
							| 
									
										
										
										
											2021-01-12 13:45:31 -05:00
										 |  |  |           error = true; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         edgeIter--; | 
					
						
							|  |  |  |         // Insert the diagonal connecting vi to helper(e_j) in D.
 | 
					
						
							|  |  |  |         AddDiagonal(vertices, &newnumvertices, vindex, helpers[edgeIter->get().index], | 
					
						
							|  |  |  |                 vertextypes, edgeTreeIterators, &edgeTree, helpers); | 
					
						
							|  |  |  |         vindex2 = newnumvertices - 2; | 
					
						
							|  |  |  |         v2 = &(vertices[vindex2]); | 
					
						
							|  |  |  |         // helper(e_j) in v_i.
 | 
					
						
							|  |  |  |         helpers[edgeIter->get().index] = vindex; | 
					
						
							|  |  |  |         // Insert e_i in T and set helper(e_i) to v_i.
 | 
					
						
							|  |  |  |         newedge.p1 = v2->p; | 
					
						
							|  |  |  |         newedge.p2 = vertices[v2->next].p; | 
					
						
							|  |  |  |         newedge.index = vindex2; | 
					
						
							|  |  |  |         //edgeTreeRet = edgeTree.insert(newedge);
 | 
					
						
							|  |  |  |         //edgeTreeIterators[vindex2] = edgeTreeRet.first;
 | 
					
						
							|  |  |  |         edgeTreeIterators[vindex2] = edgeTree.insert(newedge); | 
					
						
							|  |  |  |         helpers[vindex2] = vindex2; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case TPPL_VERTEXTYPE_MERGE: | 
					
						
							|  |  |  |         if (edgeTreeIterators[v->previous] == edgeTree.back()) { | 
					
						
							|  |  |  |           error = true; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // if helper(e_i - 1) is a merge vertex
 | 
					
						
							|  |  |  |         if (vertextypes[helpers[v->previous]] == TPPL_VERTEXTYPE_MERGE) { | 
					
						
							|  |  |  |           // Insert the diagonal connecting vi to helper(e_i - 1) in D.
 | 
					
						
							|  |  |  |           AddDiagonal(vertices, &newnumvertices, vindex, helpers[v->previous], | 
					
						
							|  |  |  |                   vertextypes, edgeTreeIterators, &edgeTree, helpers); | 
					
						
							|  |  |  |           vindex2 = newnumvertices - 2; | 
					
						
							|  |  |  |           v2 = &(vertices[vindex2]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Delete e_i - 1 from T.
 | 
					
						
							|  |  |  |         edgeTree.erase(edgeTreeIterators[v->previous]); | 
					
						
							|  |  |  |         // Search in T to find the edge e_j directly left of v_i.
 | 
					
						
							|  |  |  |         newedge.p1 = v->p; | 
					
						
							|  |  |  |         newedge.p2 = v->p; | 
					
						
							|  |  |  |         edgeIter = edgeTree.lower_bound(newedge); | 
					
						
							| 
									
										
										
										
											2021-05-21 17:12:13 +08:00
										 |  |  |         if (edgeIter == nullptr || edgeIter == edgeTree.front()) { | 
					
						
							| 
									
										
										
										
											2021-01-12 13:45:31 -05:00
										 |  |  |           error = true; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         edgeIter--; | 
					
						
							|  |  |  |         // If helper(e_j) is a merge vertex.
 | 
					
						
							|  |  |  |         if (vertextypes[helpers[edgeIter->get().index]] == TPPL_VERTEXTYPE_MERGE) { | 
					
						
							|  |  |  |           // Insert the diagonal connecting v_i to helper(e_j) in D.
 | 
					
						
							|  |  |  |           AddDiagonal(vertices, &newnumvertices, vindex2, helpers[edgeIter->get().index], | 
					
						
							|  |  |  |                   vertextypes, edgeTreeIterators, &edgeTree, helpers); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // helper(e_j) <- v_i
 | 
					
						
							|  |  |  |         helpers[edgeIter->get().index] = vindex2; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case TPPL_VERTEXTYPE_REGULAR: | 
					
						
							|  |  |  |         // If the interior of P lies to the right of v_i.
 | 
					
						
							|  |  |  |         if (Below(v->p, vertices[v->previous].p)) { | 
					
						
							|  |  |  |           if (edgeTreeIterators[v->previous] == edgeTree.back()) { | 
					
						
							|  |  |  |             error = true; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           // If helper(e_i - 1) is a merge vertex.
 | 
					
						
							|  |  |  |           if (vertextypes[helpers[v->previous]] == TPPL_VERTEXTYPE_MERGE) { | 
					
						
							|  |  |  |             // Insert the diagonal connecting v_i to helper(e_i - 1) in D.
 | 
					
						
							|  |  |  |             AddDiagonal(vertices, &newnumvertices, vindex, helpers[v->previous], | 
					
						
							|  |  |  |                     vertextypes, edgeTreeIterators, &edgeTree, helpers); | 
					
						
							|  |  |  |             vindex2 = newnumvertices - 2; | 
					
						
							|  |  |  |             v2 = &(vertices[vindex2]); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           // Delete e_i - 1 from T.
 | 
					
						
							|  |  |  |           edgeTree.erase(edgeTreeIterators[v->previous]); | 
					
						
							|  |  |  |           // Insert e_i in T and set helper(e_i) to v_i.
 | 
					
						
							|  |  |  |           newedge.p1 = v2->p; | 
					
						
							|  |  |  |           newedge.p2 = vertices[v2->next].p; | 
					
						
							|  |  |  |           newedge.index = vindex2; | 
					
						
							|  |  |  |           //edgeTreeRet = edgeTree.insert(newedge);
 | 
					
						
							|  |  |  |           //edgeTreeIterators[vindex2] = edgeTreeRet.first;
 | 
					
						
							|  |  |  |           edgeTreeIterators[vindex2] = edgeTree.insert(newedge); | 
					
						
							|  |  |  |           helpers[vindex2] = vindex; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           // Search in T to find the edge e_j directly left of v_i.
 | 
					
						
							|  |  |  |           newedge.p1 = v->p; | 
					
						
							|  |  |  |           newedge.p2 = v->p; | 
					
						
							|  |  |  |           edgeIter = edgeTree.lower_bound(newedge); | 
					
						
							| 
									
										
										
										
											2021-05-21 17:12:13 +08:00
										 |  |  |           if (edgeIter == nullptr || edgeIter == edgeTree.front()) { | 
					
						
							| 
									
										
										
										
											2021-01-12 13:45:31 -05:00
										 |  |  |             error = true; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           edgeIter = edgeIter->prev(); | 
					
						
							|  |  |  |           // If helper(e_j) is a merge vertex.
 | 
					
						
							|  |  |  |           if (vertextypes[helpers[edgeIter->get().index]] == TPPL_VERTEXTYPE_MERGE) { | 
					
						
							|  |  |  |             // Insert the diagonal connecting v_i to helper(e_j) in D.
 | 
					
						
							|  |  |  |             AddDiagonal(vertices, &newnumvertices, vindex, helpers[edgeIter->get().index], | 
					
						
							|  |  |  |                     vertextypes, edgeTreeIterators, &edgeTree, helpers); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           // helper(e_j) <- v_i.
 | 
					
						
							|  |  |  |           helpers[edgeIter->get().index] = vindex; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (error) | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   char *used = new char[newnumvertices]; | 
					
						
							|  |  |  |   memset(used, 0, newnumvertices * sizeof(char)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!error) { | 
					
						
							|  |  |  |     // Return result.
 | 
					
						
							|  |  |  |     long size; | 
					
						
							|  |  |  |     TPPLPoly mpoly; | 
					
						
							|  |  |  |     for (i = 0; i < newnumvertices; i++) { | 
					
						
							|  |  |  |       if (used[i]) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       v = &(vertices[i]); | 
					
						
							|  |  |  |       vnext = &(vertices[v->next]); | 
					
						
							|  |  |  |       size = 1; | 
					
						
							|  |  |  |       while (vnext != v) { | 
					
						
							|  |  |  |         vnext = &(vertices[vnext->next]); | 
					
						
							|  |  |  |         size++; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       mpoly.Init(size); | 
					
						
							|  |  |  |       v = &(vertices[i]); | 
					
						
							|  |  |  |       mpoly[0] = v->p; | 
					
						
							|  |  |  |       vnext = &(vertices[v->next]); | 
					
						
							|  |  |  |       size = 1; | 
					
						
							|  |  |  |       used[i] = 1; | 
					
						
							|  |  |  |       used[v->next] = 1; | 
					
						
							|  |  |  |       while (vnext != v) { | 
					
						
							|  |  |  |         mpoly[size] = vnext->p; | 
					
						
							|  |  |  |         used[vnext->next] = 1; | 
					
						
							|  |  |  |         vnext = &(vertices[vnext->next]); | 
					
						
							|  |  |  |         size++; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       monotonePolys->push_back(mpoly); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Cleanup.
 | 
					
						
							|  |  |  |   delete[] vertices; | 
					
						
							|  |  |  |   delete[] priority; | 
					
						
							|  |  |  |   delete[] vertextypes; | 
					
						
							|  |  |  |   delete[] edgeTreeIterators; | 
					
						
							|  |  |  |   delete[] helpers; | 
					
						
							|  |  |  |   delete[] used; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (error) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Adds a diagonal to the doubly-connected list of vertices.
 | 
					
						
							|  |  |  | void TPPLPartition::AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2, | 
					
						
							|  |  |  |         TPPLVertexType *vertextypes, Set<ScanLineEdge>::Element **edgeTreeIterators, | 
					
						
							|  |  |  |         Set<ScanLineEdge> *edgeTree, long *helpers) { | 
					
						
							|  |  |  |   long newindex1, newindex2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   newindex1 = *numvertices; | 
					
						
							|  |  |  |   (*numvertices)++; | 
					
						
							|  |  |  |   newindex2 = *numvertices; | 
					
						
							|  |  |  |   (*numvertices)++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   vertices[newindex1].p = vertices[index1].p; | 
					
						
							|  |  |  |   vertices[newindex2].p = vertices[index2].p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   vertices[newindex2].next = vertices[index2].next; | 
					
						
							|  |  |  |   vertices[newindex1].next = vertices[index1].next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   vertices[vertices[index2].next].previous = newindex2; | 
					
						
							|  |  |  |   vertices[vertices[index1].next].previous = newindex1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   vertices[index1].next = newindex2; | 
					
						
							|  |  |  |   vertices[newindex2].previous = index1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   vertices[index2].next = newindex1; | 
					
						
							|  |  |  |   vertices[newindex1].previous = index2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Update all relevant structures.
 | 
					
						
							|  |  |  |   vertextypes[newindex1] = vertextypes[index1]; | 
					
						
							|  |  |  |   edgeTreeIterators[newindex1] = edgeTreeIterators[index1]; | 
					
						
							|  |  |  |   helpers[newindex1] = helpers[index1]; | 
					
						
							|  |  |  |   if (edgeTreeIterators[newindex1] != edgeTree->back()) { | 
					
						
							|  |  |  |     edgeTreeIterators[newindex1]->get().index = newindex1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   vertextypes[newindex2] = vertextypes[index2]; | 
					
						
							|  |  |  |   edgeTreeIterators[newindex2] = edgeTreeIterators[index2]; | 
					
						
							|  |  |  |   helpers[newindex2] = helpers[index2]; | 
					
						
							|  |  |  |   if (edgeTreeIterators[newindex2] != edgeTree->back()) { | 
					
						
							|  |  |  |     edgeTreeIterators[newindex2]->get().index = newindex2; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TPPLPartition::Below(TPPLPoint &p1, TPPLPoint &p2) { | 
					
						
							|  |  |  |   if (p1.y < p2.y) { | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } else if (p1.y == p2.y) { | 
					
						
							|  |  |  |     if (p1.x < p2.x) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Sorts in the falling order of y values, if y is equal, x is used instead.
 | 
					
						
							|  |  |  | bool TPPLPartition::VertexSorter::operator()(long index1, long index2) { | 
					
						
							|  |  |  |   if (vertices[index1].p.y > vertices[index2].p.y) { | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } else if (vertices[index1].p.y == vertices[index2].p.y) { | 
					
						
							|  |  |  |     if (vertices[index1].p.x > vertices[index2].p.x) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TPPLPartition::ScanLineEdge::IsConvex(const TPPLPoint &p1, const TPPLPoint &p2, const TPPLPoint &p3) const { | 
					
						
							|  |  |  |   tppl_float tmp; | 
					
						
							|  |  |  |   tmp = (p3.y - p1.y) * (p2.x - p1.x) - (p3.x - p1.x) * (p2.y - p1.y); | 
					
						
							|  |  |  |   if (tmp > 0) { | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TPPLPartition::ScanLineEdge::operator<(const ScanLineEdge &other) const { | 
					
						
							|  |  |  |   if (other.p1.y == other.p2.y) { | 
					
						
							|  |  |  |     if (p1.y == p2.y) { | 
					
						
							|  |  |  |       return (p1.y < other.p1.y); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return IsConvex(p1, p2, other.p1); | 
					
						
							|  |  |  |   } else if (p1.y == p2.y) { | 
					
						
							|  |  |  |     return !IsConvex(other.p1, other.p2, p1); | 
					
						
							|  |  |  |   } else if (p1.y < other.p1.y) { | 
					
						
							|  |  |  |     return !IsConvex(other.p1, other.p2, p1); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return IsConvex(p1, p2, other.p1); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Triangulates monotone polygon.
 | 
					
						
							|  |  |  | // Time complexity: O(n)
 | 
					
						
							|  |  |  | // Space complexity: O(n)
 | 
					
						
							|  |  |  | int TPPLPartition::TriangulateMonotone(TPPLPoly *inPoly, TPPLPolyList *triangles) { | 
					
						
							|  |  |  |   if (!inPoly->Valid()) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   long i, i2, j, topindex, bottomindex, leftindex, rightindex, vindex; | 
					
						
							|  |  |  |   TPPLPoint *points = NULL; | 
					
						
							|  |  |  |   long numpoints; | 
					
						
							|  |  |  |   TPPLPoly triangle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   numpoints = inPoly->GetNumPoints(); | 
					
						
							|  |  |  |   points = inPoly->GetPoints(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Trivial case.
 | 
					
						
							|  |  |  |   if (numpoints == 3) { | 
					
						
							|  |  |  |     triangles->push_back(*inPoly); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   topindex = 0; | 
					
						
							|  |  |  |   bottomindex = 0; | 
					
						
							|  |  |  |   for (i = 1; i < numpoints; i++) { | 
					
						
							|  |  |  |     if (Below(points[i], points[bottomindex])) { | 
					
						
							|  |  |  |       bottomindex = i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (Below(points[topindex], points[i])) { | 
					
						
							|  |  |  |       topindex = i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Check if the poly is really monotone.
 | 
					
						
							|  |  |  |   i = topindex; | 
					
						
							|  |  |  |   while (i != bottomindex) { | 
					
						
							|  |  |  |     i2 = i + 1; | 
					
						
							|  |  |  |     if (i2 >= numpoints) { | 
					
						
							|  |  |  |       i2 = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!Below(points[i2], points[i])) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     i = i2; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   i = bottomindex; | 
					
						
							|  |  |  |   while (i != topindex) { | 
					
						
							|  |  |  |     i2 = i + 1; | 
					
						
							|  |  |  |     if (i2 >= numpoints) { | 
					
						
							|  |  |  |       i2 = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!Below(points[i], points[i2])) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     i = i2; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   char *vertextypes = new char[numpoints]; | 
					
						
							|  |  |  |   long *priority = new long[numpoints]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Merge left and right vertex chains.
 | 
					
						
							|  |  |  |   priority[0] = topindex; | 
					
						
							|  |  |  |   vertextypes[topindex] = 0; | 
					
						
							|  |  |  |   leftindex = topindex + 1; | 
					
						
							|  |  |  |   if (leftindex >= numpoints) { | 
					
						
							|  |  |  |     leftindex = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   rightindex = topindex - 1; | 
					
						
							|  |  |  |   if (rightindex < 0) { | 
					
						
							|  |  |  |     rightindex = numpoints - 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (i = 1; i < (numpoints - 1); i++) { | 
					
						
							|  |  |  |     if (leftindex == bottomindex) { | 
					
						
							|  |  |  |       priority[i] = rightindex; | 
					
						
							|  |  |  |       rightindex--; | 
					
						
							|  |  |  |       if (rightindex < 0) { | 
					
						
							|  |  |  |         rightindex = numpoints - 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       vertextypes[priority[i]] = -1; | 
					
						
							|  |  |  |     } else if (rightindex == bottomindex) { | 
					
						
							|  |  |  |       priority[i] = leftindex; | 
					
						
							|  |  |  |       leftindex++; | 
					
						
							|  |  |  |       if (leftindex >= numpoints) { | 
					
						
							|  |  |  |         leftindex = 0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       vertextypes[priority[i]] = 1; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       if (Below(points[leftindex], points[rightindex])) { | 
					
						
							|  |  |  |         priority[i] = rightindex; | 
					
						
							|  |  |  |         rightindex--; | 
					
						
							|  |  |  |         if (rightindex < 0) { | 
					
						
							|  |  |  |           rightindex = numpoints - 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         vertextypes[priority[i]] = -1; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         priority[i] = leftindex; | 
					
						
							|  |  |  |         leftindex++; | 
					
						
							|  |  |  |         if (leftindex >= numpoints) { | 
					
						
							|  |  |  |           leftindex = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         vertextypes[priority[i]] = 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   priority[i] = bottomindex; | 
					
						
							|  |  |  |   vertextypes[bottomindex] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   long *stack = new long[numpoints]; | 
					
						
							|  |  |  |   long stackptr = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   stack[0] = priority[0]; | 
					
						
							|  |  |  |   stack[1] = priority[1]; | 
					
						
							|  |  |  |   stackptr = 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // For each vertex from top to bottom trim as many triangles as possible.
 | 
					
						
							|  |  |  |   for (i = 2; i < (numpoints - 1); i++) { | 
					
						
							|  |  |  |     vindex = priority[i]; | 
					
						
							|  |  |  |     if (vertextypes[vindex] != vertextypes[stack[stackptr - 1]]) { | 
					
						
							|  |  |  |       for (j = 0; j < (stackptr - 1); j++) { | 
					
						
							|  |  |  |         if (vertextypes[vindex] == 1) { | 
					
						
							|  |  |  |           triangle.Triangle(points[stack[j + 1]], points[stack[j]], points[vindex]); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           triangle.Triangle(points[stack[j]], points[stack[j + 1]], points[vindex]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         triangles->push_back(triangle); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       stack[0] = priority[i - 1]; | 
					
						
							|  |  |  |       stack[1] = priority[i]; | 
					
						
							|  |  |  |       stackptr = 2; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       stackptr--; | 
					
						
							|  |  |  |       while (stackptr > 0) { | 
					
						
							|  |  |  |         if (vertextypes[vindex] == 1) { | 
					
						
							|  |  |  |           if (IsConvex(points[vindex], points[stack[stackptr - 1]], points[stack[stackptr]])) { | 
					
						
							|  |  |  |             triangle.Triangle(points[vindex], points[stack[stackptr - 1]], points[stack[stackptr]]); | 
					
						
							|  |  |  |             triangles->push_back(triangle); | 
					
						
							|  |  |  |             stackptr--; | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           if (IsConvex(points[vindex], points[stack[stackptr]], points[stack[stackptr - 1]])) { | 
					
						
							|  |  |  |             triangle.Triangle(points[vindex], points[stack[stackptr]], points[stack[stackptr - 1]]); | 
					
						
							|  |  |  |             triangles->push_back(triangle); | 
					
						
							|  |  |  |             stackptr--; | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       stackptr++; | 
					
						
							|  |  |  |       stack[stackptr] = vindex; | 
					
						
							|  |  |  |       stackptr++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   vindex = priority[i]; | 
					
						
							|  |  |  |   for (j = 0; j < (stackptr - 1); j++) { | 
					
						
							|  |  |  |     if (vertextypes[stack[j + 1]] == 1) { | 
					
						
							|  |  |  |       triangle.Triangle(points[stack[j]], points[stack[j + 1]], points[vindex]); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       triangle.Triangle(points[stack[j + 1]], points[stack[j]], points[vindex]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     triangles->push_back(triangle); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   delete[] priority; | 
					
						
							|  |  |  |   delete[] vertextypes; | 
					
						
							|  |  |  |   delete[] stack; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TPPLPartition::Triangulate_MONO(TPPLPolyList *inpolys, TPPLPolyList *triangles) { | 
					
						
							|  |  |  |   TPPLPolyList monotone; | 
					
						
							|  |  |  |   TPPLPolyList::Element *iter; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!MonotonePartition(inpolys, &monotone)) { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (iter = monotone.front(); iter; iter = iter->next()) { | 
					
						
							|  |  |  |     if (!TriangulateMonotone(&(iter->get()), triangles)) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TPPLPartition::Triangulate_MONO(TPPLPoly *poly, TPPLPolyList *triangles) { | 
					
						
							|  |  |  |   TPPLPolyList polys; | 
					
						
							|  |  |  |   polys.push_back(*poly); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return Triangulate_MONO(&polys, triangles); | 
					
						
							|  |  |  | } |