star-cpr

Clip 2D meshes with 2D polygons
git clone git://git.meso-star.fr/star-cpr.git
Log | Files | Refs | README | LICENSE

commit 3ca458e690c1bbf66f3f6384e0548f4b5598a642
parent 9aefd234d7c7b3da83d5b5ec9f6fbc26b110fa6b
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed, 28 Sep 2022 14:27:59 +0200

Merge branch 'feature-clipper2' into develop

Diffstat:
Mcmake/CMakeLists.txt | 10+++++-----
Mcmake/ClipperConfig.cmake | 48++++++++++++++++++++++++------------------------
Msrc/scpr_mesh.c | 102+++++++++++++++++++++++++++----------------------------------------------------
3 files changed, 64 insertions(+), 96 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -25,15 +25,15 @@ set(SCPR_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) # Dependencies ################################################################################ get_filename_component(_current_source_dir ${CMAKE_CURRENT_LIST_FILE} PATH) -set(Clipper_DIR ${_current_source_dir}/) +set(Clipper2_DIR ${_current_source_dir}/) -find_package(Clipper REQUIRED) find_package(RCMake REQUIRED) find_package(RSys 0.6 REQUIRED) +find_package(Clipper2 1 REQUIRED) find_package(Polygon 0.0.5 REQUIRED) include_directories( - ${Clipper_INCLUDE_DIR} + ${Clipper2_INCLUDE_DIR} ${Polygon_INCLUDE_DIR} ${RSys_INCLUDE_DIR}) @@ -41,7 +41,7 @@ set(CMAKE_MODULE_PATH ${RCMAKE_SOURCE_DIR}) include(rcmake) include(rcmake_runtime) -rcmake_append_runtime_dirs(_runtime_dirs RSys Polygon) +rcmake_append_runtime_dirs(_runtime_dirs RSys Polygon Clipper2) ################################################################################ # Define targets @@ -64,7 +64,7 @@ set_target_properties(scpr PROPERTIES DEFINE_SYMBOL SCPR_SHARED_BUILD VERSION ${VERSION} SOVERSION ${VERSION_MAJOR}) -target_link_libraries(scpr RSys Polygon Clipper) +target_link_libraries(scpr RSys Polygon Clipper2) if(CMAKE_COMPILER_IS_GNUCXX) set_target_properties(scpr PROPERTIES COMPILE_FLAGS "-Wno-long-long") diff --git a/cmake/ClipperConfig.cmake b/cmake/ClipperConfig.cmake @@ -31,21 +31,21 @@ cmake_minimum_required(VERSION 3.1) -# Try to find the Clipper devel. Once done this will define: -# - Clipper_FOUND: system has Clipper -# - Clipper_INCLUDE_DIR: the include directory -# - Clipper: Link this to use Clipper +# Try to find the Clipper2 devel. Once done this will define: +# - Clipper2_FOUND: system has Clipper2 +# - Clipper2_INCLUDE_DIR: the include directory +# - Clipper2: Link this to use Clipper2 -find_path(Clipper_INCLUDE_DIR polyclipping/clipper.hpp) -set(Clipper_INCLUDE_DIR ${Clipper_INCLUDE_DIR}/polyclipping/) +find_path(Clipper2_INCLUDE_DIR polyclipping/clipper.hpp) +set(Clipper2_INCLUDE_DIR ${Clipper2_INCLUDE_DIR}/polyclipping/) -unset(Clipper_LIBRARY CACHE) -unset(Clipper_LIBRARY_DEBUG CACHE) -unset(Clipper_LIBRARY_RELWITHDEBINFO CACHE) -unset(Clipper_LIBRARY_MINSIZEREL CACHE) -find_library(Clipper_LIBRARY polyclipping +unset(Clipper2_LIBRARY CACHE) +unset(Clipper2_LIBRARY_DEBUG CACHE) +unset(Clipper2_LIBRARY_RELWITHDEBINFO CACHE) +unset(Clipper2_LIBRARY_MINSIZEREL CACHE) +find_library(Clipper2_LIBRARY polyclipping DOC "Path to the clipper library used during release builds.") -find_library(Clipper_LIBRARY_DEBUG polyclipping-dbg +find_library(Clipper2_LIBRARY_DEBUG polyclipping-dbg DOC "Path to the clipper library used during debug builds.") # Create the imported library target @@ -53,22 +53,22 @@ if(CMAKE_HOST_WIN32) set(_property IMPORTED_IMPLIB) else(CMAKE_HOST_WIN32) set(_property IMPORTED_LOCATION) - if(NOT Clipper_LIBRARY_DEBUG) # Fallback lib - get_property(_doc CACHE Clipper_LIBRARY_DEBUG PROPERTY HELPSTRING) - set(Clipper_LIBRARY_DEBUG ${Clipper_LIBRARY} CACHE PATH ${_doc} FORCE) + if(NOT Clipper2_LIBRARY_DEBUG) # Fallback lib + get_property(_doc CACHE Clipper2_LIBRARY_DEBUG PROPERTY HELPSTRING) + set(Clipper2_LIBRARY_DEBUG ${Clipper2_LIBRARY} CACHE PATH ${_doc} FORCE) endif() endif() -add_library(Clipper SHARED IMPORTED) -set_target_properties(Clipper PROPERTIES - ${_property} ${Clipper_LIBRARY_DEBUG} - ${_property}_DEBUG ${Clipper_LIBRARY_DEBUG} - ${_property}_RELEASE ${Clipper_LIBRARY}) +add_library(Clipper2 SHARED IMPORTED) +set_target_properties(Clipper2 PROPERTIES + ${_property} ${Clipper2_LIBRARY_DEBUG} + ${_property}_DEBUG ${Clipper2_LIBRARY_DEBUG} + ${_property}_RELEASE ${Clipper2_LIBRARY}) # Check the package include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Clipper DEFAULT_MSG - Clipper_INCLUDE_DIR - Clipper_LIBRARY - Clipper_LIBRARY_DEBUG) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Clipper2 DEFAULT_MSG + Clipper2_INCLUDE_DIR + Clipper2_LIBRARY + Clipper2_LIBRARY_DEBUG) diff --git a/src/scpr_mesh.c b/src/scpr_mesh.c @@ -15,6 +15,8 @@ #include "scpr.h" +#include <clipper.core.h> +#include <clipper.engine.h> #include <rsys/double2.h> #include <rsys/dynamic_array_double.h> #include <rsys/dynamic_array_size_t.h> @@ -23,8 +25,7 @@ #include <rsys/ref_count.h> #include <polygon.h> -#include <clipper.hpp> -STATIC_ASSERT(sizeof(ClipperLib::cInt) >= sizeof(double), Unexpected_Type_Size); +#include <clipper.h> struct vertex { double pos[2]; }; static FINLINE int @@ -54,48 +55,13 @@ struct scpr_mesh { /******************************************************************************* * Helper functions ******************************************************************************/ -static FINLINE ClipperLib::cInt -double_to_cInt(const double d, const double scale) -{ - double dbl = d; - union { int64_t i; double d; } ucast; - ClipperLib::cInt i; - ASSERT(scale > 0); - - /* Map 'd' in [1, 2] => Fix the exponent */ - ucast.d = 1 + fabs(d / scale); - - /* Store the positive or null exponent in the 52^th bit. This ensure that if - * 'd' is equal to 2 then it is not encoded as 0. */ - i = (((ucast.i >> 52) & 0x7FF) - 1023) << 52; - - /* Store the mantissa in the [0 .. 51] bits */ - i = (ucast.i & 0x000FFFFFFFFFFFFF) | i; - - /* Apply the sign to the resulting integer */ - return dbl < 0 ? -i : i; -} - -static FINLINE double -cInt_to_double(const ClipperLib::cInt i, const double scale) -{ - double dbl; - union { int64_t i; double d; } ucast; - ASSERT(scale > 0); - - ucast.i = llabs(i); - ucast.i = ((1023 + (ucast.i >> 52)) << 52) | (ucast.i & 0x000FFFFFFFFFFFFF); - dbl = (ucast.d - 1) * scale; - return i < 0 ? -dbl : dbl; -} - -static FINLINE ClipperLib::ClipType +static FINLINE Clipper2Lib::ClipType scpr_operation_to_clip_type(const enum scpr_operation op) { - ClipperLib::ClipType ctype = ClipperLib::ctIntersection; + Clipper2Lib::ClipType ctype; switch(op) { - case SCPR_AND: ctype = ClipperLib::ctIntersection; break; - case SCPR_SUB: ctype = ClipperLib::ctDifference; break; + case SCPR_AND: ctype = Clipper2Lib::ClipType::Intersection; break; + case SCPR_SUB: ctype = Clipper2Lib::ClipType::Difference; break; default: FATAL("Unreachable code\n"); break; } return ctype; @@ -249,11 +215,10 @@ register_triangle static res_T register_paths - (const ClipperLib::Paths& paths, + (const Clipper2Lib::PathsD& paths, struct darray_double* coords, /* Vertex buffer */ struct darray_size_t* indices, /* Index buffer */ struct htable_vertex* vertices, /* Map a vertex to its index */ - const double extend[2], /* Scale to apply to the cInt coordinates */ struct polygon* polygon) /* Use to triangulate the clipped polygons */ { size_t ivert; @@ -265,8 +230,8 @@ register_paths if(paths[ipath].size() == 3) { FOR_EACH(ivert, 0, 3) { double pos[2]; - pos[0] = cInt_to_double(paths[ipath][ivert].X, extend[0]); - pos[1] = cInt_to_double(paths[ipath][ivert].Y, extend[1]); + pos[0] = paths[ipath][ivert].x; + pos[1] = paths[ipath][ivert].y; res = register_vertex(pos, coords, indices, vertices); if(res != RES_OK) goto error; } @@ -281,8 +246,8 @@ register_paths float fpos[3] = {0.f, 0.f, 0.f}; double pos[2]; - pos[0] = cInt_to_double(paths[ipath][ivert].X, extend[0]); - pos[1] = cInt_to_double(paths[ipath][ivert].Y, extend[1]); + pos[0] = paths[ipath][ivert].x; + pos[1] = paths[ipath][ivert].y; fpos[0] = (float)pos[0], fpos[1] = (float)pos[1]; res = polygon_vertex_add(polygon, fpos); @@ -500,17 +465,18 @@ scpr_mesh_clip const enum scpr_operation op, struct scpr_polygon* poly_desc) { - double lower[2], upper[2], extend[2]; + double lower[2], upper[2]; struct poly poly; struct polygon* polygon = NULL; /* Use to triangulate clipped polygons */ struct darray_double coords; /* Coordinates of the clipped mesh */ struct darray_size_t indices; /* Indices of the clipped mesh */ struct htable_vertex vertices; /* Map a coordinate to its index */ - ClipperLib::Clipper clipper(ClipperLib::ioStrictlySimple); - ClipperLib::Paths output; /* Contour of the clipped polgyon */ - ClipperLib::Path cand_path; /* Contour of the candidate polygon */ - ClipperLib::Path clip_path; /* Contour of the clip polygon */ - ClipperLib::ClipType clip_type; /* Type of clipping to perform */ + Clipper2Lib::ClipperD clipper; + Clipper2Lib::PathsD output; /* Contour of the clipped polgyon */ + Clipper2Lib::PathsD cand_path; /* Contour of the candidate polygon */ + Clipper2Lib::PathD tmp; + Clipper2Lib::PathsD clip_path; /* Contour of the clip polygon */ + Clipper2Lib::ClipType clip_type; /* Type of clipping to perform */ size_t ivert, nverts; size_t itri, ntris; @@ -536,17 +502,18 @@ scpr_mesh_clip /* Compute the overall aabb of the candidate and the clip polygon */ d2_min(lower, lower, poly.lower); d2_max(upper, upper, poly.upper); - d2_sub(extend, upper, lower); /* Setup the clip path */ nverts = darray_double_size_get(&poly.coords) / 2/*#coords per vertex*/; + tmp.clear(); FOR_EACH(ivert, 0, nverts) { const double* v = darray_double_cdata_get(&poly.coords) + ivert*2; - ClipperLib::IntPoint pt; - pt.X = double_to_cInt(v[0], extend[0]); - pt.Y = double_to_cInt(v[1], extend[1]); - clip_path.push_back(pt); + Clipper2Lib::PointD pt; + pt.x = v[0]; + pt.y = v[1]; + tmp.push_back(pt); } + clip_path.push_back(tmp); /* Create the polygon structure used to triangulate the clipped polygons */ res = polygon_create(mesh->allocator, &polygon); @@ -576,22 +543,23 @@ scpr_mesh_clip /* Setup the candidate path */ cand_path.clear(); + tmp.clear(); FOR_EACH(ivert, 0, 3) { - ClipperLib::IntPoint pt; - pt.X = double_to_cInt(tri[ivert][0], extend[0]); - pt.Y = double_to_cInt(tri[ivert][1], extend[1]); - cand_path.push_back(pt); + Clipper2Lib::PointD pt; + pt.x = tri[ivert][0]; + pt.y = tri[ivert][1]; + tmp.push_back(pt); } + cand_path.push_back(tmp); /* Clip the polygon */ clipper.Clear(); - clipper.AddPath(cand_path, ClipperLib::ptSubject, 1); - clipper.AddPath(clip_path, ClipperLib::ptClip, 1); - clipper.Execute(clip_type, output); + clipper.AddSubject(cand_path); + clipper.AddClip(clip_path); + clipper.Execute(clip_type, Clipper2Lib::FillRule::EvenOdd, output); /* Register the resulting clipped polygons */ - res = register_paths - (output, &coords, &indices, &vertices, extend, polygon); + res = register_paths (output, &coords, &indices, &vertices, polygon); if(res != RES_OK) goto error; }