mirror of https://github.com/axmolengine/axmol.git
754 lines
21 KiB
C++
754 lines
21 KiB
C++
/*******************************************************************************
|
|
* Author : Angus Johnson *
|
|
* Date : 28 October 2022 *
|
|
* Website : http://www.angusj.com *
|
|
* Copyright : Angus Johnson 2010-2022 *
|
|
* Purpose : This module exports the Clipper2 Library (ie DLL/so) *
|
|
* License : http://www.boost.org/LICENSE_1_0.txt *
|
|
*******************************************************************************/
|
|
|
|
// The exported functions below refer to simple structures that
|
|
// can be understood across multiple languages. Consequently
|
|
// Path64, PathD, Polytree64 etc are converted from classes
|
|
// (std::vector<> etc) into the following data structures:
|
|
//
|
|
// CPath64 (int64_t*) & CPathD (double_t*):
|
|
// Path64 and PathD are converted into arrays of x,y coordinates.
|
|
// However in these arrays the first x,y coordinate pair is a
|
|
// counter with 'x' containing the number of following coordinate
|
|
// pairs. ('y' must always be 0.)
|
|
//__________________________________
|
|
// |counter|coord1|coord2|...|coordN|
|
|
// |N ,0 |x1, y1|x2, y2|...|xN, yN|
|
|
// __________________________________
|
|
//
|
|
// CPaths64 (int64_t**) & CPathsD (double_t**):
|
|
// These are arrays of pointers to CPath64 and CPathD where
|
|
// the first pointer is to a 'counter path'. This 'counter
|
|
// path' has a single x,y coord pair where 'y' contains
|
|
// the number of paths that follow (and with 'x' always 0).
|
|
// _______________________________
|
|
// |counter|path1|path2|...|pathN|
|
|
// |addr0 |addr1|addr2|...|addrN| (*addr0[0]=0; *addr0[1]=N)
|
|
// _______________________________
|
|
//
|
|
// The structures of CPolytree64 and CPolytreeD are defined
|
|
// below and they don't need to be repeated or explained here.
|
|
//
|
|
// Finally, the pointer structures created and exported through
|
|
// these functions can't safely be destroyed externally, so
|
|
// a number of 'dispose functions are also exported.
|
|
|
|
#ifndef CLIPPER2_EXPORT_H
|
|
#define CLIPPER2_EXPORT_H
|
|
|
|
#include <cstdlib>
|
|
#include <vector>
|
|
|
|
#include "clipper2/clipper.core.h"
|
|
#include "clipper2/clipper.engine.h"
|
|
#include "clipper2/clipper.offset.h"
|
|
#include "clipper2/clipper.rectclip.h"
|
|
|
|
namespace Clipper2Lib {
|
|
|
|
typedef int64_t* CPath64;
|
|
typedef int64_t** CPaths64;
|
|
typedef double* CPathD;
|
|
typedef double** CPathsD;
|
|
|
|
typedef struct CPolyPath64 {
|
|
CPath64 polygon;
|
|
uint32_t is_hole;
|
|
uint32_t child_count;
|
|
CPolyPath64* childs;
|
|
}
|
|
CPolyTree64;
|
|
|
|
typedef struct CPolyPathD {
|
|
CPathD polygon;
|
|
uint32_t is_hole;
|
|
uint32_t child_count;
|
|
CPolyPathD* childs;
|
|
}
|
|
CPolyTreeD;
|
|
|
|
template <typename T>
|
|
struct CRect {
|
|
T left;
|
|
T top;
|
|
T right;
|
|
T bottom;
|
|
};
|
|
|
|
typedef CRect<int64_t> CRect64;
|
|
typedef CRect<double> CRectD;
|
|
|
|
template <typename T>
|
|
inline bool CRectIsEmpty(const CRect<T>& rect)
|
|
{
|
|
return (rect.right <= rect.left) || (rect.bottom <= rect.top);
|
|
}
|
|
|
|
template <typename T>
|
|
inline Rect<T> CRectToRect(const CRect<T>& rect)
|
|
{
|
|
Rect<T> result;
|
|
result.left = rect.left;
|
|
result.top = rect.top;
|
|
result.right = rect.right;
|
|
result.bottom = rect.bottom;
|
|
return result;
|
|
}
|
|
|
|
inline CPath64 CreateCPath64(size_t cnt1, size_t cnt2);
|
|
inline CPath64 CreateCPath64(const Path64& p);
|
|
inline CPaths64 CreateCPaths64(const Paths64& pp);
|
|
inline Path64 ConvertCPath64(const CPath64& p);
|
|
inline Paths64 ConvertCPaths64(const CPaths64& pp);
|
|
|
|
inline CPathD CreateCPathD(size_t cnt1, size_t cnt2);
|
|
inline CPathD CreateCPathD(const PathD& p);
|
|
inline CPathsD CreateCPathsD(const PathsD& pp);
|
|
inline PathD ConvertCPathD(const CPathD& p);
|
|
inline PathsD ConvertCPathsD(const CPathsD& pp);
|
|
|
|
// the following function avoid multiple conversions
|
|
inline Path64 ConvertCPathD(const CPathD& p, double scale);
|
|
inline Paths64 ConvertCPathsD(const CPathsD& pp, double scale);
|
|
inline CPathD CreateCPathD(const Path64& p, double scale);
|
|
inline CPathsD CreateCPathsD(const Paths64& pp, double scale);
|
|
|
|
inline CPolyTree64* CreateCPolyTree64(const PolyTree64& pt);
|
|
inline CPolyTreeD* CreateCPolyTreeD(const PolyTree64& pt, double scale);
|
|
|
|
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
|
|
|
|
|
|
EXTERN_DLL_EXPORT const char* Version()
|
|
{
|
|
return CLIPPER2_VERSION;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT void DisposeExportedCPath64(CPath64 p)
|
|
{
|
|
if (p) delete[] p;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT void DisposeExportedCPaths64(CPaths64& pp)
|
|
{
|
|
if (!pp) return;
|
|
CPaths64 v = pp;
|
|
CPath64 cnts = *v;
|
|
const size_t cnt = static_cast<size_t>(cnts[1]);
|
|
for (size_t i = 0; i <= cnt; ++i) //nb: cnt +1
|
|
DisposeExportedCPath64(*v++);
|
|
delete[] pp;
|
|
pp = nullptr;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT void DisposeExportedCPathD(CPathD p)
|
|
{
|
|
if (p) delete[] p;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT void DisposeExportedCPathsD(CPathsD& pp)
|
|
{
|
|
if (!pp) return;
|
|
CPathsD v = pp;
|
|
CPathD cnts = *v;
|
|
size_t cnt = static_cast<size_t>(cnts[1]);
|
|
for (size_t i = 0; i <= cnt; ++i) //nb: cnt +1
|
|
DisposeExportedCPathD(*v++);
|
|
delete[] pp;
|
|
pp = nullptr;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype,
|
|
uint8_t fillrule, const CPaths64 subjects,
|
|
const CPaths64 subjects_open, const CPaths64 clips,
|
|
CPaths64& solution, CPaths64& solution_open,
|
|
bool preserve_collinear = true, bool reverse_solution = false)
|
|
{
|
|
if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
|
|
if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
|
|
|
|
Paths64 sub, sub_open, clp, sol, sol_open;
|
|
sub = ConvertCPaths64(subjects);
|
|
sub_open = ConvertCPaths64(subjects_open);
|
|
clp = ConvertCPaths64(clips);
|
|
|
|
Clipper64 clipper;
|
|
clipper.PreserveCollinear = preserve_collinear;
|
|
clipper.ReverseSolution = reverse_solution;
|
|
if (sub.size() > 0) clipper.AddSubject(sub);
|
|
if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
|
|
if (clp.size() > 0) clipper.AddClip(clp);
|
|
if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), sol, sol_open))
|
|
return -1; // clipping bug - should never happen :)
|
|
solution = CreateCPaths64(sol);
|
|
solution_open = CreateCPaths64(sol_open);
|
|
return 0; //success !!
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT int BooleanOpPt64(uint8_t cliptype,
|
|
uint8_t fillrule, const CPaths64 subjects,
|
|
const CPaths64 subjects_open, const CPaths64 clips,
|
|
CPolyTree64*& solution, CPaths64& solution_open,
|
|
bool preserve_collinear = true, bool reverse_solution = false)
|
|
{
|
|
if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
|
|
if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
|
|
Paths64 sub, sub_open, clp, sol_open;
|
|
sub = ConvertCPaths64(subjects);
|
|
sub_open = ConvertCPaths64(subjects_open);
|
|
clp = ConvertCPaths64(clips);
|
|
|
|
PolyTree64 pt;
|
|
Clipper64 clipper;
|
|
clipper.PreserveCollinear = preserve_collinear;
|
|
clipper.ReverseSolution = reverse_solution;
|
|
if (sub.size() > 0) clipper.AddSubject(sub);
|
|
if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
|
|
if (clp.size() > 0) clipper.AddClip(clp);
|
|
if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), pt, sol_open))
|
|
return -1; // clipping bug - should never happen :)
|
|
|
|
solution = CreateCPolyTree64(pt);
|
|
solution_open = CreateCPaths64(sol_open);
|
|
return 0; //success !!
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT int BooleanOpD(uint8_t cliptype,
|
|
uint8_t fillrule, const CPathsD subjects,
|
|
const CPathsD subjects_open, const CPathsD clips,
|
|
CPathsD& solution, CPathsD& solution_open, int precision = 2,
|
|
bool preserve_collinear = true, bool reverse_solution = false)
|
|
{
|
|
if (precision < -8 || precision > 8) return -5;
|
|
if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
|
|
if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
|
|
const double scale = std::pow(10, precision);
|
|
|
|
Paths64 sub, sub_open, clp, sol, sol_open;
|
|
sub = ConvertCPathsD(subjects, scale);
|
|
sub_open = ConvertCPathsD(subjects_open, scale);
|
|
clp = ConvertCPathsD(clips, scale);
|
|
|
|
Clipper64 clipper;
|
|
clipper.PreserveCollinear = preserve_collinear;
|
|
clipper.ReverseSolution = reverse_solution;
|
|
if (sub.size() > 0) clipper.AddSubject(sub);
|
|
if (sub_open.size() > 0)
|
|
clipper.AddOpenSubject(sub_open);
|
|
if (clp.size() > 0) clipper.AddClip(clp);
|
|
if (!clipper.Execute(ClipType(cliptype),
|
|
FillRule(fillrule), sol, sol_open)) return -1;
|
|
|
|
if (sol.size() > 0) solution = CreateCPathsD(sol, 1 / scale);
|
|
if (sol_open.size() > 0)
|
|
solution_open = CreateCPathsD(sol_open, 1 / scale);
|
|
return 0;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT int BooleanOpPtD(uint8_t cliptype,
|
|
uint8_t fillrule, const CPathsD subjects,
|
|
const CPathsD subjects_open, const CPathsD clips,
|
|
CPolyTreeD*& solution, CPathsD& solution_open, int precision = 2,
|
|
bool preserve_collinear = true, bool reverse_solution = false)
|
|
{
|
|
if (precision < -8 || precision > 8) return -5;
|
|
if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
|
|
if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
|
|
|
|
const double scale = std::pow(10, precision);
|
|
Paths64 sub, sub_open, clp, sol_open;
|
|
sub = ConvertCPathsD(subjects, scale);
|
|
sub_open = ConvertCPathsD(subjects_open, scale);
|
|
clp = ConvertCPathsD(clips, scale);
|
|
|
|
PolyTree64 sol;
|
|
Clipper64 clipper;
|
|
clipper.PreserveCollinear = preserve_collinear;
|
|
clipper.ReverseSolution = reverse_solution;
|
|
if (sub.size() > 0) clipper.AddSubject(sub);
|
|
if (sub_open.size() > 0)
|
|
clipper.AddOpenSubject(sub_open);
|
|
if (clp.size() > 0) clipper.AddClip(clp);
|
|
if (!clipper.Execute(ClipType(cliptype),
|
|
FillRule(fillrule), sol, sol_open)) return -1;
|
|
|
|
solution = CreateCPolyTreeD(sol, 1 / scale);
|
|
if (sol_open.size() > 0)
|
|
solution_open = CreateCPathsD(sol_open, 1 / scale);
|
|
return 0;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths,
|
|
double delta, uint8_t jt, uint8_t et, double miter_limit = 2.0,
|
|
double arc_tolerance = 0.0, bool reverse_solution = false)
|
|
{
|
|
Paths64 pp;
|
|
pp = ConvertCPaths64(paths);
|
|
|
|
ClipperOffset clip_offset( miter_limit,
|
|
arc_tolerance, reverse_solution);
|
|
clip_offset.AddPaths(pp, JoinType(jt), EndType(et));
|
|
Paths64 result = clip_offset.Execute(delta);
|
|
return CreateCPaths64(result);
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths,
|
|
double delta, uint8_t jt, uint8_t et,
|
|
double precision = 2, double miter_limit = 2.0,
|
|
double arc_tolerance = 0.0, bool reverse_solution = false)
|
|
{
|
|
if (precision < -8 || precision > 8 || !paths) return nullptr;
|
|
const double scale = std::pow(10, precision);
|
|
ClipperOffset clip_offset(miter_limit, arc_tolerance, reverse_solution);
|
|
Paths64 pp = ConvertCPathsD(paths, scale);
|
|
clip_offset.AddPaths(pp, JoinType(jt), EndType(et));
|
|
Paths64 result = clip_offset.Execute(delta * scale);
|
|
return CreateCPathsD(result, 1/scale);
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect,
|
|
const CPaths64 paths)
|
|
{
|
|
log(rect.left);
|
|
log(rect.right);
|
|
if (CRectIsEmpty(rect) || !paths) return nullptr;
|
|
Rect64 r64 = CRectToRect(rect);
|
|
class RectClip rc(r64);
|
|
Paths64 pp = ConvertCPaths64(paths);
|
|
Paths64 result;
|
|
result.reserve(pp.size());
|
|
for (const Path64& p : pp)
|
|
{
|
|
Rect64 pathRec = Bounds(p);
|
|
if (!r64.Intersects(pathRec)) continue;
|
|
|
|
if (r64.Contains(pathRec))
|
|
result.push_back(p);
|
|
else
|
|
{
|
|
Path64 p2 = rc.Execute(p);
|
|
if (!p2.empty()) result.push_back(std::move(p2));
|
|
}
|
|
}
|
|
return CreateCPaths64(result);
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT CPathsD RectClipD(const CRectD& rect,
|
|
const CPathsD paths, int precision = 2)
|
|
{
|
|
if (CRectIsEmpty(rect) || !paths) return nullptr;
|
|
if (precision < -8 || precision > 8) return nullptr;
|
|
const double scale = std::pow(10, precision);
|
|
Rect64 r = ScaleRect<int64_t, double>(CRectToRect(rect), scale);
|
|
Paths64 pp = ConvertCPathsD(paths, scale);
|
|
class RectClip rc(r);
|
|
Paths64 result;
|
|
result.reserve(pp.size());
|
|
for (const Path64& p : pp)
|
|
{
|
|
Rect64 pathRec = Bounds(p);
|
|
if (!r.Intersects(pathRec)) continue;
|
|
|
|
if (r.Contains(pathRec))
|
|
result.push_back(p);
|
|
else
|
|
{
|
|
Path64 p2 = rc.Execute(p);
|
|
if (!p2.empty()) result.push_back(std::move(p2));
|
|
}
|
|
}
|
|
return CreateCPathsD(result, 1/scale);
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT CPaths64 RectClipLines64(const CRect64& rect,
|
|
const CPaths64 paths)
|
|
{
|
|
if (CRectIsEmpty(rect) || !paths) return nullptr;
|
|
Rect64 r = CRectToRect(rect);
|
|
class RectClipLines rcl (r);
|
|
Paths64 pp = ConvertCPaths64(paths);
|
|
Paths64 result;
|
|
result.reserve(pp.size());
|
|
|
|
for (const Path64& p : pp)
|
|
{
|
|
Rect64 pathRec = Bounds(p);
|
|
if (!r.Intersects(pathRec)) continue;
|
|
|
|
if (r.Contains(pathRec))
|
|
result.push_back(p);
|
|
else
|
|
{
|
|
Paths64 pp2 = rcl.Execute(p);
|
|
if (!pp2.empty())
|
|
result.insert(result.end(), pp2.begin(), pp2.end());
|
|
}
|
|
}
|
|
return CreateCPaths64(result);
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect,
|
|
const CPathsD paths, int precision = 2)
|
|
{
|
|
Paths64 result;
|
|
if (CRectIsEmpty(rect) || !paths) return nullptr;
|
|
if (precision < -8 || precision > 8) return nullptr;
|
|
const double scale = std::pow(10, precision);
|
|
Rect64 r = ScaleRect<int64_t, double>(CRectToRect(rect), scale);
|
|
class RectClipLines rcl(r);
|
|
Paths64 pp = ConvertCPathsD(paths, scale);
|
|
|
|
result.reserve(pp.size());
|
|
for (const Path64& p : pp)
|
|
{
|
|
Rect64 pathRec = Bounds(p);
|
|
if (!r.Intersects(pathRec)) continue;
|
|
|
|
if (r.Contains(pathRec))
|
|
result.push_back(p);
|
|
else
|
|
{
|
|
Paths64 pp2 = rcl.Execute(p);
|
|
if (pp2.empty()) continue;
|
|
result.insert(result.end(), pp2.begin(), pp2.end());
|
|
}
|
|
}
|
|
return CreateCPathsD(result, 1/scale);
|
|
}
|
|
|
|
inline CPath64 CreateCPath64(size_t cnt1, size_t cnt2)
|
|
{
|
|
// create a dummy counter path
|
|
CPath64 result = new int64_t[2 + cnt1 *2];
|
|
result[0] = cnt1;
|
|
result[1] = cnt2;
|
|
return result;
|
|
}
|
|
|
|
inline CPath64 CreateCPath64(const Path64& p)
|
|
{
|
|
size_t cnt = p.size();
|
|
if (!cnt) return nullptr;
|
|
CPath64 result = CreateCPath64(cnt, 0);
|
|
CPath64 v = result;
|
|
v += 2; // skip counters
|
|
for (const Point64& pt : p)
|
|
{
|
|
*v++ = pt.x;
|
|
*v++ = pt.y;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline Path64 ConvertCPath64(const CPath64& p)
|
|
{
|
|
Path64 result;
|
|
if (p && *p)
|
|
{
|
|
CPath64 v = p;
|
|
const size_t cnt = static_cast<size_t>(p[0]);
|
|
v += 2; // skip counters
|
|
result.reserve(cnt);
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
{
|
|
// x,y here avoids right to left function evaluation
|
|
// result.push_back(Point64(*v++, *v++));
|
|
int64_t x = *v++;
|
|
int64_t y = *v++;
|
|
result.push_back(Point64(x, y));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline CPaths64 CreateCPaths64(const Paths64& pp)
|
|
{
|
|
size_t cnt = pp.size(), cnt2 = cnt;
|
|
|
|
// don't allocate space for empty paths
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
if (!pp[i].size()) --cnt2;
|
|
if (!cnt2) return nullptr;
|
|
|
|
CPaths64 result = new int64_t* [cnt2 + 1];
|
|
CPaths64 v = result;
|
|
*v++ = CreateCPath64(0, cnt2); // assign a counter path
|
|
for (const Path64& p : pp)
|
|
{
|
|
*v = CreateCPath64(p);
|
|
if (*v) ++v;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline Paths64 ConvertCPaths64(const CPaths64& pp)
|
|
{
|
|
Paths64 result;
|
|
if (pp)
|
|
{
|
|
CPaths64 v = pp;
|
|
CPath64 cnts = pp[0];
|
|
const size_t cnt = static_cast<size_t>(cnts[1]); // nb 2nd cnt
|
|
++v; // skip cnts
|
|
result.reserve(cnt);
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
result.push_back(ConvertCPath64(*v++));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline CPathD CreateCPathD(size_t cnt1, size_t cnt2)
|
|
{
|
|
// create a dummy path counter
|
|
CPathD result = new double[2 + cnt1 * 2];
|
|
result[0] = static_cast<double>(cnt1);
|
|
result[1] = static_cast<double>(cnt2);
|
|
return result;
|
|
}
|
|
|
|
inline CPathD CreateCPathD(const PathD& p)
|
|
{
|
|
size_t cnt = p.size();
|
|
if (!cnt) return nullptr;
|
|
CPathD result = CreateCPathD(cnt, 0);
|
|
CPathD v = result;
|
|
v += 2; // skip counters
|
|
for (const PointD& pt : p)
|
|
{
|
|
*v++ = pt.x;
|
|
*v++ = pt.y;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline PathD ConvertCPathD(const CPathD& p)
|
|
{
|
|
PathD result;
|
|
if (p)
|
|
{
|
|
CPathD v = p;
|
|
size_t cnt = static_cast<size_t>(v[0]);
|
|
v += 2; // skip counters
|
|
result.reserve(cnt);
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
{
|
|
// x,y here avoids right to left function evaluation
|
|
// result.push_back(PointD(*v++, *v++));
|
|
double x = *v++;
|
|
double y = *v++;
|
|
result.push_back(PointD(x, y));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline CPathsD CreateCPathsD(const PathsD& pp)
|
|
{
|
|
size_t cnt = pp.size(), cnt2 = cnt;
|
|
// don't allocate space for empty paths
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
if (!pp[i].size()) --cnt2;
|
|
if (!cnt2) return nullptr;
|
|
CPathsD result = new double * [cnt2 + 1];
|
|
CPathsD v = result;
|
|
*v++ = CreateCPathD(0, cnt2); // assign counter path
|
|
for (const PathD& p : pp)
|
|
{
|
|
*v = CreateCPathD(p);
|
|
if (*v) { ++v; }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline PathsD ConvertCPathsD(const CPathsD& pp)
|
|
{
|
|
PathsD result;
|
|
if (pp)
|
|
{
|
|
CPathsD v = pp;
|
|
CPathD cnts = v[0];
|
|
size_t cnt = static_cast<size_t>(cnts[1]);
|
|
++v; // skip cnts path
|
|
result.reserve(cnt);
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
result.push_back(ConvertCPathD(*v++));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline Path64 ConvertCPathD(const CPathD& p, double scale)
|
|
{
|
|
Path64 result;
|
|
if (p)
|
|
{
|
|
CPathD v = p;
|
|
size_t cnt = static_cast<size_t>(*v);
|
|
v += 2; // skip counters
|
|
result.reserve(cnt);
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
{
|
|
// x,y here avoids right to left function evaluation
|
|
// result.push_back(PointD(*v++, *v++));
|
|
double x = *v++ * scale;
|
|
double y = *v++ * scale;
|
|
result.push_back(Point64(x, y));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline Paths64 ConvertCPathsD(const CPathsD& pp, double scale)
|
|
{
|
|
Paths64 result;
|
|
if (pp)
|
|
{
|
|
CPathsD v = pp;
|
|
CPathD cnts = v[0];
|
|
size_t cnt = static_cast<size_t>(cnts[1]);
|
|
result.reserve(cnt);
|
|
++v; // skip cnts path
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
result.push_back(ConvertCPathD(*v++, scale));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline CPathD CreateCPathD(const Path64& p, double scale)
|
|
{
|
|
size_t cnt = p.size();
|
|
if (!cnt) return nullptr;
|
|
CPathD result = CreateCPathD(cnt, 0);
|
|
CPathD v = result;
|
|
v += 2; // skip cnts
|
|
for (const Point64& pt : p)
|
|
{
|
|
*v++ = pt.x * scale;
|
|
*v++ = pt.y * scale;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline CPathsD CreateCPathsD(const Paths64& pp, double scale)
|
|
{
|
|
size_t cnt = pp.size(), cnt2 = cnt;
|
|
// don't allocate space for empty paths
|
|
for (size_t i = 0; i < cnt; ++i)
|
|
if (!pp[i].size()) --cnt2;
|
|
if (!cnt2) return nullptr;
|
|
CPathsD result = new double* [cnt2 + 1];
|
|
CPathsD v = result;
|
|
*v++ = CreateCPathD(0, cnt2);
|
|
for (const Path64& p : pp)
|
|
{
|
|
*v = CreateCPathD(p, scale);
|
|
if (*v) ++v;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline void InitCPolyPath64(CPolyTree64* cpt,
|
|
bool is_hole, const PolyPath64* pp)
|
|
{
|
|
cpt->polygon = CreateCPath64(pp->Polygon());
|
|
cpt->is_hole = is_hole;
|
|
size_t child_cnt = pp->Count();
|
|
cpt->child_count = child_cnt;
|
|
cpt->childs = nullptr;
|
|
if (!child_cnt) return;
|
|
cpt->childs = new CPolyPath64[child_cnt];
|
|
CPolyPath64* child = cpt->childs;
|
|
for (const PolyPath64* pp_child : *pp)
|
|
InitCPolyPath64(child++, !is_hole, pp_child);
|
|
}
|
|
|
|
inline CPolyTree64* CreateCPolyTree64(const PolyTree64& pt)
|
|
{
|
|
CPolyTree64* result = new CPolyTree64();
|
|
result->polygon = nullptr;
|
|
result->is_hole = false;
|
|
size_t child_cnt = pt.Count();
|
|
result->childs = nullptr;
|
|
result->child_count = child_cnt;
|
|
if (!child_cnt) return result;
|
|
result->childs = new CPolyPath64[child_cnt];
|
|
CPolyPath64* child = result->childs;
|
|
for (const PolyPath64* pp : pt)
|
|
InitCPolyPath64(child++, true, pp);
|
|
return result;
|
|
}
|
|
|
|
inline void DisposeCPolyPath64(CPolyPath64* cpp)
|
|
{
|
|
if (!cpp->child_count) return;
|
|
CPolyPath64* child = cpp->childs;
|
|
for (size_t i = 0; i < cpp->child_count; ++i)
|
|
DisposeCPolyPath64(child);
|
|
delete[] cpp->childs;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT void DisposeExportedCPolyTree64(CPolyTree64*& cpt)
|
|
{
|
|
if (!cpt) return;
|
|
DisposeCPolyPath64(cpt);
|
|
delete cpt;
|
|
cpt = nullptr;
|
|
}
|
|
|
|
inline void InitCPolyPathD(CPolyTreeD* cpt,
|
|
bool is_hole, const PolyPath64* pp, double scale)
|
|
{
|
|
cpt->polygon = CreateCPathD(pp->Polygon(), scale);
|
|
cpt->is_hole = is_hole;
|
|
size_t child_cnt = pp->Count();
|
|
cpt->child_count = child_cnt;
|
|
cpt->childs = nullptr;
|
|
if (!child_cnt) return;
|
|
cpt->childs = new CPolyPathD[child_cnt];
|
|
CPolyPathD* child = cpt->childs;
|
|
for (const PolyPath64* pp_child : *pp)
|
|
InitCPolyPathD(child++, !is_hole, pp_child, scale);
|
|
}
|
|
|
|
inline CPolyTreeD* CreateCPolyTreeD(const PolyTree64& pt, double scale)
|
|
{
|
|
CPolyTreeD* result = new CPolyTreeD();
|
|
result->polygon = nullptr;
|
|
result->is_hole = false;
|
|
size_t child_cnt = pt.Count();
|
|
result->child_count = static_cast<uint32_t>(child_cnt);
|
|
result->childs = nullptr;
|
|
if (!child_cnt) return result;
|
|
result->childs = new CPolyPathD[child_cnt];
|
|
CPolyPathD* child = result->childs;
|
|
for (const PolyPath64* pp : pt)
|
|
InitCPolyPathD(child++, true, pp, scale);
|
|
return result;
|
|
}
|
|
|
|
inline void DisposeCPolyPathD(CPolyPathD* cpp)
|
|
{
|
|
if (!cpp->child_count) return;
|
|
CPolyPathD* child = cpp->childs;
|
|
for (size_t i = 0; i < cpp->child_count; ++i)
|
|
DisposeCPolyPathD(child++);
|
|
delete[] cpp->childs;
|
|
}
|
|
|
|
EXTERN_DLL_EXPORT void DisposeExportedCPolyTreeD(CPolyTreeD*& cpt)
|
|
{
|
|
if (!cpt) return;
|
|
DisposeCPolyPathD(cpt);
|
|
delete cpt;
|
|
cpt = nullptr;
|
|
}
|
|
|
|
} // end Clipper2Lib namespace
|
|
|
|
#endif // CLIPPER2_EXPORT_H
|