1 
2 /*
3     This file is a part of the RepSnapper project.
4     Copyright (C) 2012  martin.dieringer@gmx.de
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 
21 #include "clipping.h"
22 
23 //////////////////////////////////////////////////////////////////////////////////////////
24 //
25 // old API compatibility
26 // polytree to expolygons
27 // http://www.angusj.com/delphi/clipper/documentation/Docs/Overview/Compatibility%20with%20Prior%20Versions.htm
28 
AddOuterPolyNodeToExPolygons(const CL::PolyNode * polynode,ExPolygons & expolygons)29 void Clipping::AddOuterPolyNodeToExPolygons(const CL::PolyNode * polynode,
30 					    ExPolygons& expolygons)
31 {
32   size_t cnt = expolygons.size();
33   expolygons.resize(cnt + 1);
34   expolygons[cnt].outer = polynode->Contour;
35   expolygons[cnt].holes.resize(polynode->ChildCount());
36   for (int i = 0; i < polynode->ChildCount(); ++i)
37   {
38     expolygons[cnt].holes[i] = polynode->Childs[i]->Contour;
39     //Add outer polygons contained by (nested within) holes ...
40     for (int j = 0; j < polynode->Childs[i]->ChildCount(); ++j)
41       AddOuterPolyNodeToExPolygons(polynode->Childs[i]->Childs[j], expolygons);
42   }
43 }
44 
PolyTreeToExPolygons(const CL::PolyTree * polytree,ExPolygons & expolygons)45 void Clipping::PolyTreeToExPolygons(const CL::PolyTree * polytree, ExPolygons& expolygons)
46 {
47   expolygons.clear();
48   for (int i = 0; i < polytree->ChildCount(); ++i)
49     AddOuterPolyNodeToExPolygons(polytree->Childs[i], expolygons);
50 }
51 
52 //
53 //////////////////////////////////////////////////////////////////////////////////////////
54 
55 
56 
57 
printCLpolygon(CL::Path & p)58 void printCLpolygon(CL::Path &p) {
59     cout << p.size() << endl;
60     for (uint k = 0; k < p.size(); k++) {
61       cout << p[k].X <<", " << p[k].Y << "," << endl;
62     }
63     cout << endl;
64 }
65 
printCLpolygons(CL::Paths & p)66 void printCLpolygons(CL::Paths &p) {
67   for (uint j = 0; j < p.size(); j++) {
68     printCLpolygon(p[j]);
69     cout << endl;
70   }
71 }
printCLpolygons(vector<CL::Paths> & p)72 void printCLpolygons(vector<CL::Paths> &p) {
73   uint numpolys = 0;
74   for (uint i = 0; i < p.size(); i++) numpolys += p[i].size();
75   cout << numpolys << endl;
76   for (uint i = 0; i < p.size(); i++) {
77     printCLpolygons(p[i]);
78   }
79 }
80 
81 
clear()82 void Clipping::clear()
83 {
84   clpr.Clear();
85   if(debug) {
86     subjpolygons.clear();
87     clippolygons.clear();
88   }
89 }
90 
ClipperPoint(const Vector2d & v)91 CL::IntPoint Clipping::ClipperPoint(const Vector2d &v)
92 {
93   return CL::IntPoint(CL_FACTOR*(v.x()+CL_OFFSET),
94 		       CL_FACTOR*(v.y()+CL_OFFSET));
95 }
getPoint(const CL::IntPoint & p)96 Vector2d Clipping::getPoint(const CL::IntPoint &p)
97 {
98   return Vector2d(p.X/CL_FACTOR-CL_OFFSET,
99 		  p.Y/CL_FACTOR-CL_OFFSET);
100 }
101 
getClipperPolygon(const Poly & poly)102 CL::Path Clipping::getClipperPolygon(const Poly &poly)
103 {
104   CL::Path cpoly(poly.vertices.size());
105   for(size_t i=0; i<poly.vertices.size();i++){
106     Vector2d P1;
107     // if (reverse)
108       P1 = poly.getVertexCircular(-i); // have to reverse from/to clipper
109     // else
110     //   P1 = poly.getVertexCircular(i);
111     cpoly[i]=(ClipperPoint(P1));
112   }
113   // doesn't work...:
114   // cerr<< "poly is hole? "<< hole;
115   // cerr<< " -- orient=" <<ClipperLib::Orientation(cpoly) << endl;
116   // if (ClipperLib::Orientation(cpoly) == hole)
117   //   std::reverse(cpoly.begin(),cpoly.end());
118   return cpoly;
119 }
120 
getClipperPolygons(const vector<Poly> & polys)121 CL::Paths Clipping::getClipperPolygons(const vector<Poly> &polys)
122 {
123   ClipperLib::Paths cpolys(polys.size());
124   for (uint i=0; i<polys.size(); i++)
125     {
126       cpolys[i] = getClipperPolygon(polys[i]);
127     }
128   return cpolys;
129 }
getClipperPolygons(const ExPoly & expoly)130 CL::Paths Clipping::getClipperPolygons(const ExPoly &expoly)
131 {
132   return getClipperPolygons(getPolys(expoly));
133 }
134 
135 /*  // not used
136 CL::PolyTree Clipping::getClipperTree(const vector<ExPoly> &expolys)
137 {
138   CL::PolyTree polytree;
139   // for (uint i=0; i<expolys.size(); i++)     {
140   //   CL::PolyNode expoly;
141   //   polytree[i].Contour = getClipperPolygon(expolys[i].outer);
142   //   for (uint h=0; h<expolys[i].holes.size(); h++) {
143   //     CL::PolyNode hole;
144   //     hole.Contour = getClipperPolygon(expolys[i].holes[h]);
145   //     hole.Parent  = &polytrees[i];
146   //     polytrees[i].Childs.push_back(&hole);
147   //   }
148   // }
149   return polytree;
150 }
151 */
152 
CLType(JoinType type)153 CL::JoinType Clipping::CLType(JoinType type)
154 {
155   switch (type)
156     {
157     case jsquare: return CL::jtSquare;
158     case jmiter:  return CL::jtMiter;
159     case jround:  return CL::jtRound;
160     }
161   return CL::jtMiter; // default
162 }
CLType(PolyType type)163 CL::PolyType Clipping::CLType(PolyType type)
164 {
165   switch (type)
166     {
167     case subject: return CL::ptSubject;
168     case clip: return CL::ptClip;
169     }
170   return CL::ptSubject; // default
171 }
172 
addPoly(const Poly & poly,PolyType type)173 void Clipping::addPoly(const Poly &poly, PolyType type)
174 {
175   clpr.AddPath(getClipperPolygon(poly), CLType(type), true);
176   lastZ = poly.getZ();
177   lastExtrF = poly.getExtrusionFactor();
178 }
179 
addPolys(const vector<Poly> & polys,PolyType type)180 void Clipping::addPolys(const vector<Poly> &polys, PolyType type)
181 {
182   CL::Paths cp = getClipperPolygons(polys);
183   if(debug) {
184     if (type==clip)
185       clippolygons.push_back(cp);
186     else  if (type==subject)
187       subjpolygons.push_back(cp);
188   }
189   // try {
190     clpr.AddPaths(cp, CLType(type), true);
191   // } catch (...) {
192   //   vector<CL::Paths> vcp;
193   //   vcp.push_back(cp);
194   //   printCLpolygons(vcp);
195   //   for (uint i = 0; i < cp.size(); i++) {
196   //     cerr << "try polygon "<< i << endl;
197   //     clpr.Clear();
198   //     printCLpolygon(cp[i]);
199   //     clpr.AddPath(cp[i],CLType(type), true);
200   //   }
201   //   throw("end");
202   // }
203   if (polys.size()>0) {
204     lastZ = polys.back().getZ();
205     lastExtrF = polys.back().getExtrusionFactor();
206   }
207 }
addPolys(const ExPoly & expoly,PolyType type)208 void Clipping::addPolys(const ExPoly &expoly, PolyType type)
209 {
210   vector<Poly> polys = getPolys(expoly);
211   addPolys(polys, type);
212 }
addPolys(const vector<ExPoly> & expolys,PolyType type)213 void Clipping::addPolys(const vector<ExPoly> &expolys, PolyType type)
214 {
215   for (uint i = 0; i < expolys.size(); i++)
216     addPolys(expolys[i], type);
217 }
addPolygons(const CL::Paths & cp,PolyType type)218 void Clipping::addPolygons(const CL::Paths &cp, PolyType type)
219 {
220   clpr.AddPaths(cp, CLType(type), true);
221 }
222 
223 
224 
225 // // return intersection polys
226 // vector< vector<Vector2d> > Clipping::intersect(const Poly poly1, const Poly poly2)
227 // {
228 //   CL::Path cpoly1 = getClipperPolygon(poly1),
229 //     cpoly2 =  getClipperPolygon(poly2);
230 //   clpr.Clear();
231 //   CL::Paths sol;
232 //   clpr.AddPath(cpoly1,CL::ptSubject);
233 //   clpr.AddPath(cpoly2,CL::ptClip);
234 //   clpr.Execute(CL::ctIntersection, sol, CL::pftEvenOdd, CL::pftEvenOdd);
235 
236 //   vector< vector<Vector2d> > result;
237 //   for(size_t i=0; i<sol.size();i++)
238 //     {
239 //       vector<Vector2d> polypoints;
240 //       CL::Path cpoly = sol[i];
241 //       for(size_t j=0; j<cpoly.size();j++){
242 // 	polypoints.push_back(Vector2d(cpoly[j].X,cpoly[j].Y));
243 //       }
244 //       result.push_back(polypoints);
245 //     }
246 //     return result;
247 // }
248 
249 // have added Polyons by addPolygon(s)
intersect(CL::PolyFillType sft,CL::PolyFillType cft)250 vector<Poly> Clipping::intersect(CL::PolyFillType sft,
251 				 CL::PolyFillType cft)
252 {
253   CL::Paths inter;
254   clpr.Execute(CL::ctIntersection, inter, sft, cft);
255   return getPolys(inter, lastZ, lastExtrF);
256 }
ext_intersect(CL::PolyFillType sft,CL::PolyFillType cft)257 vector<ExPoly> Clipping::ext_intersect(CL::PolyFillType sft,
258 				       CL::PolyFillType cft)
259 {
260   CL::PolyTree inter;
261   clpr.Execute(CL::ctIntersection, inter, sft, cft);
262   return getExPolys(inter, lastZ, lastExtrF);
263 }
264 
265 // have added Polyons by addPolygon(s)
unite(CL::PolyFillType sft,CL::PolyFillType cft)266 vector<Poly> Clipping::unite(CL::PolyFillType sft,
267 			     CL::PolyFillType cft)
268 {
269   CL::Paths united;
270   clpr.Execute(CL::ctUnion, united, sft, cft);
271   return getPolys(united, lastZ, lastExtrF);
272 }
ext_unite(CL::PolyFillType sft,CL::PolyFillType cft)273 vector<ExPoly> Clipping::ext_unite(CL::PolyFillType sft,
274 				   CL::PolyFillType cft)
275 {
276   CL::PolyTree inter;
277   clpr.Execute(CL::ctUnion, inter, sft, cft);
278   return getExPolys(inter, lastZ, lastExtrF);
279 }
280 
281 
282 // have added Polyons by addPolygon(s)
subtract(CL::PolyFillType sft,CL::PolyFillType cft)283 vector<Poly> Clipping::subtract(CL::PolyFillType sft,
284 				CL::PolyFillType cft)
285 {
286   CL::Paths diff;
287   clpr.Execute(CL::ctDifference, diff, sft, cft);
288   return getPolys(diff, lastZ, lastExtrF);
289 }
ext_subtract(CL::PolyFillType sft,CL::PolyFillType cft)290 vector<ExPoly> Clipping::ext_subtract(CL::PolyFillType sft,
291 				      CL::PolyFillType cft)
292 {
293   CL::PolyTree diff;
294   // if (debug) {
295   //   try {
296   //     clpr.Execute(CL::ctDifference, diff, sft, cft);
297   //   } catch (int e){
298   //     cerr << lastZ<<" - " << lastExtrF<< endl;
299   //     if (e == 22){
300   // 	cout << "Subject" << endl;
301   // 	printCLpolygons(subjpolygons);
302   // 	cout << "Clip" << endl;
303   // 	printCLpolygons(clippolygons);
304   // 	// vector<ExPoly> empty;
305   // 	// return empty;
306   //     }
307   //   }
308   // }
309   // else
310   clpr.Execute(CL::ctDifference, diff, sft, cft);//CL::pftEvenOdd, CL::pftEvenOdd);
311   return getExPolys(diff, lastZ, lastExtrF);
312 }
subtractMerged(double dist,CL::PolyFillType sft,CL::PolyFillType cft)313 vector<Poly> Clipping::subtractMerged(double dist,
314 				      CL::PolyFillType sft,
315 				      CL::PolyFillType cft)
316 {
317   CL::Paths diff;
318   clpr.Execute(CL::ctDifference, diff, sft, cft);
319   return getPolys(getMerged(diff, dist), lastZ, lastExtrF);
320 }
321 
Xor(CL::PolyFillType sft,CL::PolyFillType cft)322 vector<Poly> Clipping::Xor(CL::PolyFillType sft,
323 			   CL::PolyFillType cft)
324 {
325   CL::Paths xored;
326   clpr.Execute(CL::ctXor, xored, sft, cft);
327   return getPolys(xored, lastZ, lastExtrF);
328 }
329 
getOffset(const Poly & poly,double distance,JoinType jtype,double miterdist)330 vector<Poly> Clipping::getOffset(const Poly &poly, double distance,
331 				 JoinType jtype, double miterdist)
332 {
333   CL::Paths cpolys(1); cpolys[0]=getClipperPolygon(poly);
334   CL::Paths offset = CLOffset(cpolys, CL_FACTOR*distance, CLType(jtype), miterdist);
335   return getPolys(offset, poly.getZ(), poly.getExtrusionFactor());
336 }
getOffset(const vector<Poly> & polys,double distance,JoinType jtype,double miterdist)337 vector<Poly> Clipping::getOffset(const vector<Poly> &polys, double distance,
338 				 JoinType jtype, double miterdist)
339 {
340   CL::Paths cpolys = getClipperPolygons(polys);
341   CL::Paths offset = CLOffset(cpolys, CL_FACTOR*distance, CLType(jtype), miterdist);
342   double z=0, extrf=1.;;
343   if (polys.size()>0) {
344     z = polys.back().getZ();
345     extrf = polys.back().getExtrusionFactor();
346   }
347   return getPolys(offset,z,extrf);
348 }
getOffset(const ExPoly & expoly,double distance,JoinType jtype,double miterdist)349 vector<Poly> Clipping::getOffset(const ExPoly &expoly, double distance,
350 				 JoinType jtype, double miterdist)
351 {
352   vector<Poly> polys = getPolys(expoly);
353   return getOffset(polys,distance,jtype,miterdist);
354 }
355 
getOffset(const vector<ExPoly> & expolys,double distance,JoinType jtype,double miterdist)356 vector<Poly> Clipping::getOffset(const vector<ExPoly> &expolys, double distance,
357 				 JoinType jtype, double miterdist)
358 {
359   return getOffset(getPolys(expolys),distance,jtype,miterdist);
360 }
361 
362 
363 // vector<ExPoly> Clipping::getOffset(const vector<ExPoly> expolys, double distance,
364 // 				   JoinType jtype, double miterdist)
365 // {
366 //   CL::ExPolygons excpolys = getClipperPolygons(expolys);
367 //   double z=0, extrf=1.;;
368 //   vector<Poly> polys(excpolys.size());
369 //   if (expolys.size()>0) {
370 //     z = expolys.back().outer.getZ();
371 //     extrf = expolys.back().outer.getExtrusionFactor();
372 //   }
373 //  for (uint i = 0 ; i < expolys.size(); i++) {
374 //     CL::Paths outer = CLOffset(excpolys[i].outer,
375 // 				  CL_FACTOR*distance, CLType(jtype), miterdist);
376 //     polys[i].outer = getPoly(outer, z, extrusionfactor);
377 //     vector<Poly> polys[i].holes;
378 //     for (uint h = 0 ; h < polys[i].holes.size(); h++) {
379 //       CL::Paths holes = CLOffset(excpolys[i].holes[h],
380 // 				    CL_FACTOR*distance, CLType(jtype), miterdist);
381 //       vector<Poly> hpolys = CL:getPolys(holes, z, extrusionfactor);
382 //       polys[i].holes.insert(polys[i].holes.end(),hpolys.begin(),hpolys.end());
383 //     }
384 //   }
385 //   return getExPolys(offset,z,extrf);
386 // }
387 
388 // first goes in then out to get capped corners
getShrinkedCapped(const vector<Poly> & polys,double distance,JoinType jtype,double miterdist)389 vector<Poly> Clipping::getShrinkedCapped(const vector<Poly> &polys, double distance,
390 					 JoinType jtype, double miterdist)
391 {
392   CL::Paths cpolys = getClipperPolygons(polys);
393   CL::Paths offset1 = CLOffset(cpolys, -2*CL_FACTOR*distance, CLType(jtype), 0);// CL::jtRound);
394   CL::Paths offset = CLOffset(offset1, 1*CL_FACTOR*distance, CLType(jtype), 0);
395   double z=0, extrf=1.;;
396   if (polys.size()>0) {
397     z= polys.back().getZ();
398     extrf = polys.back().getExtrusionFactor();
399   }
400   return getPolys(offset,z,extrf);
401 }
402 
403 
404 // offset with reverse test
CLOffset(const CL::Paths & cpolys,int cldist,CL::JoinType cljtype,double miter_limit,bool reverse)405  CL::Paths Clipping::CLOffset(const CL::Paths &cpolys, int cldist,
406 				 CL::JoinType cljtype, double miter_limit, bool reverse)
407 {
408   CL::Paths opolys;
409   if (reverse)
410     CL::ReversePaths(opolys);
411   CL::ClipperOffset co(miter_limit, miter_limit);
412   co.AddPaths(cpolys, cljtype, CL::etClosedPolygon);
413   co.Execute(opolys, cldist);
414   CL::SimplifyPolygons(opolys);//, CL::pftNonZero);
415   return opolys;
416 }
417 
418 // overlap a bit and unite to merge adjacent polys
getMerged(const vector<Poly> & polys,double overlap)419 vector<Poly> Clipping::getMerged(const vector<Poly> &polys, double overlap)
420 {
421   CL::Paths cpolys = getClipperPolygons(polys);
422   CL::Paths merged = getMerged(cpolys, CL_FACTOR*overlap);
423   double z=0, extrf = 1.;
424   if (polys.size()>0) {
425     z= polys.back().getZ();
426     extrf = polys.back().getExtrusionFactor();
427   }
428   return getPolys(merged, z, extrf);
429 }
430 // overlap a bit and unite to merge adjacent polys
getMerged(const CL::Paths & cpolys,int overlap)431 CL::Paths Clipping::getMerged(const CL::Paths &cpolys, int overlap)
432 {
433   CL::Clipper clpr;
434   //  return polys;
435   // make wider to get overlap
436   CL::Paths offset;
437   offset = CLOffset(cpolys, overlap, CL::jtMiter, 1);
438   //CL::OffsetPolygons(cpolys, offset, 10, ClipperLib::jtMiter, 1);
439   // return getPolys(offset, polys.back().getZ(),polys.back().getExtrusionFactor());
440   clpr.AddPaths(offset, CL::ptSubject, true);
441   CL::Paths cpolys3;
442   clpr.Execute(CL::ctUnion, cpolys3, CL::pftEvenOdd, CL::pftEvenOdd);
443   //cerr << cpolys3.size() << " - "<<offset.size() << endl;
444   // shrink the result
445   return CLOffset(cpolys3, -overlap, CL::jtMiter, 1);
446 }
447 
getPoly(const CL::Path & cpoly,double z,double extrusionfactor)448 Poly Clipping::getPoly(const CL::Path &cpoly, double z, double extrusionfactor)
449 {
450   Poly p(z, extrusionfactor);
451   p.vertices.clear();
452   uint count = cpoly.size();
453   p.vertices.resize(count);
454   for (uint i = 0 ; i<count;  i++) {
455     p.vertices[count-i-1] = getPoint(cpoly[i]);  // reverse!
456   //   //p.vertices[i] = getPoint(cpoly[i]);
457   }
458   p.calcHole();
459   return p;
460 }
461 
getPolys(const CL::Paths & cpolys,double z,double extrusionfactor)462 vector<Poly> Clipping::getPolys(const CL::Paths &cpolys, double z, double extrusionfactor)
463 {
464   uint count = cpolys.size();
465   vector<Poly> polys(count);
466   for (uint i = 0 ; i<count;  i++)
467     polys[i] = getPoly(cpolys[i], z, extrusionfactor);
468   return polys;
469 }
470 
getExPolys(const CL::PolyTree & ctree,double z,double extrusionfactor)471 vector<ExPoly> Clipping::getExPolys(const CL::PolyTree &ctree, double z,
472 				    double extrusionfactor)
473 {
474   ExPolygons cexpolys;
475   PolyTreeToExPolygons(&ctree, cexpolys);
476   vector<ExPoly> expolys(cexpolys.size());
477   for (uint j = 0 ; j < cexpolys.size(); j++) {
478     expolys[j].outer = getPoly(cexpolys[0].outer, z, extrusionfactor);
479     for (uint i = 0 ; i < cexpolys[j].holes.size(); i++)
480       expolys[j].holes.push_back(getPoly(cexpolys[j].holes[i], z, extrusionfactor));
481   }
482   return expolys;
483 }
getPolys(const ExPoly & expoly)484 vector<Poly> Clipping::getPolys(const ExPoly &expoly)
485 {
486   Clipping clipp;
487   clipp.addPoly(expoly.outer,  subject);
488   clipp.addPolys(expoly.holes, clip);
489   vector<Poly> polys = clipp.subtract();
490   return polys;
491 }
getPolys(const vector<ExPoly> & expolys)492 vector<Poly> Clipping::getPolys(const vector<ExPoly> &expolys)
493 {
494   vector<Poly> polys;
495   for (uint i = 0; i< expolys.size(); i++) {
496     vector<Poly> p = getPolys(expolys[i]);
497     polys.insert(polys.end(),p.begin(),p.end());
498   }
499   return polys;
500 }
501 
getExPolys(const vector<Poly> & polys)502 vector<ExPoly> Clipping::getExPolys(const vector<Poly> &polys)
503 {
504   /*
505   CL::PolyTree tree = getClipperTree(polys);
506   return getExPolys(tree, polys.back().getZ(), polys.back().getExtrusionFactor());
507   */
508   vector<ExPoly> expolys;
509   vector<Poly> holes;
510   for (uint i = 0; i<polys.size(); i++) {
511     if (polys[i].isHole()) {
512       holes.push_back(polys[i]);
513     } else {
514       ExPoly expoly;
515       expoly.outer = polys[i];
516       expolys.push_back(expoly);
517     }
518   }
519   for (uint i = 0; i<holes.size(); i++)
520     for (uint j = 0; j<expolys.size(); j++)
521       if (holes[i].size()>0)
522 	if (expolys[j].outer.vertexInside(holes[i].vertices[0])) // just test one point
523 	  //if (holes[i].isInside(expolys[j].outer)) // test all
524 	  expolys[j].holes.push_back(holes[i]);
525   return expolys;
526 }
527 
getExPolys(const vector<Poly> & polys,double z,double extrusionfactor)528 vector<ExPoly> Clipping::getExPolys(const vector<Poly> &polys,
529  				    double z, double extrusionfactor)
530 {
531   vector<Poly> ppolys(polys.size());
532   for (uint i = 0; i<polys.size(); i++) {
533     ppolys[i]= Poly(polys[i],z);
534     ppolys[i].setExtrusionFactor(extrusionfactor);
535   }
536   return getExPolys(ppolys);
537 }
538 
getClipperTree(const vector<Poly> & polys)539 CL::PolyTree Clipping::getClipperTree(const vector<Poly> &polys)
540 {
541   CL::Paths cpolys = getClipperPolygons(polys);
542   CL::Clipper clpr;
543   clpr.AddPaths(cpolys, CL::ptSubject, true);
544   CL::PolyTree ctree;
545   clpr.Execute(CL::ctUnion, ctree, CL::pftEvenOdd, CL::pftEvenOdd);
546   return ctree;
547 }
548 
Area(const Poly & poly)549 double Clipping::Area(const Poly &poly){
550   CL::Path cp = getClipperPolygon(poly);
551   return (double)((long double)(CL::Area(cp))/CL_FACTOR/CL_FACTOR);
552 }
Area(const vector<Poly> & polys)553 double Clipping::Area(const vector<Poly> &polys){
554   double a=0;
555   for (uint i=0; i<polys.size(); i++)
556     a += Area(polys[i]);
557   return a;
558 }
559 
Area(const ExPoly & expoly)560 double Clipping::Area(const ExPoly &expoly){
561   double a = Area(expoly.outer);
562   for (uint i = 0; i < expoly.holes.size(); i++) {
563     a -= Area(expoly.holes[i]);
564   }
565   return a;
566 }
Area(const vector<ExPoly> & expolys)567 double Clipping::Area(const vector<ExPoly> &expolys){
568   double a=0;
569   for (uint i=0; i<expolys.size(); i++)
570     a += Area(expolys[i]);
571   return a;
572 }
573 
ReversePoints(vector<Poly> & polys)574 void Clipping::ReversePoints(vector<Poly> &polys) {
575   for (uint i=0; i<polys.size(); i++)
576     polys[i].reverse();
577 }
578 
579 
580 
581 
582