Skip to content

Commit

Permalink
Minor improvement to the segment intersection algorithm (#568)
Browse files Browse the repository at this point in the history
Fixed significant bugs in Polytree path ownership (#584, D.#576)
Fixed a minor bug in RectClip (#586)
  • Loading branch information
AngusJohnson committed Jul 16, 2023
1 parent 81b01d2 commit 5f1699d
Show file tree
Hide file tree
Showing 25 changed files with 721 additions and 650 deletions.
10 changes: 6 additions & 4 deletions CPP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ cmake_minimum_required(VERSION 3.15)
project(Clipper2 VERSION 1.2.2 LANGUAGES C CXX)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 17)
if(NOT DEFINED CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 17)
set(CMAKE_CXX_STANDARD 17)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
Expand Down Expand Up @@ -35,7 +37,7 @@ set(CLIPPER2_SRC

set(CLIPPER2_LIBS "") # one or both of Clipper2/Clipper2Z

# 2d version of Clipper2
# primary Clipper2 library
if (NOT (CLIPPER2_USINGZ STREQUAL "ONLY"))
list(APPEND CLIPPER2_LIBS Clipper2)
add_library(Clipper2 ${CLIPPER2_INC} ${CLIPPER2_SRC})
Expand All @@ -52,7 +54,7 @@ if (NOT (CLIPPER2_USINGZ STREQUAL "ONLY"))
endif()
endif()

# Clipper2 but with USINGZ defined
# secondary Clipper2 library with USINGZ defined (if required)
if (NOT (CLIPPER2_USINGZ STREQUAL "OFF"))
list(APPEND CLIPPER2_LIBS Clipper2Z)
add_library(Clipper2Z ${CLIPPER2_INC} ${CLIPPER2_SRC})
Expand Down Expand Up @@ -207,7 +209,7 @@ endif()
target_link_libraries(ClipperTests gtest gtest_main Clipper2 Clipper2utils)

gtest_discover_tests(ClipperTests
# set a working directory so your project root so that you can find test data via paths relative to the project root
# set a working directory to your project root so that you can find test data via paths relative to the project root
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/../Tests
PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_DIR}"
)
Expand Down
36 changes: 18 additions & 18 deletions 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 : 8 April 2023 *
* Date : 16 July 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : Core Clipper Library structures and functions *
Expand Down Expand Up @@ -53,6 +53,7 @@ namespace Clipper2Lib
#ifndef PI
static const double PI = 3.141592653589793238;
#endif
static const int MAX_DECIMAL_PRECISION = 8; // see https://github.com/AngusJohnson/Clipper2/discussions/564
static const int64_t MAX_COORD = INT64_MAX >> 2;
static const int64_t MIN_COORD = -MAX_COORD;
static const int64_t INVALID = INT64_MAX;
Expand Down Expand Up @@ -132,6 +133,7 @@ namespace Clipper2Lib
return Point(x * scale, y * scale, z);
}

void SetZ(const int64_t z_value) { z = z_value; }

friend std::ostream& operator<<(std::ostream& os, const Point& point)
{
Expand Down Expand Up @@ -582,10 +584,10 @@ namespace Clipper2Lib

inline void CheckPrecision(int& precision, int& error_code)
{
if (precision >= -8 && precision <= 8) return;
if (precision >= -MAX_DECIMAL_PRECISION && precision <= MAX_DECIMAL_PRECISION) return;
error_code |= precision_error_i; // non-fatal error
DoError(precision_error_i); // unless exceptions enabled
precision = precision > 8 ? 8 : -8;
DoError(precision_error_i); // does nothing unless exceptions enabled
precision = precision > 0 ? MAX_DECIMAL_PRECISION : -MAX_DECIMAL_PRECISION;
}

inline void CheckPrecision(int& precision)
Expand Down Expand Up @@ -677,29 +679,27 @@ namespace Clipper2Lib
//nb: This statement is premised on using Cartesian coordinates
return Area<T>(poly) >= 0;
}

inline int64_t CheckCastInt64(double val)
{
if ((val >= max_coord) || (val <= min_coord)) return INVALID;
else return static_cast<int64_t>(val);
}


inline bool GetIntersectPoint(const Point64& ln1a, const Point64& ln1b,
const Point64& ln2a, const Point64& ln2b, Point64& ip)
{
// https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection

double dx1 = static_cast<double>(ln1b.x - ln1a.x);
double dy1 = static_cast<double>(ln1b.y - ln1a.y);
double dx2 = static_cast<double>(ln2b.x - ln2a.x);
double dy2 = static_cast<double>(ln2b.y - ln2a.y);

double det = dy1 * dx2 - dy2 * dx1;
if (det == 0.0) return 0;
double qx = dx1 * ln1a.y - dy1 * ln1a.x;
double qy = dx2 * ln2a.y - dy2 * ln2a.x;
ip.x = CheckCastInt64((dx1 * qy - dx2 * qx) / det);
ip.y = CheckCastInt64((dy1 * qy - dy2 * qx) / det);
return (ip.x != INVALID && ip.y != INVALID);
if (det == 0.0) return false;
double t = ((ln1a.x - ln2a.x) * dy2 - (ln1a.y - ln2a.y) * dx2) / det;
if (t <= 0.0) ip = ln1a; // ?? check further (see also #568)
else if (t >= 1.0) ip = ln2a; // ?? check further
else
{
ip.x = static_cast<int64_t>(ln1a.x + t * dx1);
ip.y = static_cast<int64_t>(ln1a.y + t * dy1);
}
return true;
}

inline bool SegmentsIntersect(const Point64& seg1a, const Point64& seg1b,
Expand Down
5 changes: 2 additions & 3 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 : 15 May 2023 *
* Date : 16 July 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : This is the main polygon clipping module *
Expand All @@ -13,7 +13,7 @@
constexpr auto CLIPPER2_VERSION = "1.2.2";

#include <cstdlib>
#include <stdint.h>
#include <stdint.h> //#541
#include <iostream>
#include <queue>
#include <vector>
Expand Down Expand Up @@ -95,7 +95,6 @@ namespace Clipper2Lib {
Rect64 bounds = {};
Path64 path;
bool is_open = false;
bool horz_done = false;
~OutRec() {
if (splits) delete splits;
// nb: don't delete the split pointers
Expand Down
70 changes: 25 additions & 45 deletions CPP/Clipper2Lib/include/clipper2/clipper.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 26 May 2023 *
* Date : 16 July 2023 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Purpose : This module provides a simple interface to the Clipper Library *
Expand Down Expand Up @@ -312,75 +312,55 @@ namespace Clipper2Lib {
}

static void OutlinePolyPath(std::ostream& os,
bool isHole, size_t count, const std::string& preamble)
size_t idx, bool isHole, size_t count, const std::string& preamble)
{
std::string plural = (count == 1) ? "." : "s.";
if (isHole)
{
if (count)
os << preamble << "+- Hole with " << count <<
" nested polygon" << plural << std::endl;
else
os << preamble << "+- Hole" << std::endl;
}
os << preamble << "+- Hole (" << idx << ") contains " << count <<
" nested polygon" << plural << std::endl;
else
{
if (count)
os << preamble << "+- Polygon with " << count <<
os << preamble << "+- Polygon (" << idx << ") contains " << count <<
" hole" << plural << std::endl;
else
os << preamble << "+- Polygon" << std::endl;
}
}

static void OutlinePolyPath64(std::ostream& os, const PolyPath64& pp,
std::string preamble, bool last_child)
size_t idx, std::string preamble)
{
OutlinePolyPath(os, pp.IsHole(), pp.Count(), preamble);
preamble += (!last_child) ? "| " : " ";
if (pp.Count())
{
PolyPath64List::const_iterator it = pp.begin();
for (; it < pp.end() - 1; ++it)
OutlinePolyPath64(os, **it, preamble, false);
OutlinePolyPath64(os, **it, preamble, true);
}
OutlinePolyPath(os, idx, pp.IsHole(), pp.Count(), preamble);
for (size_t i = 0; i < pp.Count(); ++i)
if (pp.Child(i)->Count())
details::OutlinePolyPath64(os, *pp.Child(i), i, preamble + " ");
}

static void OutlinePolyPathD(std::ostream& os, const PolyPathD& pp,
std::string preamble, bool last_child)
size_t idx, std::string preamble)
{
OutlinePolyPath(os, pp.IsHole(), pp.Count(), preamble);
preamble += (!last_child) ? "| " : " ";
if (pp.Count())
{
PolyPathDList::const_iterator it = pp.begin();
for (; it < pp.end() - 1; ++it)
OutlinePolyPathD(os, **it, preamble, false);
OutlinePolyPathD(os, **it, preamble, true);
}
OutlinePolyPath(os, idx, pp.IsHole(), pp.Count(), preamble);
for (size_t i = 0; i < pp.Count(); ++i)
if (pp.Child(i)->Count())
details::OutlinePolyPathD(os, *pp.Child(i), i, preamble + " ");
}

} // end details namespace

