mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 05:31:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1849 lines
		
	
	
	
		
			49 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1849 lines
		
	
	
	
		
			49 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*************************************************************************/
 | |
| /* 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;
 | |
|   for (iter = inpolys->front(); iter; iter = iter->next()) {
 | |
|     numvertices += iter->get().GetNumPoints();
 | |
|   }
 | |
| 
 | |
|   maxnumvertices = numvertices * 3;
 | |
|   vertices = new MonotoneVertex[maxnumvertices];
 | |
|   newnumvertices = numvertices;
 | |
| 
 | |
|   polystartindex = 0;
 | |
|   for (iter = inpolys->front(); iter; iter = iter->next()) {
 | |
|     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);
 | |
|         if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
 | |
|           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);
 | |
|         if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
 | |
|           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);
 | |
|           if (edgeIter == nullptr || edgeIter == edgeTree.front()) {
 | |
|             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);
 | |
| }
 | 
