Skip to content

Commit

Permalink
Fixed DLL project file AngusJohnson#315
Browse files Browse the repository at this point in the history
Minor bugfix to polygon clipping AngusJohnson#309
C++: now using predefined __EXCEPTIONS to determine exception handling (AngusJohnson#305)
Minor update to C++ CI polygon testing
  • Loading branch information
AngusJohnson committed Nov 3, 2022
1 parent a2036d2 commit 3202481
Show file tree
Hide file tree
Showing 15 changed files with 402 additions and 265 deletions.
2 changes: 1 addition & 1 deletion CPP/Clipper2Lib/include/clipper2/clipper.core.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 29 October 2022 *
* Date : 3 November 2022 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2022 *
* Purpose : Core Clipper Library structures and functions *
Expand Down
4 changes: 2 additions & 2 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 : 30 October 2022 *
* Date : 3 November 2022 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2022 *
* Purpose : This is the main polygon clipping module *
Expand Down Expand Up @@ -210,7 +210,7 @@ namespace Clipper2Lib {
bool ValidateClosedPathEx(OutPt*& outrec);
void CleanCollinear(OutRec* outrec);
void FixSelfIntersects(OutRec* outrec);
OutPt* DoSplitOp(OutPt* outRecOp, OutPt* splitOp);
void DoSplitOp(OutRec* outRec, OutPt* splitOp);
Joiner* GetHorzTrialParent(const OutPt* op);
bool OutPtInTrialHorzList(OutPt* op);
void SafeDisposeOutPts(OutPt*& op);
Expand Down
6 changes: 3 additions & 3 deletions CPP/Clipper2Lib/include/clipper2/clipper.export.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

// The exported functions below refer to simple structures that
// can be understood across multiple languages. Consequently
// Path64, PathD, Polytree64 etc are converted from classes
// Path64, PathD, Polytree64 etc are converted from C++ classes
// (std::vector<> etc) into the following data structures:
//
// CPath64 (int64_t*) & CPathD (double_t*):
Expand Down Expand Up @@ -58,15 +58,15 @@ typedef struct CPolyPath64 {
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>
Expand Down
67 changes: 46 additions & 21 deletions CPP/Clipper2Lib/src/clipper.engine.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 28 October 2022 *
* Date : 3 November 2022 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2022 *
* Purpose : This is the main polygon clipping module *
Expand Down Expand Up @@ -523,19 +523,23 @@ namespace Clipper2Lib {
}


inline bool AreReallyClose(const Point64& pt1, const Point64& pt2)
inline bool PtsReallyClose(const Point64& pt1, const Point64& pt2)
{
return (std::llabs(pt1.x - pt2.x) < 2) && (std::llabs(pt1.y - pt2.y) < 2);
return (std::llabs(pt1.x - pt2.x) < 2) && (std::llabs(pt1.y - pt2.y) < 2);
}

inline bool IsVerySmallTriangle(const OutPt& op)
{
return op.next->next == op.prev &&
(PtsReallyClose(op.prev->pt, op.next->pt) ||
PtsReallyClose(op.pt, op.next->pt) ||
PtsReallyClose(op.pt, op.prev->pt));
}

inline bool IsValidClosedPath(const OutPt* op)
{
return (op && op->next != op && op->next != op->prev &&
//also treat inconsequential polygons as invalid
!(op->next->next == op->prev &&
(AreReallyClose(op->pt, op->next->pt) ||
AreReallyClose(op->pt, op->prev->pt))));
return op && (op->next != op) && (op->next != op->prev) &&
!IsVerySmallTriangle(*op);
}

inline bool OutrecIsAscending(const Active* hotEdge)
Expand Down Expand Up @@ -1494,11 +1498,13 @@ namespace Clipper2Lib {
FixSelfIntersects(outrec);
}

OutPt* ClipperBase::DoSplitOp(OutPt* outRecOp, OutPt* splitOp)
void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp)
{
OutPt* prevOp = splitOp->prev;
// splitOp.prev -> splitOp &&
// splitOp.next -> splitOp.next.next are intersecting
OutPt* prevOp = splitOp->prev;
OutPt* nextNextOp = splitOp->next->next;
OutPt* result = prevOp;
outrec->pts = prevOp;
PointD ipD;
GetIntersectPoint(prevOp->pt,
splitOp->pt, splitOp->next->pt, nextNextOp->pt, ipD);
Expand All @@ -1507,9 +1513,25 @@ namespace Clipper2Lib {
if (zCallback_)
zCallback_(prevOp->pt, splitOp->pt, splitOp->next->pt, nextNextOp->pt, ip);
#endif
double area1 = Area(outRecOp);
double area1 = Area(outrec->pts);
double absArea1 = std::fabs(area1);
if (absArea1 < 2)
{
SafeDisposeOutPts(outrec->pts);
// outrec.pts == nil; :)
return;
}

// nb: area1 is the path's area *before* splitting, whereas area2 is
// the area of the triangle containing splitOp & splitOp.next.
// So the only way for these areas to have the same sign is if
// the split triangle is larger than the path containing prevOp or
// if there's more than one self=intersection.
double area2 = AreaTriangle(ip, splitOp->pt, splitOp->next->pt);
double absArea2 = std::fabs(area2);

// de-link splitOp and splitOp.next from the path
// while inserting the intersection point
if (ip == prevOp->pt || ip == nextNextOp->pt)
{
nextNextOp->prev = prevOp;
Expand All @@ -1527,9 +1549,8 @@ namespace Clipper2Lib {
SafeDeleteOutPtJoiners(splitOp->next);
SafeDeleteOutPtJoiners(splitOp);

double absArea2 = std::abs(area2);
if ((absArea2 >= 1) &&
((absArea2 > std::abs(area1) || ((area2 > 0) == (area1 > 0)))))
if (absArea2 >= 1 &&
(absArea2 > absArea1 || (area2 > 0) == (area1 > 0)))
{
OutRec* newOutRec = new OutRec();
newOutRec->idx = outrec_list_.size();
Expand All @@ -1551,10 +1572,8 @@ namespace Clipper2Lib {
delete splitOp->next;
delete splitOp;
}
return result;
}


void ClipperBase::FixSelfIntersects(OutRec* outrec)
{
OutPt* op2 = outrec->pts;
Expand All @@ -1567,8 +1586,9 @@ namespace Clipper2Lib {
{
if (op2 == outrec->pts || op2->next == outrec->pts)
outrec->pts = outrec->pts->prev;
op2 = DoSplitOp(outrec->pts, op2);
outrec->pts = op2;
DoSplitOp(outrec, op2);
if (!outrec->pts) break;
op2 = outrec->pts;
continue;
}
else
Expand Down Expand Up @@ -3271,7 +3291,9 @@ namespace Clipper2Lib {

bool BuildPath64(OutPt* op, bool reverse, bool isOpen, Path64& path)
{
if (op->next == op || (!isOpen && op->next == op->prev)) return false;
if (op->next == op || (!isOpen && op->next == op->prev))
return false;

path.resize(0);
Point64 lastPt;
OutPt* op2;
Expand Down Expand Up @@ -3300,7 +3322,9 @@ namespace Clipper2Lib {
else
op2 = op2->next;
}
return true;

if (path.size() == 3 && IsVerySmallTriangle(*op2)) return false;
else return true;
}

bool ClipperBase::DeepCheckOwner(OutRec* outrec, OutRec* owner)
Expand Down Expand Up @@ -3458,6 +3482,7 @@ namespace Clipper2Lib {
else
op2 = op2->next;
}
if (path.size() == 3 && IsVerySmallTriangle(*op2)) return false;
return true;
}

Expand Down
12 changes: 12 additions & 0 deletions CPP/GoogleTest in Visual Studio.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Installing GoogleTest in Visual Studio

1. Goto https://github.com/google/googletest
2. Click on the bright green "Code" button and then click "Download ZIP".
3. Open the downloaded Zip package and locate the following:
a. CMakeLists.txt
b. googlemock folder
c. googletest folder
4. Copy these into Clipper2's empty CPP/Tests/googletest folder.
5. In Visual Studio, open Clipper2's CPP folder and wait to see
"CMake generation finished" in Visual Studio's statusbar.
6. Rebuild all files (Ctrl+Shift+B).
12 changes: 0 additions & 12 deletions CPP/MS Visual Studio.md

This file was deleted.

67 changes: 52 additions & 15 deletions CPP/Tests/TestPolygons.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
#include <gtest/gtest.h>
#include "clipper2/clipper.h"
#include "ClipFileLoad.h"
#include <fstream>

//#define log_tests
#ifdef log_tests
void Log(std::ofstream& os, int testnum, int count, int count_diff,
int area, int area_diff, double apd)
{
os << "test: " << testnum << ", count: " << count << " (" <<
count_diff << "), area: " << area << " (" << area_diff <<
") " << apd << std::endl;
}
#endif

inline Clipper2Lib::PathD MakeRandomPath(int width, int height, unsigned vertCnt)
{
Expand Down Expand Up @@ -28,6 +40,12 @@ TEST(Clipper2Tests, TestMultiplePolygons)
ASSERT_TRUE(ifs);
ASSERT_TRUE(ifs.good());

#ifdef log_tests
std::ofstream log("../polygon.log");
log << std::setprecision(4);
#endif


int test_number = 1;
while (true)
{
Expand All @@ -49,9 +67,10 @@ TEST(Clipper2Tests, TestMultiplePolygons)

const int64_t measured_area = static_cast<int64_t>(Area(solution));
const int64_t measured_count = static_cast<int64_t>(solution.size() + solution_open.size());
const int64_t count_diff = std::abs(measured_count - stored_count);
const int64_t area_diff = std::abs(measured_area - stored_area);

const int64_t count_diff = stored_count <= 0 ? 0 : std::abs(measured_count - stored_count);
const int64_t area_diff = stored_area <= 0 ? 0 : std::abs(measured_area - stored_area);
double area_diff_ratio = (area_diff == 0) ? 0 : std::fabs((double)(area_diff) / measured_area);

// check the polytree variant too
Clipper2Lib::PolyTree64 solution_polytree;
Clipper2Lib::Paths64 solution_polytree_open;
Expand All @@ -66,45 +85,63 @@ TEST(Clipper2Tests, TestMultiplePolygons)
const auto solution_polytree_paths = PolyTreeToPaths64(solution_polytree);
const int64_t measured_count_pt = static_cast<int64_t>(solution_polytree_paths.size());

if (test_number == 23)
{
EXPECT_LE(count_diff, 4);
}
else if (test_number == 27)
#ifdef log_tests
bool log_this_test = false;
#endif

// check polygon counts
if (test_number == 27)
{
EXPECT_LE(count_diff, 2);
}
else if (IsInList(test_number,
{ 18, 32, 42, 43, 45, 87, 102, 103, 111, 118, 183 }))
}
else if (IsInList(test_number, { 37, 43, 87, 102, 111, 118, 183 }))
{
EXPECT_LE(count_diff, 1);
}
else if (test_number >= 120)
{
if (stored_count > 0)
EXPECT_LE(count_diff/ stored_count, 0.02);
{
#ifdef log_tests
if ((double)count_diff / stored_count > 0.025)
log_this_test = true;
#endif
EXPECT_LE((double)count_diff / stored_count, 0.025);
}
}
else if (stored_count > 0)
else if (stored_count > 0)
{
EXPECT_EQ(count_diff, 0);
}

// check polygon areas
if (IsInList(test_number,
{ 22, 23, 24 }))
{
EXPECT_LE(area_diff, 8);
}
else if (stored_area > 0 && area_diff > 100)
{
EXPECT_LE(area_diff/stored_area, 0.02);
#ifdef log_tests
if ((double)area_diff / stored_area > 0.005)
log_this_test = true;
#endif
EXPECT_LE((double)area_diff/stored_area, 0.005);
}

EXPECT_EQ(measured_area, measured_area_pt);
EXPECT_EQ(measured_count, measured_count_pt);

#ifdef log_tests
if (log_this_test)
Log(log, test_number, measured_count, count_diff,
measured_area, area_diff, area_diff_ratio);
#endif

++test_number;
}
EXPECT_GE(test_number, 188);


Clipper2Lib::PathsD subjd, clipd, solutiond;
Clipper2Lib::FillRule frd = Clipper2Lib::FillRule::NonZero;

Expand Down
11 changes: 10 additions & 1 deletion CSharp/Clipper2Lib/Clipper.Core.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 15 October 2022 *
* Date : 3 November 2022 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2022 *
* Purpose : Core structures and functions for the Clipper Library *
Expand Down Expand Up @@ -504,6 +504,15 @@ public static class InternalClipper
internal const double floatingPointTolerance = 1E-12;
internal const double defaultMinimumEdgeLength = 0.1;

private static readonly string
precision_range_error = "Error: Precision is out of range.";

internal static void CheckPrecision(int precision)
{
if (precision < -8 || precision > 8)
throw new Exception(precision_range_error);
}

internal static bool IsAlmostZero(double value)
{
return (Math.Abs(value) <= floatingPointTolerance);
Expand Down
Loading

0 comments on commit 3202481

Please sign in to comment.