Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9c5eb6e14 | ||
|
|
642390d0d5 | ||
|
|
a5be8fa89e | ||
|
|
c324e7bdcb | ||
|
|
46f639177f | ||
|
|
458dd8572c | ||
|
|
77f5f63244 | ||
|
|
f965eae8d6 | ||
|
|
4da1564fb1 | ||
|
|
dcd339d79e | ||
|
|
20f05b475e | ||
|
|
6a36be1c8b | ||
|
|
7ee8173d24 | ||
|
|
2970649bef | ||
|
|
a262565c45 | ||
|
|
2ad4894955 | ||
|
|
21ebba05db | ||
|
|
f39457d9b7 | ||
|
|
4a50900c1f | ||
|
|
4d363dcb51 | ||
|
|
5e3bb1bec2 | ||
|
|
fbc392c08d | ||
|
|
4e74c9375b | ||
|
|
acfc6f4843 | ||
|
|
9846883750 | ||
|
|
f2858417ac | ||
|
|
19d4f1e682 | ||
|
|
ab872b2899 | ||
|
|
9040c3ad68 | ||
|
|
fa7add7736 | ||
|
|
a0c8b61d14 | ||
|
|
578ca4de97 | ||
|
|
0a9f445f05 | ||
|
|
f7972b5222 | ||
|
|
1a05520ea9 | ||
|
|
01bacc053a | ||
|
|
60696ed409 | ||
|
|
b502a4c260 | ||
|
|
a12271a28a | ||
|
|
ed0881b104 | ||
|
|
9a872541fb | ||
|
|
c535478fce | ||
|
|
150bbf9421 | ||
|
|
6853e9479a | ||
|
|
386e77a06c | ||
|
|
9a869bad38 | ||
|
|
925833b0d2 | ||
|
|
7dd02fa367 | ||
|
|
6a4f414d9d | ||
|
|
618c05cb1e | ||
|
|
879e2e8504 | ||
|
|
c5fc0b0637 | ||
|
|
0846cb86de | ||
|
|
9831776d1f | ||
|
|
53915c0500 | ||
|
|
945b8c2f18 | ||
|
|
0b0bf52db4 | ||
|
|
5de1066860 | ||
|
|
9741103211 | ||
|
|
f1d49160ef | ||
|
|
ee705be33a | ||
|
|
11ef6ca611 | ||
|
|
ef88ee97c0 | ||
|
|
75e4587a83 | ||
|
|
8bd46556f8 | ||
|
|
8ad5f755bf | ||
|
|
c40f982cb7 | ||
|
|
fa165fe836 | ||
|
|
b6e9ec1d39 | ||
|
|
ccdd052856 | ||
|
|
927daf751e | ||
|
|
0d0ba0ff98 | ||
|
|
b64e15f17f | ||
|
|
1ef1da4e69 | ||
|
|
f8dced506f | ||
|
|
459cf52da5 | ||
|
|
e8ebdef093 | ||
|
|
3dd975ad6d | ||
|
|
ccd4b88ed1 | ||
|
|
272eb9beae | ||
|
|
ca6e8fd58e | ||
|
|
c86619cf4f | ||
|
|
fcf56074a5 | ||
|
|
065f39811f |
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Install Dependencies
|
||||
run: dotnet restore
|
||||
- name: Build Solution
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(Clipper2 VERSION 1.5.2 LANGUAGES C CXX)
|
||||
project(Clipper2 VERSION 2.0.1 LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
if(NOT DEFINED CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 17)
|
||||
@@ -9,9 +9,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
##########################################################################
|
||||
##########################################################################
|
||||
|
||||
# CLIPPER2_HI_PRECISION: See GetIntersectPoint() in clipper.core.h
|
||||
option(CLIPPER2_HI_PRECISION "Caution: enabling this will compromise performance" OFF)
|
||||
|
||||
option(CLIPPER2_UTILS "Build utilities" ON)
|
||||
option(CLIPPER2_EXAMPLES "Build examples" ON)
|
||||
option(CLIPPER2_TESTS "Build tests" ON)
|
||||
@@ -19,11 +21,14 @@ option(USE_EXTERNAL_GTEST "Use system-wide installed GoogleTest" OFF)
|
||||
option(USE_EXTERNAL_GBENCHMARK "Use the googlebenchmark" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build shared libs" OFF)
|
||||
set(CLIPPER2_USINGZ "ON" CACHE STRING "Build Clipper2Z, either \"ON\" or \"OFF\" or \"ONLY\"")
|
||||
|
||||
# CLIPPER2_MAX_DECIMAL_PRECISION: maximum decimal precision when scaling PathsD to Paths64.
|
||||
# Caution: excessive scaling will increase the likelihood of integer overflow errors.
|
||||
# See https://www.angusj.com/clipper2/Docs/Overview.htm#coord_range for more info.
|
||||
set(CLIPPER2_MAX_DECIMAL_PRECISION 8 CACHE STRING "Maximum decimal precision range")
|
||||
|
||||
##########################################################################
|
||||
##########################################################################
|
||||
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
|
||||
@@ -43,12 +48,14 @@ set(CLIPPER2_INC
|
||||
${CLIPPER2_INC_FOLDER}/clipper.minkowski.h
|
||||
${CLIPPER2_INC_FOLDER}/clipper.offset.h
|
||||
${CLIPPER2_INC_FOLDER}/clipper.rectclip.h
|
||||
${CLIPPER2_INC_FOLDER}/clipper.triangulation.h
|
||||
)
|
||||
|
||||
set(CLIPPER2_SRC
|
||||
Clipper2Lib/src/clipper.engine.cpp
|
||||
Clipper2Lib/src/clipper.offset.cpp
|
||||
Clipper2Lib/src/clipper.rectclip.cpp
|
||||
Clipper2Lib/src/clipper.triangulation.cpp
|
||||
)
|
||||
|
||||
set(CLIPPER2_LIBS "") # one or both of Clipper2/Clipper2Z
|
||||
@@ -70,12 +77,19 @@ if (NOT (CLIPPER2_USINGZ STREQUAL "ONLY"))
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
# Configure the warning flags.
|
||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
target_compile_options(Clipper2 PRIVATE /W4 /WX)
|
||||
else()
|
||||
target_compile_options(Clipper2 PRIVATE -Wall -Wextra -Wpedantic -Werror -Wno-c++20-compat)
|
||||
elseif (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
|
||||
target_compile_options(Clipper2 PRIVATE -Wall -Wextra -Wpedantic -Werror)
|
||||
else ()
|
||||
message(AUTHOR_WARNING "Clipper2: cannot configure warnings for the unrecognized C++ compiler front end ${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}")
|
||||
endif ()
|
||||
|
||||
# On Windows, if using Microsoft's the standard library, there is no `m.lib`.
|
||||
if (NOT WIN32 OR MINGW)
|
||||
target_link_libraries(Clipper2 PUBLIC -lm)
|
||||
endif()
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# secondary Clipper2 library with USINGZ defined (if required)
|
||||
@@ -95,12 +109,19 @@ if (NOT (CLIPPER2_USINGZ STREQUAL "OFF"))
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(Clipper2Z PRIVATE /W4 /WX)
|
||||
else()
|
||||
target_compile_options(Clipper2Z PRIVATE -Wall -Wextra -Wpedantic -Werror -Wno-c++20-compat -Wsign-conversion)
|
||||
target_link_libraries(Clipper2Z PUBLIC -lm)
|
||||
endif()
|
||||
# Configure the warning flags.
|
||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
target_compile_options(Clipper2 PRIVATE /W4 /WX)
|
||||
elseif (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
|
||||
target_compile_options(Clipper2 PRIVATE -Wall -Wextra -Wpedantic -Werror)
|
||||
else ()
|
||||
message(AUTHOR_WARNING "Clipper2: cannot configure warnings for the unrecognized C++ compiler front end ${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}")
|
||||
endif ()
|
||||
|
||||
# On Windows, if using Microsoft's the standard library, there is no `m.lib`.
|
||||
if (NOT WIN32 OR MINGW)
|
||||
target_link_libraries(Clipper2 PUBLIC -lm)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
set_target_properties(${CLIPPER2_LIBS} PROPERTIES FOLDER Libraries
|
||||
@@ -130,9 +151,6 @@ if(CLIPPER2_UTILS OR CLIPPER2_TESTS OR CLIPPER2_EXAMPLES)
|
||||
add_library(Clipper2utils STATIC ${CLIPPER2_UTILS_INC} ${CLIPPER2_UTILS_SRC})
|
||||
|
||||
target_link_libraries(Clipper2utils PUBLIC Clipper2)
|
||||
target_include_directories(Clipper2utils
|
||||
PUBLIC Utils
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT (CLIPPER2_USINGZ STREQUAL "OFF"))
|
||||
@@ -140,9 +158,6 @@ if(CLIPPER2_UTILS OR CLIPPER2_TESTS OR CLIPPER2_EXAMPLES)
|
||||
add_library(Clipper2Zutils STATIC ${CLIPPER2_UTILS_INC} ${CLIPPER2_UTILS_SRC})
|
||||
|
||||
target_link_libraries(Clipper2Zutils PUBLIC Clipper2Z)
|
||||
target_include_directories(Clipper2Zutils
|
||||
PUBLIC Utils
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(${CLIPPER2_UTILS} PROPERTIES FOLDER Libraries)
|
||||
@@ -151,6 +166,25 @@ if(CLIPPER2_UTILS OR CLIPPER2_TESTS OR CLIPPER2_EXAMPLES)
|
||||
target_compile_options(${lib} PRIVATE -Wno-unused-variable -Wno-unused-function)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# install utils/zutils module
|
||||
foreach(lib ${CLIPPER2_UTILS})
|
||||
set_target_properties(${lib} PROPERTIES
|
||||
PUBLIC_HEADER "${CLIPPER2_UTILS_INC}"
|
||||
)
|
||||
target_include_directories(${lib}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Utils>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/clipper2/Utils>
|
||||
)
|
||||
# install(TARGETS ${lib}
|
||||
# EXPORT Clipper2-targets
|
||||
# PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/clipper2/Utils
|
||||
# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
# LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endforeach()
|
||||
|
||||
endif()
|
||||
|
||||
if(CLIPPER2_EXAMPLES)
|
||||
@@ -170,6 +204,7 @@ if(CLIPPER2_EXAMPLES)
|
||||
RectClipping
|
||||
SimpleClipping
|
||||
VariableOffset
|
||||
Triangulation
|
||||
)
|
||||
|
||||
foreach(ex ${EXAMPLES})
|
||||
@@ -178,6 +213,8 @@ if(CLIPPER2_EXAMPLES)
|
||||
endforeach()
|
||||
|
||||
file(COPY Examples/Inflate/rabbit.svg DESTINATION ${CMAKE_BINARY_DIR} FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )
|
||||
file(COPY Examples/Triangulation/TriSamples DESTINATION ${CMAKE_BINARY_DIR} FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )
|
||||
|
||||
list(APPEND ALL_EXAMPLES ${EXAMPLES})
|
||||
endif()
|
||||
|
||||
@@ -206,19 +243,20 @@ if(CLIPPER2_TESTS)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
set(BUILD_GMOCK OFF)
|
||||
if(USE_EXTERNAL_GTEST)
|
||||
find_package(GTest REQUIRED)
|
||||
else()
|
||||
include(GoogleTest)
|
||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/Tests/googletest)
|
||||
execute_process(
|
||||
COMMAND "git" "clone" "https://github.com/google/googletest"
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/Tests
|
||||
)
|
||||
|
||||
if(USE_EXTERNAL_GTEST)
|
||||
find_package(GTest REQUIRED)
|
||||
else()
|
||||
include(GoogleTest)
|
||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/Tests/googletest)
|
||||
execute_process(
|
||||
COMMAND "git" "clone" "https://github.com/google/googletest"
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/Tests
|
||||
)
|
||||
endif()
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/Tests/googletest/")
|
||||
set_target_properties(gtest gtest_main PROPERTIES FOLDER GTest)
|
||||
endif()
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/Tests/googletest/")
|
||||
set_target_properties(gtest gtest_main PROPERTIES FOLDER GTest)
|
||||
endif()
|
||||
|
||||
if(TARGET gtest AND TARGET gtest_main)
|
||||
set(gtest_libs gtest gtest_main)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 12 May 2024 *
|
||||
* Date : 12 October 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : Core Clipper Library structures and functions *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -138,7 +138,7 @@ namespace Clipper2Lib
|
||||
}
|
||||
}
|
||||
|
||||
explicit Point() : x(0), y(0), z(0) {};
|
||||
explicit Point() : x(0), y(0), z(0) {}
|
||||
|
||||
template <typename T2>
|
||||
Point(const T2 x_, const T2 y_, const z_type z_ = 0)
|
||||
@@ -190,7 +190,7 @@ namespace Clipper2Lib
|
||||
}
|
||||
}
|
||||
|
||||
explicit Point() : x(0), y(0) {};
|
||||
explicit Point() : x(0), y(0) {}
|
||||
|
||||
template <typename T2>
|
||||
Point(const T2 x_, const T2 y_) { Init(x_, y_); }
|
||||
@@ -248,6 +248,20 @@ namespace Clipper2Lib
|
||||
template <typename T>
|
||||
using Paths = std::vector<Path<T>>;
|
||||
|
||||
template <typename T, typename T2=T>
|
||||
Path<T>& operator<<(Path<T>& poly, const Point<T2>& p)
|
||||
{
|
||||
poly.emplace_back(p);
|
||||
return poly;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Paths<T>& operator<<(Paths<T>& polys, const Path<T>& p)
|
||||
{
|
||||
polys.emplace_back(p);
|
||||
return polys;
|
||||
}
|
||||
|
||||
using Path64 = Path<int64_t>;
|
||||
using PathD = Path<double>;
|
||||
using Paths64 = std::vector< Path64>;
|
||||
@@ -353,13 +367,13 @@ namespace Clipper2Lib
|
||||
bottom *= scale;
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return bottom <= top || right <= left; };
|
||||
bool IsEmpty() const { return bottom <= top || right <= left; }
|
||||
|
||||
bool Intersects(const Rect<T>& rec) const
|
||||
{
|
||||
return ((std::max)(left, rec.left) <= (std::min)(right, rec.right)) &&
|
||||
((std::max)(top, rec.top) <= (std::min)(bottom, rec.bottom));
|
||||
};
|
||||
}
|
||||
|
||||
bool operator==(const Rect<T>& other) const {
|
||||
return left == other.left && right == other.right &&
|
||||
@@ -685,29 +699,28 @@ namespace Clipper2Lib
|
||||
return (x > 0) - (x < 0);
|
||||
}
|
||||
|
||||
struct MultiplyUInt64Result
|
||||
struct UInt128Struct
|
||||
{
|
||||
const uint64_t result = 0;
|
||||
const uint64_t carry = 0;
|
||||
const uint64_t lo = 0;
|
||||
const uint64_t hi = 0;
|
||||
|
||||
bool operator==(const MultiplyUInt64Result& other) const
|
||||
bool operator==(const UInt128Struct& other) const
|
||||
{
|
||||
return result == other.result && carry == other.carry;
|
||||
};
|
||||
return lo == other.lo && hi == other.hi;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline MultiplyUInt64Result Multiply(uint64_t a, uint64_t b) // #834, #835
|
||||
inline UInt128Struct MultiplyUInt64(uint64_t a, uint64_t b) // #834, #835
|
||||
{
|
||||
// note to self - lamba expressions follow
|
||||
const auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; };
|
||||
const auto hi = [](uint64_t x) { return x >> 32; };
|
||||
|
||||
const uint64_t x1 = lo(a) * lo(b);
|
||||
const uint64_t x2 = hi(a) * lo(b) + hi(x1);
|
||||
const uint64_t x3 = lo(a) * hi(b) + lo(x2);
|
||||
const uint64_t result = lo(x3) << 32 | lo(x1);
|
||||
const uint64_t carry = hi(a) * hi(b) + hi(x2) + hi(x3);
|
||||
|
||||
return { result, carry };
|
||||
return { uint64_t(lo(x3) << 32 | lo(x1)), uint64_t(hi(a) * hi(b) + hi(x2) + hi(x3)) };
|
||||
}
|
||||
|
||||
// returns true if (and only if) a * b == c * d
|
||||
@@ -724,14 +737,50 @@ namespace Clipper2Lib
|
||||
const auto abs_c = static_cast<uint64_t>(std::abs(c));
|
||||
const auto abs_d = static_cast<uint64_t>(std::abs(d));
|
||||
|
||||
const auto abs_ab = Multiply(abs_a, abs_b);
|
||||
const auto abs_cd = Multiply(abs_c, abs_d);
|
||||
const auto ab = MultiplyUInt64(abs_a, abs_b);
|
||||
const auto cd = MultiplyUInt64(abs_c, abs_d);
|
||||
|
||||
// nb: it's important to differentiate 0 values here from other values
|
||||
const auto sign_ab = TriSign(a) * TriSign(b);
|
||||
const auto sign_cd = TriSign(c) * TriSign(d);
|
||||
|
||||
return abs_ab == abs_cd && sign_ab == sign_cd;
|
||||
return ab == cd && sign_ab == sign_cd;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline int CrossProductSign(const Point<T>& pt1, const Point<T>& pt2, const Point<T>& pt3)
|
||||
{
|
||||
const auto a = pt2.x - pt1.x;
|
||||
const auto b = pt3.y - pt2.y;
|
||||
const auto c = pt2.y - pt1.y;
|
||||
const auto d = pt3.x - pt2.x;
|
||||
|
||||
#if (defined(__clang__) || defined(__GNUC__)) && UINTPTR_MAX >= UINT64_MAX
|
||||
const auto ab = static_cast<__int128_t>(a) * static_cast<__int128_t>(b);
|
||||
const auto cd = static_cast<__int128_t>(c) * static_cast<__int128_t>(d);
|
||||
if (ab > cd) return 1;
|
||||
else if (ab < cd) return -1;
|
||||
else return 0;
|
||||
#else
|
||||
const auto ab = MultiplyUInt64(std::abs(a), std::abs(b));
|
||||
const auto cd = MultiplyUInt64(std::abs(c), std::abs(d));
|
||||
|
||||
const auto sign_ab = TriSign(a) * TriSign(b);
|
||||
const auto sign_cd = TriSign(c) * TriSign(d);
|
||||
|
||||
if (sign_ab == sign_cd)
|
||||
{
|
||||
int result;
|
||||
if (ab.hi == cd.hi)
|
||||
{
|
||||
if (ab.lo == cd.lo) return 0;
|
||||
result = (ab.lo > cd.lo) ? 1 : -1;
|
||||
}
|
||||
else result = (ab.hi > cd.hi) ? 1 : -1;
|
||||
return (sign_ab > 0) ? result : -result;
|
||||
}
|
||||
return (sign_ab > sign_cd) ? 1 : -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -835,14 +884,18 @@ namespace Clipper2Lib
|
||||
return Area<T>(poly) >= 0;
|
||||
}
|
||||
|
||||
#if CLIPPER2_HI_PRECISION
|
||||
// GetLineIntersectPt - a 'true' result is non-parallel. The 'ip' will also
|
||||
// be constrained to seg1. However, it's possible that 'ip' won't be inside
|
||||
// seg2, even when 'ip' hasn't been constrained (ie 'ip' is inside seg1).
|
||||
|
||||
#if defined(CLIPPER2_HI_PRECISION) && CLIPPER2_HI_PRECISION
|
||||
// caution: this will compromise performance
|
||||
// https://github.com/AngusJohnson/Clipper2/issues/317#issuecomment-1314023253
|
||||
// See also CPP/BenchMark/GetIntersectPtBenchmark.cpp
|
||||
#define CC_MIN(x,y) ((x)>(y)?(y):(x))
|
||||
#define CC_MAX(x,y) ((x)<(y)?(y):(x))
|
||||
template<typename T>
|
||||
inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||
inline bool GetLineIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||
const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
|
||||
{
|
||||
double ln1dy = static_cast<double>(ln1b.y - ln1a.y);
|
||||
@@ -888,11 +941,14 @@ namespace Clipper2Lib
|
||||
ip.x = originx + static_cast<T>(hitx);
|
||||
ip.y = originy + static_cast<T>(hity);
|
||||
}
|
||||
#ifdef USINGZ
|
||||
ip.z = 0;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||
inline bool GetLineIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
|
||||
const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
|
||||
@@ -910,7 +966,10 @@ namespace Clipper2Lib
|
||||
{
|
||||
ip.x = static_cast<T>(ln1a.x + t * dx1);
|
||||
ip.y = static_cast<T>(ln1a.y + t * dy1);
|
||||
}
|
||||
#ifdef USINGZ
|
||||
ip.z = 0;
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -946,21 +1005,44 @@ namespace Clipper2Lib
|
||||
inline bool SegmentsIntersect(const Point64& seg1a, const Point64& seg1b,
|
||||
const Point64& seg2a, const Point64& seg2b, bool inclusive = false)
|
||||
{
|
||||
double dy1 = static_cast<double>(seg1b.y - seg1a.y);
|
||||
double dx1 = static_cast<double>(seg1b.x - seg1a.x);
|
||||
double dy2 = static_cast<double>(seg2b.y - seg2a.y);
|
||||
double dx2 = static_cast<double>(seg2b.x - seg2a.x);
|
||||
double cp = dy1 * dx2 - dy2 * dx1;
|
||||
if (cp == 0) return false; // ie parallel segments
|
||||
|
||||
if (inclusive)
|
||||
{
|
||||
double res1 = CrossProduct(seg1a, seg2a, seg2b);
|
||||
double res2 = CrossProduct(seg1b, seg2a, seg2b);
|
||||
if (res1 * res2 > 0) return false;
|
||||
double res3 = CrossProduct(seg2a, seg1a, seg1b);
|
||||
double res4 = CrossProduct(seg2b, seg1a, seg1b);
|
||||
if (res3 * res4 > 0) return false;
|
||||
return (res1 || res2 || res3 || res4); // ensures not collinear
|
||||
//result **includes** segments that touch at an end point
|
||||
double t = ((seg1a.x - seg2a.x) * dy2 - (seg1a.y - seg2a.y) * dx2);
|
||||
if (t == 0) return true;
|
||||
if (t > 0)
|
||||
{
|
||||
if (cp < 0 || t > cp) return false;
|
||||
}
|
||||
else if (cp > 0 || t < cp) return false; // false when t more neg. than cp
|
||||
|
||||
t = ((seg1a.x - seg2a.x) * dy1 - (seg1a.y - seg2a.y) * dx1);
|
||||
if (t == 0) return true;
|
||||
if (t > 0) return (cp > 0 && t <= cp);
|
||||
else return (cp < 0 && t >= cp); // true when t less neg. than cp
|
||||
}
|
||||
else {
|
||||
return (GetSign(CrossProduct(seg1a, seg2a, seg2b)) *
|
||||
GetSign(CrossProduct(seg1b, seg2a, seg2b)) < 0) &&
|
||||
(GetSign(CrossProduct(seg2a, seg1a, seg1b)) *
|
||||
GetSign(CrossProduct(seg2b, seg1a, seg1b)) < 0);
|
||||
else
|
||||
{
|
||||
//result **excludes** segments that touch at an end point
|
||||
double t = ((seg1a.x - seg2a.x) * dy2 - (seg1a.y - seg2a.y) * dx2);
|
||||
if (t == 0) return false;
|
||||
if (t > 0)
|
||||
{
|
||||
if (cp < 0 || t >= cp) return false;
|
||||
}
|
||||
else if (cp > 0 || t <= cp ) return false; // false when t more neg. than cp
|
||||
|
||||
t = ((seg1a.x - seg2a.x) * dy1 - (seg1a.y - seg2a.y) * dx1);
|
||||
if (t == 0) return false;
|
||||
if (t > 0) return (cp > 0 && t < cp);
|
||||
else return (cp < 0 && t > cp); // true when t less neg. than cp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1048,7 +1130,7 @@ namespace Clipper2Lib
|
||||
val = 1 - val; // toggle val
|
||||
else
|
||||
{
|
||||
double d = CrossProduct(*prev, *curr, pt);
|
||||
int d = CrossProductSign(*prev, *curr, pt);
|
||||
if (d == 0) return PointInPolygonResult::IsOn;
|
||||
if ((d < 0) == is_above) val = 1 - val;
|
||||
}
|
||||
@@ -1062,7 +1144,7 @@ namespace Clipper2Lib
|
||||
if (curr == cend) curr = cbegin;
|
||||
if (curr == cbegin) prev = cend - 1;
|
||||
else prev = curr - 1;
|
||||
double d = CrossProduct(*prev, *curr, pt);
|
||||
int d = CrossProductSign(*prev, *curr, pt);
|
||||
if (d == 0) return PointInPolygonResult::IsOn;
|
||||
if ((d < 0) == is_above) val = 1 - val;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace Clipper2Lib {
|
||||
if (splits) delete splits;
|
||||
// nb: don't delete the split pointers
|
||||
// as these are owned by ClipperBase's outrec_list_
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
@@ -156,7 +156,7 @@ namespace Clipper2Lib {
|
||||
struct HorzJoin {
|
||||
OutPt* op1 = nullptr;
|
||||
OutPt* op2 = nullptr;
|
||||
HorzJoin() {};
|
||||
HorzJoin() {}
|
||||
explicit HorzJoin(OutPt* ltr, OutPt* rtl) : op1(ltr), op2(rtl) { }
|
||||
};
|
||||
|
||||
@@ -276,11 +276,11 @@ namespace Clipper2Lib {
|
||||
void AddPaths(const Paths64& paths, PathType polytype, bool is_open);
|
||||
public:
|
||||
virtual ~ClipperBase();
|
||||
int ErrorCode() const { return error_code_; };
|
||||
void PreserveCollinear(bool val) { preserve_collinear_ = val; };
|
||||
bool PreserveCollinear() const { return preserve_collinear_;};
|
||||
void ReverseSolution(bool val) { reverse_solution_ = val; };
|
||||
bool ReverseSolution() const { return reverse_solution_; };
|
||||
int ErrorCode() const { return error_code_; }
|
||||
void PreserveCollinear(bool val) { preserve_collinear_ = val; }
|
||||
bool PreserveCollinear() const { return preserve_collinear_;}
|
||||
void ReverseSolution(bool val) { reverse_solution_ = val; }
|
||||
bool ReverseSolution() const { return reverse_solution_; }
|
||||
void Clear();
|
||||
void AddReuseableData(const ReuseableDataContainer64& reuseable_data);
|
||||
#ifdef USINGZ
|
||||
@@ -300,7 +300,7 @@ namespace Clipper2Lib {
|
||||
PolyPath* parent_;
|
||||
public:
|
||||
PolyPath(PolyPath* parent = nullptr): parent_(parent){}
|
||||
virtual ~PolyPath() {};
|
||||
virtual ~PolyPath() {}
|
||||
//https://en.cppreference.com/w/cpp/language/rule_of_three
|
||||
PolyPath(const PolyPath&) = delete;
|
||||
PolyPath& operator=(const PolyPath&) = delete;
|
||||
@@ -339,7 +339,7 @@ namespace Clipper2Lib {
|
||||
explicit PolyPath64(PolyPath64* parent = nullptr) : PolyPath(parent) {}
|
||||
explicit PolyPath64(PolyPath64* parent, const Path64& path) : PolyPath(parent) { polygon_ = path; }
|
||||
|
||||
~PolyPath64() {
|
||||
~PolyPath64() override {
|
||||
childs_.resize(0);
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ namespace Clipper2Lib {
|
||||
return childs_.size();
|
||||
}
|
||||
|
||||
const Path64& Polygon() const { return polygon_; };
|
||||
const Path64& Polygon() const { return polygon_; }
|
||||
|
||||
double Area() const
|
||||
{
|
||||
@@ -406,7 +406,7 @@ namespace Clipper2Lib {
|
||||
polygon_ = path;
|
||||
}
|
||||
|
||||
~PolyPathD() {
|
||||
~PolyPathD() override {
|
||||
childs_.resize(0);
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ namespace Clipper2Lib {
|
||||
return childs_.size();
|
||||
}
|
||||
|
||||
const PathD& Polygon() const { return polygon_; };
|
||||
const PathD& Polygon() const { return polygon_; }
|
||||
|
||||
double Area() const
|
||||
{
|
||||
@@ -537,7 +537,7 @@ namespace Clipper2Lib {
|
||||
}
|
||||
|
||||
#ifdef USINGZ
|
||||
void SetZCallback(ZCallbackD cb) { zCallbackD_ = cb; };
|
||||
void SetZCallback(ZCallbackD cb) { zCallbackD_ = cb; }
|
||||
|
||||
void ZCB(const Point64& e1bot, const Point64& e1top,
|
||||
const Point64& e2bot, const Point64& e2top, Point64& pt)
|
||||
@@ -553,7 +553,7 @@ namespace Clipper2Lib {
|
||||
PointD e2t = PointD(e2top) * invScale_;
|
||||
zCallbackD_(e1b,e1t, e2b, e2t, tmp);
|
||||
pt.z = tmp.z; // only update 'z'
|
||||
};
|
||||
}
|
||||
|
||||
void CheckCallback()
|
||||
{
|
||||
|
||||
@@ -116,6 +116,7 @@ the four vertices that define the two segments that are intersecting.
|
||||
#include "clipper2/clipper.engine.h"
|
||||
#include "clipper2/clipper.offset.h"
|
||||
#include "clipper2/clipper.rectclip.h"
|
||||
#include "clipper2/clipper.triangulation.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace Clipper2Lib {
|
||||
@@ -812,6 +813,24 @@ EXTERN_DLL_EXPORT CPaths64 MinkowskiDiff64(const CPath64& cpattern, const CPath6
|
||||
return CreateCPathsFromPathsT(solution);
|
||||
}
|
||||
|
||||
EXTERN_DLL_EXPORT CPaths64 Triangulate64(const CPaths64 paths, bool use_delaunay)
|
||||
{
|
||||
Paths64 pp = ConvertCPathsToPathsT(paths);
|
||||
Paths64 sol;
|
||||
if (Triangulate(pp, sol, use_delaunay) != TriangulateResult::success) return nullptr;
|
||||
return CreateCPathsFromPathsT(sol);
|
||||
}
|
||||
|
||||
EXTERN_DLL_EXPORT CPathsD TriangulateD(const CPathsD paths, int decimal_precison, bool use_delaunay)
|
||||
{
|
||||
if (decimal_precison < -8 || decimal_precison > 8) return nullptr;
|
||||
const double scale = std::pow(10, decimal_precison);
|
||||
Paths64 pp = ConvertCPathsDToPaths64(paths, scale);
|
||||
Paths64 sol;
|
||||
if (Triangulate(pp, sol, use_delaunay) != TriangulateResult::success) return nullptr;
|
||||
return CreateCPathsDFromPaths64(sol, 1 / scale);
|
||||
}
|
||||
|
||||
#ifdef USINGZ
|
||||
typedef void (*DLLZCallback64)(const Point64& e1bot, const Point64& e1top, const Point64& e2bot, const Point64& e2top, Point64& pt);
|
||||
typedef void (*DLLZCallbackD)(const PointD& e1bot, const PointD& e1top, const PointD& e2bot, const PointD& e2top, PointD& pt);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 27 April 2024 *
|
||||
* Date : 5 March 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : This module provides a simple interface to the Clipper Library *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -13,8 +13,9 @@
|
||||
#include "clipper2/clipper.core.h"
|
||||
#include "clipper2/clipper.engine.h"
|
||||
#include "clipper2/clipper.offset.h"
|
||||
#include "clipper2/clipper.minkowski.h"
|
||||
#include "clipper2/clipper.rectclip.h"
|
||||
#include "clipper2/clipper.minkowski.h"
|
||||
#include "clipper2/clipper.triangulation.h"
|
||||
#include <type_traits>
|
||||
|
||||
namespace Clipper2Lib {
|
||||
@@ -133,7 +134,7 @@ namespace Clipper2Lib {
|
||||
JoinType jt, EndType et, double miter_limit = 2.0,
|
||||
double arc_tolerance = 0.0)
|
||||
{
|
||||
if (!delta) return paths;
|
||||
if (delta==0.0) return paths;
|
||||
ClipperOffset clip_offset(miter_limit, arc_tolerance);
|
||||
clip_offset.AddPaths(paths, jt, et);
|
||||
Paths64 solution;
|
||||
@@ -147,17 +148,17 @@ namespace Clipper2Lib {
|
||||
{
|
||||
int error_code = 0;
|
||||
CheckPrecisionRange(precision, error_code);
|
||||
if (!delta) return paths;
|
||||
if (delta==0.0) return paths;
|
||||
if (error_code) return PathsD();
|
||||
const double scale = std::pow(10, precision);
|
||||
ClipperOffset clip_offset(miter_limit, arc_tolerance);
|
||||
ClipperOffset clip_offset(miter_limit, arc_tolerance * scale);
|
||||
clip_offset.AddPaths(ScalePaths<int64_t,double>(paths, scale, error_code), jt, et);
|
||||
if (error_code) return PathsD();
|
||||
Paths64 solution;
|
||||
clip_offset.Execute(delta * scale, solution);
|
||||
return ScalePaths<double, int64_t>(solution, 1 / scale, error_code);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline Path<T> TranslatePath(const Path<T>& path, T dx, T dy)
|
||||
{
|
||||
@@ -351,6 +352,29 @@ namespace Clipper2Lib {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline size_t GetNext(size_t current, size_t high,
|
||||
const std::vector<bool>& flags)
|
||||
{
|
||||
++current;
|
||||
while (current <= high && flags[current]) ++current;
|
||||
if (current <= high) return current;
|
||||
current = 0;
|
||||
while (flags[current]) ++current;
|
||||
return current;
|
||||
}
|
||||
|
||||
inline size_t GetPrior(size_t current, size_t high,
|
||||
const std::vector<bool>& flags)
|
||||
{
|
||||
if (current == 0) current = high;
|
||||
else --current;
|
||||
while (current > 0 && flags[current]) --current;
|
||||
if (!flags[current]) return current;
|
||||
current = high;
|
||||
while (flags[current]) --current;
|
||||
return current;
|
||||
}
|
||||
|
||||
} // end details namespace
|
||||
|
||||
inline std::ostream& operator<< (std::ostream& os, const PolyTree64& pp)
|
||||
@@ -611,29 +635,6 @@ namespace Clipper2Lib {
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t GetNext(size_t current, size_t high,
|
||||
const std::vector<bool>& flags)
|
||||
{
|
||||
++current;
|
||||
while (current <= high && flags[current]) ++current;
|
||||
if (current <= high) return current;
|
||||
current = 0;
|
||||
while (flags[current]) ++current;
|
||||
return current;
|
||||
}
|
||||
|
||||
inline size_t GetPrior(size_t current, size_t high,
|
||||
const std::vector<bool>& flags)
|
||||
{
|
||||
if (current == 0) current = high;
|
||||
else --current;
|
||||
while (current > 0 && flags[current]) --current;
|
||||
if (!flags[current]) return current;
|
||||
current = high;
|
||||
while (flags[current]) --current;
|
||||
return current;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Path<T> SimplifyPath(const Path<T> &path,
|
||||
double epsilon, bool isClosedPath = true)
|
||||
@@ -665,13 +666,13 @@ namespace Clipper2Lib {
|
||||
start = curr;
|
||||
do
|
||||
{
|
||||
curr = GetNext(curr, high, flags);
|
||||
curr = details::GetNext(curr, high, flags);
|
||||
} while (curr != start && distSqr[curr] > epsSqr);
|
||||
if (curr == start) break;
|
||||
}
|
||||
|
||||
prior = GetPrior(curr, high, flags);
|
||||
next = GetNext(curr, high, flags);
|
||||
prior = details::GetPrior(curr, high, flags);
|
||||
next = details::GetNext(curr, high, flags);
|
||||
if (next == prior) break;
|
||||
|
||||
// flag for removal the smaller of adjacent 'distances'
|
||||
@@ -680,14 +681,14 @@ namespace Clipper2Lib {
|
||||
prior2 = prior;
|
||||
prior = curr;
|
||||
curr = next;
|
||||
next = GetNext(next, high, flags);
|
||||
next = details::GetNext(next, high, flags);
|
||||
}
|
||||
else
|
||||
prior2 = GetPrior(prior, high, flags);
|
||||
prior2 = details::GetPrior(prior, high, flags);
|
||||
|
||||
flags[curr] = true;
|
||||
curr = next;
|
||||
next = GetNext(next, high, flags);
|
||||
next = details::GetNext(next, high, flags);
|
||||
|
||||
if (isClosedPath || ((curr != high) && (curr != 0)))
|
||||
distSqr[curr] = PerpendicDistFromLineSqrd(path[curr], path[prior], path[next]);
|
||||
@@ -712,6 +713,35 @@ namespace Clipper2Lib {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline bool Path2ContainsPath1(const Path<T>& path1, const Path<T>& path2)
|
||||
{
|
||||
// precondition: paths must not intersect, except for
|
||||
// transient (and presumed 'micro') path intersections
|
||||
PointInPolygonResult pip = PointInPolygonResult::IsOn;
|
||||
for (const Point<T>& pt : path1)
|
||||
{
|
||||
switch (PointInPolygon(pt, path2))
|
||||
{
|
||||
case PointInPolygonResult::IsOutside:
|
||||
if (pip == PointInPolygonResult::IsOutside) return false;
|
||||
pip = PointInPolygonResult::IsOutside;
|
||||
break;
|
||||
case PointInPolygonResult::IsInside:
|
||||
if (pip == PointInPolygonResult::IsInside) return true;
|
||||
pip = PointInPolygonResult::IsInside;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pip != PointInPolygonResult::IsInside) return false;
|
||||
// result is likely true but check midpoint
|
||||
Point<T> mp1 = GetBounds(path1).MidPoint();
|
||||
return PointInPolygon(mp1, path2) == PointInPolygonResult::IsInside;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void RDP(const Path<T> path, std::size_t begin,
|
||||
std::size_t end, double epsSqrd, std::vector<bool>& flags)
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Clipper2Lib
|
||||
quad.emplace_back(tmp[i][h]);
|
||||
quad.emplace_back(tmp[i][j]);
|
||||
quad.emplace_back(tmp[g][j]);
|
||||
};
|
||||
}
|
||||
if (!IsPositive(quad))
|
||||
std::reverse(quad.begin(), quad.end());
|
||||
result.emplace_back(std::move(quad));
|
||||
|
||||
@@ -35,7 +35,7 @@ private:
|
||||
class Group {
|
||||
public:
|
||||
Paths64 paths_in;
|
||||
std::optional<size_t> lowest_path_idx{};
|
||||
std::optional<size_t> lowest_path_idx{};
|
||||
bool is_reversed = false;
|
||||
JoinType join_type;
|
||||
EndType end_type;
|
||||
@@ -88,14 +88,14 @@ public:
|
||||
bool reverse_solution = false) :
|
||||
miter_limit_(miter_limit), arc_tolerance_(arc_tolerance),
|
||||
preserve_collinear_(preserve_collinear),
|
||||
reverse_solution_(reverse_solution) { };
|
||||
reverse_solution_(reverse_solution) { }
|
||||
|
||||
~ClipperOffset() { Clear(); };
|
||||
~ClipperOffset() { Clear(); }
|
||||
|
||||
int ErrorCode() const { return error_code_; };
|
||||
int ErrorCode() const { return error_code_; }
|
||||
void AddPath(const Path64& path, JoinType jt_, EndType et_);
|
||||
void AddPaths(const Paths64& paths, JoinType jt_, EndType et_);
|
||||
void Clear() { groups_.clear(); norms.clear(); };
|
||||
void Clear() { groups_.clear(); norms.clear(); }
|
||||
|
||||
void Execute(double delta, Paths64& sols_64);
|
||||
void Execute(double delta, PolyTree64& polytree);
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Clipper2Lib
|
||||
void ExecuteInternal(const Path64& path);
|
||||
Path64 GetPath(OutPt2*& op);
|
||||
public:
|
||||
explicit RectClipLines64(const Rect64& rect) : RectClip64(rect) {};
|
||||
explicit RectClipLines64(const Rect64& rect) : RectClip64(rect) {}
|
||||
Paths64 Execute(const Paths64& paths);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 6 December 2025 *
|
||||
* Release : BETA RELEASE *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : Delaunay Triangulation *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef CLIPPER_TRIANGULATION_H
|
||||
#define CLIPPER_TRIANGULATION_H
|
||||
|
||||
#include <stack>
|
||||
#include "clipper2/clipper.core.h"
|
||||
|
||||
namespace Clipper2Lib
|
||||
{
|
||||
|
||||
enum class TriangulateResult { success, fail, no_polygons, paths_intersect };
|
||||
|
||||
// Triangulate - this function will not accept intesecting paths
|
||||
TriangulateResult Triangulate(const Paths64& pp, Paths64& solution, bool useDelaunay = true);
|
||||
TriangulateResult Triangulate(const PathsD& pp, int decPlaces, PathsD& solution, bool useDelaunay = true);
|
||||
|
||||
} // Clipper2Lib namespace
|
||||
#endif // CLIPPER_TRIANGULATION_H
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifndef CLIPPER_VERSION_H
|
||||
#define CLIPPER_VERSION_H
|
||||
|
||||
constexpr auto CLIPPER2_VERSION = "1.5.2";
|
||||
constexpr auto CLIPPER2_VERSION = "2.0.1";
|
||||
|
||||
#endif // CLIPPER_VERSION_H
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 17 September 2024 *
|
||||
* Date : 21 February 2026 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2026 *
|
||||
* Purpose : This is the main polygon clipping module *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -478,8 +478,7 @@ namespace Clipper2Lib {
|
||||
inline void SetOwner(OutRec* outrec, OutRec* new_owner)
|
||||
{
|
||||
//precondition1: new_owner is never null
|
||||
while (new_owner->owner && !new_owner->owner->pts)
|
||||
new_owner->owner = new_owner->owner->owner;
|
||||
new_owner->owner = GetRealOutRec(new_owner->owner);
|
||||
OutRec* tmp = new_owner;
|
||||
while (tmp && tmp != outrec) tmp = tmp->owner;
|
||||
if (tmp) new_owner->owner = outrec->owner;
|
||||
@@ -532,9 +531,9 @@ namespace Clipper2Lib {
|
||||
val = 1 - val; // toggle val
|
||||
else
|
||||
{
|
||||
double d = CrossProduct(op2->prev->pt, op2->pt, pt);
|
||||
if (d == 0) return PointInPolygonResult::IsOn;
|
||||
if ((d < 0) == is_above) val = 1 - val;
|
||||
int i = CrossProductSign(op2->prev->pt, op2->pt, pt);
|
||||
if (i == 0) return PointInPolygonResult::IsOn;
|
||||
if ((i < 0) == is_above) val = 1 - val;
|
||||
}
|
||||
is_above = !is_above;
|
||||
op2 = op2->next;
|
||||
@@ -542,9 +541,9 @@ namespace Clipper2Lib {
|
||||
|
||||
if (is_above != starting_above)
|
||||
{
|
||||
double d = CrossProduct(op2->prev->pt, op2->pt, pt);
|
||||
if (d == 0) return PointInPolygonResult::IsOn;
|
||||
if ((d < 0) == is_above) val = 1 - val;
|
||||
int i = CrossProductSign(op2->prev->pt, op2->pt, pt);
|
||||
if (i == 0) return PointInPolygonResult::IsOn;
|
||||
if ((i < 0) == is_above) val = 1 - val;
|
||||
}
|
||||
|
||||
if (val == 0) return PointInPolygonResult::IsOutside;
|
||||
@@ -574,30 +573,31 @@ namespace Clipper2Lib {
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool Path1InsidePath2(OutPt* op1, OutPt* op2)
|
||||
inline bool Path2ContainsPath1(OutPt* op1, OutPt* op2)
|
||||
{
|
||||
// we need to make some accommodation for rounding errors
|
||||
// so we won't jump if the first vertex is found outside
|
||||
PointInPolygonResult result;
|
||||
int outside_cnt = 0;
|
||||
// this function accommodates rounding errors that
|
||||
// can cause path micro intersections
|
||||
PointInPolygonResult pip = PointInPolygonResult::IsOn;
|
||||
OutPt* op = op1;
|
||||
do
|
||||
{
|
||||
result = PointInOpPolygon(op->pt, op2);
|
||||
if (result == PointInPolygonResult::IsOutside) ++outside_cnt;
|
||||
else if (result == PointInPolygonResult::IsInside) --outside_cnt;
|
||||
do {
|
||||
switch (PointInOpPolygon(op->pt, op2))
|
||||
{
|
||||
case PointInPolygonResult::IsOutside:
|
||||
if (pip == PointInPolygonResult::IsOutside) return false;
|
||||
pip = PointInPolygonResult::IsOutside;
|
||||
break;
|
||||
case PointInPolygonResult::IsInside:
|
||||
if (pip == PointInPolygonResult::IsInside) return true;
|
||||
pip = PointInPolygonResult::IsInside;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
op = op->next;
|
||||
} while (op != op1 && std::abs(outside_cnt) < 2);
|
||||
if (std::abs(outside_cnt) > 1) return (outside_cnt < 0);
|
||||
// since path1's location is still equivocal, check its midpoint
|
||||
Point64 mp = GetBounds(GetCleanPath(op1)).MidPoint();
|
||||
Path64 path2 = GetCleanPath(op2);
|
||||
return PointInPolygon(mp, path2) != PointInPolygonResult::IsOutside;
|
||||
} while (op != op1);
|
||||
// result unclear, so try again using cleaned paths
|
||||
return Path2ContainsPath1(GetCleanPath(op1), GetCleanPath(op2)); // (#973)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void AddLocMin(LocalMinimaList& list,
|
||||
Vertex& vert, PathType polytype, bool is_open)
|
||||
{
|
||||
@@ -617,7 +617,7 @@ namespace Clipper2Lib {
|
||||
{return a + path.size(); });
|
||||
if (total_vertex_count == 0) return;
|
||||
|
||||
Vertex* vertices = new Vertex[total_vertex_count], * v = vertices;
|
||||
Vertex* allVertices = new Vertex[total_vertex_count], * v = allVertices;
|
||||
for (const Path64& path : paths)
|
||||
{
|
||||
//for each path create a circular double linked list of vertices
|
||||
@@ -709,7 +709,7 @@ namespace Clipper2Lib {
|
||||
}
|
||||
} // end processing current path
|
||||
|
||||
vertexLists.emplace_back(vertices);
|
||||
vertexLists.emplace_back(allVertices);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -1122,21 +1122,19 @@ namespace Clipper2Lib {
|
||||
return newcomer.curr_x > resident.curr_x;
|
||||
|
||||
//get the turning direction a1.top, a2.bot, a2.top
|
||||
double d = CrossProduct(resident.top, newcomer.bot, newcomer.top);
|
||||
if (d != 0) return d < 0;
|
||||
int i = CrossProductSign(resident.top, newcomer.bot, newcomer.top);
|
||||
if (i != 0) return i < 0;
|
||||
|
||||
//edges must be collinear to get here
|
||||
//for starting open paths, place them according to
|
||||
//the direction they're about to turn
|
||||
if (!IsMaxima(resident) && (resident.top.y > newcomer.top.y))
|
||||
{
|
||||
return CrossProduct(newcomer.bot,
|
||||
resident.top, NextVertex(resident)->pt) <= 0;
|
||||
return (CrossProductSign(newcomer.bot, resident.top, NextVertex(resident)->pt) <= 0);
|
||||
}
|
||||
else if (!IsMaxima(newcomer) && (newcomer.top.y > resident.top.y))
|
||||
{
|
||||
return CrossProduct(newcomer.bot,
|
||||
newcomer.top, NextVertex(newcomer)->pt) >= 0;
|
||||
return (CrossProductSign(newcomer.bot, newcomer.top, NextVertex(newcomer)->pt) >= 0);
|
||||
}
|
||||
|
||||
int64_t y = newcomer.bot.y;
|
||||
@@ -1151,7 +1149,7 @@ namespace Clipper2Lib {
|
||||
resident.bot, resident.top)) return true;
|
||||
else
|
||||
//compare turning direction of the alternate bound
|
||||
return (CrossProduct(PrevPrevVertex(resident)->pt,
|
||||
return (CrossProductSign(PrevPrevVertex(resident)->pt,
|
||||
newcomer.bot, PrevPrevVertex(newcomer)->pt) > 0) == newcomerIsLeft;
|
||||
}
|
||||
|
||||
@@ -1561,7 +1559,7 @@ namespace Clipper2Lib {
|
||||
FixSelfIntersects(outrec);
|
||||
}
|
||||
|
||||
void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp)
|
||||
void ClipperBase::DoSplitOp (OutRec* outrec, OutPt* splitOp)
|
||||
{
|
||||
// splitOp.prev -> splitOp &&
|
||||
// splitOp.next -> splitOp.next.next are intersecting
|
||||
@@ -1570,7 +1568,7 @@ namespace Clipper2Lib {
|
||||
outrec->pts = prevOp;
|
||||
|
||||
Point64 ip;
|
||||
GetSegmentIntersectPt(prevOp->pt, splitOp->pt,
|
||||
GetLineIntersectPt(prevOp->pt, splitOp->pt,
|
||||
splitOp->next->pt, nextNextOp->pt, ip);
|
||||
|
||||
#ifdef USINGZ
|
||||
@@ -1626,7 +1624,7 @@ namespace Clipper2Lib {
|
||||
|
||||
if (using_polytree_)
|
||||
{
|
||||
if (Path1InsidePath2(prevOp, newOp))
|
||||
if (Path2ContainsPath1(prevOp, newOp))
|
||||
{
|
||||
newOr->splits = new OutRecList();
|
||||
newOr->splits->emplace_back(outrec);
|
||||
@@ -1648,10 +1646,10 @@ namespace Clipper2Lib {
|
||||
void ClipperBase::FixSelfIntersects(OutRec* outrec)
|
||||
{
|
||||
OutPt* op2 = outrec->pts;
|
||||
if (op2->prev == op2->next->next)
|
||||
return; // because triangles can't self-intersect
|
||||
for (; ; )
|
||||
{
|
||||
// triangles can't self-intersect
|
||||
if (op2->prev == op2->next->next) break;
|
||||
if (SegmentsIntersect(op2->prev->pt,
|
||||
op2->pt, op2->next->pt, op2->next->next->pt))
|
||||
{
|
||||
@@ -1660,6 +1658,8 @@ namespace Clipper2Lib {
|
||||
DoSplitOp(outrec, op2);
|
||||
if (!outrec->pts) break;
|
||||
op2 = outrec->pts;
|
||||
if (op2->prev == op2->next->next)
|
||||
break; // again, because triangles can't self-intersect
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@@ -2108,10 +2108,9 @@ namespace Clipper2Lib {
|
||||
e->prev_in_sel = e->prev_in_ael;
|
||||
e->next_in_sel = e->next_in_ael;
|
||||
e->jump = e->next_in_sel;
|
||||
if (e->join_with == JoinWith::Left)
|
||||
e->curr_x = e->prev_in_ael->curr_x; // also avoids complications
|
||||
else
|
||||
e->curr_x = TopX(*e, top_y);
|
||||
// it is safe to ignore 'joined' edges here because
|
||||
// if necessary they will be split in IntersectEdges()
|
||||
e->curr_x = TopX(*e, top_y);
|
||||
e = e->next_in_ael;
|
||||
}
|
||||
}
|
||||
@@ -2258,15 +2257,14 @@ namespace Clipper2Lib {
|
||||
|
||||
void MoveSplits(OutRec* fromOr, OutRec* toOr)
|
||||
{
|
||||
if (!fromOr->splits) return;
|
||||
if (!toOr->splits) toOr->splits = new OutRecList();
|
||||
OutRecList::iterator orIter = fromOr->splits->begin();
|
||||
for (; orIter != fromOr->splits->end(); ++orIter)
|
||||
toOr->splits->emplace_back(*orIter);
|
||||
if (toOr != *orIter) // #987
|
||||
toOr->splits->emplace_back(*orIter);
|
||||
fromOr->splits->clear();
|
||||
}
|
||||
|
||||
|
||||
void ClipperBase::ProcessHorzJoins()
|
||||
{
|
||||
for (const HorzJoin& j : horz_join_list_)
|
||||
@@ -2295,8 +2293,8 @@ namespace Clipper2Lib {
|
||||
}
|
||||
|
||||
if (using_polytree_) //#498, #520, #584, D#576, #618
|
||||
{
|
||||
if (Path1InsidePath2(or1->pts, or2->pts))
|
||||
{
|
||||
if (Path2ContainsPath1(or1->pts, or2->pts))
|
||||
{
|
||||
//swap or1's & or2's pts
|
||||
OutPt* tmp = or1->pts;
|
||||
@@ -2307,7 +2305,7 @@ namespace Clipper2Lib {
|
||||
//or2 is now inside or1
|
||||
or2->owner = or1;
|
||||
}
|
||||
else if (Path1InsidePath2(or2->pts, or1->pts))
|
||||
else if (Path2ContainsPath1(or2->pts, or1->pts))
|
||||
{
|
||||
or2->owner = or1;
|
||||
}
|
||||
@@ -2320,13 +2318,14 @@ namespace Clipper2Lib {
|
||||
else
|
||||
or2->owner = or1;
|
||||
}
|
||||
else
|
||||
else // joining, not splitting
|
||||
{
|
||||
or2->pts = nullptr;
|
||||
if (using_polytree_)
|
||||
{
|
||||
SetOwner(or2, or1);
|
||||
MoveSplits(or2, or1); //#618
|
||||
if (or2->splits)
|
||||
MoveSplits(or2, or1); //#618
|
||||
}
|
||||
else
|
||||
or2->owner = or1;
|
||||
@@ -2346,7 +2345,7 @@ namespace Clipper2Lib {
|
||||
void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y)
|
||||
{
|
||||
Point64 ip;
|
||||
if (!GetSegmentIntersectPt(e1.bot, e1.top, e2.bot, e2.top, ip))
|
||||
if (!GetLineIntersectPt(e1.bot, e1.top, e2.bot, e2.top, ip))
|
||||
ip = Point64(e1.curr_x, top_y); //parallel edges
|
||||
|
||||
//rounding errors can occasionally place the calculated intersection
|
||||
@@ -2930,22 +2929,28 @@ namespace Clipper2Lib {
|
||||
|
||||
bool ClipperBase::CheckSplitOwner(OutRec* outrec, OutRecList* splits)
|
||||
{
|
||||
for (auto split : *splits)
|
||||
// nb: use indexing (not an iterator) in case 'splits' is modified inside this loop (#1029)
|
||||
for (size_t idx = 0; idx < splits->size(); ++idx)
|
||||
{
|
||||
OutRec* split = (*splits)[idx];
|
||||
if (!split->pts && split->splits &&
|
||||
CheckSplitOwner(outrec, split->splits)) return true; //#942
|
||||
split = GetRealOutRec(split);
|
||||
if(!split || split == outrec || split->recursive_split == outrec) continue;
|
||||
if (!split || split == outrec || split->recursive_split == outrec) continue;
|
||||
split->recursive_split = outrec; // prevent infinite loops
|
||||
|
||||
if (split->splits && CheckSplitOwner(outrec, split->splits))
|
||||
return true;
|
||||
else if (CheckBounds(split) &&
|
||||
IsValidOwner(outrec, split) &&
|
||||
split->bounds.Contains(outrec->bounds) &&
|
||||
Path1InsidePath2(outrec->pts, split->pts))
|
||||
{
|
||||
outrec->owner = split; //found in split
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
if (!CheckBounds(split) || !split->bounds.Contains(outrec->bounds) ||
|
||||
!Path2ContainsPath1(outrec->pts, split->pts)) continue;
|
||||
|
||||
if (!IsValidOwner(outrec, split)) // split is owned by outrec! (#957)
|
||||
split->owner = outrec->owner;
|
||||
|
||||
outrec->owner = split;
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2956,13 +2961,12 @@ namespace Clipper2Lib {
|
||||
// post-condition: if a valid path, outrec will have a polypath
|
||||
|
||||
if (outrec->polypath || outrec->bounds.IsEmpty()) return;
|
||||
|
||||
while (outrec->owner)
|
||||
{
|
||||
if (outrec->owner->splits && CheckSplitOwner(outrec, outrec->owner->splits)) break;
|
||||
if (outrec->owner->pts && CheckBounds(outrec->owner) &&
|
||||
outrec->owner->bounds.Contains(outrec->bounds) &&
|
||||
Path1InsidePath2(outrec->pts, outrec->owner->pts)) break;
|
||||
Path2ContainsPath1(outrec->pts, outrec->owner->pts)) break;
|
||||
outrec->owner = outrec->owner->owner;
|
||||
}
|
||||
|
||||
@@ -3025,6 +3029,7 @@ namespace Clipper2Lib {
|
||||
{
|
||||
OutRec* outrec = outrec_list_[i];
|
||||
if (!outrec || !outrec->pts) continue;
|
||||
|
||||
if (outrec->is_open)
|
||||
{
|
||||
Path64 path;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 22 January 2025 *
|
||||
* Date : 11 October 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : Path Offset (Inflate/Shrink) *
|
||||
@@ -33,22 +33,28 @@ const double arc_const = 0.002; // <-- 1/500
|
||||
// Miscellaneous methods
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::optional<size_t> GetLowestClosedPathIdx(const Paths64& paths)
|
||||
void GetLowestClosedPathInfo(const Paths64& paths, std::optional<size_t>& idx, bool& is_neg_area)
|
||||
{
|
||||
std::optional<size_t> result;
|
||||
idx.reset();
|
||||
Point64 botPt = Point64(INT64_MAX, INT64_MIN);
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
{
|
||||
double a = MAX_DBL;
|
||||
for (const Point64& pt : paths[i])
|
||||
{
|
||||
if ((pt.y < botPt.y) ||
|
||||
if ((pt.y < botPt.y) ||
|
||||
((pt.y == botPt.y) && (pt.x >= botPt.x))) continue;
|
||||
result = i;
|
||||
if (a == MAX_DBL)
|
||||
{
|
||||
a = Area(paths[i]);
|
||||
if (a == 0) break; // invalid closed path, so break from inner loop
|
||||
is_neg_area = a < 0;
|
||||
}
|
||||
idx = i;
|
||||
botPt.x = pt.x;
|
||||
botPt.y = pt.y;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline double Hypot(double x, double y)
|
||||
@@ -141,15 +147,16 @@ ClipperOffset::Group::Group(const Paths64& _paths, JoinType _join_type, EndType
|
||||
|
||||
if (end_type == EndType::Polygon)
|
||||
{
|
||||
lowest_path_idx = GetLowestClosedPathIdx(paths_in);
|
||||
bool is_neg_area;
|
||||
GetLowestClosedPathInfo(paths_in, lowest_path_idx, is_neg_area);
|
||||
// the lowermost path must be an outer path, so if its orientation is negative,
|
||||
// then flag the whole group is 'reversed' (will negate delta etc.)
|
||||
// as this is much more efficient than reversing every path.
|
||||
is_reversed = (lowest_path_idx.has_value()) && Area(paths_in[lowest_path_idx.value()]) < 0;
|
||||
is_reversed = lowest_path_idx.has_value() && is_neg_area;
|
||||
}
|
||||
else
|
||||
{
|
||||
lowest_path_idx = std::nullopt;
|
||||
lowest_path_idx.reset();
|
||||
is_reversed = false;
|
||||
}
|
||||
}
|
||||
@@ -232,7 +239,7 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
|
||||
{
|
||||
PointD pt4 = PointD(pt3.x + vec.x * group_delta_, pt3.y + vec.y * group_delta_);
|
||||
PointD pt = ptQ;
|
||||
GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||
GetLineIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||
//get the second intersect point through reflecion
|
||||
path_out.emplace_back(ReflectPoint(pt, ptQ));
|
||||
path_out.emplace_back(pt);
|
||||
@@ -241,7 +248,7 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
|
||||
{
|
||||
PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_);
|
||||
PointD pt = ptQ;
|
||||
GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||
GetLineIntersectPt(pt1, pt2, pt3, pt4, pt);
|
||||
path_out.emplace_back(pt);
|
||||
//get the second intersect point through reflecion
|
||||
path_out.emplace_back(ReflectPoint(pt, ptQ));
|
||||
@@ -597,10 +604,10 @@ void ClipperOffset::ExecuteInternal(double delta)
|
||||
|
||||
if (!solution->size()) return;
|
||||
|
||||
bool paths_reversed = CheckReverseOrientation();
|
||||
bool paths_reversed = CheckReverseOrientation();
|
||||
//clean up self-intersections ...
|
||||
Clipper64 c;
|
||||
c.PreserveCollinear(false);
|
||||
c.PreserveCollinear(preserve_collinear_);
|
||||
//the solution should retain the orientation of the input
|
||||
c.ReverseSolution(reverse_solution_ != paths_reversed);
|
||||
#ifdef USINGZ
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 5 July 2024 *
|
||||
* Date : 11 October 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : FAST rectangular clipping *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -73,8 +73,8 @@ namespace Clipper2Lib {
|
||||
bool GetSegmentIntersection(const Point64& p1,
|
||||
const Point64& p2, const Point64& p3, const Point64& p4, Point64& ip)
|
||||
{
|
||||
double res1 = CrossProduct(p1, p3, p4);
|
||||
double res2 = CrossProduct(p2, p3, p4);
|
||||
int res1 = CrossProductSign(p1, p3, p4);
|
||||
int res2 = CrossProductSign(p2, p3, p4);
|
||||
if (res1 == 0)
|
||||
{
|
||||
ip = p1;
|
||||
@@ -93,8 +93,8 @@ namespace Clipper2Lib {
|
||||
}
|
||||
if ((res1 > 0) == (res2 > 0)) return false;
|
||||
|
||||
double res3 = CrossProduct(p3, p1, p2);
|
||||
double res4 = CrossProduct(p4, p1, p2);
|
||||
int res3 = CrossProductSign(p3, p1, p2);
|
||||
int res4 = CrossProductSign(p4, p1, p2);
|
||||
if (res3 == 0)
|
||||
{
|
||||
ip = p3;
|
||||
@@ -112,7 +112,7 @@ namespace Clipper2Lib {
|
||||
if ((res3 > 0) == (res4 > 0)) return false;
|
||||
|
||||
// segments must intersect to get here
|
||||
return GetSegmentIntersectPt(p1, p2, p3, p4, ip);
|
||||
return GetLineIntersectPt(p1, p2, p3, p4, ip);
|
||||
}
|
||||
|
||||
inline bool GetIntersection(const Path64& rectPath,
|
||||
@@ -223,7 +223,7 @@ namespace Clipper2Lib {
|
||||
const Point64& prev_pt, const Point64& curr_pt, const Point64& rect_mp)
|
||||
{
|
||||
if (AreOpposites(prev, curr))
|
||||
return CrossProduct(prev_pt, rect_mp, curr_pt) < 0;
|
||||
return CrossProductSign(prev_pt, rect_mp, curr_pt) < 0;
|
||||
else
|
||||
return HeadingClockwise(prev, curr);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,59 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include "clipper2/clipper.h"
|
||||
#include "clipper2/clipper.core.h"
|
||||
#include "clipper2/clipper.offset.h"
|
||||
#include "../../Utils/clipper.svg.h"
|
||||
#include "../../Utils/clipper.svg.utils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Clipper2Lib;
|
||||
|
||||
void DoRabbit();
|
||||
void DoSimpleShapes();
|
||||
void System(const std::string& filename);
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
void System(const std::string& filename)
|
||||
{
|
||||
|
||||
DoSimpleShapes();
|
||||
DoRabbit();
|
||||
//std::getchar();
|
||||
#ifdef _WIN32
|
||||
system(filename.c_str());
|
||||
#else
|
||||
system(("firefox " + filename).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void DoSimpleShapes()
|
||||
static void DisplayAsSvgImage(const std::string& caption, FillRule fillrule,
|
||||
const PathsD* subject, const PathsD* clip, const PathsD* solution)
|
||||
{
|
||||
const std::string filename = caption + ".SVG";
|
||||
SvgWriter svg;
|
||||
if (subject)
|
||||
SvgAddSubject(svg, *subject, fillrule);
|
||||
if (clip)
|
||||
SvgAddClip(svg, *clip, fillrule);
|
||||
if (solution)
|
||||
SvgAddSolution(svg, *solution, fillrule, false);
|
||||
SvgSaveToFile(svg, filename, 400, 400, 10);
|
||||
System(filename);
|
||||
}
|
||||
|
||||
static void DoRabbit()
|
||||
{
|
||||
SvgReader svg_reader("./rabbit.svg");
|
||||
PathsD p = svg_reader.paths;
|
||||
PathsD solution(p);
|
||||
while (p.size())
|
||||
{
|
||||
p = InflatePaths(p, -5, JoinType::Round, EndType::Polygon);
|
||||
// SimplifyPaths is not essential but is **highly recommended**
|
||||
// because it speeds up the loop by removing tiny artefacts
|
||||
p = SimplifyPaths(p, 0.25);
|
||||
copy(p.begin(), p.end(), back_inserter(solution));
|
||||
}
|
||||
DisplayAsSvgImage("rabbit_offset", FillRule::EvenOdd, nullptr, nullptr, &solution);
|
||||
}
|
||||
|
||||
static void DoSimpleShapes()
|
||||
{
|
||||
// OPEN_PATHS SVG:
|
||||
|
||||
@@ -53,7 +86,7 @@ void DoSimpleShapes()
|
||||
// POLYGON JOINTYPES SVG:
|
||||
|
||||
// 1. triangle offset - with large miter
|
||||
int err, scale = 100;
|
||||
int err = 0, scale = 100;
|
||||
PathsD p, solution;
|
||||
p.push_back(MakePathD({ 30,150, 60,350, 0,350 }));
|
||||
solution.insert(solution.end(), p.begin(), p.end());
|
||||
@@ -99,39 +132,9 @@ void DoSimpleShapes()
|
||||
System(filename);
|
||||
}
|
||||
|
||||
void DoRabbit()
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
SvgReader svg_reader;
|
||||
svg_reader.LoadFromFile("./rabbit.svg");
|
||||
PathsD p = svg_reader.GetPaths();
|
||||
|
||||
JoinType jt = JoinType::Round;
|
||||
PathsD solution(p);
|
||||
|
||||
while (p.size())
|
||||
{
|
||||
// nb: don't forget to scale the delta offset too!
|
||||
p = InflatePaths(p, -2.5, jt, EndType::Polygon);
|
||||
// SimplifyPaths (or RamerDouglasPeucker) is not
|
||||
// essential but is highly recommended because it
|
||||
// speeds up the loop and also tidies up the result
|
||||
p = SimplifyPaths(p, 0.25); // preferred over RDP()
|
||||
solution.reserve(solution.size() + p.size());
|
||||
copy(p.begin(), p.end(), back_inserter(solution));
|
||||
}
|
||||
|
||||
FillRule fr = FillRule::EvenOdd;
|
||||
SvgWriter svg;
|
||||
SvgAddSolution(svg, solution, fr, false);
|
||||
SvgSaveToFile(svg, "solution_off2.svg", 450, 720, 0);
|
||||
System("solution_off2.svg");
|
||||
DoSimpleShapes();
|
||||
DoRabbit();
|
||||
}
|
||||
|
||||
void System(const std::string& filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
system(filename.c_str());
|
||||
#else
|
||||
system(("firefox " + filename).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5,11 +5,7 @@
|
||||
version="1.1"
|
||||
width="300"
|
||||
height="480"
|
||||
viewBox="0 0 300 480">
|
||||
<g
|
||||
transform="translate(-88.397628,-29.626113)">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-opacity:1"
|
||||
d="m 206.225,503.122 -8.148,-2.095 -7.222,-4.233 -3.845,-7.305 0.58,-7.641 1.89,-7.452 2.575,-7.243 2.333,-5.778 -5.048,-0.572 -5.048,-0.572 -6.141,-0.733 -6.125,-0.86 -2.82,2.504 -2.802,5.561 -5.16,3.469 -8.834,0.605 -8.872,-0.029 -8.869,-0.21 -8.865,-0.338 -8.859,-0.466 -8.848,-0.647 -8.7614,-1.276 -4.6459,-7.072 2.8843,-8.492 5.478,-7.198 6.608,-6.191 4.85,-4.196 2.117,-5.783 -1.772,-5.173 -4.43,-3.518 -6.853,-5.828 -4.9814,-7.442 -2.056,-8.736 -0.2667,-8.999 0.4584,-8.995 0.7962,-8.905 0.9762,-8.887 1.088,-8.875 1.1893,-8.862 1.317,-8.842 1.655,-8.785 3.787,-7.716 5.144,-6.927 5.585,-6.58 5.786,-6.405 5.895,-6.305 6.342,-6.558 6.446,-6.458 6.519,-6.383 6.579,-6.321 6.636,-6.261 6.696,-6.198 6.766,-6.117 6.88,-5.993 7.206,-5.582 7.372,-3.146 7.613,-2.527 8.59,-2.717 7.365,-4.943 3.677,-8.186 2.607,-8.624 2.726,-8.495 3.376,-8.256 4.332,-7.792 -1.458,-5.5 -5.077,-8.354 -4.107,-6.133 -4.901,-5.546 -5.143,-5.321 -5.161,-5.33 -5.026,-5.46 -4.732,-5.71 -4.769,-8.681 -4.478,-8.836 -4.388,-8.881 -4.328,-8.9118 -4.274,-8.9376 -4.213,-8.9652 -4.122,-9.0077 -3.822,-9.1367 -1.49,-5.8115 -0.796,-5.9437 3.324,-8.4038 5.66,-4.6108 6.862,-2.4246 7.305,-0.2515 8.97,1.5992 8.434,3.4654 7.769,4.7856 7.175,5.644 6.7,6.2009 6.329,6.7251 5.725,7.2478 5.129,7.6801 4.7,7.9535 4.432,8.1049 4.275,8.1894 4.065,7.831 4.152,7.785 4.462,7.591 2.947,-8.361 1.153,-9.044 0.648,-9.095 0.55,-9.3465 1.417,-9.2418 2.861,-8.9116 2.684,-7.4629 2.844,-7.4041 3.144,-7.2812 4.078,-6.7684 8.321,-1.9385 6.629,5.7311 2.392,8.9515 0.86,9.2652 0.439,9.2971 0.266,9.3041 0.18,9.3061 0.125,7.6249 0.125,7.625 0.124,7.625 0.125,7.625 4.714,0.627 7.428,1.403 7.169,2.383 6.643,3.589 5.788,4.846 4.436,6.202 3.908,6.558 3.724,6.666 3.615,6.726 4.586,8.485 4.751,8.394 5.186,8.121 4.157,6.3 1.657,7.379 -0.019,7.584 -0.839,7.545 -1.674,7.58 -3.979,6.628 -5.465,5.526 -5.56,5.682 -3.206,7.214 -1.739,6.353 2.801,8.334 2.753,9.226 2.099,9.397 1.389,9.527 0.584,9.609 -0.365,9.619 -1.55,9.497 -2.509,9.05 -2.709,8.992 -2.82,8.958 -2.793,9.166 -2.483,9.254 -2.151,9.337 -1.818,9.408 -1.504,9.462 -1.223,9.504 -0.411,9.059 0.963,9.016 2.244,8.788 3.211,8.485 3.866,8.21 4.294,7.997 4.575,7.837 4.895,8.249 4.6,8.414 2.515,9.134 -4.607,5.514 -7.789,0.876 -7.851,0.142 -7.164,-0.054 -7.147,-0.484 -6.999,-1.494 -7.326,-2.485 -5.97,-4.777 -3.65,-6.812 -2.943,-7.161 -2.096,-5.292 -2.097,-5.293 -7.611,-0.392 -7.611,-0.392 -7.611,-0.392 -7.841,-0.434 -7.837,-0.491 -7.834,-0.555 -7.822,-0.698 -9.194,-0.324 -1.815,4.861 -1.504,4.978 -2.624,9.161 2.068,6.947 1.732,7.882 -0.428,7.949 -5.904,2.831 -6.75,0.429 -6.765,0.023 -9.656,-0.241 -9.631,-0.708 v 0 z"/>
|
||||
</g>
|
||||
viewBox="0 0 300 400">
|
||||
<path d="M88.4,397.4 L82.2,393.7, 78.9,387.5, 79.4,381.0, 81.0,374.6, 85.2,363.5, 66.1,361.1, 63.7,363.3, 61.3,368.0, 56.9,371.0, 49.3,371.5, 26.6,371.0, 11.4,370.0, 3.9,369.0, 0,362.9, 2.4,355.6, 7.1,349.5, 16.9,340.6, 18.7,335.7, 17.2,331.2, 7.5,323.2, 3.3,316.9, 1.5,309.4, 1.3,301.7, 1.7,294.0, 3.2,278.8, 6.3,256.1, 7.7,248.5, 10.9,241.9, 15.3,236.0, 30.1,219.5, 41.0,208.4, 63.6,186.9, 75.3,176.5, 81.5,171.7, 87.8,169.0, 101.6,164.6, 107.9,160.3, 111.1,153.3, 115.7,138.7, 118.5,131.6, 122.2,125.0, 121.0,120.3, 113.1,107.9, 95.8,89.3, 91.8,84.5, 87.7,77.0, 80.1,61.9, 65.6,31.2, 62.4,23.4, 61.1,18.5, 60.4,13.4, 63.3,6.2, 68.1,2.2, 74.0,0.2, 80.2,0, 87.9,1.3, 95.1,4.3, 101.8,8.4, 107.9,13.2, 113.6,18.5, 119.0,24.3, 123.9,30.5, 128.3,37.0, 132.3,43.8, 146.8,71.1, 150.6,77.6, 153.1,70.5, 154.1,62.7, 155.2,47.0, 156.4,39.1, 158.8,31.4, 163.5,18.7, 166.2,12.5, 169.7,6.7, 176.8,5.0, 182.5,9.9, 184.6,17.6, 185.3,25.5, 185.9,41.4, 186.5,75.5, 196.9,77.2, 203.0,79.3, 208.7,82.3, 213.6,86.5, 217.4,91.8, 235.0,123.3, 243.0,135.6, 244.4,141.9, 244.4,148.4, 243.7,154.9, 242.3,161.3, 238.9,167.0, 229.4,176.6, 226.7,182.8, 225.2,188.2, 230.0,203.2, 231.8,211.3, 232.9,219.4, 233.4,227.6, 233.1,235.9, 231.8,244.0, 220.4,282.8, 217.0,298.9, 214.7,315.1, 214.3,322.8, 215.2,330.5, 217.1,338.1, 219.8,345.3, 223.1,352.3, 238.8,380.1, 241.0,387.9, 237.0,392.7, 230.4,393.4, 217.5,393.5, 211.4,393.1, 205.4,391.8, 199.2,389.7, 194.1,385.6, 191,379.8, 184.8,364.6, 158.6,363.2, 138.5,361.7, 130.7,361.4, 129.1,365.6, 125.6,377.7, 127.3,383.6, 128.8,390.4, 128.5,397.2, 123.4,399.6, 117.6,400, 103.6,399.8, 95.3,399.2Z"
|
||||
style="fill:white;stroke:#000000;stroke-opacity:1"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -40,27 +40,33 @@ inline Path64 MakeRandomPoly(int width, int height, unsigned vertCnt)
|
||||
void DoMemoryLeakTest()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int edge_cnt = 1000;
|
||||
#ifndef __MINGW32__
|
||||
int edge_cnt = 1000;
|
||||
|
||||
Paths64 subject, clip;
|
||||
subject.push_back(MakeRandomPoly(800, 600, edge_cnt));
|
||||
clip.push_back(MakeRandomPoly(800, 600, edge_cnt));
|
||||
Paths64 subject, clip;
|
||||
subject.push_back(MakeRandomPoly(800, 600, edge_cnt));
|
||||
clip.push_back(MakeRandomPoly(800, 600, edge_cnt));
|
||||
|
||||
_CrtMemState sOld {}, sNew {}, sDiff {};
|
||||
_CrtMemCheckpoint(&sOld); //take a snapshot
|
||||
{
|
||||
Paths64 solution = Intersect(subject, clip, FillRule::NonZero);
|
||||
}
|
||||
_CrtMemCheckpoint(&sNew); //take another snapshot (outside code block)
|
||||
if (_CrtMemDifference(&sDiff, &sOld, &sNew)) // check for a difference
|
||||
{
|
||||
std::cout << std::endl << "Memory leaks!" << std::endl;
|
||||
//_CrtMemDumpStatistics(&sDiff);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << std::endl << "No memory leaks detected :)" << std::endl << std::endl;
|
||||
}
|
||||
_CrtMemState sOld {}, sNew {}, sDiff {};
|
||||
_CrtMemCheckpoint(&sOld); //take a snapshot
|
||||
{
|
||||
Paths64 solution = Intersect(subject, clip, FillRule::NonZero);
|
||||
}
|
||||
_CrtMemCheckpoint(&sNew); //take another snapshot (outside code block)
|
||||
if (_CrtMemDifference(&sDiff, &sOld, &sNew)) // check for a difference
|
||||
{
|
||||
std::cout << std::endl << "Memory leaks!" << std::endl;
|
||||
//_CrtMemDumpStatistics(&sDiff);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << std::endl << "No memory leaks detected :)" << std::endl << std::endl;
|
||||
}
|
||||
#else
|
||||
std::cout << "DoMemoryLeakTest only supported with MSVC on Windows - not MinGW." << std::endl << std::endl;
|
||||
#endif
|
||||
#else
|
||||
std::cout << "DoMemoryLeakTest only supported with MSVC on Windows." << std::endl << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -2,62 +2,35 @@
|
||||
#include <string>
|
||||
|
||||
#include "clipper2/clipper.h"
|
||||
#include "clipper2/clipper.core.h"
|
||||
#include "../../Utils/clipper.svg.h"
|
||||
#include "../../Utils/clipper.svg.utils.h"
|
||||
|
||||
using namespace Clipper2Lib;
|
||||
|
||||
void DoSimpleTest(bool show_solution_coords = false);
|
||||
Path64 MakeRandomPoly(int width, int height, unsigned vertCnt);
|
||||
void System(const std::string &filename);
|
||||
|
||||
int main()
|
||||
{
|
||||
DoSimpleTest();
|
||||
}
|
||||
|
||||
inline Path64 MakeStar(const Point64& center, int radius, int points)
|
||||
static void DisplayAsSvgImage(const std::string& caption, FillRule fillrule,
|
||||
const Paths64& subject, const Paths64& clip, const Paths64& solution)
|
||||
{
|
||||
if (!(points % 2)) --points;
|
||||
if (points < 5) points = 5;
|
||||
Path64 tmp = Ellipse<int64_t>(center, radius, radius, points);
|
||||
Path64 result;
|
||||
result.reserve(points);
|
||||
result.push_back(tmp[0]);
|
||||
for (int i = points - 1, j = i / 2; j;)
|
||||
{
|
||||
result.push_back(tmp[j--]);
|
||||
result.push_back(tmp[i--]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void DoSimpleTest(bool show_solution_coords)
|
||||
{
|
||||
Paths64 tmp, solution;
|
||||
FillRule fr = FillRule::NonZero;
|
||||
|
||||
Paths64 subject, clip;
|
||||
subject.push_back(MakeStar(Point64(225, 225), 220, 9));
|
||||
clip.push_back(Ellipse<int64_t>(Point64(225,225), 150, 150));
|
||||
|
||||
//Intersect both shapes and then 'inflate' result -10 (ie deflate)
|
||||
solution = Intersect(subject, clip, fr);
|
||||
solution = InflatePaths(solution, -10, JoinType::Round, EndType::Polygon);
|
||||
|
||||
const std::string filename = caption + ".SVG";
|
||||
SvgWriter svg;
|
||||
SvgAddSubject(svg, subject, fr);
|
||||
SvgAddClip(svg, clip, fr);
|
||||
SvgAddSolution(svg, solution, fr, false);
|
||||
SvgSaveToFile(svg, "solution.svg", 450, 450, 10);
|
||||
System("solution.svg");
|
||||
}
|
||||
|
||||
void System(const std::string &filename)
|
||||
{
|
||||
SvgAddSubject(svg, subject, fillrule);
|
||||
SvgAddClip(svg, clip, fillrule);
|
||||
SvgAddSolution(svg, solution, fillrule, false);
|
||||
SvgSaveToFile(svg, filename, 400, 400, 10);
|
||||
#ifdef _WIN32
|
||||
system(filename.c_str());
|
||||
#else
|
||||
system(("firefox " + filename).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// intersect a star and another modestly rotated star
|
||||
Paths64 subject, clip, solution;
|
||||
subject.push_back({ MakePath({200,100, 20,158, 130,4, 130,196, 20,42}) });
|
||||
clip.push_back({ MakePath({196,126, 8,136, 154,16, 104,200, 38,24}) });
|
||||
solution = Intersect(subject, clip, FillRule::NonZero);
|
||||
DisplayAsSvgImage("Intersect Paths", FillRule::NonZero, subject, clip, solution);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 647 350 L 626 459 568 553 480 619 373 650 263 640 163 589 89 508 50 404 50 293 89 191 163 108 263 59 373 50 480 80 568 146 626 240 ZM 565 298 L 547 249 518 204 480 169 435 142 385 127 333 124 281 132 232 153 190 186 156 225 132 272 121 323 121 376 132 427 156 473 190 514 232 546 281 565 333 575 385 572 435 557 480 530 518 495 547 450 565 401 571 350 ZM 495 350 L 472 431 408 487 324 498 247 463 201 392 201 307 247 236 324 201 408 212 472 268 ZM 392 291 L 329 277 278 317 278 382 329 422 392 408 421 350 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 897 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 1027 183 L 1050 363 494 209 101 573 50 552 475 174 608 176 517 136 613 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 465 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 599 237 L 636 229 50 650 512 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 423 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 232 288 L 496 129 643 181 699 211 676 141 856 85 1050 50 720 550 50 426 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 463 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 50 50 L 1050 50 1050 648 50 648 ZM 90 513 L 690 622 982 176 809 209 648 258 669 321 620 293 489 249 314 389 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 499 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 470 419 L 851 629 884 431 1017 433 858 632 875 641 856 636 849 643 851 634 204 412 ZM 749 347 L 903 326 884 431 470 419 50 188 267 134 ZM 1050 307 L 903 326 947 50 ZM 267 134 L 164 90 473 85 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 582 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 645 186 L 685 158 621 252 597 237 544 295 583 308 350 650 275 420 493 281 504 283 502 275 581 226 480 162 460 58 409 116 308 52 766 50 ZM 275 420 L 50 561 59 511 239 308 ZM 833 387 L 583 308 621 252 ZM 314 224 L 239 308 198 188 ZM 480 162 L 502 275 493 281 314 224 409 116 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 664 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 442 286 L 50 569 340 237 ZM 594 316 L 879 426 597 323 611 361 442 286 456 274 372 244 393 242 466 267 531 220 555 218 ZM 1050 148 L 555 218 552 206 531 220 393 242 351 225 363 209 550 202 520 125 410 155 503 50 ZM 270 192 L 410 155 363 209 316 211 351 225 340 237 284 213 183 218 253 197 90 125 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 686 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 637 650 L 466 447 582 411 ZM 282 235 L 503 211 505 211 923 164 731 270 896 313 582 411 570 358 447 427 466 447 333 488 272 523 268 509 266 511 50 262 207 243 178 117 ZM 505 211 L 503 211 472 203 356 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 593 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 281 139 L 330 141 309 146 744 253 781 337 1003 494 842 475 914 636 50 132 190 136 150 108 ZM 1050 164 L 330 141 648 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 510 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 514 650 L 218 474 195 645 50 516 174 447 118 414 218 340 235 340 224 419 386 330 516 323 478 280 573 228 312 69 788 54 ZM 478 280 L 386 330 235 340 273 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 546 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 380 253 L 515 100 420 281 610 208 443 324 645 350 443 373 610 490 420 417 515 598 380 445 380 650 331 450 236 631 285 434 117 550 253 397 50 421 240 350 50 277 253 302 117 149 285 264 236 66 331 247 380 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 597 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 553 232 L 553 258 573 258 581 244 617 256 914 244 801 322 862 345 615 458 345 650 399 555 211 640 127 278 316 268 50 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 511 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 556 436 L 348 404 510 474 815 541 535 548 136 650 273 492 175 400 322 431 345 404 152 376 50 283 345 404 647 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 503 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 423 650 L 50 473 259 267 297 334 503 50 ZM 420 560 L 433 546 304 348 ZM 335 193 L 259 267 213 180 ZM 213 180 L 133 173 180 122 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 518 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 833 650 L 305 614 162 504 226 466 ZM 305 614 L 345 643 100 599 ZM 162 504 L 78 557 109 464 ZM 780 118 L 352 387 370 423 294 423 226 466 118 433 122 425 125 420 122 420 220 120 279 239 442 50 ZM 122 420 L 122 425 116 431 118 433 109 464 50 420 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 634 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 492 220 L 568 385 652 375 632 446 595 443 689 650 459 435 323 427 320 417 425 404 275 264 267 270 196 69 ZM 320 417 L 50 453 267 270 ZM 191 53 L 196 69 160 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 550 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 375 511 L 58 650 177 253 ZM 412 559 L 375 511 396 502 ZM 437 484 L 396 502 364 386 ZM 567 436 L 668 89 671 89 ZM 311 198 L 364 386 218 189 ZM 218 189 L 50 173 192 153 ZM 668 89 L 192 153 125 64 680 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 592 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 647 615 L 656 650 627 607 ZM 674 625 L 647 615 576 333 ZM 627 607 L 196 432 344 414 445 327 ZM 391 216 L 671 133 445 327 353 186 50 225 567 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 534 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 489 585 L 461 650 429 567 ZM 601 619 L 489 585 492 577 ZM 492 577 L 423 552 376 426 689 109 ZM 137 337 L 274 159 376 426 300 506 352 525 423 552 429 567 283 522 252 555 200 497 77 459 50 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 581 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 357 650 L 281 507 298 501 ZM 281 507 L 54 599 260 466 ZM 139 99 L 127 68 508 104 560 393 298 501 278 453 407 371 313 246 149 124 145 114 120 101 50 50 ZM 120 101 L 149 124 278 453 260 466 50 68 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 585 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 624 344 L 699 325 643 361 705 413 622 438 560 413 539 428 594 447 421 500 186 650 50 466 118 342 94 267 148 287 276 50 ZM 964 579 L 594 447 622 438 ZM 351 359 L 432 389 475 378 306 310 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 576 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 508 78 L 298 87 575 650 50 249 247 87 82 94 83 90 270 71 286 58 291 68 477 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 469 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 442 327 L 561 334 415 400 410 394 406 404 399 418 543 470 439 650 352 429 343 434 362 490 307 449 143 523 107 546 243 401 141 327 163 312 165 312 237 387 279 350 289 354 307 334 334 410 337 414 341 400 312 330 320 320 365 323 385 256 392 250 387 249 578 50 ZM 187 432 L 132 480 134 406 ZM 435 418 L 406 404 415 400 ZM 134 389 L 134 406 76 375 92 364 ZM 134 372 L 101 357 134 333 ZM 89 351 L 101 357 92 364 89 362 50 195 ZM 222 222 L 270 230 251 176 272 230 282 232 340 211 393 232 387 249 320 320 309 320 312 330 307 334 302 319 165 312 163 310 163 312 135 310 135 281 51 194 103 202 89 166 111 204 135 208 135 204 141 208 186 216 120 129 ZM 141 327 L 134 333 135 322 ZM 135 310 L 135 322 117 309 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 408 345 L 394 338 385 389 418 383 466 577 460 596 470 592 477 623 455 610 460 596 441 603 348 553 329 647 320 650 50 448 58 436 114 428 78 408 334 50 ZM 114 428 L 348 553 385 389 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 570 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 209 80 L 97 83 143 132 265 114 337 157 345 103 354 101 359 172 337 157 313 310 324 323 369 299 399 650 50 99 80 83 97 83 92 78 122 62 142 81 157 50 ZM 476 243 L 369 299 359 172 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 568 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 300 585 L 284 591 307 591 401 650 149 599 237 545 ZM 149 599 L 50 581 143 517 ZM 556 502 L 539 500 550 529 601 546 630 575 307 591 300 585 479 516 487 431 ZM 653 509 L 638 558 601 546 556 502 ZM 461 405 L 237 545 227 539 458 402 ZM 373 317 L 363 340 381 325 399 343 143 517 109 50 ZM 573 480 L 522 425 543 408 ZM 496 159 L 499 218 525 209 499 221 500 245 510 251 500 253 502 274 503 273 502 284 503 314 500 306 494 356 504 355 503 314 519 352 553 345 550 349 491 384 491 385 550 349 536 369 527 373 530 378 516 399 506 391 506 381 491 386 487 431 461 405 487 389 486 389 484 388 458 402 399 343 489 283 476 251 487 254 500 253 500 245 483 235 476 231 468 234 399 73 ZM 543 408 L 530 378 536 369 647 326 ZM 666 312 L 647 326 553 345 578 309 509 171 ZM 470 238 L 483 235 473 244 476 251 467 250 381 325 373 317 398 261 447 245 444 245 468 234 ZM 532 314 L 530 313 533 310 ZM 471 228 L 476 231 499 221 499 218 ZM 509 171 L 496 159 496 145 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 566 650 L 212 368 242 347 ZM 258 247 L 323 220 328 232 321 233 328 233 349 276 343 280 353 283 349 276 401 241 409 241 385 295 404 302 422 290 413 306 452 321 458 280 523 330 476 330 552 359 553 356 563 363 577 369 575 372 625 412 553 415 480 553 531 415 467 417 439 403 451 330 400 330 387 355 375 330 270 328 242 347 222 328 160 327 212 368 123 426 152 292 174 283 50 168 ZM 121 431 L 117 431 123 426 ZM 674 406 L 577 369 632 263 594 260 609 209 631 206 ZM 562 331 L 553 356 523 330 ZM 594 260 L 572 331 562 331 588 258 ZM 455 279 L 442 314 425 287 447 271 ZM 451 245 L 426 282 425 286 425 287 422 290 425 286 423 286 426 282 447 245 ZM 458 280 L 455 279 461 261 ZM 467 247 L 461 261 464 247 ZM 588 258 L 467 247 479 219 607 209 ZM 447 245 L 409 241 413 233 401 241 328 233 328 232 417 225 413 233 428 223 460 220 ZM 473 194 L 428 223 417 225 435 185 358 206 436 174 439 174 441 172 479 156 ZM 469 220 L 460 220 471 198 ZM 323 220 L 321 216 358 206 ZM 479 219 L 469 220 490 190 ZM 609 209 L 607 209 616 184 ZM 471 198 L 473 194 476 191 ZM 493 179 L 476 191 501 147 508 144 ZM 490 190 L 493 179 499 177 ZM 499 177 L 527 136 615 99 ZM 441 172 L 436 174 159 121 476 93 ZM 527 136 L 508 144 521 109 501 147 479 156 489 92 560 86 ZM 489 92 L 476 93 495 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 486 199 L 459 227 505 238 521 266 554 249 610 262 573 322 573 293 521 268 558 343 570 330 561 347 577 379 524 410 499 456 502 460 516 515 531 515 518 521 516 515 472 515 495 534 449 559 443 553 465 515 405 511 384 492 301 540 332 437 266 368 236 578 118 650 164 521 171 523 177 516 169 511 182 511 195 497 187 460 233 336 220 324 258 266 289 188 292 192 285 227 301 206 370 293 394 212 419 219 324 171 410 50 ZM 405 511 L 443 553 422 589 324 559 373 511 ZM 220 324 L 112 480 182 441 187 460 169 511 164 521 96 502 50 567 88 187 ZM 531 564 L 495 534 518 521 ZM 583 515 L 531 515 580 486 ZM 465 515 L 472 515 467 510 ZM 419 472 L 467 510 499 456 481 435 ZM 620 465 L 580 486 577 381 ZM 308 378 L 311 379 319 371 ZM 731 289 L 577 379 573 325 589 311 664 312 634 266 ZM 319 371 L 355 352 362 325 ZM 634 266 L 610 262 620 244 ZM 604 223 L 554 249 505 238 486 199 548 137 ZM 620 244 L 604 223 645 201 ZM 324 171 L 301 206 292 192 293 176 289 188 244 133 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 616 347 L 584 650 337 640 466 457 459 436 525 434 436 369 421 322 ZM 337 640 L 331 647 326 638 ZM 326 638 L 195 633 50 270 ZM 358 286 L 408 284 421 322 376 315 386 333 436 369 459 436 242 446 232 358 264 319 275 330 277 327 278 330 277 331 282 337 288 337 291 341 291 344 302 354 302 352 305 357 320 351 306 312 302 305 277 302 264 319 240 299 242 298 202 292 243 291 239 285 243 279 247 288 250 282 247 278 244 278 247 277 246 277 247 274 257 261 270 263 289 288 288 289 289 289 289 288 305 267 270 263 263 254 257 261 233 258 272 139 ZM 232 350 L 232 348 230 348 ZM 645 274 L 408 284 397 246 641 50 ZM 247 277 L 247 278 253 278 254 277 ZM 193 162 L 110 139 173 135 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 435 138 L 450 148 436 152 438 165 428 155 345 180 333 190 330 186 312 191 279 186 286 181 282 170 270 184 233 179 249 211 254 225 243 221 256 226 268 253 296 243 256 226 254 225 303 240 305 240 284 226 302 214 299 208 310 207 302 214 312 237 326 232 344 205 310 207 316 202 310 191 312 191 422 208 434 223 375 242 375 243 396 271 366 261 359 277 375 286 396 272 439 243 445 218 443 212 446 212 445 218 448 239 439 243 432 281 428 282 396 272 408 289 390 296 382 293 386 293 375 286 333 315 333 317 331 317 326 376 329 383 406 467 319 431 293 650 50 507 191 378 71 327 247 261 229 236 225 221 233 215 225 218 201 138 424 50 ZM 180 495 L 267 523 274 584 298 469 274 413 250 403 ZM 298 467 L 306 425 282 415 ZM 316 369 L 317 371 317 369 316 366 ZM 327 299 L 316 313 316 323 306 327 303 330 305 333 316 324 316 357 319 362 329 319 320 322 329 317 330 307 329 299 ZM 420 303 L 462 359 354 309 390 296 ZM 239 319 L 242 326 244 329 251 323 247 315 253 316 251 309 ZM 337 329 L 333 317 343 313 ZM 316 324 L 316 323 320 322 ZM 237 320 L 239 319 236 310 233 309 ZM 477 316 L 420 303 408 289 428 282 431 284 432 281 472 267 ZM 354 309 L 343 313 347 306 ZM 223 310 L 232 309 223 306 ZM 232 309 L 250 307 246 292 225 292 ZM 567 230 L 472 267 465 215 ZM 225 236 L 219 264 219 263 214 247 216 243 225 235 ZM 225 221 L 221 223 218 221 225 218 ZM 462 191 L 466 197 463 197 465 215 446 212 449 198 442 198 438 165 452 180 457 152 ZM 443 212 L 422 208 415 200 442 198 ZM 299 208 L 249 211 293 197 ZM 279 186 L 253 204 270 184 ZM 184 172 L 184 170 188 179 ZM 293 157 L 302 173 315 165 302 148 ZM 457 152 L 456 134 472 78 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 231 585 L 216 650 168 583 ZM 507 593 L 405 649 484 601 477 592 ZM 390 590 L 335 613 347 588 ZM 527 594 L 507 593 512 591 500 552 460 587 470 584 477 592 390 590 417 578 428 582 421 577 539 527 ZM 491 65 L 414 209 400 205 414 210 406 224 438 242 449 223 478 233 472 318 492 306 469 350 466 393 560 402 543 502 414 459 402 482 381 475 396 493 391 503 384 507 389 508 380 525 369 515 364 517 364 532 369 536 375 535 373 539 369 536 364 536 364 532 307 487 299 493 301 490 295 488 297 480 278 464 268 483 295 488 295 491 296 496 267 520 259 500 248 521 362 560 347 588 231 585 243 530 248 521 180 499 259 450 278 464 299 425 304 422 301 421 313 400 306 398 223 394 164 375 158 370 157 372 59 339 365 135 365 192 398 204 375 128 492 50 ZM 168 583 L 50 579 131 529 ZM 421 577 L 417 578 362 560 373 539 ZM 589 537 L 575 546 572 546 562 533 564 532 570 531 ZM 388 534 L 375 535 380 525 ZM 481 527 L 427 531 412 512 ZM 180 499 L 131 529 88 468 ZM 539 527 L 543 502 552 505 602 500 ZM 412 512 L 396 509 405 505 ZM 396 509 L 391 511 393 509 ZM 393 509 L 389 508 391 503 398 500 ZM 259 500 L 268 483 251 479 ZM 400 499 L 398 500 399 498 ZM 408 483 L 399 498 396 493 402 482 ZM 311 473 L 299 475 297 480 307 487 319 477 318 476 331 461 319 457 ZM 683 480 L 697 465 766 430 ZM 230 475 L 251 479 246 466 ZM 371 472 L 381 475 377 469 ZM 326 470 L 327 471 328 470 ZM 331 461 L 337 462 357 446 351 439 ZM 223 394 L 301 421 299 425 259 450 187 393 ZM 431 440 L 434 441 434 440 432 439 ZM 164 375 L 187 393 181 393 178 415 165 411 144 431 157 372 ZM 662 377 L 663 392 589 424 567 405 576 379 596 363 ZM 724 390 L 713 391 714 388 ZM 821 327 L 769 385 734 389 791 318 ZM 697 385 L 693 385 694 384 ZM 158 370 L 159 368 153 367 ZM 501 343 L 500 346 495 342 ZM 866 225 L 791 318 654 278 645 171 ZM 523 141 L 644 170 613 266 556 250 560 263 527 251 517 286 494 273 509 245 478 233 491 65 497 53 ZM 337 186 L 365 194 364 227 392 251 401 233 381 224 371 205 403 222 405 227 406 224 403 222 398 204 365 194 365 192 333 180 ZM 401 233 L 407 236 405 227 ZM 538 190 L 541 201 552 163 ZM 645 171 L 644 170 645 169 ZM 223 150 L 221 149 222 147 ZM 375 128 L 365 135 365 92 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 220 524 L 217 537 227 527 321 555 187 574 178 511 ZM 488 152 L 476 164 487 164 489 161 490 164 504 164 613 94 627 189 546 202 508 241 528 265 506 260 503 246 492 257 506 260 507 268 485 266 509 279 507 268 532 271 564 311 583 321 573 321 578 327 562 397 533 414 534 420 556 424 551 444 544 447 538 448 538 445 524 450 513 451 538 445 534 420 526 419 533 414 517 323 426 326 443 351 415 339 415 335 413 338 415 339 413 354 407 343 390 361 398 422 391 425 374 377 364 387 367 405 357 395 336 416 360 437 284 469 324 479 277 485 275 478 227 527 220 524 228 492 224 493 229 491 237 458 185 445 191 440 154 335 151 335 167 441 185 445 170 460 178 511 54 474 95 309 50 81 118 113 107 79 206 108 298 160 313 161 326 109 363 141 355 161 386 162 393 162 408 142 409 120 417 129 408 142 407 162 445 163 417 129 444 92 445 87 445 91 471 55 ZM 477 517 L 455 494 475 494 ZM 548 508 L 540 494 546 494 ZM 423 492 L 416 494 425 494 439 506 398 496 399 486 412 483 ZM 455 494 L 425 494 423 492 445 483 ZM 489 494 L 475 494 474 474 478 472 ZM 540 494 L 513 494 503 462 514 457 ZM 661 418 L 1050 445 734 494 546 494 538 449 544 447 551 446 551 444 590 431 556 424 562 397 649 347 ZM 381 483 L 360 487 324 479 379 471 ZM 436 476 L 412 483 405 477 432 471 ZM 474 474 L 445 483 436 476 473 465 ZM 405 477 L 400 478 401 472 ZM 401 472 L 396 468 401 468 ZM 511 454 L 501 457 503 462 478 472 473 465 473 457 501 453 501 454 510 452 ZM 375 450 L 396 468 379 471 375 450 360 437 372 433 ZM 471 461 L 432 471 425 464 469 458 ZM 405 442 L 425 464 401 468 403 457 403 456 405 442 400 438 398 422 407 418 ZM 473 457 L 469 458 441 405 468 394 ZM 538 449 L 514 457 511 454 524 450 538 448 ZM 490 421 L 510 452 501 453 490 421 471 392 479 389 ZM 255 372 L 250 383 216 416 214 409 192 439 216 416 224 440 250 383 258 376 259 372 ZM 388 426 L 372 433 367 405 ZM 393 432 L 388 426 391 425 ZM 441 405 L 407 418 413 354 ZM 471 392 L 468 394 467 387 ZM 506 378 L 479 389 470 362 ZM 465 360 L 467 387 443 351 ZM 470 362 L 465 360 463 344 ZM 649 347 L 649 340 728 302 ZM 640 286 L 627 189 898 144 ZM 572 275 L 532 271 528 265 ZM 109 252 L 116 227 112 217 ZM 489 161 L 488 152 500 139 ZM 405 114 L 383 159 363 141 384 89 ZM 326 109 L 294 82 282 109 271 87 279 114 273 128 206 108 179 93 341 50 ZM 409 120 L 405 114 410 102 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 559 256 L 576 232 594 272 662 307 1050 559 742 576 779 646 671 578 375 594 499 365 370 157 ZM 293 599 L 167 608 50 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 509 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 204 611 L 140 650 191 573 ZM 151 177 L 159 195 168 196 183 211 160 198 195 267 226 257 246 277 255 272 106 444 289 323 362 398 334 334 311 310 324 304 322 301 367 272 362 260 369 271 369 270 372 276 378 284 399 277 398 263 399 260 398 258 397 251 402 248 405 252 399 260 407 274 411 273 414 240 444 221 426 267 460 254 507 179 513 174 514 165 522 153 525 166 525 167 589 506 573 500 610 548 538 555 511 496 519 483 502 477 501 475 512 205 444 411 474 468 389 442 391 446 391 449 351 494 383 440 261 402 302 485 447 521 480 584 324 527 344 570 174 477 164 490 157 468 151 464 117 536 98 436 97 435 90 442 90 431 50 409 89 384 68 269 94 281 94 263 71 188 96 191 96 180 51 136 97 163 98 123 ZM 118 549 L 95 579 117 536 ZM 501 475 L 501 477 498 476 500 484 499 516 474 468 498 476 489 452 ZM 502 477 L 508 490 505 498 500 484 501 477 ZM 92 353 L 92 348 85 345 ZM 308 306 L 318 292 322 301 310 309 308 306 303 313 307 311 289 323 285 319 230 340 222 324 277 310 256 286 271 272 ZM 277 310 L 285 319 289 318 283 310 ZM 311 310 L 307 311 310 309 ZM 211 300 L 215 297 204 285 ZM 316 286 L 284 270 304 260 ZM 422 161 L 400 171 386 198 418 197 381 209 403 211 418 204 417 212 403 211 398 214 414 214 417 212 417 213 414 240 402 248 397 241 397 251 369 270 358 249 362 260 356 249 357 249 355 244 354 245 349 238 337 244 347 254 328 281 315 255 337 244 320 228 319 229 320 227 337 211 336 206 334 204 335 204 333 200 332 200 331 199 327 199 328 201 316 201 327 199 323 193 326 190 331 199 333 199 329 186 331 183 337 198 351 196 358 192 408 146 380 182 400 171 426 123 ZM 265 265 L 255 272 263 263 ZM 263 263 L 249 249 253 251 254 248 281 240 ZM 276 204 L 254 248 249 249 226 257 183 211 247 248 196 198 ZM 377 224 L 355 235 358 240 355 243 357 248 358 248 358 247 384 234 379 224 ZM 293 236 L 281 240 291 229 ZM 321 227 L 340 222 349 238 351 237 339 216 ZM 353 236 L 355 235 347 223 ZM 320 227 L 303 233 297 223 305 214 ZM 264 91 L 323 193 316 201 314 201 292 202 279 190 286 202 292 202 296 205 311 207 305 214 296 205 287 204 297 223 291 229 279 204 276 204 276 203 279 203 271 181 168 88 ZM 320 227 L 320 228 321 227 ZM 372 223 L 377 224 398 214 379 212 ZM 519 50 L 514 165 507 179 444 221 454 191 476 178 457 184 467 160 489 128 476 134 509 50 ZM 343 213 L 343 215 352 217 372 211 348 210 ZM 436 202 L 418 213 417 213 417 212 427 200 435 196 430 196 433 192 438 191 ZM 341 208 L 341 210 348 210 354 206 345 205 ZM 329 203 L 331 208 311 207 315 202 ZM 364 199 L 354 206 381 208 386 198 ZM 435 207 L 436 202 439 200 ZM 337 200 L 339 205 345 205 351 199 ZM 427 200 L 418 204 418 197 419 197 430 196 ZM 315 202 L 314 201 316 201 ZM 454 191 L 439 200 448 187 457 184 ZM 358 192 L 351 199 364 199 368 196 380 182 ZM 196 198 L 168 196 151 177 128 132 ZM 467 160 L 448 187 438 191 440 183 433 192 419 197 418 197 422 161 476 134 ZM 406 96 L 331 183 303 114 329 186 326 190 266 91 ZM 441 97 L 426 123 429 97 ZM 429 97 L 406 96 432 66 ZM 266 91 L 264 91 247 62 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 415 378 L 586 650 289 399 329 366 ZM 164 615 L 50 591 157 504 ZM 159 502 L 157 504 156 472 158 472 ZM 587 490 L 592 500 531 486 542 459 ZM 152 398 L 156 472 101 492 95 327 ZM 182 434 L 184 463 158 472 156 403 ZM 234 420 L 236 442 207 465 182 434 181 409 ZM 238 462 L 236 442 240 438 ZM 555 429 L 542 459 489 420 543 405 ZM 379 450 L 414 442 410 420 ZM 257 425 L 240 438 241 422 ZM 287 428 L 278 430 257 425 275 409 ZM 489 420 L 471 426 474 410 ZM 250 301 L 247 346 272 304 427 328 427 335 430 329 491 338 486 344 483 359 514 348 511 342 524 344 523 345 514 348 519 358 510 392 415 378 381 325 329 366 246 356 246 362 241 422 234 420 227 346 244 360 225 332 222 297 ZM 289 399 L 275 409 246 362 ZM 526 344 L 527 344 551 402 543 405 519 358 523 345 526 344 524 344 524 342 ZM 148 134 L 144 131 147 146 148 146 149 153 155 185 149 181 156 403 152 398 141 175 117 158 124 140 140 144 139 128 130 121 146 71 ZM 209 223 L 188 275 200 293 222 296 222 297 200 293 225 332 227 346 181 308 155 185 ZM 596 319 L 527 344 525 339 526 334 532 335 527 332 538 293 ZM 441 134 L 440 146 447 146 442 134 569 178 538 293 536 293 514 315 501 279 496 277 492 301 501 318 507 322 514 315 520 329 527 332 526 334 523 334 525 339 524 342 515 333 507 332 504 325 505 323 501 318 504 325 499 331 434 322 453 291 501 318 461 278 468 264 433 249 266 79 250 299 222 296 199 50 ZM 507 332 L 511 342 491 338 499 331 ZM 434 322 L 430 329 427 328 428 322 ZM 95 327 L 71 297 92 235 ZM 431 279 L 428 322 273 302 325 220 ZM 273 302 L 272 304 250 301 250 299 ZM 461 278 L 453 291 431 279 433 249 ZM 436 209 L 444 209 456 231 483 237 484 237 472 212 444 209 437 196 ZM 108 151 L 117 158 92 235 89 137 100 145 100 137 ZM 171 152 L 148 146 148 134 ZM 127 119 L 130 121 124 140 98 132 98 107 ZM 581 130 L 540 138 549 119 ZM 88 129 L 89 137 71 125 ZM 98 132 L 100 137 95 131 ZM 442 134 L 441 134 441 133 ZM 95 131 L 88 129 88 120 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 425 632 L 421 632 415 650 404 645 411 633 421 632 421 631 ZM 376 52 L 381 113 426 88 448 134 496 139 497 102 502 140 526 142 590 103 553 144 585 147 591 272 571 270 568 277 568 274 570 270 568 270 568 274 553 298 554 294 538 322 542 329 546 328 551 308 568 277 567 318 546 328 544 333 554 355 566 347 567 346 566 450 589 480 566 457 564 570 563 575 496 538 476 518 484 515 486 448 489 451 490 474 488 478 490 480 490 474 500 457 489 451 488 420 487 420 486 448 474 441 486 420 487 420 487 419 486 420 473 426 480 414 448 431 457 434 452 436 414 454 316 354 242 585 258 582 249 609 348 569 407 561 361 641 325 632 322 642 324 632 178 601 176 575 69 632 110 584 50 598 76 417 160 366 159 354 173 353 177 355 181 352 173 353 158 344 158 348 159 354 108 358 147 337 121 324 151 335 158 331 158 339 172 347 182 352 211 334 200 308 246 283 194 229 174 234 200 308 158 331 148 212 82 199 148 209 146 181 137 172 146 172 143 142 280 143 285 140 260 50 ZM 397 625 L 389 634 387 633 386 623 ZM 586 624 L 585 616 649 609 ZM 555 622 L 553 620 555 620 ZM 585 616 L 555 620 563 575 564 576 564 570 567 548 ZM 476 518 L 466 521 496 538 505 547 463 553 445 530 418 541 413 551 438 556 407 561 413 551 401 548 348 569 258 582 280 520 327 496 378 471 375 470 393 460 396 463 414 454 ZM 472 564 L 438 556 463 553 ZM 436 508 L 433 514 431 509 332 532 401 548 418 541 433 514 445 530 466 521 439 507 ZM 491 497 L 491 496 488 496 ZM 73 473 L 170 496 168 469 133 480 108 472 122 462 ZM 378 471 L 421 496 396 463 ZM 480 460 L 477 469 465 460 470 450 ZM 493 441 L 505 443 500 457 504 459 507 443 515 443 515 444 516 443 541 444 538 428 532 423 516 443 515 443 521 420 516 419 508 436 512 418 510 418 ZM 462 443 L 461 445 452 436 ZM 507 443 L 505 443 508 436 ZM 466 438 L 457 434 473 426 ZM 521 420 L 531 422 523 414 ZM 496 416 L 510 418 512 415 512 418 516 419 520 410 518 408 512 414 512 413 517 407 515 406 ZM 534 386 L 537 384 534 384 ZM 555 357 L 556 359 560 354 ZM 567 346 L 567 318 595 307 ZM 644 310 L 644 289 657 282 ZM 644 289 L 595 307 645 244 ZM 369 190 L 398 229 391 237 394 272 418 256 421 259 420 254 569 151 416 209 411 214 385 140 ZM 420 238 L 420 254 418 256 398 229 411 214 ZM 173 234 L 186 222 183 218 166 216 ZM 463 158 L 461 160 466 172 485 152 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 538 638 L 538 650 537 637 ZM 369 412 L 355 419 385 419 392 453 464 432 469 444 393 462 402 518 414 511 408 535 443 552 446 531 455 557 473 554 481 537 481 549 477 553 481 552 481 549 498 532 500 534 487 551 509 548 510 552 481 559 458 565 484 577 451 567 435 571 536 637 534 614 535 617 537 637 425 596 407 578 403 579 408 590 402 588 398 581 398 580 397 580 398 581 397 586 390 582 387 582 387 581 368 574 366 588 332 597 314 581 312 583 331 597 322 599 306 580 287 592 309 602 132 647 263 481 264 481 267 478 278 483 278 481 279 484 282 484 282 478 280 472 295 482 299 481 301 482 301 481 300 480 302 480 306 475 297 466 292 449 321 436 321 453 334 437 357 464 362 462 342 425 339 419 347 419 361 399 369 398 ZM 545 640 L 538 638 538 624 ZM 387 598 L 392 605 397 586 402 588 420 613 408 590 425 596 467 638 366 617 366 588 387 582 ZM 538 624 L 535 617 530 547 540 545 ZM 565 611 L 570 621 548 610 ZM 160 94 L 161 89 163 93 188 87 188 86 189 86 191 78 193 87 229 80 227 73 241 72 247 77 373 53 372 121 435 143 512 102 511 102 511 99 518 99 565 75 520 99 527 100 524 103 514 102 438 144 487 161 490 163 443 198 439 200 440 201 443 198 501 185 494 190 501 188 522 179 502 206 476 243 473 246 420 318 417 310 407 320 416 324 378 377 361 283 304 353 322 388 375 380 369 388 369 384 363 385 368 390 361 399 332 404 331 405 339 419 322 419 329 430 330 431 321 436 320 419 319 419 320 418 320 415 318 409 311 419 285 419 285 422 286 421 287 423 287 426 291 444 285 453 292 449 287 455 297 466 300 480 299 481 273 467 263 481 242 473 249 470 248 469 256 459 227 444 87 611 97 613 81 619 85 611 53 608 117 548 126 531 103 532 128 522 129 524 127 529 182 422 175 418 158 418 159 445 135 424 142 418 129 418 145 416 154 407 68 364 124 198 69 115 64 111 66 111 60 101 68 110 152 95 138 50 ZM 341 619 L 309 602 322 599 ZM 577 615 L 565 611 577 611 ZM 534 614 L 510 552 529 547 ZM 578 611 L 577 611 577 610 ZM 340 604 L 331 597 332 597 ZM 526 599 L 519 595 519 594 ZM 507 581 L 520 589 519 594 494 579 494 577 ZM 166 591 L 165 592 164 582 165 582 ZM 310 577 L 314 581 327 567 ZM 522 570 L 524 570 523 568 ZM 541 317 L 569 351 627 341 626 340 628 341 634 340 633 343 612 389 609 390 540 410 540 543 530 544 520 417 519 417 529 545 509 548 469 444 492 439 498 423 464 432 460 420 385 419 382 405 417 389 381 396 378 380 440 369 425 331 509 293 516 290 533 309 541 287 ZM 530 547 L 529 547 529 545 530 544 ZM 540 545 L 540 543 564 538 ZM 487 523 L 481 537 481 516 ZM 361 469 L 368 476 368 498 365 501 368 501 368 512 371 513 369 515 391 527 395 524 365 468 ZM 321 478 L 322 492 335 498 331 485 326 478 ZM 298 483 L 299 484 300 483 ZM 321 473 L 322 473 321 472 ZM 310 468 L 315 463 311 458 ZM 606 415 L 595 462 592 412 598 404 ZM 157 461 L 155 461 156 458 ZM 150 453 L 148 453 150 452 ZM 319 419 L 292 449 291 444 311 419 ZM 334 437 L 330 431 341 425 ZM 157 414 L 164 412 157 409 ZM 382 405 L 380 406 380 403 374 397 381 396 ZM 369 391 L 368 390 369 388 ZM 378 380 L 375 380 378 377 ZM 53 350 L 50 350 53 348 ZM 645 342 L 625 325 632 219 636 214 ZM 425 331 L 416 324 420 318 ZM 599 326 L 599 328 594 325 594 324 ZM 243 266 L 249 290 253 281 245 262 ZM 540 168 L 542 169 541 279 544 278 541 287 541 279 516 290 476 243 503 212 540 171 522 179 537 158 ZM 586 180 L 589 175 597 186 595 188 633 201 632 219 619 233 625 241 605 251 584 274 583 274 579 261 544 278 578 168 ZM 371 214 L 350 219 323 256 323 251 343 221 276 236 278 233 272 237 271 237 264 233 258 240 245 244 249 253 242 257 245 262 250 254 258 271 275 239 317 266 334 258 322 268 348 269 371 252 371 243 387 235 381 218 371 228 371 214 379 212 372 193 ZM 371 243 L 334 258 371 228 ZM 250 254 L 249 253 252 250 ZM 275 239 L 271 237 272 237 276 236 ZM 229 215 L 230 218 236 216 228 211 ZM 644 205 L 636 214 635 202 ZM 635 202 L 633 201 634 191 ZM 125 193 L 138 157 70 115 ZM 634 191 L 633 176 635 174 ZM 575 116 L 595 114 578 168 556 132 569 115 575 111 ZM 493 166 L 490 163 494 160 ZM 502 155 L 494 160 497 153 ZM 577 103 L 569 115 567 116 547 118 549 120 556 132 537 158 533 133 525 138 542 125 542 118 531 119 530 112 547 101 ZM 503 155 L 502 155 503 153 ZM 503 153 L 504 148 525 138 ZM 640 107 L 629 123 628 110 595 114 598 104 ZM 598 104 L 577 103 615 52 ZM 224 63 L 227 73 210 74 212 62 ZM 279 68 L 254 71 253 67 253 71 241 72 232 64 ZM 452 68 L 449 68 452 64 ZM 232 64 L 224 63 222 55 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:0.50; stroke-width:1.00;"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 328 251 L 520 307 1050 118 702 316 625 337 648 347 454 456 50 477 344 372 113 69 431 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 479 B |
@@ -0,0 +1,6 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 186 602 L 168 650 186 602 ZM 600 637 L 506 617 186 602 188 599 248 600 392 528 ZM 410 159 L 497 151 492 157 508 150 497 151 528 108 538 109 520 145 589 113 538 109 560 66 635 67 610 114 606 114 604 114 561 182 585 162 572 186 560 200 556 192 540 218 582 219 517 288 497 285 486 305 468 292 451 335 476 319 463 342 465 343 464 344 462 343 457 352 457 352 456 353 430 395 430 397 469 358 457 352 464 344 476 350 479 347 508 356 513 369 576 403 574 405 516 379 542 455 488 481 540 557 476 521 461 495 444 503 424 492 362 512 349 506 346 506 348 506 339 500 337 505 332 505 330 497 331 496 330 496 330 497 317 502 300 496 306 483 294 477 290 466 229 495 220 520 247 520 285 514 270 520 337 521 219 559 212 542 210 543 211 541 210 540 209 543 69 596 68 596 69 596 50 604 166 530 203 526 200 520 217 520 226 497 202 508 197 511 177 468 212 395 176 387 155 426 133 377 56 360 112 334 79 264 79 263 63 246 80 253 81 244 66 219 236 271 233 278 242 273 254 277 251 273 259 279 266 281 278 256 284 254 286 259 278 284 285 286 286 278 297 283 301 292 308 294 306 300 340 378 350 385 358 368 356 366 360 363 361 361 363 360 325 299 356 309 325 252 325 252 326 248 372 313 377 315 367 215 367 215 367 215 362 156 402 56 ZM 187 599 L 186 602 69 596 69 596 ZM 188 599 L 187 599 209 543 210 543 ZM 359 584 L 360 586 361 584 ZM 112 519 L 110 554 112 519 ZM 184 520 L 166 530 145 533 152 519 ZM 407 521 L 392 528 378 521 ZM 476 521 L 476 522 407 521 444 503 ZM 378 521 L 337 521 362 512 ZM 200 520 L 184 520 197 511 ZM 163 450 L 165 444 177 468 152 519 112 519 113 509 147 443 ZM 112 519 L 107 519 112 511 ZM 324 504 L 332 505 333 507 335 507 337 505 346 506 285 514 317 502 ZM 117 443 L 113 509 112 511 115 441 ZM 226 447 L 224 447 223 461 217 476 234 465 237 465 238 463 243 461 241 465 245 465 252 459 254 460 256 458 253 459 254 457 257 458 259 456 257 455 254 457 250 456 277 440 263 409 245 455 243 454 260 407 241 402 ZM 238 472 L 236 476 238 476 249 465 245 465 ZM 104 473 L 100 475 104 471 ZM 234 449 L 234 451 243 454 238 463 234 465 221 466 223 461 226 447 ZM 276 463 L 289 466 288 464 277 461 ZM 630 465 L 629 463 636 463 ZM 250 456 L 243 461 245 455 ZM 260 459 L 261 458 258 458 ZM 167 432 L 168 433 168 432 170 433 172 433 170 434 170 437 168 433 165 444 157 429 ZM 154 429 L 147 443 145 442 152 428 ZM 115 427 L 115 441 51 395 ZM 157 429 L 154 429 155 426 ZM 360 363 L 358 368 375 381 358 391 376 403 383 395 383 393 378 384 381 386 377 379 376 380 363 360 ZM 378 384 L 375 381 376 380 ZM 381 377 L 382 379 382 376 ZM 584 360 L 577 361 578 359 ZM 505 320 L 479 347 465 343 494 312 ZM 451 337 L 457 340 451 336 ZM 492 311 L 476 319 486 305 ZM 494 312 L 492 311 501 305 ZM 525 291 L 501 305 517 288 ZM 362 156 L 359 165 308 170 367 215 333 231 326 248 319 237 317 238 325 252 315 250 322 261 319 265 295 252 313 281 310 288 321 293 325 299 308 294 310 288 297 283 286 259 289 252 284 254 282 249 278 256 242 273 236 271 253 239 280 244 266 214 267 213 266 213 256 189 262 172 251 181 245 165 277 146 280 149 266 162 262 172 284 152 295 159 318 116 341 95 329 94 340 74 355 69 ZM 658 257 L 636 278 633 250 ZM 420 270 L 446 276 419 254 ZM 298 248 L 311 250 319 265 312 250 315 250 310 243 ZM 633 250 L 616 246 631 231 ZM 256 189 L 248 212 245 213 266 213 266 214 253 239 100 210 216 212 251 181 ZM 631 231 L 629 217 664 199 ZM 570 218 L 562 204 572 186 614 140 ZM 280 61 L 273 62 265 82 318 81 285 91 204 86 207 78 203 78 197 79 203 86 204 86 192 123 221 113 245 165 187 198 172 180 164 202 97 154 139 140 81 70 131 73 129 84 178 84 181 83 170 76 195 77 197 79 200 78 203 78 251 68 253 60 ZM 594 199 L 586 198 605 184 ZM 274 173 L 281 187 289 172 ZM 618 132 L 585 162 610 114 629 114 ZM 253 158 L 251 158 252 159 245 159 251 158 248 154 250 153 ZM 329 94 L 318 116 285 145 290 148 284 152 280 149 285 145 282 142 277 146 230 110 285 91 ZM 614 140 L 618 132 634 118 ZM 103 122 L 102 122 94 107 ZM 155 99 L 148 94 153 100 149 101 154 101 175 122 172 91 ZM 122 114 L 126 113 123 110 ZM 230 110 L 221 113 215 99 ZM 213 104 L 202 97 208 97 ZM 600 104 L 605 101 601 101 ZM 605 101 L 614 102 620 94 ZM 593 89 L 591 101 601 101 610 84 ZM 176 89 L 181 97 180 87 ZM 588 91 L 593 89 594 81 ZM 181 83 L 182 84 187 84 194 81 ZM 251 68 L 247 83 259 82 273 62 ZM 329 81 L 318 81 329 77 ZM 236 60 L 200 78 195 77 179 59 ZM 346 61 L 340 74 329 77 328 61 ZM 170 76 L 131 73 136 54 ZM 374 62 L 355 69 354 62 ZM 560 66 L 559 66 561 62 ZM 377 62 L 374 62 379 60 ZM 388 62 L 387 62 386 58 396 55 ZM 354 62 L 346 61 353 50 ZM 328 61 L 280 61 328 51 ZM 253 60 L 236 60 257 51 ZM 386 58 L 379 60 384 56 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 1050 307 L 1010 305 985 274 900 295 564 265 615 342 50 438 527 263 71 223 926 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 472 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 510 139 L 333 328 688 246 730 260 720 211 1050 120 695 557 720 298 316 372 288 410 239 438 244 396 50 449 319 50 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 50 50 L 650 50 650 650 50 650 ZM 250 250 L 250 450 450 450 450 250 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:0.50; stroke-width:1.00;"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 321 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="1100px" height="700px" viewBox="0 0 1100 700" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 603 50 L 738 230 754 165 887 191 748 421 840 650 435 410 50 605 ZM 644 281 L 717 347 736 261 Z"
|
||||
style="fill:#000099; fill-opacity:0.13; fill-rule:nonzero; stroke:#000033; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
<path d=""
|
||||
style="fill:#009900; fill-opacity:0.13; fill-rule:nonzero; stroke:#003300; stroke-opacity:1.00; stroke-width:1.00;"/>
|
||||
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 484 B |
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="300px"
|
||||
height="300px"
|
||||
viewBox="0 0 600 600"
|
||||
version="1.1">
|
||||
<path d="M588.3,259.7 L586.2,269.2, 572.4,287.2, 552.2,303.1, 534.2,310.6, 523.6,310.6, 517.3,308.4, 508.8,304.2, 496.1,300.5, 487.6,303.1, 480.2,315.9, 466.4,357.2, 452.6,408.1, 445.2,432.5, 434.6,452.6, 416.6,470.6, 392.2,487.6, 374.2,504.5, 369.9,514.1, 372.0,524.7, 377.3,531.0, 383.7,534.2, 401.7,535.3, 420.8,531.0, 437.8,523.6, 461.1,506.7, 483.3,481.2, 523.6,418.7, 553.3,369.9, 561.8,363.0, 568.1,364.1, 571.3,367.8, 573.4,386.9, 569.2,407.0, 548.0,450.5, 520.4,490.8, 496.1,522.6, 484.4,535.3, 466.4,546.9, 422.9,568.1, 377.3,583.0, 342.4,589.3, 306.3,588.3, 269.2,584.0, 234.2,576.6, 201.4,562.8, 169.6,539.5, 143.1,510.9, 94.3,448.4, 53.0,410.2, 33.9,390.1, 21.2,366.7, 10.6,327.5, 10.6,309.5, 14.8,303.1, 21.2,298.9, 29.6,300, 36.0,305.3, 43.4,325.4, 49.8,350.8, 59.3,371.0, 92.2,410.2, 110.2,422.9, 119.7,424.0, 127.2,419.7, 136.7,404.9, 134.6,389.0, 124.0,372.0, 108.1,353.0, 69.9,314.8, 55.1,295.7, 44.5,275.6, 37.1,254.4, 36.0,244.8, 41.3,238.5, 48.7,238.5, 55.1,243.8, 64.6,266.0, 75.2,286.2, 81.6,291.5, 87.9,291.5, 93.2,286.2, 95.4,280.9, 92.2,266.0, 68.9,231.0, 45.5,195.0, 42.4,181.2, 44.5,174.9, 49.8,170.6, 59.3,168.5, 66.7,171.7, 80.5,188.6, 102.8,236.3, 111.3,256.5, 115.5,278.7, 126.1,323.3, 163.2,418.7, 170.6,446.2, 178.0,477.0, 188.6,501.4, 197.1,506.7, 206.7,505.6, 217.3,500.3, 224.7,493.9, 230.0,474.9, 225.7,450.5, 215.1,422.9, 172.7,333.9, 164.3,306.3, 154.7,281.9, 140.9,255.4, 111.3,201.4, 100.7,177.0, 95.4,153.7, 98.5,135.6, 103.8,128.2, 113.4,121.9, 124.0,120.8, 133.5,127.2, 140.9,140.9, 144.1,161.1, 147.3,196.1, 153.7,235.3, 160.0,251.2, 167.4,265.0, 178.0,272.4, 191.8,273.4, 203.5,268.1, 210.9,256.5, 213.0,241.6, 212.0,223.6, 196.1,129.3, 188.6,109.1, 169.6,67.8, 162.1,49.8, 160.0,32.8, 164.3,21.2, 174.9,13.7, 186.5,14.8, 193.9,24.3, 202.4,63.6, 209.8,104.9, 218.3,118.7, 231.0,124.0, 239.5,120.8, 244.8,111.3, 255.4,59.3, 260.7,53.0, 269.2,51.9, 281.9,60.4, 286.2,74.2, 285.1,92.2, 278.7,112.3, 259.7,156.8, 246.9,198.2, 232.1,259.7, 225.7,291.5, 222.6,322.2, 220.4,373.1, 224.7,395.4, 230.0,401.7, 238.5,406.0, 246.9,404.9, 253.3,400.7, 262.8,382.6, 274.5,338.1, 281.9,306.3, 286.2,273.4, 293.6,208.8, 311.6,128.2, 310.6,101.7, 306.3,72.0, 306.3,47.7, 310.6,39.2, 320.1,33.9, 333.9,33.9, 341.3,39.2, 345.5,47.7, 346.6,58.3, 346.6,82.6, 348.7,92.2, 355.1,98.5, 366.7,101.7, 379.5,97.5, 387.9,87.9, 392.2,75.2, 397.5,42.4, 400.7,27.5, 406.0,15.9, 417.6,10.6, 434.6,11.6, 442.0,16.9, 445.2,25.4, 440.9,50.8, 430.3,79.5, 424.0,107.0, 419.7,157.9, 422.9,179.1, 428.2,186.5, 435.6,190.8, 444.1,190.8, 450.5,186.5, 460.0,171.7, 466.4,149.4, 474.9,97.5, 481.2,76.3, 489.7,62.5, 496.1,60.4, 504.5,60.9, 516.2,67.8, 521.5,79.5, 521.5,94.3, 518.3,111.3, 506.7,148.4, 491.8,181.2, 479.1,197.1, 460.0,210.9, 446.2,223.6, 444.1,231.0, 446.2,237.4, 451.5,242.7, 459.0,244.8, 477.0,239.5, 513.0,217.3, 527.9,200.3, 540.6,177.0, 553.3,160.0, 559.7,157.9, 567.1,159.0, 572.4,164.3, 574.5,171.7, 570.3,184.4, 517.3,252.2, 512.0,268.1, 513.0,275.6, 517.3,281.9, 524.7,284.0, 533.2,280.9, 552.2,266.0, 571.3,250.1, 578.7,249.1, 584.6,251.7Z M301.0,355.1 L285.1,401.7, 271.3,438.8, 265.0,470.6, 269.2,479.1, 279.8,485.5, 294.7,486.5, 306.3,484.4, 321.2,472.7, 331.8,457.9, 338.1,438.8, 342.4,418.7, 347.7,375.2, 356.1,333.9, 381.6,283.0, 392.2,256.5, 398.5,230.0, 401.7,205.6, 401.7,179.1, 396.4,156.8, 390.1,148.4, 381.6,143.1, 367.8,143.1, 356.1,151.5, 336.0,178.0, 324.3,204.5, 320.1,234.2, 315.9,294.7Z M395.4,308.4 L385.8,328.6, 375.2,373.1, 358.3,426.1, 356.1,450.5, 359.3,459.0, 367.8,463.2, 392.2,459.0, 410.2,448.4, 421.9,431.4, 430.3,411.3, 439.9,363.6, 446.2,339.2, 454.7,316.9, 463.2,298.9, 464.3,287.2, 460.0,279.8, 452.6,276.6, 431.4,279.8, 411.3,290.4Z" style="fill:#000033;fill-opacity:0.25;fill-rule:evenodd;stroke:#000033;stroke-width:1.2;stroke-opacity:1"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,174 @@
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
#include "clipper2/clipper.h"
|
||||
#include "clipper2/clipper.core.h"
|
||||
#include "../../Utils/clipper.svg.h"
|
||||
#include "../../Utils/clipper.svg.utils.h"
|
||||
#include "clipper2/clipper.triangulation.h"
|
||||
|
||||
using namespace Clipper2Lib;
|
||||
using namespace std;
|
||||
|
||||
void System(const std::string& filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
system(filename.c_str());
|
||||
#else
|
||||
system(("firefox " + filename).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static PathD MakeRandomPoly(unsigned vertCnt, int width, int height)
|
||||
{
|
||||
PathD result;
|
||||
result.reserve(vertCnt);
|
||||
for (unsigned i = 0; i < vertCnt; ++i)
|
||||
result.push_back(PointD(rand() % width, rand() % height));
|
||||
return result;
|
||||
}
|
||||
|
||||
static PathsD MakeRandomPolys(unsigned polyCount, unsigned vertCnt, int width, int height)
|
||||
{
|
||||
PathsD result;
|
||||
result.reserve(polyCount);
|
||||
result.push_back(MakeRandomPoly(vertCnt, width, height));
|
||||
return result;
|
||||
}
|
||||
|
||||
static string TriangulateResultAsString(TriangulateResult tr)
|
||||
{
|
||||
switch (tr)
|
||||
{
|
||||
case TriangulateResult::fail: return "Fail!";
|
||||
case TriangulateResult::no_polygons: return "Paths are not polygons!";
|
||||
case TriangulateResult::paths_intersect: return "Paths intersect!";
|
||||
default: return "Success!";
|
||||
}
|
||||
}
|
||||
|
||||
static void DisplaySolution(const string filename, const PathsD& sol, bool multicolor)
|
||||
{
|
||||
SvgWriter svg;
|
||||
//SvgAddSubject(svg, sub, FillRule::NonZero);
|
||||
if (multicolor)
|
||||
SvgAddRCSolution(svg, sol, FillRule::NonZero, false);
|
||||
else
|
||||
SvgAddSolution(svg, sol, FillRule::NonZero, false);
|
||||
SvgSaveToFile(svg, filename, 400, 400, 0);
|
||||
System(filename);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// main
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class Test { single_test, range_test, random, sample_1, sample_2, sample_3};
|
||||
|
||||
int main()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
Test t = Test::sample_1; //Test::random; //Test::single_test; //Test::range_test; //Test::clipper; //
|
||||
int minRange = 44, maxRange = 52;
|
||||
bool doDelaunay = true;
|
||||
bool multicolor = true;
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
TriangulateResult tr;
|
||||
PathsD subject, sol;
|
||||
string folder = ".\\TriSamples\\";
|
||||
srand((unsigned)time(0));
|
||||
|
||||
switch (t)
|
||||
{
|
||||
|
||||
case Test::single_test:
|
||||
{
|
||||
string filename = "Test" + to_string(maxRange) + ".svg";
|
||||
if (!FileExists(folder + filename)) break;
|
||||
SvgReader sr = SvgReader(folder + filename);
|
||||
PathsD subject = sr.paths, sol;
|
||||
Triangulate(subject, 0, sol, doDelaunay);
|
||||
DisplaySolution(filename, sol, multicolor);
|
||||
break;
|
||||
}
|
||||
|
||||
case Test::range_test:
|
||||
{
|
||||
for (int i = minRange; i <= maxRange; ++i)
|
||||
{
|
||||
string filename = "Test" + to_string(i) + ".svg";
|
||||
if (!FileExists(folder + filename)) break;
|
||||
SvgReader sr = SvgReader(folder + filename);
|
||||
PathsD subject = sr.paths, sol;
|
||||
tr = Triangulate(subject, 0, sol, doDelaunay);
|
||||
switch (tr)
|
||||
{
|
||||
case TriangulateResult::success:
|
||||
case TriangulateResult::fail:
|
||||
{
|
||||
std::cout << i << " " << TriangulateResultAsString(tr) << endl;
|
||||
DisplaySolution(filename, sol, multicolor);
|
||||
break; // break inner case
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
if (tr != TriangulateResult::success) break; // break for() loop
|
||||
}
|
||||
break; // break case Test::range_test
|
||||
}
|
||||
|
||||
case Test::random:
|
||||
{
|
||||
subject = MakeRandomPolys(1, 25, 800, 600);
|
||||
// The Triangulate function below only accepts **non-intersecting** paths, so ...
|
||||
subject = Union(subject, FillRule::NonZero);
|
||||
//std::cout << subject << endl;
|
||||
tr = Triangulate(subject, 0, sol, doDelaunay);
|
||||
DisplaySolution("random.svg", sol, multicolor);
|
||||
break;
|
||||
}
|
||||
|
||||
case Test::sample_1:
|
||||
{
|
||||
SvgReader sr = SvgReader(folder + "coral3.svg");
|
||||
PathsD subject = sr.paths;
|
||||
Triangulate(subject, 0, sol, true);
|
||||
DisplaySolution("coral3_t.svg", sol, multicolor);
|
||||
break;
|
||||
}
|
||||
|
||||
case Test::sample_2:
|
||||
{
|
||||
SvgReader sr = SvgReader("rabbit.svg");
|
||||
PathsD subject = sr.paths;
|
||||
Triangulate(subject, 0, sol, true);
|
||||
DisplaySolution("rabbit_t.svg", sol, multicolor);
|
||||
break;
|
||||
}
|
||||
|
||||
case Test::sample_3:
|
||||
{
|
||||
PathsD subject = { MakePathD({
|
||||
44.1,114.0, 11.9,114.0, 13.9,72.9, 0.0,59.9, 0.0,53.2, 12.2,41.0, 16.8,41.0, 10.1,37.2, 8.0,19.9,
|
||||
11.3,6.7, 20.0,1.9, 20.0,0.0, 34.6,0.0, 44.9,6.8, 48.0,29.1, 45.7,37.3, 39.2,41.0, 43.8,41.0,
|
||||
56.0,53.2, 56.0,59.9, 42.0,72.9
|
||||
}) };
|
||||
Triangulate(subject, 0, sol, true);
|
||||
DisplaySolution("sample3.svg", sol, multicolor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//#ifdef _DEBUG
|
||||
PathD* p = new PathD();
|
||||
std::cout << "Press Enter to continue" << std::endl;
|
||||
std::string s;
|
||||
std::getline(std::cin, s);
|
||||
//#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include "clipper2/clipper.h"
|
||||
#include "clipper2/clipper.core.h"
|
||||
#include "clipper2/clipper.engine.h"
|
||||
#include "clipper2/clipper.triangulation.h"
|
||||
#include "../../Utils/clipper.svg.h"
|
||||
#include "../../Utils/clipper.svg.utils.h"
|
||||
|
||||
@@ -9,8 +16,9 @@ using namespace Clipper2Lib;
|
||||
|
||||
|
||||
void System(const std::string &filename);
|
||||
void TestingZ_Int64();
|
||||
void TestingZ_Double();
|
||||
void Test1_64();
|
||||
void Test1_Double();
|
||||
void Test2_Double();
|
||||
|
||||
// use the Z callback to flag intersections by setting z = 1;
|
||||
|
||||
@@ -34,11 +42,77 @@ public:
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
//TestingZ_Int64();
|
||||
TestingZ_Double();
|
||||
Test1_64();
|
||||
Test1_Double();
|
||||
Test2_Double();
|
||||
}
|
||||
|
||||
void TestingZ_Int64()
|
||||
static uint32_t ByteToRainbowColor(uint8_t b)
|
||||
{
|
||||
uint8_t b2;
|
||||
switch (b / 43)
|
||||
{
|
||||
//0..42
|
||||
case 0: b2 = (b - 0) * 6; return 0xFFFF0000 | (b2 << 8); // 0xFFFF0000 -> 0xFFFFFF00 (red..yellow)
|
||||
//43..85
|
||||
case 1: b2 = (85 - b) * 6; return 0xFF00FF00 | (b2 << 16); // 0xFFFFFF00 -> 0xFF00FF00 (yellow..lime)
|
||||
//86..128
|
||||
case 2: b2 = (b - 86) * 6; return 0xFF00FF00 | b2; // 0xFF00FF00 -> 0xFF00FFFF (lime..aqua)
|
||||
//129..171
|
||||
case 3: b2 = (171 - b) * 6; return 0xFF0000FF | (b2 << 8); // 0xFF00FFFF -> 0xFF0000FF (aqua..blue)
|
||||
//172..214
|
||||
case 4: b2 = (b - 172) * 6; return 0xFF0000FF | (b2 << 16); // 0xFF0000FF -> 0xFFFF00FF (blue..fuschia)
|
||||
//215..255
|
||||
default: b2 = (255 - b) * 6; return 0xFFFF0000 | b2; // 0xFF0000FF -> 0xFFFF00FF (fuschia..red)
|
||||
}
|
||||
}
|
||||
|
||||
static void DisplayAsSvg(const string& filename,
|
||||
const Paths64* subject, const Paths64* clip, const Paths64* solution)
|
||||
{
|
||||
SvgWriter svg;
|
||||
if (subject)
|
||||
SvgAddSubject(svg, *subject, FillRule::NonZero);
|
||||
if (clip)
|
||||
SvgAddClip(svg, *clip, FillRule::NonZero);
|
||||
if (solution)
|
||||
SvgAddSolution(svg, *solution, FillRule::NonZero, false);
|
||||
SvgSaveToFile(svg, filename, 320, 320, 0);
|
||||
System(filename);
|
||||
}
|
||||
|
||||
static void DisplayAsSvg(const string& filename,
|
||||
const PathsD* subject, const PathsD* clip, const PathsD* solution, bool multi_color = false)
|
||||
{
|
||||
SvgWriter svg;
|
||||
if (subject)
|
||||
SvgAddSubject(svg, *subject, FillRule::NonZero);
|
||||
if (clip)
|
||||
SvgAddClip(svg, *clip, FillRule::NonZero);
|
||||
if (solution)
|
||||
{
|
||||
if (multi_color)
|
||||
{
|
||||
#ifdef USINGZ
|
||||
for (const PathD& path : *solution)
|
||||
{
|
||||
// set color using the average 'z' for each triangle
|
||||
uint8_t d = (path.size() == 3) ? (path[0].z + path[1].z + path[2].z) / 3.0 : 128;
|
||||
svg.AddPath(path, false, FillRule::NonZero, ByteToRainbowColor(d), 0x80808080, 0.8, false);
|
||||
}
|
||||
#else
|
||||
// just set a random color
|
||||
SvgAddRCSolution(svg, *solution, FillRule::NonZero, false);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
SvgAddSolution(svg, *solution, FillRule::NonZero, false);
|
||||
}
|
||||
SvgSaveToFile(svg, filename, 320, 320, 0);
|
||||
System(filename);
|
||||
}
|
||||
|
||||
void Test1_64()
|
||||
{
|
||||
|
||||
Paths64 subject, solution;
|
||||
@@ -53,24 +127,21 @@ void TestingZ_Int64()
|
||||
std::placeholders::_4, std::placeholders::_5));
|
||||
c64.Execute(ClipType::Union, FillRule::NonZero, solution);
|
||||
|
||||
SvgWriter svg;
|
||||
SvgAddSolution(svg, solution, FillRule::NonZero, false);
|
||||
if (solution.size() > 0) {
|
||||
Paths64 ellipses;
|
||||
if (solution.size() > 0)
|
||||
{
|
||||
// draw circles around intersection points - flagged by z == 1
|
||||
PathsD ellipses;
|
||||
double r = 3.0;
|
||||
for (const Point64& pt : solution[0])
|
||||
if (pt.z == 1)
|
||||
{
|
||||
ellipses.push_back(Ellipse(RectD(pt.x - r, pt.y - r, pt.x + r, pt.y + r), 11));
|
||||
ellipses.push_back(Ellipse(Rect64(pt.x - r, pt.y - r, pt.x + r, pt.y + r), 11));
|
||||
}
|
||||
SvgAddClip(svg, ellipses, FillRule::NonZero);
|
||||
}
|
||||
SvgSaveToFile(svg, "usingz_int64.svg", 800, 600, 20);
|
||||
System("usingz_int64.svg");
|
||||
DisplayAsSvg("TestingZ1_64.svg", &subject, &ellipses, &solution);
|
||||
}
|
||||
|
||||
void TestingZ_Double()
|
||||
void Test1_Double()
|
||||
{
|
||||
PathsD subject, solution;
|
||||
MyClass mc;
|
||||
@@ -84,22 +155,33 @@ void TestingZ_Double()
|
||||
std::placeholders::_4, std::placeholders::_5));
|
||||
c.Execute(ClipType::Union, FillRule::NonZero, solution);
|
||||
|
||||
SvgWriter svg;
|
||||
SvgAddSubject(svg, subject, FillRule::NonZero);
|
||||
if (solution.size() > 0)
|
||||
PathsD ellipses;
|
||||
if (solution.size() > 0)
|
||||
{
|
||||
// draw circles around intersection points
|
||||
PathsD ellipses;
|
||||
double r = 3.0;
|
||||
for (const PointD& pt : solution[0])
|
||||
if (pt.z == 1)
|
||||
ellipses.push_back(Ellipse(RectD(pt.x - r, pt.y - r,
|
||||
ellipses.push_back(Ellipse(RectD(pt.x - r, pt.y - r,
|
||||
pt.x + r, pt.y + r), 11));
|
||||
|
||||
SvgAddSolution(svg, ellipses, FillRule::NonZero, false);
|
||||
}
|
||||
SvgSaveToFile(svg, "usingz_double.svg", 320, 320, 0);
|
||||
System("usingz_double.svg");
|
||||
DisplayAsSvg("TestingZ1_D.svg", &subject, &ellipses, &solution, false);
|
||||
}
|
||||
|
||||
void Test2_Double()
|
||||
{
|
||||
SvgReader sr = SvgReader(".\\TriSamples\\coral3.svg");
|
||||
PathsD subject = sr.paths, sol;
|
||||
RectD r = GetBounds(subject);
|
||||
PointD mp = r.MidPoint();
|
||||
double d = (mp.y - r.top) / 255;
|
||||
// for each point in subject, set its 'z' as a
|
||||
// relative distance fron 'mp' (scaled to 255)
|
||||
for (PathD& path : subject)
|
||||
for (PointD& pt : path)
|
||||
pt.z = Distance(pt, mp) / d;
|
||||
Triangulate(subject, 0, sol, true);
|
||||
DisplayAsSvg("coral3_t2.svg", nullptr, nullptr, &sol, true);
|
||||
}
|
||||
|
||||
void System(const std::string &filename)
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "clipper2/clipper.h"
|
||||
|
||||
TEST(Clipper2Tests, TestCarryCalculation) {
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x51eaed81157de061, 0x3a271fb2745b6fe9).carry, 0x129bbebdfae0464e);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x3a271fb2745b6fe9, 0x51eaed81157de061).carry, 0x129bbebdfae0464e);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0xc2055706a62883fa, 0x26c78bc79c2322cc).carry, 0x1d640701d192519b);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x26c78bc79c2322cc, 0xc2055706a62883fa).carry, 0x1d640701d192519b);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x874ddae32094b0de, 0x9b1559a06fdf83e0).carry, 0x51f76c49563e5bfe);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x9b1559a06fdf83e0, 0x874ddae32094b0de).carry, 0x51f76c49563e5bfe);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x81fb3ad3636ca900, 0x239c000a982a8da4).carry, 0x12148e28207b83a3);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x239c000a982a8da4, 0x81fb3ad3636ca900).carry, 0x12148e28207b83a3);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x4be0b4c5d2725c44, 0x990cd6db34a04c30).carry, 0x2d5d1a4183fd6165);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x990cd6db34a04c30, 0x4be0b4c5d2725c44).carry, 0x2d5d1a4183fd6165);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x978ec0c0433c01f6, 0x2df03d097966b536).carry, 0x1b3251d91fe272a5);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x2df03d097966b536, 0x978ec0c0433c01f6).carry, 0x1b3251d91fe272a5);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x49c5cbbcfd716344, 0xc489e3b34b007ad3).carry, 0x38a32c74c8c191a4);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0xc489e3b34b007ad3, 0x49c5cbbcfd716344).carry, 0x38a32c74c8c191a4);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0xd3361cdbeed655d5, 0x1240da41e324953a).carry, 0x0f0f4fa11e7e8f2a);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x1240da41e324953a, 0xd3361cdbeed655d5).carry, 0x0f0f4fa11e7e8f2a);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x51b854f8e71b0ae0, 0x6f8d438aae530af5).carry, 0x239c04ee3c8cc248);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0x6f8d438aae530af5, 0x51b854f8e71b0ae0).carry, 0x239c04ee3c8cc248);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0xbbecf7dbc6147480, 0xbb0f73d0f82e2236).carry, 0x895170f4e9a216a7);
|
||||
EXPECT_EQ(Clipper2Lib::Multiply(0xbb0f73d0f82e2236, 0xbbecf7dbc6147480).carry, 0x895170f4e9a216a7);
|
||||
TEST(Clipper2Tests, TesthiCalculation) {
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x51eaed81157de061, 0x3a271fb2745b6fe9).hi, 0x129bbebdfae0464e);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x3a271fb2745b6fe9, 0x51eaed81157de061).hi, 0x129bbebdfae0464e);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0xc2055706a62883fa, 0x26c78bc79c2322cc).hi, 0x1d640701d192519b);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0xc2055706a62883fa, 0x26c78bc79c2322cc).hi, 0x1d640701d192519b);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x26c78bc79c2322cc, 0xc2055706a62883fa).hi, 0x1d640701d192519b);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x874ddae32094b0de, 0x9b1559a06fdf83e0).hi, 0x51f76c49563e5bfe);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x9b1559a06fdf83e0, 0x874ddae32094b0de).hi, 0x51f76c49563e5bfe);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x81fb3ad3636ca900, 0x239c000a982a8da4).hi, 0x12148e28207b83a3);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x239c000a982a8da4, 0x81fb3ad3636ca900).hi, 0x12148e28207b83a3);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x4be0b4c5d2725c44, 0x990cd6db34a04c30).hi, 0x2d5d1a4183fd6165);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x990cd6db34a04c30, 0x4be0b4c5d2725c44).hi, 0x2d5d1a4183fd6165);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x978ec0c0433c01f6, 0x2df03d097966b536).hi, 0x1b3251d91fe272a5);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x2df03d097966b536, 0x978ec0c0433c01f6).hi, 0x1b3251d91fe272a5);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x49c5cbbcfd716344, 0xc489e3b34b007ad3).hi, 0x38a32c74c8c191a4);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0xc489e3b34b007ad3, 0x49c5cbbcfd716344).hi, 0x38a32c74c8c191a4);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0xd3361cdbeed655d5, 0x1240da41e324953a).hi, 0x0f0f4fa11e7e8f2a);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x1240da41e324953a, 0xd3361cdbeed655d5).hi, 0x0f0f4fa11e7e8f2a);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x51b854f8e71b0ae0, 0x6f8d438aae530af5).hi, 0x239c04ee3c8cc248);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0x6f8d438aae530af5, 0x51b854f8e71b0ae0).hi, 0x239c04ee3c8cc248);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0xbbecf7dbc6147480, 0xbb0f73d0f82e2236).hi, 0x895170f4e9a216a7);
|
||||
EXPECT_EQ(Clipper2Lib::MultiplyUInt64(0xbb0f73d0f82e2236, 0xbbecf7dbc6147480).hi, 0x895170f4e9a216a7);
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestIsCollinear) {
|
||||
|
||||
@@ -46,7 +46,7 @@ TEST(Clipper2Tests, TestOffsets2) { // see #448 & #456
|
||||
Paths64 subject, solution;
|
||||
ClipperOffset c;
|
||||
subject.push_back(MakePath({ 50,50, 100,50, 100,150, 50,150, 0,100 }));
|
||||
int err;
|
||||
int err = 0;
|
||||
subject = ScalePaths<int64_t, int64_t>(subject, scale, err);
|
||||
c.AddPaths(subject, JoinType::Round, EndType::Polygon);
|
||||
c.ArcTolerance(arc_tol);
|
||||
@@ -674,4 +674,27 @@ TEST(Clipper2Tests, TestOffsets12) // see #873
|
||||
};
|
||||
Paths64 solution = InflatePaths(subject, -249561088, JoinType::Miter, EndType::Polygon);
|
||||
EXPECT_TRUE(solution.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestOffsets13) // see #965
|
||||
{
|
||||
const Path64 subject1 = {{0, 0}, {0, 10}, {10, 0}};
|
||||
const auto delta = 2;
|
||||
const auto joinType = JoinType::Miter;
|
||||
const auto endType = EndType::Polygon;
|
||||
|
||||
const Paths64 subjects1 = {
|
||||
subject1
|
||||
};
|
||||
const Paths64 solution1 = InflatePaths(subjects1, delta, joinType, endType);
|
||||
const auto area1 = std::abs(Area(solution1));
|
||||
EXPECT_EQ(area1, 122);
|
||||
|
||||
const Paths64 subjects2 = {
|
||||
subject1,
|
||||
{{0, 20}} // adding this single-point path should not really change the solution
|
||||
};
|
||||
const Paths64 solution2 = InflatePaths(subjects2, delta, joinType, endType);
|
||||
const auto area2 = std::abs(Area(solution2));
|
||||
EXPECT_EQ(area2, 122);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,9 @@ TEST(Clipper2Tests, TestMultiplePolygons)
|
||||
else if (IsInList(test_number, { 120, 121, 130, 138,
|
||||
140, 148, 163, 165, 166, 167, 168, 172, 173, 175, 178, 180 }))
|
||||
EXPECT_NEAR(measured_count, stored_count, 5) << " in test " << test_number;
|
||||
else if (IsInList(test_number, { 27, 181 }))
|
||||
else if (IsInList(test_number, { 126 }))
|
||||
EXPECT_NEAR(measured_count, stored_count, 3) << " in test " << test_number;
|
||||
else if (IsInList(test_number, { 16, 27, 181 }))
|
||||
EXPECT_NEAR(measured_count, stored_count, 2) << " in test " << test_number;
|
||||
else if (test_number >= 120 && test_number <= 184)
|
||||
EXPECT_NEAR(measured_count, stored_count, 2) << " in test " << test_number;
|
||||
|
||||
@@ -21,6 +21,7 @@ TEST(Clipper2Tests, TestPolytreeHoles1)
|
||||
c.Execute(ct, fr, solution, solution_open);
|
||||
EXPECT_TRUE(CheckPolytreeFullyContainsChildren(solution));
|
||||
}
|
||||
|
||||
void PolyPathContainsPoint(const PolyPath64& pp, const Point64 pt, int& counter)
|
||||
{
|
||||
if (pp.Polygon().size() > 0)
|
||||
@@ -34,6 +35,7 @@ void PolyPathContainsPoint(const PolyPath64& pp, const Point64 pt, int& counter)
|
||||
for (const auto& child : pp)
|
||||
PolyPathContainsPoint(*child, pt, counter);
|
||||
}
|
||||
|
||||
bool PolytreeContainsPoint(const PolyPath64& pp, const Point64 pt)
|
||||
{
|
||||
int counter = 0;
|
||||
@@ -42,6 +44,7 @@ bool PolytreeContainsPoint(const PolyPath64& pp, const Point64 pt)
|
||||
EXPECT_GE(counter, 0); //ie 'pt' can't be inside more holes than outers
|
||||
return counter != 0;
|
||||
}
|
||||
|
||||
void GetPolyPathArea(const PolyPath64& pp, double& area)
|
||||
{
|
||||
area += Area(pp.Polygon());
|
||||
@@ -55,6 +58,7 @@ double GetPolytreeArea(const PolyPath64& pp)
|
||||
GetPolyPathArea(*child, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles2)
|
||||
{
|
||||
std::ifstream ifs("PolytreeHoleOwner2.txt");
|
||||
@@ -125,6 +129,7 @@ TEST(Clipper2Tests, TestPolytreeHoles2)
|
||||
for (const auto& poi_inside : points_of_interest_inside)
|
||||
EXPECT_TRUE(PolytreeContainsPoint(solution_tree, poi_inside));
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles3)
|
||||
{
|
||||
Paths64 subject, clip, sol;
|
||||
@@ -142,6 +147,7 @@ TEST(Clipper2Tests, TestPolytreeHoles3)
|
||||
c.Execute(ClipType::Intersection, FillRule::NonZero, solution);
|
||||
EXPECT_TRUE(solution.Count() == 1 && solution[0]->Count() == 2);
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles4) //#618
|
||||
{
|
||||
Paths64 subject;
|
||||
@@ -162,6 +168,7 @@ TEST(Clipper2Tests, TestPolytreeHoles4) //#618
|
||||
// +- Hole
|
||||
EXPECT_TRUE(solution.Count() == 1 && solution[0]->Count() == 3);
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles5)
|
||||
{
|
||||
Paths64 subject, clip;
|
||||
@@ -179,6 +186,7 @@ TEST(Clipper2Tests, TestPolytreeHoles5)
|
||||
// + -Polygon (2) contains 2 holes.
|
||||
EXPECT_TRUE(tree.Count() == 3 && tree[2]->Count() == 2);
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles6) //#618
|
||||
{
|
||||
Paths64 subject, clip;
|
||||
@@ -201,6 +209,7 @@ TEST(Clipper2Tests, TestPolytreeHoles6) //#618
|
||||
// + -Polygon (2) contains 1 holes.
|
||||
EXPECT_TRUE(tree.Count() == 3 && tree[2]->Count() == 1);
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles7) //#618
|
||||
{
|
||||
Paths64 subject;
|
||||
@@ -213,4 +222,98 @@ TEST(Clipper2Tests, TestPolytreeHoles7) //#618
|
||||
c.Execute(ClipType::Union, FillRule::NonZero, polytree);
|
||||
//std::cout << polytree << std::endl;
|
||||
EXPECT_TRUE(polytree.Count() == 1 && polytree[0]->Count() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles8) // #942
|
||||
{
|
||||
Paths64 subject;
|
||||
PolyTree64 solution;
|
||||
Clipper64 c;
|
||||
subject.push_back(MakePath({ 1588700,-8717600, 1616200,-8474800,
|
||||
1588700,-8474800 }));
|
||||
subject.push_back(MakePath({ 13583800,-15601600, 13582800,-15508500,
|
||||
13555300,-15508500, 13555500,-15182200, 13010900,-15185400 }));
|
||||
subject.push_back(MakePath({ 956700,-3092300, 1152600,3147400, 25600,3151700 }));
|
||||
subject.push_back(MakePath({ 22575900,-16604000, 31286800,-12171900,
|
||||
31110200,4882800, 30996200,4826300, 30414400,5447400, 30260000,5391500,
|
||||
29662200,5805400, 28844500,5337900, 28435000,5789300, 27721400,5026400,
|
||||
22876300,5034300, 21977700,4414900, 21148000,4654700, 20917600,4653400,
|
||||
19334300,12411000, -2591700,12177200, 53200,3151100, -2564300,12149800,
|
||||
7819400,4692400, 10116000,5228600, 6975500,3120100, 7379700,3124700,
|
||||
11037900,596200, 12257000,2587800, 12257000,596200, 15227300,2352700,
|
||||
18444400,1112100, 19961100,5549400, 20173200,5078600, 20330000,5079300,
|
||||
20970200,4544300, 20989600,4563700, 19465500,1112100, 21611600,4182100,
|
||||
22925100,1112200, 22952700,1637200, 23059000,1112200, 24908100,4181200,
|
||||
27070100,3800600, 27238000,3800700, 28582200,520300, 29367800,1050100,
|
||||
29291400,179400, 29133700,360700, 29056700,312600, 29121900,332500,
|
||||
29269900,162300, 28941400,213100, 27491300,-3041500, 27588700,-2997800,
|
||||
22104900,-16142800, 13010900,-15603000, 13555500,-15182200,
|
||||
13555300,-15508500, 13582800,-15508500, 13583100,-15154700,
|
||||
1588700,-8822800, 1588700,-8379900, 1588700,-8474800, 1616200,-8474800,
|
||||
1003900,-630100, 1253300,-12284500, 12983400,-16239900 }));
|
||||
subject.push_back(MakePath({ 198200,12149800, 1010600,12149800, 1011500,11859600 }));
|
||||
subject.push_back(MakePath({ 21996700,-7432000, 22096700,-7432000, 22096700,-7332000 }));
|
||||
c.AddSubject(subject);
|
||||
c.Execute(ClipType::Union, FillRule::NonZero, solution);
|
||||
EXPECT_TRUE(solution.Count() == 1 && solution[0]->Count() == 2 && (*solution[0])[1]->Count() == 1);
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles9) // #957
|
||||
{
|
||||
Paths64 subject = {
|
||||
MakePath({ 77910,46865, 78720,46865, 78720,48000, 77910,48000, 77910,46865}),
|
||||
MakePath({ 82780,53015, 93600,53015, 93600,54335, 82780,54335, 82780,53015}),
|
||||
MakePath({ 82780,48975, 84080,48975, 84080,53015, 82780,53015, 82780,48975}),
|
||||
MakePath({ 77910,48000, 84080,48000, 84080,48975, 77910,48975, 77910,48000}),
|
||||
MakePath({ 89880,40615, 90700,40615, 90700,46865, 89880,46865, 89880,40615}),
|
||||
MakePath({ 92700,54335, 93600,54335, 93600,61420, 92700,61420, 92700,54335}),
|
||||
MakePath({ 78950,47425, 84080,47425, 84080,47770, 78950,47770, 78950,47425}),
|
||||
MakePath({ 82780,61420, 93600,61420, 93600,62435, 82780,62435, 82780,61420}),
|
||||
MakePath({ 101680,63085, 100675,63085, 100675,47770, 100680,47770, 100680,40615, 101680,40615, 101680,63085}),
|
||||
MakePath({ 76195,39880, 89880,39880, 89880,41045, 76195,41045, 76195,39880}),
|
||||
MakePath({ 85490,56145, 90520,56145, 90520,59235, 85490,59235, 85490,56145}),
|
||||
MakePath({ 89880,39880, 101680,39880, 101680,40615, 89880,40615, 89880,39880}),
|
||||
MakePath({ 89880,46865, 100680,46865, 100680,47770, 89880,47770, 89880,46865}),
|
||||
MakePath({ 82780,54335, 83280,54335, 83280,61420, 82780,61420, 82780,54335}),
|
||||
MakePath({ 76195,41045, 76855,41045, 76855,62665, 76195,62665, 76195,41045}),
|
||||
MakePath({ 76195,62665, 100675,62665, 100675,63085, 76195,63085, 76195,62665}),
|
||||
MakePath({ 82780,41045, 84080,41045, 84080,47425, 82780,47425, 82780,41045}) };
|
||||
|
||||
PolyTree64 solution;
|
||||
Clipper64 c;
|
||||
c.AddSubject(subject);
|
||||
c.Execute(ClipType::Union, FillRule::NonZero, solution);
|
||||
|
||||
// Polytree with 1 polygon.
|
||||
// + -Polygon(0) contains 2 holes.
|
||||
// + -Hole(0) contains 1 nested polygon.
|
||||
// + -Polygon(0) contains 1 hole.
|
||||
// + -Hole(0) contains 1 nested polygon.
|
||||
|
||||
EXPECT_TRUE(solution.Count() == 1 && solution[0]->Count() == 2 && (*solution[0])[0]->Count() == 1);
|
||||
}
|
||||
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeHoles10) // #973
|
||||
{
|
||||
Paths64 subject = {
|
||||
MakePath({ 0,0, 79530,0, 79530,940, 0,940, 0,0 }),
|
||||
MakePath({ 0,33360, 79530,33360, 79530,34300, 0,34300, 0,33360 }),
|
||||
MakePath({ 78470,940, 79530,940, 79530,33360, 78470,33360, 78470,940 }),
|
||||
MakePath({ 0,940, 940,940, 940,33360, 0,33360, 0,940 }),
|
||||
MakePath({ 29290,940, 30350,940, 30350,33360, 29290,33360, 29290,940 })
|
||||
};
|
||||
|
||||
Clipper64 c;
|
||||
c.AddSubject(subject);
|
||||
|
||||
Paths64 sol;
|
||||
PolyTree64 solution;
|
||||
c.Execute(ClipType::Union, FillRule::NonZero, solution);
|
||||
|
||||
// cout << solution << endl;
|
||||
// // Polytree with 1 polygon.
|
||||
// // + -Polygon(0) contains 2 holes.
|
||||
EXPECT_TRUE(solution.Count() == 1 && solution[0]->Count() == 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,79 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "clipper2/clipper.h"
|
||||
|
||||
using namespace Clipper2Lib;
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeUnion) {
|
||||
Paths64 subject;
|
||||
subject.push_back(MakePath({ 0,0, 0,5, 5,5, 5,0 }));
|
||||
subject.push_back(MakePath({ 1,1, 1,6, 6,6, 6,1 }));
|
||||
Clipper64 clipper;
|
||||
clipper.AddSubject(subject);
|
||||
PolyTree64 solution;
|
||||
Paths64 open_paths;
|
||||
if (IsPositive(subject[0]))
|
||||
clipper.Execute(ClipType::Union,
|
||||
FillRule::Positive, solution, open_paths);
|
||||
else
|
||||
{
|
||||
//because clipping ops normally return Positive solutions
|
||||
clipper.ReverseSolution(true);
|
||||
clipper.Execute(ClipType::Union,
|
||||
FillRule::Negative, solution, open_paths);
|
||||
}
|
||||
EXPECT_EQ(open_paths.size(), 0);
|
||||
ASSERT_EQ(solution.Count(), 1);
|
||||
EXPECT_EQ(solution[0]->Polygon().size(), 8);
|
||||
EXPECT_EQ(IsPositive(subject[0]), IsPositive(solution[0]->Polygon()));
|
||||
}
|
||||
Paths64 subject;
|
||||
subject.push_back(MakePath({ 0,0, 0,5, 5,5, 5,0 }));
|
||||
subject.push_back(MakePath({ 1,1, 1,6, 6,6, 6,1 }));
|
||||
Clipper64 clipper;
|
||||
clipper.AddSubject(subject);
|
||||
PolyTree64 solution;
|
||||
Paths64 open_paths;
|
||||
if (IsPositive(subject[0]))
|
||||
clipper.Execute(ClipType::Union,
|
||||
FillRule::Positive, solution, open_paths);
|
||||
else
|
||||
{
|
||||
//because clipping ops normally return Positive solutions
|
||||
clipper.ReverseSolution(true);
|
||||
clipper.Execute(ClipType::Union,
|
||||
FillRule::Negative, solution, open_paths);
|
||||
}
|
||||
EXPECT_EQ(open_paths.size(), 0);
|
||||
ASSERT_EQ(solution.Count(), 1);
|
||||
EXPECT_EQ(solution[0]->Polygon().size(), 8);
|
||||
EXPECT_EQ(IsPositive(subject[0]), IsPositive(solution[0]->Polygon()));
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeUnion2) { // #987
|
||||
Paths64 subject;
|
||||
subject.push_back(MakePath({ 534, 1024, 534, -800, 1026, -800, 1026, 1024 }));
|
||||
subject.push_back(MakePath({ 1, 1024, 8721, 1024, 8721, 1920, 1, 1920 }));
|
||||
subject.push_back(MakePath({ 30, 1024, 30, -800, 70, -800, 70, 1024 }));
|
||||
subject.push_back(MakePath({ 1, 1024, 1, -1024, 3841, -1024, 3841, 1024 }));
|
||||
subject.push_back(MakePath({ 3900, -1024, 6145, -1024, 6145, 1024, 3900, 1024 }));
|
||||
subject.push_back(MakePath({ 5884, 1024, 5662, 1024, 5662, -1024, 5884, -1024 }));
|
||||
subject.push_back(MakePath({ 534, 1024, 200, 1024, 200, -800, 534, -800 }));
|
||||
subject.push_back(MakePath({ 200, -800, 200, 1024, 70, 1024, 70, -800 }));
|
||||
subject.push_back(MakePath({ 1200, 1920, 1313, 1920, 1313, -800, 1200, -800 }));
|
||||
subject.push_back(MakePath({ 6045, -800, 6045, 1024, 5884, 1024, 5884, -800 }));
|
||||
|
||||
Clipper64 clipper;
|
||||
clipper.AddSubject(subject);
|
||||
PolyTree64 solution;
|
||||
Paths64 open_paths;
|
||||
clipper.Execute(ClipType::Union, FillRule::EvenOdd, solution, open_paths);
|
||||
|
||||
ASSERT_EQ(solution.Count(), 1);
|
||||
EXPECT_EQ(solution[0]->Count(), 1);
|
||||
}
|
||||
|
||||
TEST(Clipper2Tests, TestPolytreeUnion3)
|
||||
{
|
||||
Paths64 subject;
|
||||
subject.push_back(MakePath({
|
||||
-120927680, 590077597,
|
||||
-120919386, 590077307,
|
||||
-120919432, 590077309,
|
||||
-120919451, 590077309,
|
||||
-120919455, 590077310,
|
||||
-120099297, 590048669,
|
||||
-120928004, 590077608,
|
||||
-120902794, 590076728,
|
||||
-120919444, 590077309,
|
||||
-120919450, 590077309,
|
||||
-120919842, 590077323,
|
||||
-120922852, 590077428,
|
||||
-120902452, 590076716,
|
||||
-120902455, 590076716,
|
||||
-120912590, 590077070,
|
||||
11914491, 249689797
|
||||
}));
|
||||
|
||||
Clipper64 clipper;
|
||||
clipper.AddSubject(subject);
|
||||
Clipper2Lib::PolyTree64 solution;
|
||||
clipper.Execute(ClipType::Union, FillRule::EvenOdd, solution);
|
||||
}
|
||||
|
||||
@@ -14,10 +14,13 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
inline bool FileExists(const std::string& name)
|
||||
#include <fstream>
|
||||
|
||||
inline bool FileExists(const std::string& filename)
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat(name.c_str(), &buffer) == 0);
|
||||
//return std::filesystem::exists(filename); // <filesystem> not available in Ubuntu (#990)
|
||||
std::ifstream file(filename);
|
||||
return file.good();
|
||||
}
|
||||
|
||||
bool LoadTestNum(std::ifstream& source, int test_num,
|
||||
|
||||
@@ -8,9 +8,9 @@ struct Hsl {
|
||||
uint8_t hue = 0;
|
||||
uint8_t sat = 0;
|
||||
uint8_t lum = 0;
|
||||
Hsl() {};
|
||||
Hsl() {}
|
||||
Hsl(uint8_t a, uint8_t h, uint8_t s, uint8_t l) :
|
||||
alpha(a), hue(h), sat(s), lum(l) {};
|
||||
alpha(a), hue(h), sat(s), lum(l) {}
|
||||
};
|
||||
|
||||
union Color32 {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@@ -16,14 +15,15 @@
|
||||
|
||||
namespace Clipper2Lib {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// SvgWriter
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const char svg_xml_header_0[] =
|
||||
"<?xml version=\"1.0\" standalone=\"no\"?>\n"
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
|
||||
"\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n\n <svg width=\"";
|
||||
"<?xml version=\"1.0\" standalone=\"no\"?>\n<svg width=\"";
|
||||
const char svg_xml_header_1[] = "\" height=\"";
|
||||
const char svg_xml_header_2[] = "\" viewBox=\"0 0 ";
|
||||
const char svg_xml_header_3[] = "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n\n";
|
||||
|
||||
const char svg_xml_header_3[] = "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
|
||||
|
||||
const char svg_xml_0[] = "\"\n style=\"fill:";
|
||||
const char svg_xml_1[] = "; fill-opacity:";
|
||||
@@ -33,7 +33,7 @@ namespace Clipper2Lib {
|
||||
const char svg_xml_5[] = "; stroke-width:";
|
||||
const char svg_xml_6[] = ";\"/>\n";
|
||||
|
||||
inline std::string ColorToHtml(unsigned clr)
|
||||
static std::string ColorToHtml(unsigned clr)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << '#' << std::hex << std::setfill('0') << std::setw(6) << (clr & 0xFFFFFF);
|
||||
@@ -41,7 +41,7 @@ namespace Clipper2Lib {
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline float GetAlphaAsFrac(unsigned int clr)
|
||||
static float GetAlphaAsFrac(unsigned int clr)
|
||||
{
|
||||
return ((float)(clr >> 24) / 255.0f);
|
||||
}
|
||||
@@ -64,10 +64,17 @@ namespace Clipper2Lib {
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SvgWriter::AddText(const std::string &text,
|
||||
void SvgWriter::AddText(const std::string& text,
|
||||
unsigned font_color, unsigned font_size, double x, double y)
|
||||
{
|
||||
text_infos.push_back(new TextInfo(text, "", font_color, 600, font_size, x, y));
|
||||
text_infos.push_back(new TextInfo(text, "", font_color, 600, font_size, x, y));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SvgWriter::AddText(const std::string& text, const std::string& font_family,
|
||||
unsigned font_color, unsigned font_size, double x, double y)
|
||||
{
|
||||
text_infos.push_back(new TextInfo(text, font_family, font_color, 600, font_size, x, y));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -125,13 +132,13 @@ namespace Clipper2Lib {
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PathsD SimulateNegativeFill(const PathsD paths)
|
||||
static PathsD SimulateNegativeFill(const PathsD paths)
|
||||
{
|
||||
return Union(paths, FillRule::Negative);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PathsD SimulatePositiveFill(const PathsD paths)
|
||||
static PathsD SimulatePositiveFill(const PathsD paths)
|
||||
{
|
||||
return Union(paths, FillRule::Positive);
|
||||
}
|
||||
@@ -140,6 +147,7 @@ namespace Clipper2Lib {
|
||||
bool SvgWriter::SaveToFile(const std::string &filename,
|
||||
int max_width, int max_height, int margin)
|
||||
{
|
||||
// get the bounds of all path_infos
|
||||
RectD rec = InvalidRectD;
|
||||
for (const PathInfo* pi : path_infos)
|
||||
for (const PathD& path : pi->paths_)
|
||||
@@ -172,9 +180,10 @@ namespace Clipper2Lib {
|
||||
max_height << "px" << svg_xml_header_2 <<
|
||||
max_width << " " <<
|
||||
max_height << svg_xml_header_3;
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
setlocale(LC_NUMERIC, "C"); // decimal separator == '.' and no thousand separators
|
||||
file.precision(2);
|
||||
|
||||
// code block used to simulate POSITIVE or NEGATIVE filling rules
|
||||
for (PathInfo* pi : path_infos)
|
||||
{
|
||||
if (pi->is_open_path || GetAlphaAsFrac(pi->brush_color_) == 0 ||
|
||||
@@ -207,6 +216,7 @@ namespace Clipper2Lib {
|
||||
|
||||
for (PathInfo* pi : path_infos)
|
||||
{
|
||||
// ignore filling (brushColor == 0) if POSITIVE or NEGATIVE filling
|
||||
unsigned brushColor =
|
||||
(pi->fillrule_ == FillRule::Positive || pi->fillrule_ == FillRule::Negative) ?
|
||||
0 : pi->brush_color_;
|
||||
@@ -272,9 +282,10 @@ namespace Clipper2Lib {
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// SvgReader
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool SkipBlanks(std::string::const_iterator& si,
|
||||
static bool SkipBlanks(std::string::const_iterator& si,
|
||||
const std::string::const_iterator se)
|
||||
{
|
||||
while (si != se && *si <= ' ') ++si;
|
||||
@@ -282,7 +293,17 @@ namespace Clipper2Lib {
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool GetNum(std::string::const_iterator& si,
|
||||
static bool SkipOptionalComma(std::string::const_iterator& si,
|
||||
const std::string::const_iterator se)
|
||||
{
|
||||
while (si != se && *si <= ' ') ++si;
|
||||
if (si != se && *si == ',') ++si;
|
||||
return si != se;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
static bool GetNum(std::string::const_iterator& si,
|
||||
const std::string::const_iterator se, double& value)
|
||||
{
|
||||
while (si != se && *si <= ' ') ++si;
|
||||
@@ -316,129 +337,63 @@ namespace Clipper2Lib {
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool GetCommand(std::string::const_iterator& si,
|
||||
char& command, bool& is_relative)
|
||||
|
||||
static bool FileExists(const std::string& filename)
|
||||
{
|
||||
if (*si >= 'a' && *si <= 'z')
|
||||
//return std::filesystem::exists(filename); // <filesystem> not available in Ubuntu (#990)
|
||||
std::ifstream file(filename);
|
||||
return file.good();
|
||||
}
|
||||
|
||||
SvgReader::SvgReader(const std::string& filename)
|
||||
{
|
||||
if (!FileExists(filename)) return;
|
||||
std::ifstream file(filename);
|
||||
if (!file.good()) return;
|
||||
std::stringstream xml_buff;
|
||||
xml_buff << file.rdbuf();
|
||||
file.close();
|
||||
|
||||
const std::string xml = xml_buff.str();
|
||||
size_t i = xml.find("d=\"M");
|
||||
if (i == std::string::npos) return;
|
||||
std::string::const_iterator it = xml.cbegin() + (i + 4), itEnd = xml.cend();
|
||||
if (!SkipBlanks(it, itEnd)) return;
|
||||
PathD p;
|
||||
PointD m, pt;
|
||||
GetNum(it, itEnd, m.x);
|
||||
SkipOptionalComma(it, itEnd);
|
||||
if (!GetNum(it, itEnd, m.y)) return;
|
||||
p.push_back(m);
|
||||
while (SkipBlanks(it, itEnd))
|
||||
{
|
||||
is_relative = true;
|
||||
command = toupper(*si);
|
||||
}
|
||||
else if (*si >= 'A' && *si <= 'Z')
|
||||
{
|
||||
command = *si;
|
||||
is_relative = false;
|
||||
}
|
||||
else return false; //ie leave command and is_relative unchanged!
|
||||
++si; //only increment the offset with a valid command
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline bool Find(const std::string& text,
|
||||
std::string::const_iterator& start, const std::string::const_iterator& end)
|
||||
{
|
||||
start = std::search(start, end, text.cbegin(), text.cend());
|
||||
return start != end;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool SvgReader::LoadPath(std::string::const_iterator& p,
|
||||
const std::string::const_iterator& pe)
|
||||
{
|
||||
if (!Find("d=\"", p, pe)) return false;
|
||||
p += 3;
|
||||
if (!SkipBlanks(p, pe)) return false;
|
||||
char command;
|
||||
bool is_relative;
|
||||
int vals_needed = 2;
|
||||
//nb: M == absolute move, m == relative move
|
||||
if (!GetCommand(p, command, is_relative) || command != 'M') return false;
|
||||
double vals[2] { 0, 0 };
|
||||
double x = 0, y = 0;
|
||||
++p;
|
||||
if (!GetNum(p, pe, x) || !GetNum(p, pe, y)) return false;
|
||||
PathsD ppp;
|
||||
PathD pp;
|
||||
pp.push_back(PointD(x, y));
|
||||
while (SkipBlanks(p, pe))
|
||||
{
|
||||
if (GetCommand(p, command, is_relative))
|
||||
if (*it == 'L') ++it;
|
||||
if (*it == 'M' || *it == 'Z')
|
||||
{
|
||||
switch (command) {
|
||||
case 'L':
|
||||
case 'M': {vals_needed = 2; break; }
|
||||
case 'H':
|
||||
case 'V': {vals_needed = 1; break; }
|
||||
case 'Z': {
|
||||
if (pp.size() > 2) ppp.push_back(pp);
|
||||
pp.clear();
|
||||
vals_needed = 0;
|
||||
break;
|
||||
if (p.size() > 2) paths.push_back(p);
|
||||
p.resize(0);
|
||||
if (*it == 'Z')
|
||||
{
|
||||
++it;
|
||||
if (!SkipBlanks(it, itEnd)) break;
|
||||
}
|
||||
default: vals_needed = -1;
|
||||
if (*it == 'M')
|
||||
{
|
||||
++it;
|
||||
if (!GetNum(it, itEnd, pt.x)) break;
|
||||
SkipOptionalComma(it, itEnd);
|
||||
if (!GetNum(it, itEnd, pt.y)) break;
|
||||
}
|
||||
if (vals_needed < 0) break; //oops!
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < vals_needed; ++i)
|
||||
if (!GetNum(p, pe, vals[i])) vals_needed = -1;
|
||||
if (vals_needed <= 0) break; //oops!
|
||||
switch (vals_needed) {
|
||||
case 1:
|
||||
{
|
||||
if (command == 'V') y = (is_relative ? y + vals[0] : vals[0]);
|
||||
else x = (is_relative ? x + vals[0] : vals[0]);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
x = (is_relative ? x + vals[0] : vals[0]);
|
||||
y = (is_relative ? y + vals[1] : vals[1]);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
pp.push_back(PointD(x, y));
|
||||
p.push_back(pt);
|
||||
continue;
|
||||
}
|
||||
GetNum(it, itEnd, pt.x);
|
||||
SkipOptionalComma(it, itEnd);
|
||||
if (!GetNum(it, itEnd, pt.y)) break;
|
||||
p.push_back(pt);
|
||||
SkipOptionalComma(it, itEnd);
|
||||
}
|
||||
if (pp.size() > 3) ppp.push_back(pp);
|
||||
//todo - fix fillrule
|
||||
path_infos.push_back(new PathInfo(ppp, false, FillRule::EvenOdd, 0, 0xFF000000, 1, false));
|
||||
return (ppp.size() > 0);
|
||||
}
|
||||
|
||||
bool SvgReader::LoadFromFile(const std::string &filename)
|
||||
{
|
||||
Clear();
|
||||
std::ifstream file(filename);
|
||||
if (!file.good()) return false;
|
||||
|
||||
std::stringstream xml_buff;
|
||||
xml_buff << file.rdbuf();
|
||||
file.close();
|
||||
xml = xml_buff.str();
|
||||
std::string::const_iterator p = xml.cbegin(), q, xml_end = xml.cend();
|
||||
|
||||
while (Find("<path", p, xml_end))
|
||||
{
|
||||
p += 6;
|
||||
q = p;
|
||||
if (!Find("/>", p, xml_end)) break;
|
||||
LoadPath(q, p);
|
||||
p += 2;
|
||||
}
|
||||
return path_infos.size() > 0;
|
||||
}
|
||||
|
||||
PathsD SvgReader::GetPaths()
|
||||
{
|
||||
PathsD result;
|
||||
for (size_t i = 0; i < path_infos.size(); ++i)
|
||||
for (size_t j = 0; j < path_infos[i]->paths_.size(); ++j)
|
||||
result.push_back(path_infos[i]->paths_[j]);
|
||||
return result;
|
||||
if (p.size() > 2) paths.push_back(p);
|
||||
}
|
||||
|
||||
} //namespace
|
||||
|
||||
@@ -9,32 +9,32 @@
|
||||
#ifndef svglib_h
|
||||
#define svglib_h
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include "clipper2/clipper.h"
|
||||
|
||||
namespace Clipper2Lib {
|
||||
|
||||
class PathInfo {
|
||||
private:
|
||||
PathsD paths_;
|
||||
bool is_open_path;
|
||||
FillRule fillrule_;
|
||||
unsigned brush_color_;
|
||||
unsigned pen_color_;
|
||||
double pen_width_;
|
||||
bool show_coords_;
|
||||
class PathInfo {
|
||||
private:
|
||||
PathsD paths_;
|
||||
bool is_open_path;
|
||||
FillRule fillrule_;
|
||||
unsigned brush_color_;
|
||||
unsigned pen_color_;
|
||||
double pen_width_;
|
||||
bool show_coords_;
|
||||
|
||||
public:
|
||||
PathInfo(const PathsD& paths, bool is_open, FillRule fillrule,
|
||||
unsigned brush_clr, unsigned pen_clr, double pen_width, bool show_coords) :
|
||||
paths_(paths), is_open_path(is_open), fillrule_(fillrule),
|
||||
brush_color_(brush_clr), pen_color_(pen_clr),
|
||||
pen_width_(pen_width), show_coords_(show_coords) {};
|
||||
friend class SvgWriter;
|
||||
friend class SvgReader;
|
||||
};
|
||||
typedef std::vector< PathInfo* > PathInfoList;
|
||||
public:
|
||||
PathInfo(const PathsD& paths, bool is_open, FillRule fillrule,
|
||||
unsigned brush_clr, unsigned pen_clr, double pen_width, bool show_coords) :
|
||||
paths_(paths), is_open_path(is_open), fillrule_(fillrule),
|
||||
brush_color_(brush_clr), pen_color_(pen_clr),
|
||||
pen_width_(pen_width), show_coords_(show_coords) {
|
||||
}
|
||||
friend class SvgWriter;
|
||||
friend class SvgReader;
|
||||
};
|
||||
typedef std::vector< PathInfo* > PathInfoList;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// SvgWriter
|
||||
@@ -51,30 +51,31 @@ namespace Clipper2Lib {
|
||||
|
||||
class TextInfo {
|
||||
public:
|
||||
std::string text;
|
||||
std::string font_name;
|
||||
unsigned font_color = 0xFF000000;
|
||||
unsigned font_weight = 600;
|
||||
unsigned font_size = 11;
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
std::string text;
|
||||
std::string font_name;
|
||||
unsigned font_color = 0xFF000000;
|
||||
unsigned font_weight = 600;
|
||||
unsigned font_size = 11;
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
|
||||
TextInfo(const std::string &txt, const std::string &fnt_name, unsigned color,
|
||||
unsigned weight, unsigned size, double coord_x, double coord_y) :
|
||||
text(txt), font_name(fnt_name), font_color(color), font_weight(weight), font_size(size),
|
||||
x(coord_x), y(coord_y) {};
|
||||
friend class SvgWriter;
|
||||
TextInfo(const std::string& txt, const std::string& fnt_name, unsigned color,
|
||||
unsigned weight, unsigned size, double coord_x, double coord_y) :
|
||||
text(txt), font_name(fnt_name), font_color(color), font_weight(weight), font_size(size),
|
||||
x(coord_x), y(coord_y) {
|
||||
}
|
||||
friend class SvgWriter;
|
||||
};
|
||||
|
||||
typedef std::vector< TextInfo* > TextInfoList;
|
||||
|
||||
private:
|
||||
double scale_;
|
||||
FillRule fill_rule_;
|
||||
CoordsStyle coords_style;
|
||||
TextInfoList text_infos;
|
||||
PathInfoList path_infos;
|
||||
void DrawCircle(std::ofstream& file, double x, double y, double radius);
|
||||
double scale_;
|
||||
FillRule fill_rule_;
|
||||
CoordsStyle coords_style;
|
||||
TextInfoList text_infos;
|
||||
PathInfoList path_infos;
|
||||
void DrawCircle(std::ofstream& file, double x, double y, double radius);
|
||||
public:
|
||||
explicit SvgWriter(int precision = 0)
|
||||
{
|
||||
@@ -83,14 +84,15 @@ namespace Clipper2Lib {
|
||||
coords_style.font_color = 0xFF000000;
|
||||
coords_style.font_size = 11;
|
||||
scale_ = std::pow(10, precision);
|
||||
};
|
||||
}
|
||||
|
||||
~SvgWriter() { Clear(); };
|
||||
~SvgWriter() { Clear(); }
|
||||
|
||||
void Clear();
|
||||
FillRule Fill_Rule() { return fill_rule_; }
|
||||
void SetCoordsStyle(const std::string &font_name, unsigned font_color, unsigned font_size);
|
||||
void AddText(const std::string &text, unsigned font_color, unsigned font_size, double x, double y);
|
||||
FillRule Fill_Rule() const { return fill_rule_; }
|
||||
void SetCoordsStyle(const std::string& font_name, unsigned font_color, unsigned font_size);
|
||||
void AddText(const std::string& text, unsigned font_color, unsigned font_size, double x, double y);
|
||||
void AddText(const std::string& text, const std::string& font_family, unsigned font_color, unsigned font_size, double x, double y);
|
||||
void AddPath(const Path64& path, bool is_open, FillRule fillrule,
|
||||
unsigned brush_color, unsigned pen_color, double pen_width, bool show_coords);
|
||||
void AddPath(const PathD& path, bool is_open, FillRule fillrule,
|
||||
@@ -99,7 +101,7 @@ namespace Clipper2Lib {
|
||||
unsigned brush_color, unsigned pen_color, double pen_width, bool show_coords);
|
||||
void AddPaths(const Paths64& paths, bool is_open, FillRule fillrule,
|
||||
unsigned brush_color, unsigned pen_color, double pen_width, bool show_coords);
|
||||
bool SaveToFile(const std::string &filename, int max_width, int max_height, int margin);
|
||||
bool SaveToFile(const std::string& filename, int max_width, int max_height, int margin);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -108,17 +110,11 @@ namespace Clipper2Lib {
|
||||
|
||||
class SvgReader
|
||||
{
|
||||
private:
|
||||
PathInfoList path_infos;
|
||||
bool LoadPath(std::string::const_iterator& p,
|
||||
const std::string::const_iterator& pe);
|
||||
public:
|
||||
std::string xml;
|
||||
bool LoadFromFile(const std::string &filename);
|
||||
void Clear() { path_infos.clear(); };
|
||||
PathsD GetPaths();
|
||||
PathsD paths;
|
||||
SvgReader(const std::string& filename);
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
#endif //svglib_h
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 16 June 2022 *
|
||||
* Date : 6 December 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2022 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
#define svgutillib_h
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include "clipper2/clipper.h"
|
||||
#include "clipper2/clipper.core.h"
|
||||
#include "clipper.svg.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
@@ -19,6 +22,8 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace Clipper2Lib {
|
||||
|
||||
static const unsigned subj_brush_clr = 0x1800009C;
|
||||
@@ -27,10 +32,18 @@ namespace Clipper2Lib {
|
||||
static const unsigned clip_stroke_clr = 0xCCFFA07A;
|
||||
static const unsigned solution_brush_clr = 0x4466FF66;
|
||||
|
||||
inline bool FileExists(const std::string& name)
|
||||
|
||||
|
||||
inline int32_t RandomColor()
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat(name.c_str(), &buffer) == 0);
|
||||
return rand() | (rand() << 15) | 0xFF000000;
|
||||
}
|
||||
|
||||
inline bool FileExists(const std::string& filename)
|
||||
{
|
||||
//return std::filesystem::exists(filename); // <filesystem> not available in Ubuntu (#990)
|
||||
std::ifstream file(filename);
|
||||
return file.good();
|
||||
}
|
||||
|
||||
inline void SvgAddCaption(SvgWriter& svg, const std::string& caption, int x, int y)
|
||||
@@ -96,9 +109,16 @@ namespace Clipper2Lib {
|
||||
}
|
||||
|
||||
|
||||
inline void SvgAddSolution(SvgWriter& svg, const PathsD &path, FillRule fillrule, bool show_coords)
|
||||
inline void SvgAddSolution(SvgWriter& svg, const PathsD& path, FillRule fillrule, bool show_coords)
|
||||
{
|
||||
svg.AddPaths(path, false, fillrule, solution_brush_clr, 0xFF003300, 1.2, show_coords);
|
||||
svg.AddPaths(path, false, fillrule, solution_brush_clr, 0x80666666, 1.0, show_coords);
|
||||
}
|
||||
|
||||
// SvgAddRCSolution - random color for each individual polygon (eg when triangulating)
|
||||
inline void SvgAddRCSolution(SvgWriter& svg, const PathsD& paths, FillRule fillrule, bool show_coords)
|
||||
{
|
||||
for (const PathD& path : paths)
|
||||
svg.AddPath(path, false, fillrule, RandomColor(), 0xFF999999, 1.0, show_coords);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +128,15 @@ namespace Clipper2Lib {
|
||||
false, fillrule, solution_brush_clr, 0xFF003300, 1.0, show_coords);
|
||||
}
|
||||
|
||||
// SvgAddRCSolution - random color for each individual polygon (eg when triangulating)
|
||||
inline void SvgAddRCSolution(SvgWriter& svg, const Paths64& paths, FillRule fillrule, bool show_coords)
|
||||
{
|
||||
for (const Path64& path : paths)
|
||||
{
|
||||
svg.AddPath(TransformPath<double, int64_t>(path),
|
||||
false, fillrule, RandomColor(), 0xFF999999, 1.0, show_coords);
|
||||
}
|
||||
}
|
||||
|
||||
inline void SvgAddOpenSolution(SvgWriter& svg, const PathsD& path, FillRule fillrule,
|
||||
bool show_coords, bool is_joined = false)
|
||||
|
||||
@@ -3,7 +3,11 @@ using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
|
||||
#if USINGZ
|
||||
namespace Clipper2ZLib.Benchmark
|
||||
#else
|
||||
namespace Clipper2Lib.Benchmark
|
||||
#endif
|
||||
{
|
||||
public class FastConfig : ManualConfig
|
||||
{
|
||||
@@ -1,8 +1,12 @@
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
#if USINGZ
|
||||
namespace Clipper2ZLib.Benchmark
|
||||
#else
|
||||
namespace Clipper2Lib.Benchmark
|
||||
#endif
|
||||
{
|
||||
public static class Program
|
||||
public static class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
@@ -1,245 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 1 January 2023 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2023 *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using Clipper2Lib;
|
||||
using System;
|
||||
|
||||
namespace ClipperDemo1
|
||||
{
|
||||
public static class Application
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
//ClipTestPolys();
|
||||
|
||||
//LoopThruTestPolygons(); // summary test all
|
||||
//LoopThruTestPolygons(110, 113); // display test range
|
||||
//LoopThruTestPolygons(46); // display one
|
||||
|
||||
SquaresTest(true);
|
||||
TrianglesTest(true);
|
||||
DiamondsTest(true);
|
||||
}
|
||||
|
||||
public static Paths64 Polytree_Union(Paths64 subjects, FillRule fillrule)
|
||||
{
|
||||
// of course this function is inefficient,
|
||||
// but it's purpose is simply to test polytrees.
|
||||
PolyTree64 polytree = new();
|
||||
Clipper.BooleanOp(ClipType.Union, subjects, null, polytree, fillrule);
|
||||
return Clipper.PolyTreeToPaths64(polytree);
|
||||
}
|
||||
|
||||
public static void SquaresTest(bool test_polytree = false)
|
||||
{
|
||||
const int size = 10;
|
||||
const int w = 800, h = 600;
|
||||
const FillRule fillrule = FillRule.NonZero;
|
||||
|
||||
Path64 shape = Clipper.MakePath(new int[] { 0, 0, size, 0, size, size, 0, size });
|
||||
Paths64 subjects = new(), solution;
|
||||
Random rand = new();
|
||||
for (int i = 0; i < h / size; ++i)
|
||||
{
|
||||
for (int j = 0; j < w / size; ++j)
|
||||
{
|
||||
shape = Clipper.TranslatePath(shape, size, 0);
|
||||
if (rand.Next(5) != 0) subjects.Add(shape);
|
||||
}
|
||||
shape = Clipper.TranslatePath(shape, (-w / size) * size, size);
|
||||
}
|
||||
|
||||
if (test_polytree)
|
||||
solution = Polytree_Union(subjects, fillrule);
|
||||
else
|
||||
solution = Clipper.Union(subjects, fillrule);
|
||||
|
||||
SvgWriter svg = new();
|
||||
SvgUtils.AddSubject(svg, subjects);
|
||||
SvgUtils.AddSolution(svg, solution, false);
|
||||
const string filename = @"..\..\..\squares.svg";
|
||||
SvgUtils.SaveToFile(svg, filename, fillrule, w, h, 10);
|
||||
ClipperFileIO.OpenFileWithDefaultApp(filename);
|
||||
}
|
||||
|
||||
public static void TrianglesTest(bool test_polytree = false)
|
||||
{
|
||||
const int size = 10;
|
||||
const int w = 800, h = 600;
|
||||
const FillRule fillrule = FillRule.NonZero;
|
||||
|
||||
Path64 tri1 = Clipper.MakePath(new int[] { 0,0, size * 2,0, size,size * 2 });
|
||||
Path64 tri2 = Clipper.MakePath(new int[] { size * 2, 0, size, size * 2, size*3, size*2 });
|
||||
|
||||
Paths64 subjects = new(), solution;
|
||||
Random rand = new();
|
||||
for (int i = 0; i < h / size / 2; ++i)
|
||||
{
|
||||
for (int j = 0; j < w / size / 2; ++j)
|
||||
{
|
||||
if (rand.Next(4) != 0) subjects.Add(tri1);
|
||||
if (rand.Next(4) != 0) subjects.Add(tri2);
|
||||
tri1 = Clipper.TranslatePath(tri1, size * 2, 0);
|
||||
tri2 = Clipper.TranslatePath(tri2, size * 2, 0);
|
||||
}
|
||||
tri1 = Clipper.TranslatePath(tri1, (-w / size) * size, size * 2);
|
||||
tri2 = Clipper.TranslatePath(tri2, (-w / size) * size, size * 2);
|
||||
}
|
||||
|
||||
if (test_polytree)
|
||||
solution = Polytree_Union(subjects, fillrule);
|
||||
else
|
||||
solution = Clipper.Union(subjects, fillrule);
|
||||
|
||||
SvgWriter svg = new();
|
||||
SvgUtils.AddSubject(svg, subjects);
|
||||
SvgUtils.AddSolution(svg, solution, false);
|
||||
const string filename = @"..\..\..\triangles.svg";
|
||||
SvgUtils.SaveToFile(svg, filename, fillrule, w, h, 10);
|
||||
ClipperFileIO.OpenFileWithDefaultApp(filename);
|
||||
}
|
||||
|
||||
public static void DiamondsTest(bool test_polytree = false)
|
||||
{
|
||||
const int size = 10;
|
||||
const int w = 800, h = 600;
|
||||
const FillRule fillrule = FillRule.NonZero;
|
||||
|
||||
Path64 shape = Clipper.MakePath(new int[] { size, 0, size * 2, size, size, size * 2, 0, size });
|
||||
Paths64 subjects = new(), solution;
|
||||
Random rand = new();
|
||||
for (int i = 0; i < h / size / 2; ++i)
|
||||
{
|
||||
for (int j = 0; j < w / size; ++j)
|
||||
{
|
||||
if (rand.Next(7) != 0) subjects.Add(shape);
|
||||
if ((j & 1) == 0)
|
||||
shape = Clipper.TranslatePath(shape, size, size);
|
||||
else
|
||||
shape = Clipper.TranslatePath(shape, size, -size);
|
||||
}
|
||||
shape = Clipper.TranslatePath(shape, (-w / size) * size, size * 2);
|
||||
}
|
||||
|
||||
if (test_polytree)
|
||||
solution = Polytree_Union(subjects, fillrule);
|
||||
else
|
||||
solution = Clipper.Union(subjects, fillrule);
|
||||
|
||||
SvgWriter svg = new();
|
||||
SvgUtils.AddSubject(svg, subjects);
|
||||
SvgUtils.AddSolution(svg, solution, false);
|
||||
const string filename = @"..\..\..\diamonds.svg";
|
||||
SvgUtils.SaveToFile(svg, filename, fillrule, w, h, 10);
|
||||
ClipperFileIO.OpenFileWithDefaultApp(filename);
|
||||
}
|
||||
|
||||
public static void LoopThruTestPolygons(int start = 0, int end = 0)
|
||||
{
|
||||
Paths64 subject = new();
|
||||
Paths64 subject_open = new();
|
||||
Paths64 clip = new();
|
||||
Paths64 solution = new();
|
||||
Paths64 solution_open = new();
|
||||
bool do_all = (start == 0 && end == 0);
|
||||
if (do_all) { start = 1; end = 0xFFFF; }
|
||||
else if (end == 0) end = start;
|
||||
|
||||
if (do_all)
|
||||
Console.WriteLine("\nCount and area differences (expected vs measured):\n");
|
||||
int test_number = start;
|
||||
for (; test_number <= end; ++test_number)
|
||||
{
|
||||
if (!ClipperFileIO.LoadTestNum(@"..\..\..\..\..\..\Tests\Polygons.txt",
|
||||
test_number, subject, subject_open, clip,
|
||||
out ClipType ct, out FillRule fr, out long area, out int cnt, out _)) break;
|
||||
Clipper64 c64 = new();
|
||||
c64.AddSubject(subject);
|
||||
c64.AddOpenSubject(subject_open);
|
||||
c64.AddClip(clip);
|
||||
if (!c64.Execute(ct, fr, solution, solution_open)) return;
|
||||
|
||||
if (do_all)
|
||||
{
|
||||
int measuredCnt = solution.Count;
|
||||
double measuredArea = Clipper.Area(solution);
|
||||
|
||||
double count_diff = (cnt <= 0) ? 0 :
|
||||
Math.Abs( measuredCnt / (double)cnt - 1.0);
|
||||
|
||||
double area_diff = area <= 0 ? 0 : Math.Abs(measuredArea / area -1.0);
|
||||
|
||||
if (count_diff > 0.05)
|
||||
Console.WriteLine($"{test_number}: count {cnt} vs {measuredCnt}");
|
||||
if (area_diff > 0.1)
|
||||
Console.WriteLine($"{test_number}: area {area} vs {measuredArea}");
|
||||
|
||||
// don't display when looping through every test
|
||||
continue;
|
||||
}
|
||||
|
||||
SvgWriter svg = new();
|
||||
SvgUtils.AddSubject(svg, subject);
|
||||
SvgUtils.AddClip(svg, clip);
|
||||
if (fr == FillRule.Negative)
|
||||
solution = Clipper.ReversePaths(solution);
|
||||
SvgUtils.AddSolution(svg, solution, false);
|
||||
SvgUtils.AddCaption(svg, test_number.ToString(), 20, 20);
|
||||
string filename = @"..\..\..\poly" + (test_number - 1).ToString() + ".svg";
|
||||
SvgUtils.SaveToFile(svg, filename, fr, 800, 600, 10);
|
||||
ClipperFileIO.OpenFileWithDefaultApp(filename);
|
||||
}
|
||||
|
||||
if (!do_all) return;
|
||||
Console.WriteLine($"\ntest ended at polygon {test_number}.\n");
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
public static Paths64 LoadPathsFromResource(string resourceName)
|
||||
{
|
||||
using Stream stream = Assembly.GetExecutingAssembly().
|
||||
GetManifestResourceStream(resourceName);
|
||||
if (stream == null) return new Paths64();
|
||||
using BinaryReader reader = new (stream);
|
||||
int len = reader.ReadInt32();
|
||||
Paths64 result = new (len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
int len2 = reader.ReadInt32();
|
||||
Path64 p = new (len2);
|
||||
for (int j = 0; j < len2; j++)
|
||||
{
|
||||
long X = reader.ReadInt64();
|
||||
long Y = reader.ReadInt64();
|
||||
p.Add(new Point64(X, Y));
|
||||
}
|
||||
result.Add(p);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void ClipTestPolys()
|
||||
{
|
||||
const FillRule fillrule = FillRule.NonZero;
|
||||
Paths64 subject = LoadPathsFromResource("ConsoleDemo.subj.bin");
|
||||
Paths64 clip = LoadPathsFromResource("ConsoleDemo.clip.bin");
|
||||
Paths64 solution = Clipper.Intersect(subject, clip, fillrule);
|
||||
|
||||
SvgWriter svg = new();
|
||||
SvgUtils.AddSubject(svg, subject);
|
||||
SvgUtils.AddClip(svg, clip);
|
||||
SvgUtils.AddSolution(svg, solution, false);
|
||||
SvgUtils.SaveToFile(svg, @"..\..\..\clipperD.svg", fillrule, 800, 600, 20);
|
||||
ClipperFileIO.OpenFileWithDefaultApp(@"..\..\..\clipperD.svg");
|
||||
}
|
||||
|
||||
|
||||
} //end Application
|
||||
} //namespace
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32804.467
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestsZ", "TestsZ.csproj", "{BA651459-DAE8-4551-9E66-5F47C9BCDA4D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Clipper2LibZ", "..\..\USINGZ\Clipper2LibZ.csproj", "{45C3F035-9ABC-4CB0-B178-39DE365271F2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{BA651459-DAE8-4551-9E66-5F47C9BCDA4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BA651459-DAE8-4551-9E66-5F47C9BCDA4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BA651459-DAE8-4551-9E66-5F47C9BCDA4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BA651459-DAE8-4551-9E66-5F47C9BCDA4D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{45C3F035-9ABC-4CB0-B178-39DE365271F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{45C3F035-9ABC-4CB0-B178-39DE365271F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{45C3F035-9ABC-4CB0-B178-39DE365271F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{45C3F035-9ABC-4CB0-B178-39DE365271F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {AA98C6DD-16D2-4C58-8A41-F215CB93159E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,24 +1,27 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32630.192
|
||||
# Visual Studio Version 18
|
||||
VisualStudioVersion = 18.1.11304.174
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Clipper2Lib", "Clipper2Lib\Clipper2Lib.csproj", "{4CE00B81-F1B2-4012-9BBD-B0DB6BF8CAD3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Clipper2Lib.Benchmark", "Clipper2Lib.Benchmark\Clipper2Lib.Benchmark.csproj", "{F8A168C6-286A-4ECF-8750-C505ADBCB7D5}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3B52CBF2-1267-44C7-B447-C51ACDD25371}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Clipper2.SVG", "Utils\SVG\Clipper2.SVG.csproj", "{BC8E75BA-24E1-4D6A-AE54-0B1019C18EFE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Clipper.FileIO", "Utils\ClipFileIO\Clipper.FileIO.csproj", "{2EF8FB02-E3F6-46CE-954F-5E1B0AD64DB7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleDemo", "Clipper2Lib.Examples\ConsoleDemo\ConsoleDemo.csproj", "{DBFB59C1-C08D-48DC-9A15-CD18B5897BE4}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark", "Benchmark\Benchmark.csproj", "{42730287-9B8A-7ED6-2F08-B7B524CBA6F7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InflateDemo", "Clipper2Lib.Examples\InflateDemo\InflateDemo.csproj", "{DB7B56ED-474F-49A7-91F1-75EEB76A8B2B}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleDemo", "Examples\ConsoleDemo\ConsoleDemo.csproj", "{A8D262BC-3A04-D3BB-F7DE-8526D185AD2D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InflateDemo", "Examples\InflateDemo\InflateDemo.csproj", "{F43E0A11-E1BA-845E-8F13-F9FD6850D674}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RectClipDemo", "Examples\RectClip\RectClipDemo.csproj", "{B38A2827-6966-94C4-E1A5-193BB72DEFAC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TriangulationDemo", "Examples\Triangulation\TriangulationDemo.csproj", "{40EA8E33-F235-6FB9-6D4E-E0B8100A0200}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{F90F601E-9778-45C5-8E84-94323E2C74C0}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{A08D465C-8A47-4337-A720-15498FAAE63E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -30,10 +33,6 @@ Global
|
||||
{4CE00B81-F1B2-4012-9BBD-B0DB6BF8CAD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4CE00B81-F1B2-4012-9BBD-B0DB6BF8CAD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4CE00B81-F1B2-4012-9BBD-B0DB6BF8CAD3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F8A168C6-286A-4ECF-8750-C505ADBCB7D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F8A168C6-286A-4ECF-8750-C505ADBCB7D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F8A168C6-286A-4ECF-8750-C505ADBCB7D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F8A168C6-286A-4ECF-8750-C505ADBCB7D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BC8E75BA-24E1-4D6A-AE54-0B1019C18EFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BC8E75BA-24E1-4D6A-AE54-0B1019C18EFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BC8E75BA-24E1-4D6A-AE54-0B1019C18EFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -42,18 +41,38 @@ Global
|
||||
{2EF8FB02-E3F6-46CE-954F-5E1B0AD64DB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2EF8FB02-E3F6-46CE-954F-5E1B0AD64DB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2EF8FB02-E3F6-46CE-954F-5E1B0AD64DB7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DBFB59C1-C08D-48DC-9A15-CD18B5897BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DBFB59C1-C08D-48DC-9A15-CD18B5897BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DBFB59C1-C08D-48DC-9A15-CD18B5897BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DBFB59C1-C08D-48DC-9A15-CD18B5897BE4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DB7B56ED-474F-49A7-91F1-75EEB76A8B2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DB7B56ED-474F-49A7-91F1-75EEB76A8B2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DB7B56ED-474F-49A7-91F1-75EEB76A8B2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DB7B56ED-474F-49A7-91F1-75EEB76A8B2B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{42730287-9B8A-7ED6-2F08-B7B524CBA6F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{42730287-9B8A-7ED6-2F08-B7B524CBA6F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{42730287-9B8A-7ED6-2F08-B7B524CBA6F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{42730287-9B8A-7ED6-2F08-B7B524CBA6F7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A8D262BC-3A04-D3BB-F7DE-8526D185AD2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A8D262BC-3A04-D3BB-F7DE-8526D185AD2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A8D262BC-3A04-D3BB-F7DE-8526D185AD2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A8D262BC-3A04-D3BB-F7DE-8526D185AD2D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F43E0A11-E1BA-845E-8F13-F9FD6850D674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F43E0A11-E1BA-845E-8F13-F9FD6850D674}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F43E0A11-E1BA-845E-8F13-F9FD6850D674}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F43E0A11-E1BA-845E-8F13-F9FD6850D674}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B38A2827-6966-94C4-E1A5-193BB72DEFAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B38A2827-6966-94C4-E1A5-193BB72DEFAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B38A2827-6966-94C4-E1A5-193BB72DEFAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B38A2827-6966-94C4-E1A5-193BB72DEFAC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{40EA8E33-F235-6FB9-6D4E-E0B8100A0200}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{40EA8E33-F235-6FB9-6D4E-E0B8100A0200}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{40EA8E33-F235-6FB9-6D4E-E0B8100A0200}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{40EA8E33-F235-6FB9-6D4E-E0B8100A0200}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{BC8E75BA-24E1-4D6A-AE54-0B1019C18EFE} = {A08D465C-8A47-4337-A720-15498FAAE63E}
|
||||
{2EF8FB02-E3F6-46CE-954F-5E1B0AD64DB7} = {A08D465C-8A47-4337-A720-15498FAAE63E}
|
||||
{A8D262BC-3A04-D3BB-F7DE-8526D185AD2D} = {F90F601E-9778-45C5-8E84-94323E2C74C0}
|
||||
{F43E0A11-E1BA-845E-8F13-F9FD6850D674} = {F90F601E-9778-45C5-8E84-94323E2C74C0}
|
||||
{B38A2827-6966-94C4-E1A5-193BB72DEFAC} = {F90F601E-9778-45C5-8E84-94323E2C74C0}
|
||||
{40EA8E33-F235-6FB9-6D4E-E0B8100A0200} = {F90F601E-9778-45C5-8E84-94323E2C74C0}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {EB14E46A-0760-411E-B991-4E0B4DBBFF93}
|
||||
EndGlobalSection
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 22 January 2025 *
|
||||
* Date : 12 December 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : Core structures and functions for the Clipper Library *
|
||||
@@ -12,7 +12,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#if USINGZ
|
||||
namespace Clipper2ZLib
|
||||
#else
|
||||
namespace Clipper2Lib
|
||||
#endif
|
||||
{
|
||||
public struct Point64
|
||||
{
|
||||
@@ -429,11 +433,7 @@ namespace Clipper2Lib
|
||||
public Path64(IEnumerable<Point64> path) : base(path) { }
|
||||
public override string ToString()
|
||||
{
|
||||
string s = "";
|
||||
foreach (Point64 p in this)
|
||||
s = s + p.ToString() + ", ";
|
||||
if (s != "") s = s.Remove(s.Length - 2);
|
||||
return s;
|
||||
return string.Join(", ", this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,10 +444,7 @@ namespace Clipper2Lib
|
||||
public Paths64(IEnumerable<Path64> paths) : base(paths) { }
|
||||
public override string ToString()
|
||||
{
|
||||
string s = "";
|
||||
foreach (Path64 p in this)
|
||||
s = s + p + "\n";
|
||||
return s;
|
||||
return string.Join(Environment.NewLine, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,11 +455,7 @@ namespace Clipper2Lib
|
||||
public PathD(IEnumerable<PointD> path) : base(path) { }
|
||||
public string ToString(int precision = 2)
|
||||
{
|
||||
string s = "";
|
||||
foreach (PointD p in this)
|
||||
s = s + p.ToString(precision) + ", ";
|
||||
if (s != "") s = s.Remove(s.Length - 2);
|
||||
return s;
|
||||
return string.Join(", ", ConvertAll(x => x.ToString(precision)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,10 +466,7 @@ namespace Clipper2Lib
|
||||
public PathsD(IEnumerable<PathD> paths) : base(paths) { }
|
||||
public string ToString(int precision = 2)
|
||||
{
|
||||
string s = "";
|
||||
foreach (PathD p in this)
|
||||
s = s + p.ToString(precision) + "\n";
|
||||
return s;
|
||||
return string.Join(Environment.NewLine, ConvertAll(x => x.ToString(precision)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,14 +497,6 @@ namespace Clipper2Lib
|
||||
Negative
|
||||
}
|
||||
|
||||
// PointInPolygon
|
||||
internal enum PipResult
|
||||
{
|
||||
Inside,
|
||||
Outside,
|
||||
OnEdge
|
||||
}
|
||||
|
||||
public static class InternalClipper
|
||||
{
|
||||
internal const long MaxInt64 = 9223372036854775807;
|
||||
@@ -536,6 +518,31 @@ namespace Clipper2Lib
|
||||
(double) (pt2.Y - pt1.Y) * (pt3.X - pt2.X));
|
||||
}
|
||||
|
||||
public static int CrossProductSign(Point64 pt1, Point64 pt2, Point64 pt3)
|
||||
{
|
||||
long a = pt2.X - pt1.X;
|
||||
long b = pt3.Y - pt2.Y;
|
||||
long c = pt2.Y - pt1.Y;
|
||||
long d = pt3.X - pt2.X;
|
||||
UInt128Struct ab = MultiplyUInt64((ulong) Math.Abs(a), (ulong) Math.Abs(b));
|
||||
UInt128Struct cd = MultiplyUInt64((ulong) Math.Abs(c), (ulong) Math.Abs(d));
|
||||
int signAB = TriSign(a) * TriSign(b);
|
||||
int signCD = TriSign(c) * TriSign(d);
|
||||
|
||||
if (signAB == signCD)
|
||||
{
|
||||
int result;
|
||||
if (ab.hi64 == cd.hi64)
|
||||
{
|
||||
if (ab.lo64 == cd.lo64) return 0;
|
||||
result = (ab.lo64 > cd.lo64) ? 1 : -1;
|
||||
}
|
||||
else result = (ab.hi64 > cd.hi64) ? 1 : -1;
|
||||
return (signAB > 0) ? result : -result;
|
||||
}
|
||||
return (signAB > signCD) ? 1 : -1;
|
||||
}
|
||||
|
||||
#if USINGZ
|
||||
public static Path64 SetZ(Path64 path, long Z)
|
||||
{
|
||||
@@ -561,23 +568,22 @@ namespace Clipper2Lib
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int TriSign(long x) // returns 0, 1 or -1
|
||||
{
|
||||
if (x < 0) return -1;
|
||||
return x > 1 ? 1 : 0;
|
||||
return (x < 0) ? -1 : (x > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
public struct MultiplyUInt64Result
|
||||
public struct UInt128Struct
|
||||
{
|
||||
public ulong lo64;
|
||||
public ulong hi64;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static MultiplyUInt64Result MultiplyUInt64(ulong a, ulong b) // #834,#835
|
||||
public static UInt128Struct MultiplyUInt64(ulong a, ulong b) // #834,#835
|
||||
{
|
||||
ulong x1 = (a & 0xFFFFFFFF) * (b & 0xFFFFFFFF);
|
||||
ulong x2 = (a >> 32) * (b & 0xFFFFFFFF) + (x1 >> 32);
|
||||
ulong x3 = (a & 0xFFFFFFFF) * (b >> 32) + (x2 & 0xFFFFFFFF);
|
||||
MultiplyUInt64Result result;
|
||||
UInt128Struct result;
|
||||
result.lo64 = (x3 & 0xFFFFFFFF) << 32 | (x1 & 0xFFFFFFFF);
|
||||
result.hi64 = (a >> 32) * (b >> 32) + (x2 >> 32) + (x3 >> 32);
|
||||
return result;
|
||||
@@ -592,8 +598,8 @@ namespace Clipper2Lib
|
||||
ulong absC = (ulong) Math.Abs(c);
|
||||
ulong absD = (ulong) Math.Abs(d);
|
||||
|
||||
MultiplyUInt64Result mul_ab = MultiplyUInt64(absA, absB);
|
||||
MultiplyUInt64Result mul_cd = MultiplyUInt64(absC, absD);
|
||||
UInt128Struct mul_ab = MultiplyUInt64(absA, absB);
|
||||
UInt128Struct mul_cd = MultiplyUInt64(absC, absD);
|
||||
|
||||
// nb: it's important to differentiate 0 values here from other values
|
||||
int sign_ab = TriSign(a) * TriSign(b);
|
||||
@@ -641,9 +647,12 @@ namespace Clipper2Lib
|
||||
return (long)Math.Round(val, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
|
||||
// GetLineIntersectPt - a 'true' result is non-parallel. The 'ip' will also
|
||||
// be constrained to seg1. However, it's possible that 'ip' won't be inside
|
||||
// seg2, even when 'ip' hasn't been constrained (ie 'ip' is inside seg1).
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool GetSegmentIntersectPt(Point64 ln1a,
|
||||
public static bool GetLineIntersectPt(Point64 ln1a,
|
||||
Point64 ln1b, Point64 ln2a, Point64 ln2b, out Point64 ip)
|
||||
{
|
||||
double dy1 = (ln1b.Y - ln1a.Y);
|
||||
@@ -660,7 +669,8 @@ namespace Clipper2Lib
|
||||
double t = ((ln1a.X - ln2a.X) * dy2 - (ln1a.Y - ln2a.Y) * dx2) / det;
|
||||
if (t <= 0.0) ip = ln1a;
|
||||
else if (t >= 1.0) ip = ln1b;
|
||||
else {
|
||||
else
|
||||
{
|
||||
// avoid using constructor (and rounding too) as they affect performance //664
|
||||
ip.X = (long) (ln1a.X + t * dx1);
|
||||
ip.Y = (long) (ln1a.Y + t * dy1);
|
||||
@@ -671,23 +681,94 @@ namespace Clipper2Lib
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool GetLineIntersectPt(PointD ln1a,
|
||||
PointD ln1b, PointD ln2a, PointD ln2b, out PointD ip)
|
||||
{
|
||||
double dy1 = (ln1b.y - ln1a.y);
|
||||
double dx1 = (ln1b.x - ln1a.x);
|
||||
double dy2 = (ln2b.y - ln2a.y);
|
||||
double dx2 = (ln2b.x - ln2a.x);
|
||||
double det = dy1 * dx2 - dy2 * dx1;
|
||||
if (det == 0.0)
|
||||
{
|
||||
ip = new PointD();
|
||||
return false;
|
||||
}
|
||||
|
||||
double t = ((ln1a.x - ln2a.x) * dy2 - (ln1a.y - ln2a.y) * dx2) / det;
|
||||
if (t <= 0.0) ip = ln1a;
|
||||
else if (t >= 1.0) ip = ln1b;
|
||||
else
|
||||
{
|
||||
// avoid using constructor (and rounding too) as they affect performance //664
|
||||
ip.x = (ln1a.x + t * dx1);
|
||||
ip.y = (ln1a.y + t * dy1);
|
||||
#if USINGZ
|
||||
ip.z = 0;
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool SegsIntersect(Point64 seg1a,
|
||||
Point64 seg1b, Point64 seg2a, Point64 seg2b, bool inclusive = false)
|
||||
{
|
||||
if (!inclusive)
|
||||
return (CrossProduct(seg1a, seg2a, seg2b) *
|
||||
CrossProduct(seg1b, seg2a, seg2b) < 0) &&
|
||||
(CrossProduct(seg2a, seg1a, seg1b) *
|
||||
CrossProduct(seg2b, seg1a, seg1b) < 0);
|
||||
double res1 = CrossProduct(seg1a, seg2a, seg2b);
|
||||
double res2 = CrossProduct(seg1b, seg2a, seg2b);
|
||||
if (res1 * res2 > 0) return false;
|
||||
double res3 = CrossProduct(seg2a, seg1a, seg1b);
|
||||
double res4 = CrossProduct(seg2b, seg1a, seg1b);
|
||||
if (res3 * res4 > 0) return false;
|
||||
// ensure NOT collinear
|
||||
return (res1 != 0 || res2 != 0 || res3 != 0 || res4 != 0);
|
||||
double dy1 = (seg1b.Y - seg1a.Y);
|
||||
double dx1 = (seg1b.X - seg1a.X);
|
||||
double dy2 = (seg2b.Y - seg2a.Y);
|
||||
double dx2 = (seg2b.X - seg2a.X);
|
||||
double cp = dy1 * dx2 - dy2 * dx1;
|
||||
if (cp == 0) return false; // ie parallel segments
|
||||
|
||||
if (inclusive)
|
||||
{
|
||||
//result **includes** segments that touch at an end point
|
||||
double t = ((seg1a.X - seg2a.X) * dy2 - (seg1a.Y - seg2a.Y) * dx2);
|
||||
if (t == 0) return true;
|
||||
if (t > 0)
|
||||
{
|
||||
if (cp < 0 || t > cp) return false;
|
||||
}
|
||||
else if (cp > 0 || t < cp) return false; // false when t more neg. than cp
|
||||
|
||||
t = ((seg1a.X - seg2a.X) * dy1 - (seg1a.Y - seg2a.Y) * dx1);
|
||||
if (t == 0) return true;
|
||||
if (t > 0) return (cp > 0 && t <= cp);
|
||||
else return (cp < 0 && t >= cp); // true when t less neg. than cp
|
||||
}
|
||||
else
|
||||
{
|
||||
//result **excludes** segments that touch at an end point
|
||||
double t = ((seg1a.X - seg2a.X) * dy2 - (seg1a.Y - seg2a.Y) * dx2);
|
||||
if (t == 0) return false;
|
||||
if (t > 0)
|
||||
{
|
||||
if (cp < 0 || t >= cp) return false;
|
||||
}
|
||||
else if (cp > 0 || t <= cp) return false; // false when t more neg. than cp
|
||||
|
||||
t = ((seg1a.X - seg2a.X) * dy1 - (seg1a.Y - seg2a.Y) * dx1);
|
||||
if (t == 0) return false;
|
||||
if (t > 0) return (cp > 0 && t < cp);
|
||||
else return (cp < 0 && t > cp); // true when t less neg. than cp
|
||||
}
|
||||
}
|
||||
|
||||
public static Rect64 GetBounds(Path64 path)
|
||||
{
|
||||
if (path.Count == 0) return new Rect64();
|
||||
Rect64 result = Clipper.InvalidRect64;
|
||||
foreach (Point64 pt in path)
|
||||
{
|
||||
if (pt.X < result.left) result.left = pt.X;
|
||||
if (pt.X > result.right) result.right = pt.X;
|
||||
if (pt.Y < result.top) result.top = pt.Y;
|
||||
if (pt.Y > result.bottom) result.bottom = pt.Y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Point64 GetClosestPtOnSegment(Point64 offPt,
|
||||
Point64 seg1, Point64 seg2)
|
||||
{
|
||||
@@ -712,7 +793,6 @@ namespace Clipper2Lib
|
||||
while (start < len && polygon[start].Y == pt.Y) start++;
|
||||
if (start == len) return PointInPolygonResult.IsOutside;
|
||||
|
||||
double d;
|
||||
bool isAbove = polygon[start].Y < pt.Y, startingAbove = isAbove;
|
||||
int val = 0, i = start + 1, end = len;
|
||||
while (true)
|
||||
@@ -759,23 +839,51 @@ namespace Clipper2Lib
|
||||
}
|
||||
else
|
||||
{
|
||||
d = CrossProduct(prev, curr, pt);
|
||||
if (d == 0) return PointInPolygonResult.IsOn;
|
||||
if ((d < 0) == isAbove) val = 1 - val;
|
||||
int cps2 = CrossProductSign(prev, curr, pt);
|
||||
if (cps2 == 0) return PointInPolygonResult.IsOn;
|
||||
if ((cps2 < 0) == isAbove) val = 1 - val;
|
||||
}
|
||||
isAbove = !isAbove;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (isAbove == startingAbove) return val == 0 ? PointInPolygonResult.IsOutside : PointInPolygonResult.IsInside;
|
||||
if (i == len) i = 0;
|
||||
d = i == 0 ? CrossProduct(polygon[len - 1], polygon[0], pt) : CrossProduct(polygon[i - 1], polygon[i], pt);
|
||||
if (d == 0) return PointInPolygonResult.IsOn;
|
||||
if ((d < 0) == isAbove) val = 1 - val;
|
||||
if (i == len) i = 0;
|
||||
int cps = (i == 0) ?
|
||||
CrossProductSign(polygon[len - 1], polygon[0], pt) :
|
||||
CrossProductSign(polygon[i - 1], polygon[i], pt);
|
||||
|
||||
if (cps == 0) return PointInPolygonResult.IsOn;
|
||||
if ((cps < 0) == isAbove) val = 1 - val;
|
||||
return val == 0 ? PointInPolygonResult.IsOutside : PointInPolygonResult.IsInside;
|
||||
}
|
||||
|
||||
public static bool Path2ContainsPath1(Path64 path1, Path64 path2)
|
||||
{
|
||||
// we need to make some accommodation for rounding errors
|
||||
// so we won't jump if the first vertex is found outside
|
||||
PointInPolygonResult pip = PointInPolygonResult.IsOn;
|
||||
foreach (Point64 pt in path1)
|
||||
{
|
||||
switch (PointInPolygon(pt, path2))
|
||||
{
|
||||
case PointInPolygonResult.IsOutside:
|
||||
if (pip == PointInPolygonResult.IsOutside) return false;
|
||||
pip = PointInPolygonResult.IsOutside;
|
||||
break;
|
||||
case PointInPolygonResult.IsInside:
|
||||
if (pip == PointInPolygonResult.IsInside) return true;
|
||||
pip = PointInPolygonResult.IsInside;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
// since path1's location is still equivocal, check its midpoint
|
||||
Point64 mp = GetBounds(path1).MidPoint();
|
||||
return InternalClipper.PointInPolygon(mp, path2) != PointInPolygonResult.IsOutside;
|
||||
}
|
||||
|
||||
|
||||
} // InternalClipper
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 10 October 2024 *
|
||||
* Date : 21 February 2026 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2026 *
|
||||
* Purpose : This is the main polygon clipping module *
|
||||
* Thanks : Special thanks to Thong Nguyen, Guus Kuiper, Phil Stopford, *
|
||||
* : and Daniel Gosnell for their invaluable assistance with C#. *
|
||||
@@ -15,7 +15,11 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#if USINGZ
|
||||
namespace Clipper2ZLib
|
||||
#else
|
||||
namespace Clipper2Lib
|
||||
#endif
|
||||
{
|
||||
|
||||
// Vertex: a pre-clipping data structure. It is used to separate polygons
|
||||
@@ -41,7 +45,7 @@ namespace Clipper2Lib
|
||||
|
||||
internal class Vertex
|
||||
{
|
||||
public readonly Point64 pt;
|
||||
public Point64 pt;
|
||||
public Vertex? next;
|
||||
public Vertex? prev;
|
||||
public VertexFlags flags;
|
||||
@@ -141,6 +145,7 @@ namespace Clipper2Lib
|
||||
internal class OutRec
|
||||
{
|
||||
public int idx;
|
||||
public int outPtCount;
|
||||
public OutRec? owner;
|
||||
public Active? frontEdge;
|
||||
public Active? backEdge;
|
||||
@@ -233,7 +238,7 @@ namespace Clipper2Lib
|
||||
}
|
||||
|
||||
internal static void AddPathsToVertexList(Paths64 paths, PathType polytype, bool isOpen,
|
||||
List<LocalMinima> minimaList, List<Vertex> vertexList)
|
||||
List<LocalMinima> minimaList, VertexPoolList vertexList)
|
||||
{
|
||||
int totalVertCnt = 0;
|
||||
foreach (Path64 path in paths) totalVertCnt += path.Count;
|
||||
@@ -246,14 +251,12 @@ namespace Clipper2Lib
|
||||
{
|
||||
if (v0 == null)
|
||||
{
|
||||
v0 = new Vertex(pt, VertexFlags.None, null);
|
||||
vertexList.Add(v0);
|
||||
v0 = vertexList.Add(pt, VertexFlags.None, null);
|
||||
prev_v = v0;
|
||||
}
|
||||
else if (prev_v!.pt != pt) // ie skips duplicates
|
||||
{
|
||||
curr_v = new Vertex(pt, VertexFlags.None, prev_v);
|
||||
vertexList.Add(curr_v);
|
||||
curr_v = vertexList.Add(pt, VertexFlags.None, prev_v);
|
||||
prev_v.next = curr_v;
|
||||
prev_v = curr_v;
|
||||
}
|
||||
@@ -329,11 +332,11 @@ namespace Clipper2Lib
|
||||
public class ReuseableDataContainer64
|
||||
{
|
||||
internal readonly List<LocalMinima> _minimaList;
|
||||
internal readonly List<Vertex> _vertexList;
|
||||
internal readonly VertexPoolList _vertexList;
|
||||
public ReuseableDataContainer64()
|
||||
{
|
||||
_minimaList = new List<LocalMinima>();
|
||||
_vertexList = new List<Vertex>();
|
||||
_vertexList = new VertexPoolList();
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
@@ -353,13 +356,15 @@ namespace Clipper2Lib
|
||||
private FillRule _fillrule;
|
||||
private Active? _actives;
|
||||
private Active? _sel;
|
||||
private Stack<Active> _freeActives;
|
||||
private readonly List<LocalMinima> _minimaList;
|
||||
private readonly List<IntersectNode> _intersectList;
|
||||
private readonly List<Vertex> _vertexList;
|
||||
private readonly List<OutRec> _outrecList;
|
||||
private readonly VertexPoolList _vertexList;
|
||||
private readonly OutRecPoolList _outrecList;
|
||||
private readonly List<long> _scanlineList;
|
||||
private readonly List<HorzSegment> _horzSegList;
|
||||
private readonly List<HorzJoin> _horzJoinList;
|
||||
private readonly HorzJoinPoolList _horzJoinList;
|
||||
private readonly OutPtPoolList _outPtPool;
|
||||
private int _currentLocMin;
|
||||
private long _currentBotY;
|
||||
private bool _isSortedMinimaList;
|
||||
@@ -380,11 +385,13 @@ namespace Clipper2Lib
|
||||
{
|
||||
_minimaList = new List<LocalMinima>();
|
||||
_intersectList = new List<IntersectNode>();
|
||||
_vertexList = new List<Vertex>();
|
||||
_outrecList = new List<OutRec>();
|
||||
_vertexList = new VertexPoolList();
|
||||
_outrecList = new OutRecPoolList();
|
||||
_scanlineList = new List<long>();
|
||||
_horzSegList = new List<HorzSegment>();
|
||||
_horzJoinList = new List<HorzJoin>();
|
||||
_horzJoinList = new HorzJoinPoolList();
|
||||
_outPtPool = new OutPtPoolList();
|
||||
_freeActives = new Stack<Active>();
|
||||
PreserveCollinear = true;
|
||||
}
|
||||
|
||||
@@ -758,6 +765,8 @@ namespace Clipper2Lib
|
||||
_outrecList.Clear();
|
||||
_horzSegList.Clear();
|
||||
_horzJoinList.Clear();
|
||||
_outPtPool.Clear();
|
||||
_freeActives.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -1075,7 +1084,7 @@ namespace Clipper2Lib
|
||||
return newcomer.curX > resident.curX;
|
||||
|
||||
// get the turning direction a1.top, a2.bot, a2.top
|
||||
double d = InternalClipper.CrossProduct(resident.top, newcomer.bot, newcomer.top);
|
||||
int d = InternalClipper.CrossProductSign(resident.top, newcomer.bot, newcomer.top);
|
||||
if (d != 0) return (d < 0);
|
||||
|
||||
// edges must be collinear to get here
|
||||
@@ -1084,13 +1093,13 @@ namespace Clipper2Lib
|
||||
// the direction they're about to turn
|
||||
if (!IsMaxima(resident) && (resident.top.Y > newcomer.top.Y))
|
||||
{
|
||||
return InternalClipper.CrossProduct(newcomer.bot,
|
||||
return InternalClipper.CrossProductSign(newcomer.bot,
|
||||
resident.top, NextVertex(resident).pt) <= 0;
|
||||
}
|
||||
|
||||
if (!IsMaxima(newcomer) && (newcomer.top.Y > resident.top.Y))
|
||||
{
|
||||
return InternalClipper.CrossProduct(newcomer.bot,
|
||||
return InternalClipper.CrossProductSign(newcomer.bot,
|
||||
newcomer.top, NextVertex(newcomer).pt) >= 0;
|
||||
}
|
||||
|
||||
@@ -1105,7 +1114,7 @@ namespace Clipper2Lib
|
||||
if (InternalClipper.IsCollinear(PrevPrevVertex(resident).pt,
|
||||
resident.bot, resident.top)) return true;
|
||||
// compare turning direction of the alternate bound
|
||||
return (InternalClipper.CrossProduct(PrevPrevVertex(resident).pt,
|
||||
return (InternalClipper.CrossProductSign(PrevPrevVertex(resident).pt,
|
||||
newcomer.bot, PrevPrevVertex(newcomer).pt) > 0) == newcomerIsLeft;
|
||||
}
|
||||
|
||||
@@ -1162,16 +1171,14 @@ namespace Clipper2Lib
|
||||
}
|
||||
else
|
||||
{
|
||||
leftBound = new Active
|
||||
{
|
||||
bot = localMinima.vertex.pt,
|
||||
curX = localMinima.vertex.pt.X,
|
||||
windDx = -1,
|
||||
vertexTop = localMinima.vertex.prev,
|
||||
top = localMinima.vertex.prev!.pt,
|
||||
outrec = null,
|
||||
localMin = localMinima
|
||||
};
|
||||
leftBound = NewActive();
|
||||
leftBound.bot = localMinima.vertex.pt;
|
||||
leftBound.curX = localMinima.vertex.pt.X;
|
||||
leftBound.windDx = -1;
|
||||
leftBound.vertexTop = localMinima.vertex.prev;
|
||||
leftBound.top = localMinima.vertex.prev!.pt;
|
||||
leftBound.outrec = null;
|
||||
leftBound.localMin = localMinima;
|
||||
SetDx(leftBound);
|
||||
}
|
||||
|
||||
@@ -1182,16 +1189,14 @@ namespace Clipper2Lib
|
||||
}
|
||||
else
|
||||
{
|
||||
rightBound = new Active
|
||||
{
|
||||
bot = localMinima.vertex.pt,
|
||||
curX = localMinima.vertex.pt.X,
|
||||
windDx = 1,
|
||||
vertexTop = localMinima.vertex.next, // i.e. ascending
|
||||
top = localMinima.vertex.next!.pt,
|
||||
outrec = null,
|
||||
localMin = localMinima
|
||||
};
|
||||
rightBound = NewActive();
|
||||
rightBound.bot = localMinima.vertex.pt;
|
||||
rightBound.curX = localMinima.vertex.pt.X;
|
||||
rightBound.windDx = 1;
|
||||
rightBound.vertexTop = localMinima.vertex.next; // i.e. ascending
|
||||
rightBound.top = localMinima.vertex.next!.pt;
|
||||
rightBound.outrec = null;
|
||||
rightBound.localMin = localMinima;
|
||||
SetDx(rightBound);
|
||||
}
|
||||
|
||||
@@ -1331,7 +1336,7 @@ namespace Clipper2Lib
|
||||
}
|
||||
}
|
||||
|
||||
OutPt op = new OutPt(pt, outrec);
|
||||
OutPt op = _outPtPool.Add(pt, outrec);
|
||||
outrec.pts = op;
|
||||
return op;
|
||||
}
|
||||
@@ -1425,6 +1430,7 @@ namespace Clipper2Lib
|
||||
ae2.outrec.frontEdge = null;
|
||||
ae2.outrec.backEdge = null;
|
||||
ae2.outrec.pts = null;
|
||||
ae1.outrec.outPtCount += ae2.outrec.outPtCount;
|
||||
SetOwner(ae2.outrec, ae1.outrec);
|
||||
|
||||
if (IsOpenEnd(ae1))
|
||||
@@ -1439,7 +1445,7 @@ namespace Clipper2Lib
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static OutPt AddOutPt(Active ae, Point64 pt)
|
||||
private OutPt AddOutPt(Active ae, Point64 pt)
|
||||
{
|
||||
|
||||
// Outrec.OutPts: a circular doubly-linked-list of POutPt where ...
|
||||
@@ -1457,7 +1463,7 @@ namespace Clipper2Lib
|
||||
return opBack;
|
||||
}
|
||||
|
||||
OutPt newOp = new OutPt(pt, outrec);
|
||||
OutPt newOp = _outPtPool.Add(pt, outrec);
|
||||
opBack.prev = newOp;
|
||||
newOp.prev = opFront;
|
||||
newOp.next = opBack;
|
||||
@@ -1469,11 +1475,9 @@ namespace Clipper2Lib
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private OutRec NewOutRec()
|
||||
{
|
||||
OutRec result = new OutRec
|
||||
{
|
||||
idx = _outrecList.Count
|
||||
};
|
||||
_outrecList.Add(result);
|
||||
int idx = _outrecList.Count;
|
||||
OutRec result = _outrecList.Add();
|
||||
result.idx = idx;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1494,7 +1498,7 @@ namespace Clipper2Lib
|
||||
}
|
||||
|
||||
ae.outrec = outrec;
|
||||
OutPt op = new OutPt(pt, outrec);
|
||||
OutPt op = _outPtPool.Add(pt, outrec);
|
||||
outrec.pts = op;
|
||||
return op;
|
||||
}
|
||||
@@ -1810,6 +1814,45 @@ namespace Clipper2Lib
|
||||
_actives = next;
|
||||
if (next != null) next.prevInAEL = prev;
|
||||
// delete &ae;
|
||||
PoolDeletedActive(ae);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void PoolDeletedActive(Active ae)
|
||||
{
|
||||
//clear refs to allow GC
|
||||
ae.bot = new Point64();
|
||||
ae.top = new Point64();
|
||||
ae.dx = 0.0;
|
||||
ae.windCount = 0;
|
||||
ae.windCount2 = 0;
|
||||
ae.outrec = null;
|
||||
ae.prevInAEL = null;
|
||||
ae.nextInAEL = null;
|
||||
ae.prevInSEL = null;
|
||||
ae.nextInSEL = null;
|
||||
ae.jump = null;
|
||||
ae.vertexTop = null;
|
||||
ae.localMin = new LocalMinima();
|
||||
ae.isLeftBound = false;
|
||||
ae.joinWith = JoinWith.None;
|
||||
_freeActives.Push(ae);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private Active NewActive()
|
||||
{
|
||||
Active ae;
|
||||
if (_freeActives.Count == 0)
|
||||
{
|
||||
ae = new Active();
|
||||
}
|
||||
else
|
||||
{
|
||||
//recycle active from free list
|
||||
ae = _freeActives.Pop();
|
||||
}
|
||||
return ae;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -1822,8 +1865,9 @@ namespace Clipper2Lib
|
||||
ae.prevInSEL = ae.prevInAEL;
|
||||
ae.nextInSEL = ae.nextInAEL;
|
||||
ae.jump = ae.nextInSEL;
|
||||
ae.curX = ae.joinWith == JoinWith.Left ? ae.prevInAEL!.curX : // this also avoids complications
|
||||
TopX(ae, topY);
|
||||
// it is safe to ignore 'joined' edges here because
|
||||
// if necessary they will be split in IntersectEdges()
|
||||
ae.curX = TopX(ae, topY);
|
||||
// NB don't update ae.curr.Y yet (see AddNewIntersectNode)
|
||||
ae = ae.nextInAEL;
|
||||
}
|
||||
@@ -1873,7 +1917,7 @@ namespace Clipper2Lib
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void AddNewIntersectNode(Active ae1, Active ae2, long topY)
|
||||
{
|
||||
if (!InternalClipper.GetSegmentIntersectPt(
|
||||
if (!InternalClipper.GetLineIntersectPt(
|
||||
ae1.bot, ae1.top, ae2.bot, ae2.top, out Point64 ip))
|
||||
ip = new Point64(ae1.curX, topY);
|
||||
|
||||
@@ -2494,9 +2538,9 @@ private void DoHorizontal(Active horz)
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static OutPt DuplicateOp(OutPt op, bool insert_after)
|
||||
private OutPt DuplicateOp(OutPt op, bool insert_after)
|
||||
{
|
||||
OutPt result = new OutPt(op.pt, op.outrec);
|
||||
OutPt result = _outPtPool.Add(op.pt, op.outrec);
|
||||
if (insert_after)
|
||||
{
|
||||
result.next = op.next;
|
||||
@@ -2553,10 +2597,9 @@ private void DoHorizontal(Active horz)
|
||||
while (hs2.leftOp.prev.pt.Y == curr_y &&
|
||||
hs2.leftOp.prev.pt.X <= hs1.leftOp.pt.X)
|
||||
(hs2).leftOp = (hs2).leftOp.prev;
|
||||
HorzJoin join = new HorzJoin(
|
||||
HorzJoin join = _horzJoinList.Add(
|
||||
DuplicateOp((hs1).leftOp, true),
|
||||
DuplicateOp((hs2).leftOp, false));
|
||||
_horzJoinList.Add(join);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2566,10 +2609,9 @@ private void DoHorizontal(Active horz)
|
||||
while (hs2.leftOp.next!.pt.Y == curr_y &&
|
||||
hs2.leftOp.next.pt.X <= (hs1).leftOp.pt.X)
|
||||
hs2.leftOp = (hs2).leftOp.next;
|
||||
HorzJoin join = new HorzJoin(
|
||||
HorzJoin join = _horzJoinList.Add(
|
||||
DuplicateOp((hs2).leftOp, true),
|
||||
DuplicateOp((hs1).leftOp, false));
|
||||
_horzJoinList.Add(join);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2647,7 +2689,7 @@ private void DoHorizontal(Active horz)
|
||||
val = 1 - val; // toggle val
|
||||
else
|
||||
{
|
||||
double d = InternalClipper.CrossProduct(op2.prev.pt, op2.pt, pt);
|
||||
int d = InternalClipper.CrossProductSign(op2.prev.pt, op2.pt, pt);
|
||||
if (d == 0) return PointInPolygonResult.IsOn;
|
||||
if ((d < 0) == isAbove) val = 1 - val;
|
||||
}
|
||||
@@ -2658,7 +2700,7 @@ private void DoHorizontal(Active horz)
|
||||
|
||||
if (isAbove == startingAbove) return val == 0 ? PointInPolygonResult.IsOutside : PointInPolygonResult.IsInside;
|
||||
{
|
||||
double d = InternalClipper.CrossProduct(op2.prev.pt, op2.pt, pt);
|
||||
int d = InternalClipper.CrossProductSign(op2.prev.pt, op2.pt, pt);
|
||||
if (d == 0) return PointInPolygonResult.IsOn;
|
||||
if ((d < 0) == isAbove) val = 1 - val;
|
||||
}
|
||||
@@ -2670,27 +2712,26 @@ private void DoHorizontal(Active horz)
|
||||
{
|
||||
// we need to make some accommodation for rounding errors
|
||||
// so we won't jump if the first vertex is found outside
|
||||
int outside_cnt = 0;
|
||||
PointInPolygonResult pip = PointInPolygonResult.IsOn;
|
||||
OutPt op = op1;
|
||||
do
|
||||
{
|
||||
PointInPolygonResult result = PointInOpPolygon(op.pt, op2);
|
||||
switch (result)
|
||||
switch (PointInOpPolygon(op.pt, op2))
|
||||
{
|
||||
case PointInPolygonResult.IsOutside:
|
||||
++outside_cnt;
|
||||
if (pip == PointInPolygonResult.IsOutside) return false;
|
||||
pip = PointInPolygonResult.IsOutside;
|
||||
break;
|
||||
case PointInPolygonResult.IsInside:
|
||||
--outside_cnt;
|
||||
if (pip == PointInPolygonResult.IsInside) return true;
|
||||
pip = PointInPolygonResult.IsInside;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
op = op.next!;
|
||||
} while (op != op1 && Math.Abs(outside_cnt) < 2);
|
||||
if (Math.Abs(outside_cnt) > 1) return (outside_cnt < 0);
|
||||
// since path1's location is still equivocal, check its midpoint
|
||||
Point64 mp = GetBounds(GetCleanPath(op1)).MidPoint();
|
||||
Path64 path2 = GetCleanPath(op2);
|
||||
return InternalClipper.PointInPolygon(mp, path2) != PointInPolygonResult.IsOutside;
|
||||
} while (op != op1);
|
||||
// result is unclear, so try again using cleaned paths
|
||||
return InternalClipper.Path2ContainsPath1(GetCleanPath(op1), GetCleanPath(op2)); // (#973)
|
||||
}
|
||||
|
||||
private static void MoveSplits(OutRec fromOr, OutRec toOr)
|
||||
@@ -2698,7 +2739,8 @@ private void DoHorizontal(Active horz)
|
||||
if (fromOr.splits == null) return;
|
||||
toOr.splits ??= new List<int>();
|
||||
foreach (int i in fromOr.splits)
|
||||
toOr.splits.Add(i);
|
||||
if (i != toOr.idx)
|
||||
toOr.splits.Add(i);
|
||||
fromOr.splits = null;
|
||||
}
|
||||
|
||||
@@ -2847,7 +2889,7 @@ private void DoHorizontal(Active horz)
|
||||
OutPt nextNextOp = splitOp.next!.next!;
|
||||
outrec.pts = prevOp;
|
||||
|
||||
InternalClipper.GetSegmentIntersectPt(
|
||||
InternalClipper.GetLineIntersectPt(
|
||||
prevOp.pt, splitOp.pt, splitOp.next.pt, nextNextOp.pt, out Point64 ip);
|
||||
|
||||
#if USINGZ
|
||||
@@ -2876,7 +2918,9 @@ private void DoHorizontal(Active horz)
|
||||
}
|
||||
else
|
||||
{
|
||||
OutPt newOp2 = new OutPt(ip, outrec) { prev = prevOp, next = nextNextOp };
|
||||
OutPt newOp2 = _outPtPool.Add(ip, outrec);
|
||||
newOp2.prev = prevOp;
|
||||
newOp2.next = nextNextOp;
|
||||
nextNextOp.prev = newOp2;
|
||||
prevOp.next = newOp2;
|
||||
}
|
||||
@@ -2894,7 +2938,9 @@ private void DoHorizontal(Active horz)
|
||||
splitOp.outrec = newOutRec;
|
||||
splitOp.next.outrec = newOutRec;
|
||||
|
||||
OutPt newOp = new OutPt(ip, newOutRec) { prev = splitOp.next, next = splitOp };
|
||||
OutPt newOp = _outPtPool.Add(ip, newOutRec);
|
||||
newOp.prev = splitOp.next;
|
||||
newOp.next = splitOp;
|
||||
newOutRec.pts = newOp;
|
||||
splitOp.prev = newOp;
|
||||
splitOp.next.next = newOp;
|
||||
@@ -2917,20 +2963,24 @@ private void DoHorizontal(Active horz)
|
||||
private void FixSelfIntersects(OutRec outrec)
|
||||
{
|
||||
OutPt op2 = outrec.pts!;
|
||||
if (op2.prev == op2.next!.next)
|
||||
return; // because triangles can't self-intersect
|
||||
for (; ; )
|
||||
{
|
||||
// triangles can't self-intersect
|
||||
if (op2.prev == op2.next!.next) break;
|
||||
if (InternalClipper.SegsIntersect(op2.prev.pt,
|
||||
op2.pt, op2.next.pt, op2.next.next!.pt))
|
||||
if (InternalClipper.SegsIntersect(op2!.prev.pt,
|
||||
op2.pt, op2.next!.pt, op2.next.next!.pt))
|
||||
{
|
||||
if (op2 == outrec.pts || op2.next == outrec.pts)
|
||||
outrec.pts = outrec.pts.prev;
|
||||
DoSplitOp(outrec, op2);
|
||||
if (outrec.pts == null) return;
|
||||
op2 = outrec.pts;
|
||||
// triangles can't self-intersect
|
||||
if (op2.prev == op2.next!.next) break;
|
||||
continue;
|
||||
}
|
||||
|
||||
op2 = op2.next;
|
||||
op2 = op2.next!;
|
||||
if (op2 == outrec.pts) break;
|
||||
}
|
||||
}
|
||||
@@ -2986,7 +3036,7 @@ private void DoHorizontal(Active horz)
|
||||
OutRec outrec = _outrecList[i++];
|
||||
if (outrec.pts == null) continue;
|
||||
|
||||
Path64 path = new Path64();
|
||||
Path64 path = new Path64(outrec.outPtCount);
|
||||
if (outrec.isOpen)
|
||||
{
|
||||
if (BuildPath(outrec.pts, ReverseSolution, true, path))
|
||||
@@ -3004,21 +3054,6 @@ private void DoHorizontal(Active horz)
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Rect64 GetBounds(Path64 path)
|
||||
{
|
||||
if (path.Count == 0) return new Rect64();
|
||||
Rect64 result = Clipper.InvalidRect64;
|
||||
foreach (Point64 pt in path)
|
||||
{
|
||||
if (pt.X < result.left) result.left = pt.X;
|
||||
if (pt.X > result.right) result.right = pt.X;
|
||||
if (pt.Y < result.top) result.top = pt.Y;
|
||||
if (pt.Y > result.bottom) result.bottom = pt.Y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool CheckBounds(OutRec outrec)
|
||||
{
|
||||
@@ -3028,22 +3063,31 @@ private void DoHorizontal(Active horz)
|
||||
if (outrec.pts == null ||
|
||||
!BuildPath(outrec.pts, ReverseSolution, false, outrec.path))
|
||||
return false;
|
||||
outrec.bounds = GetBounds(outrec.path);
|
||||
outrec.bounds = InternalClipper.GetBounds(outrec.path);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool CheckSplitOwner(OutRec outrec, List<int>? splits)
|
||||
{
|
||||
foreach (int i in splits!)
|
||||
// nb: use indexing (not an iterator) in case 'splits' is modified inside this loop (#1029)
|
||||
for (int i = 0; i < splits!.Count; i++)
|
||||
{
|
||||
OutRec? split = GetRealOutRec(_outrecList[i]);
|
||||
OutRec? split = _outrecList[splits[i]];
|
||||
if (split.pts == null && split.splits != null &&
|
||||
CheckSplitOwner(outrec, split.splits)) return true; //#942
|
||||
split = GetRealOutRec(split);
|
||||
if (split == null || split == outrec || split.recursiveSplit == outrec) continue;
|
||||
split.recursiveSplit = outrec; //#599
|
||||
|
||||
if (split.splits != null && CheckSplitOwner(outrec, split.splits)) return true;
|
||||
if (!IsValidOwner(outrec, split) ||
|
||||
!CheckBounds(split) ||
|
||||
|
||||
if (!CheckBounds(split) ||
|
||||
!split.bounds.Contains(outrec.bounds) ||
|
||||
!Path1InsidePath2(outrec.pts!, split.pts!)) continue;
|
||||
|
||||
if (!IsValidOwner(outrec, split)) // split is owned by outrec (#957)
|
||||
split.owner = outrec.owner;
|
||||
|
||||
outrec.owner = split; //found in split
|
||||
return true;
|
||||
}
|
||||
@@ -3093,7 +3137,7 @@ private void DoHorizontal(Active horz)
|
||||
|
||||
if (outrec.isOpen)
|
||||
{
|
||||
Path64 open_path = new Path64();
|
||||
Path64 open_path = new Path64(outrec.outPtCount);
|
||||
if (BuildPath(outrec.pts, ReverseSolution, true, open_path))
|
||||
solutionOpen.Add(open_path);
|
||||
continue;
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
|
||||
#if USINGZ
|
||||
namespace Clipper2ZLib
|
||||
#else
|
||||
namespace Clipper2Lib
|
||||
#endif
|
||||
{
|
||||
public static class Minkowski
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 22 January 2025 *
|
||||
* Date : 11 October 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : Path Offset (Inflate/Shrink) *
|
||||
@@ -11,7 +11,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#if USINGZ
|
||||
namespace Clipper2ZLib
|
||||
#else
|
||||
namespace Clipper2Lib
|
||||
#endif
|
||||
{
|
||||
public enum JoinType
|
||||
{
|
||||
@@ -53,11 +57,12 @@ namespace Clipper2Lib
|
||||
|
||||
if (endType == EndType.Polygon)
|
||||
{
|
||||
lowestPathIdx = GetLowestPathIdx(inPaths);
|
||||
bool isNegArea;
|
||||
GetLowestPathInfo(inPaths, out lowestPathIdx, out isNegArea);
|
||||
// the lowermost path must be an outer path, so if its orientation is negative,
|
||||
// then flag that the whole group is 'reversed' (will negate delta etc.)
|
||||
// as this is much more efficient than reversing every path.
|
||||
pathsReversed = (lowestPathIdx >= 0) && (Clipper.Area(inPaths[lowestPathIdx]) < 0);
|
||||
pathsReversed = (lowestPathIdx >= 0) && isNegArea;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -81,7 +86,7 @@ namespace Clipper2Lib
|
||||
// default arc tolerance (offset_radius / 500) generally produces good (smooth)
|
||||
// arc approximations without producing excessively small segment lengths.
|
||||
// See also: https://www.angusj.com/clipper2/Docs/Trigonometry.htm
|
||||
const double arc_const = 0.002; // <-- 1/500
|
||||
private const double arc_const = 0.002; // <-- 1/500
|
||||
|
||||
private readonly List<Group> _groupList = new List<Group>();
|
||||
private Path64 pathOut = new Path64();
|
||||
@@ -199,8 +204,9 @@ namespace Clipper2Lib
|
||||
FillRule fillRule = pathsReversed ? FillRule.Negative : FillRule.Positive;
|
||||
|
||||
// clean up self-intersections ...
|
||||
Clipper64 c = new Clipper64 { PreserveCollinear = PreserveCollinear, // the solution should retain the orientation of the input
|
||||
ReverseSolution = ReverseSolution != pathsReversed };
|
||||
Clipper64 c = new Clipper64();
|
||||
c.PreserveCollinear = PreserveCollinear;
|
||||
c.ReverseSolution = ReverseSolution != pathsReversed;
|
||||
#if USINGZ
|
||||
c.ZCallback = ZCB;
|
||||
#endif
|
||||
@@ -248,22 +254,29 @@ namespace Clipper2Lib
|
||||
Execute(1.0, solution);
|
||||
}
|
||||
|
||||
internal static int GetLowestPathIdx(Paths64 paths)
|
||||
internal static void GetLowestPathInfo(Paths64 paths, out int idx, out bool isNegArea)
|
||||
{
|
||||
int result = -1;
|
||||
idx = -1;
|
||||
isNegArea = false;
|
||||
Point64 botPt = new Point64(long.MaxValue, long.MinValue);
|
||||
for (int i = 0; i < paths.Count; ++i)
|
||||
{
|
||||
double a = double.MaxValue;
|
||||
foreach (Point64 pt in paths[i])
|
||||
{
|
||||
if ((pt.Y < botPt.Y) ||
|
||||
((pt.Y == botPt.Y) && (pt.X >= botPt.X))) continue;
|
||||
result = i;
|
||||
if (a == double.MaxValue)
|
||||
{
|
||||
a = Clipper.Area(paths[i]);
|
||||
if (a == 0) break; // invalid closed path so break from inner loop
|
||||
isNegArea = a < 0;
|
||||
}
|
||||
idx = i;
|
||||
botPt.X = pt.X;
|
||||
botPt.Y = pt.Y;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -314,35 +327,6 @@ namespace Clipper2Lib
|
||||
return NormalizeVector(new PointD(vec1.x + vec2.x, vec1.y + vec2.y));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static PointD IntersectPoint(PointD pt1a, PointD pt1b, PointD pt2a, PointD pt2b)
|
||||
{
|
||||
if (InternalClipper.IsAlmostZero(pt1a.x - pt1b.x)) //vertical
|
||||
{
|
||||
if (InternalClipper.IsAlmostZero(pt2a.x - pt2b.x)) return new PointD(0, 0);
|
||||
double m2 = (pt2b.y - pt2a.y) / (pt2b.x - pt2a.x);
|
||||
double b2 = pt2a.y - m2 * pt2a.x;
|
||||
return new PointD(pt1a.x, m2* pt1a.x + b2);
|
||||
}
|
||||
|
||||
if (InternalClipper.IsAlmostZero(pt2a.x - pt2b.x)) //vertical
|
||||
{
|
||||
double m1 = (pt1b.y - pt1a.y) / (pt1b.x - pt1a.x);
|
||||
double b1 = pt1a.y - m1 * pt1a.x;
|
||||
return new PointD(pt2a.x, m1* pt2a.x + b1);
|
||||
}
|
||||
else
|
||||
{
|
||||
double m1 = (pt1b.y - pt1a.y) / (pt1b.x - pt1a.x);
|
||||
double b1 = pt1a.y - m1 * pt1a.x;
|
||||
double m2 = (pt2b.y - pt2a.y) / (pt2b.x - pt2a.x);
|
||||
double b2 = pt2a.y - m2 * pt2a.x;
|
||||
if (InternalClipper.IsAlmostZero(m1 - m2)) return new PointD(0, 0);
|
||||
double x = (b2 - b1) / (m1 - m2);
|
||||
return new PointD(x, m1 * x + b1);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private Point64 GetPerpendic(Point64 pt, PointD norm)
|
||||
{
|
||||
@@ -443,7 +427,7 @@ namespace Clipper2Lib
|
||||
PointD pt4 = new PointD(
|
||||
pt3.x + vec.x * _groupDelta,
|
||||
pt3.y + vec.y * _groupDelta);
|
||||
PointD pt = IntersectPoint(pt1, pt2, pt3, pt4);
|
||||
InternalClipper.GetLineIntersectPt(pt1, pt2, pt3, pt4, out PointD pt);
|
||||
#if USINGZ
|
||||
pt.z = ptQ.z;
|
||||
#endif
|
||||
@@ -454,7 +438,7 @@ namespace Clipper2Lib
|
||||
else
|
||||
{
|
||||
PointD pt4 = GetPerpendicD(path[j], _normals[k]);
|
||||
PointD pt = IntersectPoint(pt1, pt2, pt3, pt4);
|
||||
InternalClipper.GetLineIntersectPt(pt1, pt2, pt3, pt4, out PointD pt);
|
||||
#if USINGZ
|
||||
pt.z = ptQ.z;
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* Author : Angus Johnson *
|
||||
* Date : 10 October 2024 *
|
||||
* Date : 11 October 2025 *
|
||||
* Website : https://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2024 *
|
||||
* Copyright : Angus Johnson 2010-2025 *
|
||||
* Purpose : FAST rectangular clipping *
|
||||
* License : https://www.boost.org/LICENSE_1_0.txt *
|
||||
*******************************************************************************/
|
||||
@@ -12,7 +12,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#if USINGZ
|
||||
namespace Clipper2ZLib
|
||||
#else
|
||||
namespace Clipper2Lib
|
||||
#endif
|
||||
{
|
||||
public class OutPt2
|
||||
{
|
||||
@@ -112,7 +116,7 @@ namespace Clipper2Lib
|
||||
Point64 prevPt, Point64 currPt, Point64 rectMidPoint)
|
||||
{
|
||||
if (AreOpposites(prev, curr))
|
||||
return InternalClipper.CrossProduct(prevPt, rectMidPoint, currPt) < 0;
|
||||
return InternalClipper.CrossProductSign(prevPt, rectMidPoint, currPt) < 0;
|
||||
return HeadingClockwise(prev, curr);
|
||||
}
|
||||
|
||||
@@ -278,8 +282,8 @@ namespace Clipper2Lib
|
||||
private static bool GetSegmentIntersection(Point64 p1,
|
||||
Point64 p2, Point64 p3, Point64 p4, out Point64 ip)
|
||||
{
|
||||
double res1 = InternalClipper.CrossProduct(p1, p3, p4);
|
||||
double res2 = InternalClipper.CrossProduct(p2, p3, p4);
|
||||
int res1 = InternalClipper.CrossProductSign(p1, p3, p4);
|
||||
int res2 = InternalClipper.CrossProductSign(p2, p3, p4);
|
||||
if (res1 == 0)
|
||||
{
|
||||
ip = p1;
|
||||
@@ -303,8 +307,8 @@ namespace Clipper2Lib
|
||||
return false;
|
||||
}
|
||||
|
||||
double res3 = InternalClipper.CrossProduct(p3, p1, p2);
|
||||
double res4 = InternalClipper.CrossProduct(p4, p1, p2);
|
||||
int res3 = InternalClipper.CrossProductSign(p3, p1, p2);
|
||||
int res4 = InternalClipper.CrossProductSign(p4, p1, p2);
|
||||
if (res3 == 0)
|
||||
{
|
||||
ip = p3;
|
||||
@@ -326,7 +330,7 @@ namespace Clipper2Lib
|
||||
}
|
||||
|
||||
// segments must intersect to get here
|
||||
return InternalClipper.GetSegmentIntersectPt(p1, p2, p3, p4, out ip);
|
||||
return InternalClipper.GetLineIntersectPt(p1, p2, p3, p4, out ip);
|
||||
}
|
||||
|
||||
|
||||
|
||||