00001 //Copyright (C) 2011 by Ivan Fratric 00002 // 00003 //Permission is hereby granted, free of charge, to any person obtaining a copy 00004 //of this software and associated documentation files (the "Software"), to deal 00005 //in the Software without restriction, including without limitation the rights 00006 //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00007 //copies of the Software, and to permit persons to whom the Software is 00008 //furnished to do so, subject to the following conditions: 00009 // 00010 //The above copyright notice and this permission notice shall be included in 00011 //all copies or substantial portions of the Software. 00012 // 00013 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00014 //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00015 //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00016 //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00017 //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00018 //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00019 //THE SOFTWARE. 00020 00021 00022 #include <list> 00023 using namespace std; 00024 00025 typedef double tppl_float; 00026 00027 #define TPPL_CCW 1 00028 #define TPPL_CW -1 00029 00030 //2D point structure 00031 struct TPPLPoint { 00032 tppl_float x; 00033 tppl_float y; 00034 int id; 00035 00036 TPPLPoint operator + (const TPPLPoint& p) const { 00037 TPPLPoint r; 00038 r.x = x + p.x; 00039 r.y = y + p.y; 00040 return r; 00041 } 00042 00043 TPPLPoint operator - (const TPPLPoint& p) const { 00044 TPPLPoint r; 00045 r.x = x - p.x; 00046 r.y = y - p.y; 00047 return r; 00048 } 00049 00050 TPPLPoint operator * (const tppl_float f ) const { 00051 TPPLPoint r; 00052 r.x = x*f; 00053 r.y = y*f; 00054 return r; 00055 } 00056 00057 TPPLPoint operator / (const tppl_float f ) const { 00058 TPPLPoint r; 00059 r.x = x/f; 00060 r.y = y/f; 00061 return r; 00062 } 00063 00064 bool operator==(const TPPLPoint& p) const { 00065 if((x == p.x)&&(y==p.y)) return true; 00066 else return false; 00067 } 00068 00069 bool operator!=(const TPPLPoint& p) const { 00070 if((x == p.x)&&(y==p.y)) return false; 00071 else return true; 00072 } 00073 }; 00074 00075 //Polygon implemented as an array of points with a 'hole' flag 00076 class TPPLPoly { 00077 protected: 00078 00079 TPPLPoint *points; 00080 long numpoints; 00081 bool hole; 00082 00083 public: 00084 00085 //constructors/destructors 00086 TPPLPoly(); 00087 ~TPPLPoly(); 00088 00089 TPPLPoly(const TPPLPoly &src); 00090 TPPLPoly& operator=(const TPPLPoly &src); 00091 00092 //getters and setters 00093 long GetNumPoints() { 00094 return numpoints; 00095 } 00096 00097 bool IsHole() { 00098 return hole; 00099 } 00100 00101 void SetHole(bool hole) { 00102 this->hole = hole; 00103 } 00104 00105 TPPLPoint &GetPoint(long i) { 00106 return points[i]; 00107 } 00108 00109 TPPLPoint *GetPoints() { 00110 return points; 00111 } 00112 00113 TPPLPoint& operator[] (int i) { 00114 return points[i]; 00115 } 00116 00117 //clears the polygon points 00118 void Clear(); 00119 00120 //inits the polygon with numpoints vertices 00121 void Init(long numpoints); 00122 00123 //creates a triangle with points p1,p2,p3 00124 void Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3); 00125 00126 //inverts the orfer of vertices 00127 void Invert(); 00128 00129 //returns the orientation of the polygon 00130 //possible values: 00131 // TPPL_CCW : polygon vertices are in counter-clockwise order 00132 // TPPL_CW : polygon vertices are in clockwise order 00133 // 0 : the polygon has no (measurable) area 00134 int GetOrientation(); 00135 00136 //sets the polygon orientation 00137 //orientation can be 00138 // TPPL_CCW : sets vertices in counter-clockwise order 00139 // TPPL_CW : sets vertices in clockwise order 00140 void SetOrientation(int orientation); 00141 }; 00142 00143 class TPPLPartition { 00144 protected: 00145 struct PartitionVertex { 00146 bool isActive; 00147 bool isConvex; 00148 bool isEar; 00149 00150 TPPLPoint p; 00151 tppl_float angle; 00152 PartitionVertex *previous; 00153 PartitionVertex *next; 00154 }; 00155 00156 struct MonotoneVertex { 00157 TPPLPoint p; 00158 long previous; 00159 long next; 00160 }; 00161 00162 class VertexSorter{ 00163 MonotoneVertex *vertices; 00164 public: 00165 VertexSorter(MonotoneVertex *v) : vertices(v) {} 00166 bool operator() (long index1, long index2); 00167 }; 00168 00169 struct Diagonal { 00170 long index1; 00171 long index2; 00172 }; 00173 00174 //dynamic programming state for minimum-weight triangulation 00175 struct DPState { 00176 bool visible; 00177 tppl_float weight; 00178 long bestvertex; 00179 }; 00180 00181 //dynamic programming state for convex partitioning 00182 struct DPState2 { 00183 bool visible; 00184 long weight; 00185 list<Diagonal> pairs; 00186 }; 00187 00188 //edge that intersects the scanline 00189 struct ScanLineEdge { 00190 long index; 00191 TPPLPoint p1; 00192 TPPLPoint p2; 00193 00194 //determines if the edge is to the left of another edge 00195 bool operator< (const ScanLineEdge & other) const; 00196 00197 bool IsConvex(const TPPLPoint& p1, const TPPLPoint& p2, const TPPLPoint& p3) const; 00198 }; 00199 00200 //standard helper functions 00201 bool IsConvex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3); 00202 bool IsReflex(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3); 00203 bool IsInside(TPPLPoint& p1, TPPLPoint& p2, TPPLPoint& p3, TPPLPoint &p); 00204 00205 bool InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p); 00206 bool InCone(PartitionVertex *v, TPPLPoint &p); 00207 00208 int Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22); 00209 00210 TPPLPoint Normalize(const TPPLPoint &p); 00211 tppl_float Distance(const TPPLPoint &p1, const TPPLPoint &p2); 00212 00213 //helper functions for Triangulate_EC 00214 void UpdateVertexReflexity(PartitionVertex *v); 00215 void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices); 00216 00217 //helper functions for ConvexPartition_OPT 00218 void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates); 00219 void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); 00220 void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); 00221 00222 //helper functions for MonotonePartition 00223 bool Below(TPPLPoint &p1, TPPLPoint &p2); 00224 void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2); 00225 00226 //triangulates a monotone polygon, used in Triangulate_MONO 00227 int TriangulateMonotone(TPPLPoly *inPoly, list<TPPLPoly> *triangles); 00228 00229 public: 00230 00231 //simple heuristic procedure for removing holes from a list of polygons 00232 //works by creating a diagonal from the rightmost hole vertex to some visible vertex 00233 //time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices 00234 //space complexity: O(n) 00235 //params: 00236 // inpolys : a list of polygons that can contain holes 00237 // vertices of all non-hole polys have to be in counter-clockwise order 00238 // vertices of all hole polys have to be in clockwise order 00239 // outpolys : a list of polygons without holes 00240 //returns 1 on success, 0 on failure 00241 int RemoveHoles(list<TPPLPoly> *inpolys, list<TPPLPoly> *outpolys); 00242 00243 //triangulates a polygon by ear clipping 00244 //time complexity O(n^2), n is the number of vertices 00245 //space complexity: O(n) 00246 //params: 00247 // poly : an input polygon to be triangulated 00248 // vertices have to be in counter-clockwise order 00249 // triangles : a list of triangles (result) 00250 //returns 1 on success, 0 on failure 00251 int Triangulate_EC(TPPLPoly *poly, list<TPPLPoly> *triangles); 00252 00253 //triangulates a list of polygons that may contain holes by ear clipping algorithm 00254 //first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon 00255 //time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices 00256 //space complexity: O(n) 00257 //params: 00258 // inpolys : a list of polygons to be triangulated (can contain holes) 00259 // vertices of all non-hole polys have to be in counter-clockwise order 00260 // vertices of all hole polys have to be in clockwise order 00261 // triangles : a list of triangles (result) 00262 //returns 1 on success, 0 on failure 00263 int Triangulate_EC(list<TPPLPoly> *inpolys, list<TPPLPoly> *triangles); 00264 00265 //creates an optimal polygon triangulation in terms of minimal edge length 00266 //time complexity: O(n^3), n is the number of vertices 00267 //space complexity: O(n^2) 00268 //params: 00269 // poly : an input polygon to be triangulated 00270 // vertices have to be in counter-clockwise order 00271 // triangles : a list of triangles (result) 00272 //returns 1 on success, 0 on failure 00273 int Triangulate_OPT(TPPLPoly *poly, list<TPPLPoly> *triangles); 00274 00275 //triangulates a polygons by firstly partitioning it into monotone polygons 00276 //time complexity: O(n*log(n)), n is the number of vertices 00277 //space complexity: O(n) 00278 //params: 00279 // poly : an input polygon to be triangulated 00280 // vertices have to be in counter-clockwise order 00281 // triangles : a list of triangles (result) 00282 //returns 1 on success, 0 on failure 00283 int Triangulate_MONO(TPPLPoly *poly, list<TPPLPoly> *triangles); 00284 00285 //triangulates a list of polygons by firstly partitioning them into monotone polygons 00286 //time complexity: O(n*log(n)), n is the number of vertices 00287 //space complexity: O(n) 00288 //params: 00289 // inpolys : a list of polygons to be triangulated (can contain holes) 00290 // vertices of all non-hole polys have to be in counter-clockwise order 00291 // vertices of all hole polys have to be in clockwise order 00292 // triangles : a list of triangles (result) 00293 //returns 1 on success, 0 on failure 00294 int Triangulate_MONO(list<TPPLPoly> *inpolys, list<TPPLPoly> *triangles); 00295 00296 //creates a monotone partition of a list of polygons that can contain holes 00297 //time complexity: O(n*log(n)), n is the number of vertices 00298 //space complexity: O(n) 00299 //params: 00300 // inpolys : a list of polygons to be triangulated (can contain holes) 00301 // vertices of all non-hole polys have to be in counter-clockwise order 00302 // vertices of all hole polys have to be in clockwise order 00303 // monotonePolys : a list of monotone polygons (result) 00304 //returns 1 on success, 0 on failure 00305 int MonotonePartition(list<TPPLPoly> *inpolys, list<TPPLPoly> *monotonePolys); 00306 00307 //partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm 00308 //the algorithm gives at most four times the number of parts as the optimal algorithm 00309 //however, in practice it works much better than that and often gives optimal partition 00310 //uses triangulation obtained by ear clipping as intermediate result 00311 //time complexity O(n^2), n is the number of vertices 00312 //space complexity: O(n) 00313 //params: 00314 // poly : an input polygon to be partitioned 00315 // vertices have to be in counter-clockwise order 00316 // parts : resulting list of convex polygons 00317 //returns 1 on success, 0 on failure 00318 int ConvexPartition_HM(TPPLPoly *poly, list<TPPLPoly> *parts); 00319 00320 //partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm 00321 //the algorithm gives at most four times the number of parts as the optimal algorithm 00322 //however, in practice it works much better than that and often gives optimal partition 00323 //uses triangulation obtained by ear clipping as intermediate result 00324 //time complexity O(n^2), n is the number of vertices 00325 //space complexity: O(n) 00326 //params: 00327 // inpolys : an input list of polygons to be partitioned 00328 // vertices of all non-hole polys have to be in counter-clockwise order 00329 // vertices of all hole polys have to be in clockwise order 00330 // parts : resulting list of convex polygons 00331 //returns 1 on success, 0 on failure 00332 int ConvexPartition_HM(list<TPPLPoly> *inpolys, list<TPPLPoly> *parts); 00333 00334 //optimal convex partitioning (in terms of number of resulting convex polygons) 00335 //using the Keil-Snoeyink algorithm 00336 //M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998 00337 //time complexity O(n^3), n is the number of vertices 00338 //space complexity: O(n^3) 00339 // poly : an input polygon to be partitioned 00340 // vertices have to be in counter-clockwise order 00341 // parts : resulting list of convex polygons 00342 //returns 1 on success, 0 on failure 00343 int ConvexPartition_OPT(TPPLPoly *poly, list<TPPLPoly> *parts); 00344 };