star-cpr

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

commit da676844a8bc3ef7f768b76e18c84ef8accf4ad2
parent 86ea3e4dbb7b0d2180433376275776054ee0466c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 29 Aug 2016 11:31:02 +0200

Remove the ADD and XOR operators

These operators do not make sense when applied per mesh triangle;
add/xor a clip polygon to a mesh triangle may generate primitives that
overlap the adjacent mesh triangles.

Diffstat:
Msrc/cpr.h | 2--
Msrc/cpr_mesh.c | 28+++++++++++++++++++---------
Msrc/test_cpr_clip.c | 27++++++++++++++++++++++++++-
3 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/src/cpr.h b/src/cpr.h @@ -33,10 +33,8 @@ #endif enum cpr_operation { - CPR_ADD, CPR_AND, CPR_SUB, - CPR_XOR, CPR_OPERATIONS_COUNT__ }; diff --git a/src/cpr_mesh.c b/src/cpr_mesh.c @@ -24,14 +24,14 @@ #include <polygon.h> #include <clipper.hpp> -STATIC_ASSERT(sizeof(ClipperLib::cInt) == sizeof(double), Unexpected_Type_Size); +STATIC_ASSERT(sizeof(ClipperLib::cInt) >= sizeof(double), Unexpected_Type_Size); struct vertex { double pos[2]; }; - static FINLINE int vertex_eq(const struct vertex* a, const struct vertex* b) { return d2_eq(a->pos, b->pos); } +/* Define the vertex to index hash table */ #define HTABLE_NAME vertex #define HTABLE_DATA size_t #define HTABLE_KEY struct vertex @@ -40,8 +40,7 @@ vertex_eq(const struct vertex* a, const struct vertex* b) struct poly { struct darray_double coords; - double lower[2]; - double upper[2]; + double lower[2], upper[2]; /* Polygon AABB */ }; struct cpr_mesh { @@ -63,9 +62,17 @@ double_to_cInt(const double d, const double scale) 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; } @@ -87,10 +94,8 @@ 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; @@ -499,7 +504,7 @@ cpr_mesh_clip 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::Clipper clipper(ClipperLib::ioStrictlySimple); ClipperLib::Paths output; ClipperLib::Path cand_path; ClipperLib::Path clip_path; @@ -545,20 +550,25 @@ cpr_mesh_clip res = polygon_create(mesh->allocator, &polygon); if(res != RES_OK) goto error; + /* Clip the triangles of the mesh */ CPR(mesh_get_triangles_count(mesh, &ntris)); FOR_EACH(itri, 0, ntris) { size_t ids[3]; double tri[3][2]; + /* Fetch the triangle vertices and compute its AABB */ CPR(mesh_get_indices(mesh, itri, ids)); CPR(mesh_get_position(mesh, ids[0], tri[0])); CPR(mesh_get_position(mesh, ids[1], tri[1])); CPR(mesh_get_position(mesh, ids[2], tri[2])); triangle_compute_aabb(tri, lower, upper); + /* Do not clip triangles that don not intersect the clip AABB */ if(!aabb_intersect(lower, upper, poly.lower, poly.upper)) { - res = register_triangle(tri, &coords, &indices, &vertices); - if(res != RES_OK) goto error; + if(op != CPR_AND) { + res = register_triangle(tri, &coords, &indices, &vertices); + if(res != RES_OK) goto error; + } continue; } diff --git a/src/test_cpr_clip.c b/src/test_cpr_clip.c @@ -84,13 +84,37 @@ test_triangle(struct cpr_mesh* mesh) 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); } static void +test_quad(struct cpr_mesh* mesh) +{ + const double quad_pos[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0 }; + const size_t quad_ids[] = { 0, 1, 3, 3, 1, 2 }; + const double clip_pos[] = { -0.25, 0.25, -0.25, 0.75, 1.25, 0.75, 1.25, 0.25 }; + struct cpr_polygon poly; + struct mesh_context ctx; + + ctx.coords = quad_pos; + ctx.nverts = sizeof(quad_pos)/sizeof(double[2]); + ctx.indices = quad_ids; + ctx.ntris = sizeof(quad_ids)/sizeof(size_t[3]); + CHECK(cpr_mesh_setup_indexed_vertices + (mesh, ctx.ntris, get_ids, ctx.nverts, get_pos, &ctx), RES_OK); + + poly.get_position = get_clip_pos; + poly.nvertices = sizeof(clip_pos)/sizeof(double[2]); + poly.context = (void*)clip_pos; + CHECK(cpr_mesh_clip(mesh, CPR_AND, &poly), RES_OK); + + /*dump_obj(stdout, mesh);*/ +} + +static void test_disk(struct cpr_mesh* mesh) { const double clip[] = { -1.75, -1.75, 1.75, -1.75, 1.75, 1.75, -1.75, 1.75 }; @@ -178,6 +202,7 @@ main(int argc, char** argv) CHECK(cpr_mesh_create(&allocator, &mesh), RES_OK); test_triangle(mesh); + test_quad(mesh); test_disk(mesh); CHECK(cpr_mesh_ref_put(mesh), RES_OK);