inline std::ostream& operator<< (std::ostream& os, const PolyTree64& pp)
{
os << std::endl << "Polytree root" << std::endl;
PolyPath64List::const_iterator it = pp.begin();
for (; it < pp.end() - 1; ++it)
details::OutlinePolyPath64(os, **it, " ", false);
details::OutlinePolyPath64(os, **it, " ", true);
std::string plural = (pp.Count() == 1) ? " polygon." : " polygons.";
os << std::endl << "Polytree with " << pp.Count() << plural << std::endl;
for (size_t i = 0; i < pp.Count(); ++i)
if (pp.Child(i)->Count())
details::OutlinePolyPath64(os, *pp.Child(i), i, " ");
os << std::endl << std::endl;
if (!pp.Level()) os << std::endl;
return os;
}

inline std::ostream& operator<< (std::ostream& os, const PolyTreeD& pp)
{
PolyPathDList::const_iterator it = pp.begin();
for (; it < pp.end() - 1; ++it)
details::OutlinePolyPathD(os, **it, " ", false);
details::OutlinePolyPathD(os, **it, " ", true);
std::string plural = (pp.Count() == 1) ? " polygon." : " polygons.";
os << std::endl << "Polytree with " << pp.Count() << plural << std::endl;
for (size_t i = 0; i < pp.Count(); ++i)
if (pp.Child(i)->Count())
details::OutlinePolyPathD(os, *pp.Child(i), i, " ");
os << std::endl << std::endl;
if (!pp.Level()) os << std::endl;
return os;
Expand Down
Loading

0 comments on commit 5f1699d

Please sign in to comment.