star-cpr

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

commit b095cf8a3d4f96ef18902843759f789eecef5164
parent d85b80b8c7564388486a732caef0e16c93f36ea6
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 24 Aug 2016 11:36:09 +0200

Finalise the 1st version of the clip function

Diffstat:
Mcmake/CMakeLists.txt | 12++++++++----
Msrc/cpr.h | 3+++
Msrc/cpr_mesh.c | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/test_cpr_mesh.c | 34+---------------------------------
Msrc/test_cpr_utils.h | 32++++++++++++++++++++++++++++++++
5 files changed, 123 insertions(+), 57 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -69,10 +69,14 @@ rcmake_setup_devel(cpr CPR ${VERSION} cpr_version.h) # Define tests ################################################################################ if(NOT NO_TEST) - add_executable(test_cpr_mesh ${CPR_SOURCE_DIR}/test_cpr_mesh.c) - target_link_libraries(test_cpr_mesh cpr) - add_test(test_cpr_mesh test_cpr_mesh) - rcmake_set_test_runtime_dirs(test_cpr_mesh _runtime_dirs) + function(new_test _name) + add_executable(${_name} ${CPR_SOURCE_DIR}/${_name}.c) + target_link_libraries(${_name} cpr RSys) + add_test(${_name} ${_name}) + rcmake_set_test_runtime_dirs(${_name} _runtime_dirs) + endfunction() + new_test(test_cpr_clip) + new_test(test_cpr_mesh) endif() ################################################################################ diff --git a/src/cpr.h b/src/cpr.h @@ -41,6 +41,9 @@ struct cpr_polygon { void* context; }; +#define CPR_POLYGON_NULL__ { NULL, 0, NULL } +static const struct cpr_polygon CPR_POLYGON_NULL = CPR_POLYGON_NULL__; + /* Opaque 2 dimensionnal mesh data type */ struct cpr_mesh; diff --git a/src/cpr_mesh.c b/src/cpr_mesh.c @@ -15,6 +15,8 @@ #include "cpr.h" +#include <polygon.h> + #include <rsys/double2.h> #include <rsys/dynamic_array_double.h> #include <rsys/dynamic_array_size_t.h> @@ -265,7 +267,7 @@ setup_intersection_nodes d2_set(POS(coords0) + ihit_pos, hit.pos); ihit_pos /= 2/* #coords per vertex */; - /* + /* * Note that the hit position is not registered in the coords1 array */ @@ -338,36 +340,44 @@ vertices_setup_inside_poly_flag static res_T clip - (const struct darray_node* cand_nodes, - const struct darray_node* clip_nodes, - const char* is_inside, - struct darray_size_t* output) + (const struct cpr_mesh* mesh, + const struct darray_node* cand_nodes, /* Candidate polygon node list */ + const struct darray_node* clip_nodes, /* Clipping polygon node list */ + const char* is_inside, /* Define if candidate vertex is inside the clip polygon */ + struct polygon* polygon, /* Use to triangulate the clipped polygons */ + struct darray_size_t* scratch, /* Temporary buffer */ + struct darray_size_t* output) /* Index of the triangulated vertices */ { enum { CAND, CLIP }; size_t icand_node, ncand_nodes; const struct node* node_lists[2]; res_T res = RES_OK; - ASSERT(cand_nodes && clip_nodes && is_inside && output); + ASSERT(cand_nodes && clip_nodes && is_inside && polygon && scratch && output); ncand_nodes = darray_node_size_get(cand_nodes); node_lists[CAND] = darray_node_cdata_get(cand_nodes); node_lists[CLIP] = darray_node_cdata_get(clip_nodes); + /* TODO iterate over the intersection nodes only */ FOR_EACH(icand_node, 0, ncand_nodes) { + const size_t* scratch_data; size_t ilist = CAND; + size_t i, n; const struct node* n0 = node_lists[CAND] + icand_node; const struct node* n1 = node_lists[CAND] + node_lists[CAND][icand_node].next; const struct node* node_start; const struct node* node; + const uint32_t* ids; + uint32_t nids; - if(n0->link != SIZE_MAX || n1->link == SIZE_MAX || is_inside[n1->id]) + if(n0->link == SIZE_MAX || n1->link != SIZE_MAX || is_inside[n1->id]) continue; - darray_size_t_clear(output); + /* Clip the candidate polygon */ + darray_size_t_clear(scratch); node_start = node = n1; - do { - res = darray_size_t_push_back(output, &node->id); + res = darray_size_t_push_back(scratch, &node->id); if(res != RES_OK) goto error; node = node_lists[ilist] + node->next; @@ -376,6 +386,30 @@ clip node = node_lists[ilist] + node->link; } } while(node != node_start); + + /* Setup the clipped polygon to triangulate */ + n = darray_size_t_size_get(scratch); + scratch_data = darray_size_t_cdata_get(scratch); + POLYGON(clear(polygon)); + FOR_EACH(i, 0, n) { + float posf[3] = { 0.f, 0.f, 0.f }; + double pos[2]; + CPR(mesh_get_position(mesh, scratch_data[i], pos)); + + posf[0] = (float)pos[0], posf[1] = (float)pos[1]; + res = polygon_vertex_add(polygon, posf); + if(res != RES_OK) goto error; + } + + /* Triangulate the polygon */ + res = polygon_triangulate(polygon, &ids, &nids); + if(res != RES_OK) goto error; + + /* Register the created triangles */ + FOR_EACH(i, 0, nids) { + res = darray_size_t_push_back(output, scratch_data + ids[i]); + if(res != RES_OK) goto error; + } } exit: @@ -548,29 +582,42 @@ cpr_mesh_get_position } res_T -cpr_mesh_clip(struct cpr_mesh* mesh, struct cpr_polygon* polygon) +cpr_mesh_clip(struct cpr_mesh* mesh, struct cpr_polygon* poly_desc) { struct darray_node poly_nodes; struct darray_node cand_nodes; /* Candidate */ - struct darray_node clip_nodes; + struct darray_node clip_nodes; struct darray_char is_inside; + struct darray_size_t indices; + struct darray_size_t scratch; struct poly poly; + struct polygon* polygon = NULL; /* Use to triangulate the clipped polygons */ size_t itri, ntris, nverts; res_T res = RES_OK; + if(!mesh) { + res = RES_BAD_ARG; + goto error; + } + darray_node_init(mesh->allocator, &poly_nodes); darray_node_init(mesh->allocator, &cand_nodes); darray_node_init(mesh->allocator, &clip_nodes); darray_char_init(mesh->allocator, &is_inside); + darray_size_t_init(mesh->allocator, &indices); + darray_size_t_init(mesh->allocator, &scratch); poly_init(mesh->allocator, &poly); - if(!mesh || !polygon) { + if(!poly_desc) { res = RES_BAD_ARG; goto error; } - /* Setup the polygon */ - res = poly_setup(&poly, polygon); + res = polygon_create(NULL, &polygon); + if(res != RES_OK) goto error; + + /* Setup the clip polygon */ + res = poly_setup(&poly, poly_desc); if(res != RES_OK) goto error; res = poly_setup_nodes(&poly, &poly_nodes); if(res != RES_OK) goto error; @@ -596,14 +643,26 @@ cpr_mesh_clip(struct cpr_mesh* mesh, struct cpr_polygon* polygon) res = setup_intersection_nodes (&cand_nodes, &mesh->coords, &poly_nodes, &poly.coords); if(res != RES_OK) goto error; + + darray_size_t_clear(&indices); + clip(mesh, &cand_nodes, &poly_nodes, darray_char_cdata_get(&is_inside), + polygon, &scratch, &indices); } + res = darray_size_t_copy_and_release(&mesh->indices, &indices); + if(res != RES_OK) goto error; + exit: - darray_node_release(&poly_nodes); - darray_node_release(&cand_nodes); - darray_node_release(&clip_nodes); - darray_char_release(&is_inside); - poly_release(&poly); + if(mesh) { + darray_node_release(&poly_nodes); + darray_node_release(&cand_nodes); + darray_node_release(&clip_nodes); + darray_char_release(&is_inside); + darray_size_t_release(&indices); + darray_size_t_release(&scratch); + poly_release(&poly); + } + if(polygon) POLYGON(ref_put(polygon)); return res; error: diff --git a/src/test_cpr_mesh.c b/src/test_cpr_mesh.c @@ -16,38 +16,6 @@ #include "cpr.h" #include "test_cpr_utils.h" -struct context { - const double* coords; - size_t nverts; - const size_t* indices; - size_t ntris; -}; - -static void -get_pos(const size_t ivert, double pos[2], void* context) -{ - const struct context* ctx = context; - NCHECK(pos, NULL); - NCHECK(context, NULL); - NCHECK(ctx->coords, NULL); - CHECK(ivert < ctx->nverts, 1); - pos[0] = ctx->coords[ivert*2 + 0]; - pos[1] = ctx->coords[ivert*2 + 1]; -} - -static void -get_ids(const size_t itri, size_t ids[3], void* context) -{ - const struct context* ctx = context; - NCHECK(ids, NULL); - NCHECK(context, NULL); - NCHECK(ctx->indices, NULL); - CHECK(itri < ctx->ntris, 1); - ids[0] = ctx->indices[itri*3 + 0]; - ids[1] = ctx->indices[itri*3 + 1]; - ids[2] = ctx->indices[itri*3 + 2]; -} - int main(int argc, char** argv) { @@ -79,7 +47,7 @@ main(int argc, char** argv) double pos[2]; size_t i, n; struct mem_allocator allocator; - struct context ctx; + struct mesh_context ctx; struct cpr_mesh* mesh; (void)argc, (void)argv; diff --git a/src/test_cpr_utils.h b/src/test_cpr_utils.h @@ -19,6 +19,38 @@ #include <rsys/mem_allocator.h> #include <stdio.h> +struct mesh_context { + const double* coords; + size_t nverts; + const size_t* indices; + size_t ntris; +}; + +static void +get_pos(const size_t ivert, double pos[2], void* context) +{ + const struct mesh_context* ctx = context; + NCHECK(pos, NULL); + NCHECK(context, NULL); + NCHECK(ctx->coords, NULL); + CHECK(ivert < ctx->nverts, 1); + pos[0] = ctx->coords[ivert*2 + 0]; + pos[1] = ctx->coords[ivert*2 + 1]; +} + +static void +get_ids(const size_t itri, size_t ids[3], void* context) +{ + const struct mesh_context* ctx = context; + NCHECK(ids, NULL); + NCHECK(context, NULL); + NCHECK(ctx->indices, NULL); + CHECK(itri < ctx->ntris, 1); + ids[0] = ctx->indices[itri*3 + 0]; + ids[1] = ctx->indices[itri*3 + 1]; + ids[2] = ctx->indices[itri*3 + 2]; +} + static void check_memory_allocator(struct mem_allocator* allocator) {