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:
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);