You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
7.6 KiB
C++
203 lines
7.6 KiB
C++
|
1 month ago
|
#include <gtest/gtest.h>
|
||
|
|
#include "clipper2/clipper.h"
|
||
|
|
#include "clipper2/clipper.core.h"
|
||
|
|
#include "clipper2/clipper.export.h"
|
||
|
|
|
||
|
|
using namespace Clipper2Lib;
|
||
|
|
|
||
|
|
static bool CreatePolyPath64FromCPolyPath(CPolyPath64& v, PolyPath64& owner)
|
||
|
|
{
|
||
|
|
int64_t poly_len = *v++, child_count = *v++;
|
||
|
|
if (!poly_len) return false;
|
||
|
|
Path64 path;
|
||
|
|
path.reserve(poly_len);
|
||
|
|
for (size_t i = 0; i < poly_len; ++i)
|
||
|
|
{
|
||
|
|
int64_t x = *v++, y = *v++;
|
||
|
|
#ifdef USINGZ
|
||
|
|
z_type z = Reinterpret<z_type>(*v++);
|
||
|
|
path.push_back(Point64(x, y, z));
|
||
|
|
#else
|
||
|
|
path.push_back(Point64(x, y));
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
PolyPath64* new_owner = owner.AddChild(path);
|
||
|
|
for (size_t i = 0; i < child_count; ++i)
|
||
|
|
CreatePolyPath64FromCPolyPath(v, *new_owner);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool BuildPolyTree64FromCPolyTree(CPolyTree64 tree, PolyTree64& result)
|
||
|
|
{
|
||
|
|
result.Clear();
|
||
|
|
int64_t* v = tree;
|
||
|
|
int64_t array_len = *v++, child_count = *v++;
|
||
|
|
for (size_t i = 0; i < child_count; ++i)
|
||
|
|
if (!CreatePolyPath64FromCPolyPath(v, result)) return false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool CreatePolyPathDFromCPolyPath(CPolyPathD& v, PolyPathD& owner)
|
||
|
|
{
|
||
|
|
size_t poly_len = static_cast<size_t>(*v++);
|
||
|
|
size_t child_count = static_cast<size_t>(*v++);
|
||
|
|
if (!poly_len) return false;
|
||
|
|
PathD path;
|
||
|
|
path.reserve(poly_len);
|
||
|
|
for (size_t i = 0; i < poly_len; ++i)
|
||
|
|
{
|
||
|
|
double x = *v++, y = *v++;
|
||
|
|
#ifdef USINGZ
|
||
|
|
z_type z = Reinterpret<z_type>(*v++);
|
||
|
|
path.push_back(PointD(x, y, z));
|
||
|
|
#else
|
||
|
|
path.push_back(PointD(x, y));
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
PolyPathD* new_owner = owner.AddChild(path);
|
||
|
|
for (size_t i = 0; i < child_count; ++i)
|
||
|
|
CreatePolyPathDFromCPolyPath(v, *new_owner);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool BuildPolyTreeDFromCPolyTree(CPolyTreeD tree, PolyTreeD& result)
|
||
|
|
{
|
||
|
|
result.Clear();
|
||
|
|
double* v = tree;
|
||
|
|
int64_t array_len = static_cast<int64_t>(*v++);
|
||
|
|
int64_t child_count = static_cast<int64_t>(*v++);
|
||
|
|
for (size_t i = 0; i < child_count; ++i)
|
||
|
|
if (!CreatePolyPathDFromCPolyPath(v, result)) return false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Clipper2Tests, ExportHeader64)
|
||
|
|
{
|
||
|
|
uint8_t None = 0, Intersection = 1, Union = 2, Difference = 3, Xor = 4;
|
||
|
|
uint8_t EvenOdd = 0, NonZero = 1, Positive = 2, Negative = 3;
|
||
|
|
Paths64 subj, clip, solution;
|
||
|
|
//subj.push_back(MakeRandomPoly(600, 400, 25));
|
||
|
|
//clip.push_back(MakeRandomPoly(600, 400, 25));
|
||
|
|
for (int i = 1; i < 6; ++i)
|
||
|
|
subj.push_back(MakePath({ -i*20,-i * 20, i * 20,-i * 20, i * 20,i * 20, -i * 20,i * 20 }));
|
||
|
|
clip.push_back(MakePath({ -90,-120,90,-120, 90,120, -90,120 }));
|
||
|
|
CPaths64 c_subj_open = nullptr, c_sol = nullptr, c_sol_open = nullptr;
|
||
|
|
// Note: while CreateCPaths64 isn't exported in clipper.export.h, it can still
|
||
|
|
// be used here because we're simply statically compiling clipper.export.h.
|
||
|
|
// Normally clipper.export.h will be compiled into a DLL/so so it can be called
|
||
|
|
// by non C++ applications. If CreateCPaths64 was an exported function and it
|
||
|
|
// was called by a non C++ application, it would crash that application.
|
||
|
|
CPaths64 c_subj = CreateCPathsFromPathsT(subj);
|
||
|
|
CPaths64 c_clip = CreateCPathsFromPathsT(clip);
|
||
|
|
BooleanOp64(Intersection, EvenOdd, c_subj, c_subj_open, c_clip, c_sol, c_sol_open);
|
||
|
|
solution = ConvertCPathsToPathsT(c_sol);
|
||
|
|
//clean up !!!
|
||
|
|
delete[] c_subj;
|
||
|
|
delete[] c_clip;
|
||
|
|
DisposeArray64(c_sol);
|
||
|
|
DisposeArray64(c_sol_open);
|
||
|
|
EXPECT_EQ(solution.size(), 5);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Clipper2Tests, ExportHeaderD)
|
||
|
|
{
|
||
|
|
uint8_t None = 0, Intersection = 1, Union = 2, Difference = 3, Xor = 4;
|
||
|
|
uint8_t EvenOdd = 0, NonZero = 1, Positive = 2, Negative = 3;
|
||
|
|
PathsD subj, clip, solution;
|
||
|
|
//subj.push_back(MakeRandomPolyD(600, 400, 25));
|
||
|
|
//clip.push_back(MakeRandomPolyD(600, 400, 25));
|
||
|
|
for (int i = 1; i < 6; ++i)
|
||
|
|
subj.push_back(MakePathD({ -i * 20,-i * 20, i * 20,-i * 20, i * 20,i * 20, -i * 20,i * 20 }));
|
||
|
|
clip.push_back(MakePathD({ -90,-120,90,-120, 90,120, -90,120 }));
|
||
|
|
CPathsD c_subj_open = nullptr, c_sol = nullptr, c_sol_open = nullptr;
|
||
|
|
// Note: while CreateCPathsD isn't exported in clipper.export.h, it can still
|
||
|
|
// be used here because we're simply statically compiling clipper.export.h.
|
||
|
|
// Normally clipper.export.h will be compiled into a DLL/so so it can be called
|
||
|
|
// by non C++ applications. If CreateCPathsD was an exported function and it
|
||
|
|
// was called by a non C++ application, it would crash that application.
|
||
|
|
CPathsD c_subj = CreateCPathsFromPathsT(subj);
|
||
|
|
CPathsD c_clip = CreateCPathsFromPathsT(clip);
|
||
|
|
BooleanOpD(Intersection, EvenOdd, c_subj, c_subj_open, c_clip, c_sol, c_sol_open);
|
||
|
|
solution = ConvertCPathsToPathsT(c_sol);
|
||
|
|
//clean up !!!
|
||
|
|
delete[] c_subj;
|
||
|
|
delete[] c_clip;
|
||
|
|
DisposeArrayD(c_sol);
|
||
|
|
DisposeArrayD(c_sol_open);
|
||
|
|
EXPECT_EQ(solution.size(), 5);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Clipper2Tests, ExportHeaderTree64)
|
||
|
|
{
|
||
|
|
uint8_t None = 0, Intersection = 1, Union = 2, Difference = 3, Xor = 4;
|
||
|
|
uint8_t EvenOdd = 0, NonZero = 1, Positive = 2, Negative = 3;
|
||
|
|
Paths64 subj, clip, solution;
|
||
|
|
for (int i = 1; i < 6; ++i)
|
||
|
|
subj.push_back(MakePath({ -i * 20,-i * 20, i * 20,-i * 20, i * 20,i * 20, -i * 20,i * 20 }));
|
||
|
|
clip.push_back(MakePath({ -90,-120,90,-120, 90,120, -90,120 }));
|
||
|
|
CPaths64 c_subj_open = nullptr, c_sol = nullptr, c_sol_open = nullptr;
|
||
|
|
// Note: while CreateCPaths64 isn't exported in clipper.export.h, it can still
|
||
|
|
// be used here because we're statically compiling clipper.export.h.
|
||
|
|
// More likely, clipper.export.h will be compiled into a DLL/so so it can be
|
||
|
|
// called by non C++ applications. If CreateCPaths64 was an exported function
|
||
|
|
// and it was called by a non C++ application, it would crash that application.
|
||
|
|
CPaths64 c_subj = CreateCPathsFromPathsT(subj);
|
||
|
|
CPaths64 c_clip = CreateCPathsFromPathsT(clip);
|
||
|
|
int64_t* c_sol_tree = nullptr;
|
||
|
|
BooleanOp_PolyTree64(Intersection, EvenOdd, c_subj, c_subj_open, c_clip, c_sol_tree, c_sol_open);
|
||
|
|
PolyTree64 sol_tree;
|
||
|
|
// convert CPolyTree64 to PolyTree64
|
||
|
|
BuildPolyTree64FromCPolyTree(c_sol_tree, sol_tree);
|
||
|
|
// convert PolyTree64 to Paths64
|
||
|
|
solution = PolyTreeToPaths64(sol_tree);
|
||
|
|
//clean up !!!
|
||
|
|
delete[] c_subj;
|
||
|
|
delete[] c_clip;
|
||
|
|
DisposeArray64(c_sol_tree);
|
||
|
|
DisposeArray64(c_sol_open);
|
||
|
|
|
||
|
|
PolyPath64* pp = &sol_tree;
|
||
|
|
for (int i = 0; i < 5; ++i)
|
||
|
|
{
|
||
|
|
EXPECT_TRUE(pp->Count() == 1);
|
||
|
|
pp = pp->Child(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Clipper2Tests, ExportHeaderTreeD)
|
||
|
|
{
|
||
|
|
uint8_t None = 0, Intersection = 1, Union = 2, Difference = 3, Xor = 4;
|
||
|
|
uint8_t EvenOdd = 0, NonZero = 1, Positive = 2, Negative = 3;
|
||
|
|
PathsD subj, clip, solution;
|
||
|
|
for (int i = 1; i < 6; ++i)
|
||
|
|
subj.push_back(MakePathD({ -i * 20,-i * 20, i * 20,-i * 20, i * 20,i * 20, -i * 20,i * 20 }));
|
||
|
|
clip.push_back(MakePathD({ -90,-120,90,-120, 90,120, -90,120 }));
|
||
|
|
CPathsD c_subj_open = nullptr, c_sol = nullptr, c_sol_open = nullptr;
|
||
|
|
// Note: while CreateCPathsD isn't exported in clipper.export.h, it can still
|
||
|
|
// be used here because we're statically compiling clipper.export.h.
|
||
|
|
// More likely, clipper.export.h will be compiled into a DLL/so so it can be
|
||
|
|
// called by non C++ applications. If CreateCPathsD was an exported function
|
||
|
|
// and it was called by a non C++ application, it would crash that application.
|
||
|
|
CPathsD c_subj = CreateCPathsFromPathsT(subj);
|
||
|
|
CPathsD c_clip = CreateCPathsFromPathsT(clip);
|
||
|
|
static const int precision = 4;
|
||
|
|
CPolyPathD c_sol_tree = nullptr;
|
||
|
|
BooleanOp_PolyTreeD(Intersection, EvenOdd, c_subj, c_subj_open, c_clip,
|
||
|
|
c_sol_tree, c_sol_open, precision);
|
||
|
|
PolyTreeD sol_tree;
|
||
|
|
// convert CPolyTreeD to PolyTreeD
|
||
|
|
BuildPolyTreeDFromCPolyTree(c_sol_tree, sol_tree);
|
||
|
|
// convert PolyTreeD to PathsD
|
||
|
|
solution = PolyTreeToPathsD(sol_tree);
|
||
|
|
//clean up !!!
|
||
|
|
delete[] c_subj;
|
||
|
|
delete[] c_clip;
|
||
|
|
DisposeArrayD(c_sol_tree);
|
||
|
|
DisposeArrayD(c_sol_open);
|
||
|
|
PolyPathD* pp = &sol_tree;
|
||
|
|
for (int i = 0; i < 5; ++i)
|
||
|
|
{
|
||
|
|
EXPECT_TRUE(pp->Count() == 1);
|
||
|
|
pp = pp->Child(0);
|
||
|
|
}
|
||
|
|
}
|