File indexing completed on 2024-05-12 03:52:07

0001 /*******************************************************************************
0002 * Author    :  Angus Johnson                                                   *
0003 * Date      :  30 May 2023                                                     *
0004 * Website   :  http://www.angusj.com                                           *
0005 * Copyright :  Angus Johnson 2010-2023                                         *
0006 * Purpose   :  This module exports the Clipper2 Library (ie DLL/so)            *
0007 * License   :  http://www.boost.org/LICENSE_1_0.txt                            *
0008 *******************************************************************************/
0009 
0010 // The exported functions below refer to simple structures that
0011 // can be understood across multiple languages. Consequently
0012 // Path64, PathD, Polytree64 etc are converted from C++ classes
0013 // (std::vector<> etc) into the following data structures:
0014 //
0015 // CPath64 (int64_t*) & CPathD (double_t*):
0016 // Path64 and PathD are converted into arrays of x,y coordinates.
0017 // However in these arrays the first x,y coordinate pair is a
0018 // counter with 'x' containing the number of following coordinate
0019 // pairs. ('y' should be 0, with one exception explained below.)
0020 // __________________________________
0021 // |counter|coord1|coord2|...|coordN|
0022 // |N ,0   |x1, y1|x2, y2|...|xN, yN|
0023 // __________________________________
0024 //
0025 // CPaths64 (int64_t**) & CPathsD (double_t**):
0026 // These are arrays of pointers to CPath64 and CPathD where
0027 // the first pointer is to a 'counter path'. This 'counter
0028 // path' has a single x,y coord pair with 'y' (not 'x')
0029 // containing the number of paths that follow. ('x' = 0).
0030 // _______________________________
0031 // |counter|path1|path2|...|pathN|
0032 // |addr0  |addr1|addr2|...|addrN| (*addr0[0]=0; *addr0[1]=N)
0033 // _______________________________
0034 //
0035 // The structures of CPolytree64 and CPolytreeD are defined
0036 // below and these structures don't need to be explained here.
0037 
0038 #ifndef CLIPPER2_EXPORT_H
0039 #define CLIPPER2_EXPORT_H
0040 
0041 #include <cstdlib>
0042 #include <vector>
0043 
0044 #include "clipper2/clipper.core.h"
0045 #include "clipper2/clipper.engine.h"
0046 #include "clipper2/clipper.offset.h"
0047 #include "clipper2/clipper.rectclip.h"
0048 
0049 namespace Clipper2Lib {
0050 
0051 typedef int64_t* CPath64;
0052 typedef int64_t** CPaths64;
0053 typedef double* CPathD;
0054 typedef double** CPathsD;
0055 
0056 typedef struct CPolyPath64 {
0057   CPath64       polygon;
0058   uint32_t      is_hole;
0059   uint32_t      child_count;
0060   CPolyPath64*  childs;
0061 }
0062 CPolyTree64;
0063 
0064 typedef struct CPolyPathD {
0065   CPathD        polygon;
0066   uint32_t      is_hole;
0067   uint32_t      child_count;
0068   CPolyPathD*   childs;
0069 }
0070 CPolyTreeD;
0071 
0072 template <typename T>
0073 struct CRect {
0074   T left;
0075   T top;
0076   T right;
0077   T bottom;
0078 };
0079 
0080 typedef CRect<int64_t> CRect64;
0081 typedef CRect<double> CRectD;
0082 
0083 template <typename T>
0084 inline bool CRectIsEmpty(const CRect<T>& rect)
0085 {
0086   return (rect.right <= rect.left) || (rect.bottom <= rect.top);
0087 }
0088 
0089 template <typename T>
0090 inline Rect<T> CRectToRect(const CRect<T>& rect)
0091 {
0092   Rect<T> result;
0093   result.left = rect.left;
0094   result.top = rect.top;
0095   result.right = rect.right;
0096   result.bottom = rect.bottom;
0097   return result;
0098 }
0099 
0100 #define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
0101 
0102 //////////////////////////////////////////////////////
0103 // EXPORTED FUNCTION DEFINITIONS
0104 //////////////////////////////////////////////////////
0105 
0106 EXTERN_DLL_EXPORT const char* Version();
0107 
0108 // Some of the functions below will return data in the various CPath
0109 // and CPolyTree structures which are pointers to heap allocated
0110 // memory. Eventually this memory will need to be released with one
0111 // of the following 'DisposeExported' functions.  (This may be the
0112 // only safe way to release this memory since the executable
0113 // accessing these exported functions may use a memory manager that
0114 // allocates and releases heap memory in a different way. Also,
0115 // CPath structures that have been constructed by the executable
0116 // should not be destroyed using these 'DisposeExported' functions.)
0117 EXTERN_DLL_EXPORT void DisposeExportedCPath64(CPath64 p);
0118 EXTERN_DLL_EXPORT void DisposeExportedCPaths64(CPaths64& pp);
0119 EXTERN_DLL_EXPORT void DisposeExportedCPathD(CPathD p);
0120 EXTERN_DLL_EXPORT void DisposeExportedCPathsD(CPathsD& pp);
0121 EXTERN_DLL_EXPORT void DisposeExportedCPolyTree64(CPolyTree64*& cpt);
0122 EXTERN_DLL_EXPORT void DisposeExportedCPolyTreeD(CPolyTreeD*& cpt);
0123 
0124 // Boolean clipping:
0125 // cliptype: None=0, Intersection=1, Union=2, Difference=3, Xor=4
0126 // fillrule: EvenOdd=0, NonZero=1, Positive=2, Negative=3
0127 EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype,
0128   uint8_t fillrule, const CPaths64 subjects,
0129   const CPaths64 subjects_open, const CPaths64 clips,
0130   CPaths64& solution, CPaths64& solution_open,
0131   bool preserve_collinear = true, bool reverse_solution = false);
0132 EXTERN_DLL_EXPORT int BooleanOpPt64(uint8_t cliptype,
0133   uint8_t fillrule, const CPaths64 subjects,
0134   const CPaths64 subjects_open, const CPaths64 clips,
0135   CPolyTree64*& solution, CPaths64& solution_open,
0136   bool preserve_collinear = true, bool reverse_solution = false);
0137 EXTERN_DLL_EXPORT int BooleanOpD(uint8_t cliptype,
0138   uint8_t fillrule, const CPathsD subjects,
0139   const CPathsD subjects_open, const CPathsD clips,
0140   CPathsD& solution, CPathsD& solution_open, int precision = 2,
0141   bool preserve_collinear = true, bool reverse_solution = false);
0142 EXTERN_DLL_EXPORT int BooleanOpPtD(uint8_t cliptype,
0143   uint8_t fillrule, const CPathsD subjects,
0144   const CPathsD subjects_open, const CPathsD clips,
0145   CPolyTreeD*& solution, CPathsD& solution_open, int precision = 2,
0146   bool preserve_collinear = true, bool reverse_solution = false);
0147 
0148 // Polygon offsetting (inflate/deflate):
0149 // jointype: Square=0, Round=1, Miter=2
0150 // endtype: Polygon=0, Joined=1, Butt=2, Square=3, Round=4
0151 EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths,
0152   double delta, uint8_t jointype, uint8_t endtype, 
0153   double miter_limit = 2.0, double arc_tolerance = 0.0, 
0154   bool reverse_solution = false);
0155 EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths,
0156   double delta, uint8_t jointype, uint8_t endtype,
0157   int precision = 2, double miter_limit = 2.0,
0158   double arc_tolerance = 0.0, bool reverse_solution = false);
0159 
0160 // RectClip & RectClipLines:
0161 EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect,
0162   const CPaths64 paths);
0163 EXTERN_DLL_EXPORT CPathsD RectClipD(const CRectD& rect,
0164   const CPathsD paths, int precision = 2);
0165 EXTERN_DLL_EXPORT CPaths64 RectClipLines64(const CRect64& rect,
0166   const CPaths64 paths);
0167 EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect,
0168   const CPathsD paths, int precision = 2);
0169 
0170 //////////////////////////////////////////////////////
0171 // INTERNAL FUNCTIONS
0172 //////////////////////////////////////////////////////
0173 
0174 inline CPath64 CreateCPath64(size_t cnt1, size_t cnt2);
0175 inline CPath64 CreateCPath64(const Path64& p);
0176 inline CPaths64 CreateCPaths64(const Paths64& pp);
0177 inline Path64 ConvertCPath64(const CPath64& p);
0178 inline Paths64 ConvertCPaths64(const CPaths64& pp);
0179 
0180 inline CPathD CreateCPathD(size_t cnt1, size_t cnt2);
0181 inline CPathD CreateCPathD(const PathD& p);
0182 inline CPathsD CreateCPathsD(const PathsD& pp);
0183 inline PathD ConvertCPathD(const CPathD& p);
0184 inline PathsD ConvertCPathsD(const CPathsD& pp);
0185 
0186 // the following function avoid multiple conversions
0187 inline CPathD CreateCPathD(const Path64& p, double scale);
0188 inline CPathsD CreateCPathsD(const Paths64& pp, double scale);
0189 inline Path64 ConvertCPathD(const CPathD& p, double scale);
0190 inline Paths64 ConvertCPathsD(const CPathsD& pp, double scale);
0191 
0192 inline CPolyTree64* CreateCPolyTree64(const PolyTree64& pt);
0193 inline CPolyTreeD* CreateCPolyTreeD(const PolyTree64& pt, double scale);
0194 
0195 EXTERN_DLL_EXPORT const char* Version()
0196 {
0197   return CLIPPER2_VERSION;
0198 }
0199 
0200 EXTERN_DLL_EXPORT void DisposeExportedCPath64(CPath64 p)
0201 {
0202   if (p) delete[] p;
0203 }
0204 
0205 EXTERN_DLL_EXPORT void DisposeExportedCPaths64(CPaths64& pp)
0206 {
0207   if (!pp) return;
0208   CPaths64 v = pp;
0209   CPath64 cnts = *v;
0210   const size_t cnt = static_cast<size_t>(cnts[1]);
0211   for (size_t i = 0; i <= cnt; ++i) //nb: cnt +1
0212     DisposeExportedCPath64(*v++);
0213   delete[] pp;
0214   pp = nullptr;
0215 }
0216 
0217 EXTERN_DLL_EXPORT void DisposeExportedCPathD(CPathD p)
0218 {
0219   if (p) delete[] p;
0220 }
0221 
0222 EXTERN_DLL_EXPORT void DisposeExportedCPathsD(CPathsD& pp)
0223 {
0224   if (!pp) return;
0225   CPathsD v = pp;
0226   CPathD cnts = *v;
0227   size_t cnt = static_cast<size_t>(cnts[1]);
0228   for (size_t i = 0; i <= cnt; ++i) //nb: cnt +1
0229     DisposeExportedCPathD(*v++);
0230   delete[] pp;
0231   pp = nullptr;
0232 }
0233 
0234 EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype, 
0235   uint8_t fillrule, const CPaths64 subjects,
0236   const CPaths64 subjects_open, const CPaths64 clips,
0237   CPaths64& solution, CPaths64& solution_open,
0238   bool preserve_collinear, bool reverse_solution)
0239 {
0240   if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
0241   if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
0242   
0243   Paths64 sub, sub_open, clp, sol, sol_open;
0244   sub       = ConvertCPaths64(subjects);
0245   sub_open  = ConvertCPaths64(subjects_open);
0246   clp       = ConvertCPaths64(clips);
0247 
0248   Clipper64 clipper;
0249   clipper.PreserveCollinear = preserve_collinear;
0250   clipper.ReverseSolution = reverse_solution;
0251   if (sub.size() > 0) clipper.AddSubject(sub);
0252   if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
0253   if (clp.size() > 0) clipper.AddClip(clp);
0254   if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), sol, sol_open)) 
0255     return -1; // clipping bug - should never happen :)
0256   solution = CreateCPaths64(sol);
0257   solution_open = CreateCPaths64(sol_open);
0258   return 0; //success !!
0259 }
0260 
0261 EXTERN_DLL_EXPORT int BooleanOpPt64(uint8_t cliptype,
0262   uint8_t fillrule, const CPaths64 subjects,
0263   const CPaths64 subjects_open, const CPaths64 clips,
0264   CPolyTree64*& solution, CPaths64& solution_open,
0265   bool preserve_collinear, bool reverse_solution)
0266 {
0267   if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
0268   if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
0269   Paths64 sub, sub_open, clp, sol_open;
0270   sub = ConvertCPaths64(subjects);
0271   sub_open = ConvertCPaths64(subjects_open);
0272   clp = ConvertCPaths64(clips);
0273 
0274   PolyTree64 pt;
0275   Clipper64 clipper;
0276   clipper.PreserveCollinear = preserve_collinear;
0277   clipper.ReverseSolution = reverse_solution;
0278   if (sub.size() > 0) clipper.AddSubject(sub);
0279   if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
0280   if (clp.size() > 0) clipper.AddClip(clp);
0281   if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), pt, sol_open))
0282     return -1; // clipping bug - should never happen :)
0283 
0284   solution = CreateCPolyTree64(pt);
0285   solution_open = CreateCPaths64(sol_open);
0286   return 0; //success !!
0287 }
0288 
0289 EXTERN_DLL_EXPORT int BooleanOpD(uint8_t cliptype,
0290   uint8_t fillrule, const CPathsD subjects,
0291   const CPathsD subjects_open, const CPathsD clips,
0292   CPathsD& solution, CPathsD& solution_open, int precision,
0293   bool preserve_collinear, bool reverse_solution)
0294 {
0295   if (precision < -8 || precision > 8) return -5;
0296   if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
0297   if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
0298   const double scale = std::pow(10, precision);
0299 
0300   Paths64 sub, sub_open, clp, sol, sol_open;
0301   sub       = ConvertCPathsD(subjects, scale);
0302   sub_open  = ConvertCPathsD(subjects_open, scale);
0303   clp       = ConvertCPathsD(clips, scale);
0304 
0305   Clipper64 clipper;
0306   clipper.PreserveCollinear = preserve_collinear;
0307   clipper.ReverseSolution = reverse_solution;
0308   if (sub.size() > 0) clipper.AddSubject(sub);
0309   if (sub_open.size() > 0)
0310     clipper.AddOpenSubject(sub_open);
0311   if (clp.size() > 0) clipper.AddClip(clp);
0312   if (!clipper.Execute(ClipType(cliptype),
0313     FillRule(fillrule), sol, sol_open)) return -1;
0314 
0315   if (sol.size() > 0) solution = CreateCPathsD(sol, 1 / scale);
0316   if (sol_open.size() > 0)
0317     solution_open = CreateCPathsD(sol_open, 1 / scale);
0318   return 0;
0319 }
0320 
0321 EXTERN_DLL_EXPORT int BooleanOpPtD(uint8_t cliptype,
0322   uint8_t fillrule, const CPathsD subjects,
0323   const CPathsD subjects_open, const CPathsD clips,
0324   CPolyTreeD*& solution, CPathsD& solution_open, int precision,
0325   bool preserve_collinear, bool reverse_solution)
0326 {
0327   if (precision < -8 || precision > 8) return -5;
0328   if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
0329   if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
0330   
0331   const double scale = std::pow(10, precision);
0332   Paths64 sub, sub_open, clp, sol_open;
0333   sub       = ConvertCPathsD(subjects, scale);
0334   sub_open  = ConvertCPathsD(subjects_open, scale);
0335   clp       = ConvertCPathsD(clips, scale);
0336 
0337   PolyTree64 sol;
0338   Clipper64 clipper;
0339   clipper.PreserveCollinear = preserve_collinear;
0340   clipper.ReverseSolution = reverse_solution;
0341   if (sub.size() > 0) clipper.AddSubject(sub);
0342   if (sub_open.size() > 0)
0343     clipper.AddOpenSubject(sub_open);
0344   if (clp.size() > 0) clipper.AddClip(clp);
0345   if (!clipper.Execute(ClipType(cliptype),
0346     FillRule(fillrule), sol, sol_open)) return -1;
0347 
0348   solution = CreateCPolyTreeD(sol, 1 / scale);
0349   if (sol_open.size() > 0)
0350     solution_open = CreateCPathsD(sol_open, 1 / scale);
0351   return 0;
0352 }
0353 
0354 EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths,
0355   double delta, uint8_t jointype, uint8_t endtype, double miter_limit,
0356   double arc_tolerance, bool reverse_solution)
0357 {
0358   Paths64 pp;
0359   pp = ConvertCPaths64(paths);
0360 
0361   ClipperOffset clip_offset( miter_limit, 
0362     arc_tolerance, reverse_solution);
0363   clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype));
0364   Paths64 result; 
0365   clip_offset.Execute(delta, result);
0366   return CreateCPaths64(result);
0367 }
0368 
0369 EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths,
0370   double delta, uint8_t jointype, uint8_t endtype,
0371   int precision, double miter_limit,
0372   double arc_tolerance, bool reverse_solution)
0373 {
0374   if (precision < -8 || precision > 8 || !paths) return nullptr;
0375   const double scale = std::pow(10, precision);
0376   ClipperOffset clip_offset(miter_limit, arc_tolerance, reverse_solution);
0377   Paths64 pp = ConvertCPathsD(paths, scale);
0378   clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype));
0379   Paths64 result;
0380   clip_offset.Execute(delta * scale, result);
0381   return CreateCPathsD(result, 1/scale);
0382 }
0383 
0384 EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect, const CPaths64 paths)
0385 {
0386   if (CRectIsEmpty(rect) || !paths) return nullptr;
0387   Rect64 r64 = CRectToRect(rect);
0388   class RectClip64 rc(r64);
0389   Paths64 pp = ConvertCPaths64(paths);
0390   Paths64 result = rc.Execute(pp);
0391   return CreateCPaths64(result);
0392 }
0393 
0394 EXTERN_DLL_EXPORT CPathsD RectClipD(const CRectD& rect, const CPathsD paths, int precision)
0395 {
0396   if (CRectIsEmpty(rect) || !paths) return nullptr;
0397   if (precision < -8 || precision > 8) return nullptr;
0398   const double scale = std::pow(10, precision);
0399 
0400   RectD r = CRectToRect(rect);
0401   Rect64 rec = ScaleRect<int64_t, double>(r, scale);
0402   Paths64 pp = ConvertCPathsD(paths, scale);
0403   class RectClip64 rc(rec);
0404   Paths64 result = rc.Execute(pp);
0405   return CreateCPathsD(result, 1/scale);
0406 }
0407 
0408 EXTERN_DLL_EXPORT CPaths64 RectClipLines64(const CRect64& rect,
0409   const CPaths64 paths)
0410 {
0411   if (CRectIsEmpty(rect) || !paths) return nullptr;
0412   Rect64 r = CRectToRect(rect);
0413   class RectClipLines64 rcl (r);
0414   Paths64 pp = ConvertCPaths64(paths);
0415   Paths64 result = rcl.Execute(pp);
0416   return CreateCPaths64(result);
0417 }
0418 
0419 EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect,
0420   const CPathsD paths, int precision)
0421 {
0422   if (CRectIsEmpty(rect) || !paths) return nullptr;
0423   if (precision < -8 || precision > 8) return nullptr;
0424   const double scale = std::pow(10, precision);
0425   Rect64 r = ScaleRect<int64_t, double>(CRectToRect(rect), scale);
0426   class RectClipLines64 rcl(r);
0427   Paths64 pp = ConvertCPathsD(paths, scale);
0428   Paths64 result = rcl.Execute(pp);
0429   return CreateCPathsD(result, 1/scale);
0430 }
0431 
0432 inline CPath64 CreateCPath64(size_t cnt1, size_t cnt2)
0433 {
0434   // allocates memory for CPath64, fills in the counter, and
0435   // returns the structure ready to be filled with path data
0436   CPath64 result = new int64_t[2 + cnt1 *2];
0437   result[0] = cnt1;
0438   result[1] = cnt2;
0439   return result;
0440 }
0441 
0442 inline CPath64 CreateCPath64(const Path64& p)
0443 {
0444   // allocates memory for CPath64, fills the counter
0445   // and returns the memory filled with path data
0446   size_t cnt = p.size();
0447   if (!cnt) return nullptr;
0448   CPath64 result = CreateCPath64(cnt, 0);
0449   CPath64 v = result;
0450   v += 2; // skip counters
0451   for (const Point64& pt : p)
0452   {
0453     *v++ = pt.x;
0454     *v++ = pt.y;
0455   }
0456   return result;
0457 }
0458 
0459 inline Path64 ConvertCPath64(const CPath64& p)
0460 {
0461   Path64 result;
0462   if (p && *p)
0463   {
0464     CPath64 v = p;
0465     const size_t cnt = static_cast<size_t>(p[0]);
0466     v += 2; // skip counters
0467     result.reserve(cnt);
0468     for (size_t i = 0; i < cnt; ++i)
0469     {
0470       // x,y here avoids right to left function evaluation
0471       // result.push_back(Point64(*v++, *v++));
0472       int64_t x = *v++;
0473       int64_t y = *v++;
0474       result.push_back(Point64(x, y));
0475     }
0476   }
0477   return result;
0478 }
0479 
0480 inline CPaths64 CreateCPaths64(const Paths64& pp)
0481 {
0482   // allocates memory for multiple CPath64 and
0483   // and returns this memory filled with path data
0484   size_t cnt = pp.size(), cnt2 = cnt;
0485 
0486   // don't allocate space for empty paths
0487   for (size_t i = 0; i < cnt; ++i)
0488     if (!pp[i].size()) --cnt2;
0489   if (!cnt2) return nullptr;
0490 
0491   CPaths64 result = new int64_t* [cnt2 + 1];
0492   CPaths64 v = result;
0493   *v++ = CreateCPath64(0, cnt2); // assign a counter path
0494   for (const Path64& p : pp)
0495   {
0496     *v = CreateCPath64(p);
0497     if (*v) ++v;
0498   }
0499   return result;
0500 }
0501 
0502 inline Paths64 ConvertCPaths64(const CPaths64& pp)
0503 {
0504   Paths64 result;
0505   if (pp) 
0506   {
0507     CPaths64 v = pp;
0508     CPath64 cnts = pp[0];
0509     const size_t cnt = static_cast<size_t>(cnts[1]); // nb 2nd cnt
0510     ++v; // skip cnts
0511     result.reserve(cnt);
0512     for (size_t i = 0; i < cnt; ++i)
0513       result.push_back(ConvertCPath64(*v++));
0514   }
0515   return result;
0516 }
0517 
0518 inline CPathD CreateCPathD(size_t cnt1, size_t cnt2)
0519 {
0520   // allocates memory for CPathD, fills in the counter, and
0521   // returns the structure ready to be filled with path data
0522   CPathD result = new double[2 + cnt1 * 2];
0523   result[0] = static_cast<double>(cnt1);
0524   result[1] = static_cast<double>(cnt2);
0525   return result;
0526 }
0527 
0528 inline CPathD CreateCPathD(const PathD& p)
0529 {
0530   // allocates memory for CPath, fills the counter
0531   // and returns the memory fills with path data
0532   size_t cnt = p.size();
0533   if (!cnt) return nullptr; 
0534   CPathD result = CreateCPathD(cnt, 0);
0535   CPathD v = result;
0536   v += 2; // skip counters
0537   for (const PointD& pt : p)
0538   {
0539     *v++ = pt.x;
0540     *v++ = pt.y;
0541   }
0542   return result;
0543 }
0544 
0545 inline PathD ConvertCPathD(const CPathD& p)
0546 {
0547   PathD result;
0548   if (p)
0549   {
0550     CPathD v = p;
0551     size_t cnt = static_cast<size_t>(v[0]);
0552     v += 2; // skip counters
0553     result.reserve(cnt);
0554     for (size_t i = 0; i < cnt; ++i)
0555     {
0556       // x,y here avoids right to left function evaluation
0557       // result.push_back(PointD(*v++, *v++));
0558       double x = *v++;
0559       double y = *v++;
0560       result.push_back(PointD(x, y));
0561     }
0562   }
0563   return result;
0564 }
0565 
0566 inline CPathsD CreateCPathsD(const PathsD& pp)
0567 {
0568   size_t cnt = pp.size(), cnt2 = cnt;
0569   // don't allocate space for empty paths
0570   for (size_t i = 0; i < cnt; ++i)
0571     if (!pp[i].size()) --cnt2;
0572   if (!cnt2) return nullptr;
0573   CPathsD result = new double * [cnt2 + 1];
0574   CPathsD v = result;
0575   *v++ = CreateCPathD(0, cnt2); // assign counter path
0576   for (const PathD& p : pp)
0577   {
0578     *v = CreateCPathD(p);
0579     if (*v) { ++v; }
0580   }
0581   return result;
0582 }
0583 
0584 inline PathsD ConvertCPathsD(const CPathsD& pp)
0585 {
0586   PathsD result;
0587   if (pp)
0588   {
0589     CPathsD v = pp;
0590     CPathD cnts = v[0];
0591     size_t cnt = static_cast<size_t>(cnts[1]);
0592     ++v; // skip cnts path
0593     result.reserve(cnt);
0594     for (size_t i = 0; i < cnt; ++i)
0595       result.push_back(ConvertCPathD(*v++));
0596   }
0597   return result;
0598 }
0599 
0600 inline Path64 ConvertCPathD(const CPathD& p, double scale)
0601 {
0602   Path64 result;
0603   if (p)
0604   {
0605     CPathD v = p;
0606     size_t cnt = static_cast<size_t>(*v);
0607     v += 2; // skip counters
0608     result.reserve(cnt);
0609     for (size_t i = 0; i < cnt; ++i)
0610     {
0611       // x,y here avoids right to left function evaluation
0612       // result.push_back(PointD(*v++, *v++));
0613       double x = *v++ * scale;
0614       double y = *v++ * scale;
0615       result.push_back(Point64(x, y));
0616     }
0617   }
0618   return result;
0619 }
0620 
0621 inline Paths64 ConvertCPathsD(const CPathsD& pp, double scale)
0622 {
0623   Paths64 result;
0624   if (pp)
0625   {
0626     CPathsD v = pp;
0627     CPathD cnts = v[0];
0628     size_t cnt = static_cast<size_t>(cnts[1]);
0629     result.reserve(cnt);
0630     ++v; // skip cnts path
0631     for (size_t i = 0; i < cnt; ++i)
0632       result.push_back(ConvertCPathD(*v++, scale));
0633   }
0634   return result;
0635 }
0636 
0637 inline CPathD CreateCPathD(const Path64& p, double scale)
0638 {
0639   // allocates memory for CPathD, fills in the counter, and
0640   // returns the structure filled with *scaled* path data
0641   size_t cnt = p.size();
0642   if (!cnt) return nullptr;
0643   CPathD result = CreateCPathD(cnt, 0);
0644   CPathD v = result;
0645   v += 2; // skip cnts 
0646   for (const Point64& pt : p)
0647   {
0648     *v++ = pt.x * scale;
0649     *v++ = pt.y * scale;
0650   }
0651   return result;
0652 }
0653 
0654 inline CPathsD CreateCPathsD(const Paths64& pp, double scale)
0655 {
0656   // allocates memory for *multiple* CPathD, and
0657   // returns the structure filled with scaled path data
0658   size_t cnt = pp.size(), cnt2 = cnt;
0659   // don't allocate space for empty paths
0660   for (size_t i = 0; i < cnt; ++i)
0661     if (!pp[i].size()) --cnt2;
0662   if (!cnt2) return nullptr;
0663   CPathsD result = new double* [cnt2 + 1];
0664   CPathsD v = result;
0665   *v++ = CreateCPathD(0, cnt2);
0666   for (const Path64& p : pp)
0667   {
0668     *v = CreateCPathD(p, scale);
0669     if (*v) ++v;
0670   }
0671   return result;
0672 }
0673 
0674 inline void InitCPolyPath64(CPolyTree64* cpt, 
0675   bool is_hole, const std::unique_ptr <PolyPath64>& pp)
0676 {
0677   cpt->polygon = CreateCPath64(pp->Polygon());
0678   cpt->is_hole = is_hole;
0679   size_t child_cnt = pp->Count();
0680   cpt->child_count = static_cast<uint32_t>(child_cnt);
0681   cpt->childs = nullptr;
0682   if (!child_cnt) return;
0683   cpt->childs = new CPolyPath64[child_cnt];
0684   CPolyPath64* child = cpt->childs;
0685   for (const std::unique_ptr <PolyPath64>& pp_child : *pp)
0686     InitCPolyPath64(child++, !is_hole, pp_child);  
0687 }
0688 
0689 inline CPolyTree64* CreateCPolyTree64(const PolyTree64& pt)
0690 {
0691   CPolyTree64* result = new CPolyTree64();
0692   result->polygon = nullptr;
0693   result->is_hole = false;
0694   size_t child_cnt = pt.Count();
0695   result->childs = nullptr;
0696   result->child_count = static_cast<uint32_t>(child_cnt);
0697   if (!child_cnt) return result;
0698   result->childs = new CPolyPath64[child_cnt];
0699   CPolyPath64* child = result->childs;
0700   for (const std::unique_ptr <PolyPath64>& pp : pt)
0701     InitCPolyPath64(child++, true, pp);
0702   return result;
0703 }
0704 
0705 inline void DisposeCPolyPath64(CPolyPath64* cpp) 
0706 {
0707   if (!cpp->child_count) return;
0708   CPolyPath64* child = cpp->childs;
0709   for (size_t i = 0; i < cpp->child_count; ++i)
0710     DisposeCPolyPath64(child);
0711   delete[] cpp->childs;
0712 }
0713 
0714 EXTERN_DLL_EXPORT void DisposeExportedCPolyTree64(CPolyTree64*& cpt)
0715 {
0716   if (!cpt) return;
0717   DisposeCPolyPath64(cpt);
0718   delete cpt;
0719   cpt = nullptr;
0720 }
0721 
0722 inline void InitCPolyPathD(CPolyTreeD* cpt,
0723   bool is_hole, const std::unique_ptr <PolyPath64>& pp, double scale)
0724 {
0725   cpt->polygon = CreateCPathD(pp->Polygon(), scale);
0726   cpt->is_hole = is_hole;
0727   size_t child_cnt = pp->Count();
0728   cpt->child_count = static_cast<uint32_t>(child_cnt);
0729   cpt->childs = nullptr;
0730   if (!child_cnt) return;
0731   cpt->childs = new CPolyPathD[child_cnt];
0732   CPolyPathD* child = cpt->childs;
0733   for (const std::unique_ptr <PolyPath64>& pp_child : *pp)
0734     InitCPolyPathD(child++, !is_hole, pp_child, scale);
0735 }
0736 
0737 inline CPolyTreeD* CreateCPolyTreeD(const PolyTree64& pt, double scale)
0738 {
0739   CPolyTreeD* result = new CPolyTreeD();
0740   result->polygon = nullptr;
0741   result->is_hole = false;
0742   size_t child_cnt = pt.Count();
0743   result->child_count = static_cast<uint32_t>(child_cnt);
0744   result->childs = nullptr;
0745   if (!child_cnt) return result;
0746   result->childs = new CPolyPathD[child_cnt];
0747   CPolyPathD* child = result->childs;
0748   for (const std::unique_ptr <PolyPath64>& pp : pt)
0749     InitCPolyPathD(child++, true, pp, scale);
0750   return result;
0751 }
0752 
0753 inline void DisposeCPolyPathD(CPolyPathD* cpp)
0754 {
0755   if (!cpp->child_count) return;
0756   CPolyPathD* child = cpp->childs;
0757   for (size_t i = 0; i < cpp->child_count; ++i)
0758     DisposeCPolyPathD(child++);
0759   delete[] cpp->childs;
0760 }
0761 
0762 EXTERN_DLL_EXPORT void DisposeExportedCPolyTreeD(CPolyTreeD*& cpt)
0763 {
0764   if (!cpt) return;
0765   DisposeCPolyPathD(cpt);
0766   delete cpt;
0767   cpt = nullptr;
0768 }
0769 
0770 }  // end Clipper2Lib namespace
0771   
0772 #endif  // CLIPPER2_EXPORT_H