star-cpr

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

commit 86ea3e4dbb7b0d2180433376275776054ee0466c
parent 46e8dfae2032995927a7950a3a94e8e93037e0a0
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 26 Aug 2016 16:37:13 +0200

Update the API of the cpr_mesh_clip method

Add the clip operation as input parameter. The following ADD, AND, SUB
and XOR operations are provided. Note that actually the XOR operation
seems bugged.

Diffstat:
Msrc/cpr.h | 13++++++++++---
Msrc/cpr_mesh.c | 28++++++++++++++++++++++++----
Msrc/test_cpr_clip.c | 20++++++++++++--------
3 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/src/cpr.h b/src/cpr.h @@ -32,6 +32,14 @@ #define CPR(Func) cpr_##Func #endif +enum cpr_operation { + CPR_ADD, + CPR_AND, + CPR_SUB, + CPR_XOR, + CPR_OPERATIONS_COUNT__ +}; + /* Public polygon data type. Define the list of the countour vertices. */ struct cpr_polygon { void (*get_position)(const size_t ivert, double pos[2], void* ctx); @@ -74,12 +82,11 @@ cpr_mesh_setup_indexed_vertices void (*get_position)(const size_t ivert, double pos[2], void* ctx), void* data); /* Client data set as the last param of the callbacks */ -/* Clip the mesh against the polygon contour. Keep the triangles lying inside - * or outside the polygon whether its vertices are CW or CCW ordered, - * respectively. */ +/* Clip the mesh against the polygon contour */ CPR_API res_T cpr_mesh_clip (struct cpr_mesh* mesh, + const enum cpr_operation op, struct cpr_polygon* polygon); CPR_API res_T diff --git a/src/cpr_mesh.c b/src/cpr_mesh.c @@ -82,6 +82,20 @@ cInt_to_double(const ClipperLib::cInt i, const double scale) return i < 0 ? -dbl : dbl; } +static FINLINE ClipperLib::ClipType +cpr_operation_to_clip_type(const enum cpr_operation op) +{ + ClipperLib::ClipType ctype = ClipperLib::ctIntersection; + switch(op) { + case CPR_ADD: ctype = ClipperLib::ctUnion; break; + case CPR_AND: ctype = ClipperLib::ctIntersection; break; + case CPR_SUB: ctype = ClipperLib::ctDifference; break; + case CPR_XOR: ctype = ClipperLib::ctXor; break; + default: FATAL("Unreachable code\n"); break; + } + return ctype; +} + static INLINE int aabb_intersect (const double lower0[2], @@ -96,7 +110,6 @@ aabb_intersect && lower1[1] < upper0[1]; } - static INLINE int aabb_is_degenerated(const double lower[2], const double upper[2]) { @@ -475,7 +488,10 @@ cpr_mesh_get_position } res_T -cpr_mesh_clip(struct cpr_mesh* mesh, struct cpr_polygon* poly_desc) +cpr_mesh_clip + (struct cpr_mesh* mesh, + const enum cpr_operation op, + struct cpr_polygon* poly_desc) { double lower[2], upper[2], extend[2]; struct poly poly; @@ -487,12 +503,16 @@ cpr_mesh_clip(struct cpr_mesh* mesh, struct cpr_polygon* poly_desc) ClipperLib::Paths output; ClipperLib::Path cand_path; ClipperLib::Path clip_path; + ClipperLib::ClipType clip_type; size_t ivert, nverts; size_t itri, ntris; res_T res = RES_OK; - if(!mesh || !poly_desc) return RES_BAD_ARG; + if(!mesh || !poly_desc || (unsigned)op >= CPR_OPERATIONS_COUNT__) + return RES_BAD_ARG; + + clip_type = cpr_operation_to_clip_type(op); darray_double_init(mesh->allocator, &coords); darray_size_t_init(mesh->allocator, &indices); @@ -555,7 +575,7 @@ cpr_mesh_clip(struct cpr_mesh* mesh, struct cpr_polygon* poly_desc) clipper.Clear(); clipper.AddPath(cand_path, ClipperLib::ptSubject, 1); clipper.AddPath(clip_path, ClipperLib::ptClip, 1); - clipper.Execute(ClipperLib::ctDifference, output); + clipper.Execute(clip_type, output); /* Register the polygons */ res = register_paths diff --git a/src/test_cpr_clip.c b/src/test_cpr_clip.c @@ -60,7 +60,7 @@ test_triangle(struct cpr_mesh* mesh) { const double triangle_pos[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0 }; const size_t triangle_ids[] = { 0, 1, 2 }; - const double clip_pos[] = { -1.0, 0.25, 1.0, 0.25, 1, 0.75 }; + const double clip_pos[] = { -1.0, 0.25, 1.0, 0.75, 1, 0.25 }; struct cpr_polygon poly; struct mesh_context ctx; size_t ntris; @@ -73,14 +73,18 @@ test_triangle(struct cpr_mesh* mesh) (mesh, ctx.ntris, get_ids, 3, get_pos, &ctx), RES_OK); poly.get_position = get_clip_pos; - poly.nvertices = 3; + poly.nvertices = sizeof(clip_pos)/sizeof(double[2]); poly.context = (void*)clip_pos; - CHECK(cpr_mesh_clip(NULL, NULL), RES_BAD_ARG); - CHECK(cpr_mesh_clip(mesh, NULL), RES_BAD_ARG); - CHECK(cpr_mesh_clip(NULL, &poly), RES_BAD_ARG); - CHECK(cpr_mesh_clip(mesh, &poly), RES_OK); + CHECK(cpr_mesh_clip(NULL, CPR_OPERATIONS_COUNT__, NULL), RES_BAD_ARG); + CHECK(cpr_mesh_clip(mesh, CPR_OPERATIONS_COUNT__, NULL), RES_BAD_ARG); + CHECK(cpr_mesh_clip(NULL, CPR_OPERATIONS_COUNT__, &poly), RES_BAD_ARG); + CHECK(cpr_mesh_clip(mesh, CPR_OPERATIONS_COUNT__, &poly), RES_BAD_ARG); + CHECK(cpr_mesh_clip(NULL, CPR_SUB, NULL), RES_BAD_ARG); + CHECK(cpr_mesh_clip(mesh, CPR_SUB, NULL), RES_BAD_ARG); + CHECK(cpr_mesh_clip(NULL, CPR_SUB, &poly), RES_BAD_ARG); + CHECK(cpr_mesh_clip(mesh, CPR_SUB, &poly), RES_OK); - /*dump_obj(stdout, mesh);*/ + dump_obj(stdout, mesh); CHECK(cpr_mesh_get_triangles_count(mesh, &ntris), RES_OK); CHECK(ntris, 3); @@ -154,7 +158,7 @@ test_disk(struct cpr_mesh* mesh) poly.get_position = get_clip_pos; poly.nvertices = sizeof(clip)/sizeof(double[2]); poly.context = (void*)clip; - CHECK(cpr_mesh_clip(mesh, &poly), RES_OK); + CHECK(cpr_mesh_clip(mesh, CPR_SUB, &poly), RES_OK); dump_obj(stdout, mesh);