Skip to content

Commit

Permalink
Minor bugfix in clipper.export.h
Browse files Browse the repository at this point in the history
Added clipper.export.h CI test
  • Loading branch information
AngusJohnson committed Oct 25, 2023
1 parent 9ffd077 commit 11c97a1
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 27 deletions.
1 change: 1 addition & 0 deletions CPP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ else()
set_target_properties(gtest gtest_main PROPERTIES FOLDER GTest)
endif()
set(ClipperTests_SRC
Tests/TestExportHeaders.cpp
Tests/TestLines.cpp
Tests/TestOffsets.cpp
Tests/TestOffsetOrientation.cpp
Expand Down
10 changes: 5 additions & 5 deletions CPP/Clipper2Lib/include/clipper2/clipper.engine.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 24 October 2023 *
* Date : 25 October 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : This is the main polygon clipping module *
Expand Down Expand Up @@ -344,12 +344,12 @@ namespace Clipper2Lib {
childs_.resize(0);
}

const PolyPath64* operator [] (size_t index) const
PolyPath64* operator [] (size_t index) const
{
return childs_[index].get(); //std::unique_ptr
}

const PolyPath64* Child(size_t index) const
PolyPath64* Child(size_t index) const
{
return childs_[index].get();
}
Expand Down Expand Up @@ -401,12 +401,12 @@ namespace Clipper2Lib {
childs_.resize(0);
}

const PolyPathD* operator [] (size_t index) const
PolyPathD* operator [] (size_t index) const
{
return childs_[index].get();
}

const PolyPathD* Child(size_t index) const
PolyPathD* Child(size_t index) const
{
return childs_[index].get();
}
Expand Down
35 changes: 13 additions & 22 deletions CPP/Clipper2Lib/include/clipper2/clipper.export.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 24 October 2023 *
* Date : 25 October 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : This module exports the Clipper2 Library (ie DLL/so) *
Expand Down Expand Up @@ -106,13 +106,13 @@ inline Rect<T> CRectToRect(const CRect<T>& rect)

EXTERN_DLL_EXPORT const char* Version();

// Some exported functions will return data in structures that
// have been allocated in heap memory. Eventually this memory will
// Most of the exported functions below return data in structures that
// has been allocated in heap memory. Eventually this memory will
// need to be released using one of the following 'DisposeExported...'
// functions. (This may be the only safe way to release this memory
// since the executable accessing these exported functions may use
// a memory manager that allocates and releases heap memory in a
// different way.
// a different memory manager (MM)., And allocating memory using one
// MM and releasing the same memory in another will cause problems.)
EXTERN_DLL_EXPORT void DisposeExportedCPaths64(CPaths64& p)
{
delete[] p;
Expand Down Expand Up @@ -184,23 +184,13 @@ EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect,
// INTERNAL FUNCTIONS
//////////////////////////////////////////////////////

static void GetPathCountAndCPaths64ArrayLen(const Paths64& paths, size_t& cnt, size_t& array_len)
{
array_len = 2;
cnt = 0;
for (const Path64& path : paths)
if (path.size())
{
array_len += path.size() * 2 + 2;
++cnt;
}
}

static void GetPathCountAndCPathsDArrayLen(const PathsD& paths, size_t& cnt, size_t& array_len)
template <typename T>
static void GetPathCountAndCPathsArrayLen(const std::vector < std::vector <Point<T>>>& paths,
size_t& cnt, size_t& array_len)
{
array_len = 2;
cnt = 0;
for (const PathD& path : paths)
for (const Path<T>& path : paths)
if (path.size())
{
array_len += path.size() * 2 + 2;
Expand Down Expand Up @@ -234,7 +224,7 @@ static size_t GetPolyPathDArrayLen(const PolyPathD& pp)
static CPaths64 CreateCPaths64(const Paths64& paths)
{
size_t cnt, array_len;
GetPathCountAndCPaths64ArrayLen(paths, cnt, array_len);
GetPathCountAndCPathsArrayLen(paths, cnt, array_len);
int64_t* result = new int64_t[array_len], * v = result;
*v++ = 0;
*v++ = cnt;
Expand All @@ -255,7 +245,7 @@ static CPaths64 CreateCPaths64(const Paths64& paths)
static CPathsD CreateCPathsD(const PathsD& paths)
{
size_t cnt, array_len;
GetPathCountAndCPathsDArrayLen(paths, cnt, array_len);
GetPathCountAndCPathsArrayLen(paths, cnt, array_len);
double* result = new double[array_len], * v = result;
*v++ = 0;
*v++ = (double)cnt;
Expand All @@ -277,7 +267,7 @@ CPathsD CreateCPathsDFromPaths64(const Paths64& paths, double scale)
{
if (!paths.size()) return nullptr;
size_t cnt, array_len;
GetPathCountAndCPaths64ArrayLen(paths, cnt, array_len);
GetPathCountAndCPathsArrayLen(paths, cnt, array_len);
CPathsD result = new double[array_len], v = result;
*v++ = 0;
*v++ = (double)cnt;
Expand Down Expand Up @@ -331,6 +321,7 @@ static PathsD ConvertCPathsD(const CPathsD paths)
v += 2;
PathD path;
path.reserve(cnt2);
for (size_t j = 0; j < cnt2; ++j)
{
double x = *v++, y = *v++;
path.push_back(PointD(x, y));
Expand Down
222 changes: 222 additions & 0 deletions CPP/Tests/TestExportHeaders.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
#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 magic = *v++, hole = *v++, child_count = *v++, poly_len = *v++;
if (magic != magic_64 || !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++;
path.push_back(Point64(x,y));
}

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 magic = *v++, hole = *v++, child_count = *v++, poly_len = *v++;
if (magic != magic_64 || poly_len) return false;
for (size_t i = 0; i < child_count; ++i)
if (!CreatePolyPath64FromCPolyPath(v, result)) return false;
return true;
}

static bool CreatePolyPathDFromCPolyPath(CPolyPathD& v, PolyPathD& owner)
{
int64_t magic = *v++, hole = *v++, child_count = *v++, poly_len = *v++;
if (magic != magic_64 || !poly_len) return false;
PathD path;
path.reserve(poly_len);
for (size_t i = 0; i < poly_len; ++i)
{
int64_t x = *v++, y = *v++;
path.push_back(PointD(x, y));
}
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 magic = *v++, hole = *v++, child_count = *v++, poly_len = *v++;
if (magic != magic_64 || poly_len) return false;
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 = CreateCPaths64(subj);
CPaths64 c_clip = CreateCPaths64(clip);

BooleanOp64(Intersection, EvenOdd, c_subj, c_subj_open, c_clip, c_sol, c_sol_open);
solution = ConvertCPaths64(c_sol);

//clean up !!!
delete[] c_subj;
delete[] c_clip;
DisposeExportedCPaths64(c_sol);
DisposeExportedCPaths64(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 = CreateCPathsD(subj);
CPathsD c_clip = CreateCPathsD(clip);

BooleanOpD(Intersection, EvenOdd, c_subj, c_subj_open, c_clip, c_sol, c_sol_open);
solution = ConvertCPathsD(c_sol);

//clean up !!!
delete[] c_subj;
delete[] c_clip;
DisposeExportedCPathsD(c_sol);
DisposeExportedCPathsD(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 = CreateCPaths64(subj);
CPaths64 c_clip = CreateCPaths64(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;
DisposeExportedCPolyTree64(c_sol_tree);
DisposeExportedCPaths64(c_sol_open);

PolyPath64* pp = &sol_tree;
for (int i = 0; i < 4; ++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 = CreateCPathsD(subj);
CPathsD c_clip = CreateCPathsD(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;
DisposeExportedCPolyTreeD(c_sol_tree);
DisposeExportedCPathsD(c_sol_open);

PolyPathD* pp = &sol_tree;
for (int i = 0; i < 4; ++i)
{
EXPECT_TRUE(pp->Count() == 1); pp = pp->Child(0);
}
}

0 comments on commit 11c97a1

Please sign in to comment.