star-cpr

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

commit 5da0a0368ae784afa09150d8b4cc13ee918dc0f4
parent e8b3d8f1e3e18f9e51768c318a52c21a8b86a6d2
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 15 Sep 2023 15:29:03 +0200

Add component_in_component and get_vertex_in_component API calls

Diffstat:
Msrc/scpr.h | 20+++++++++++++++++++-
Msrc/scpr_polygon.c | 110++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/src/scpr.h b/src/scpr.h @@ -253,7 +253,14 @@ scpr_polygon_eq const struct scpr_polygon* polygon2, int* is_eq); -/* Check if a given vertex is in a given component. */ +/* Return a vertex that is inside a component. */ +SCPR_API res_T +scpr_get_vertex_in_component + (const struct scpr_polygon* polygon, + const size_t icomponent, + double vertex[2]); + +/* Check if a vertex is in a component. */ SCPR_API res_T scpr_is_vertex_in_component (const struct scpr_polygon* polygon, @@ -261,6 +268,17 @@ scpr_is_vertex_in_component const double vertex[2], int* situation); /* +1: inside, 0: on, -1: outside */ +/* Check if a component is inside a component, given the 2 components do not + * overlap. + * Only meaningful for 2 simple polygons. */ +SCPR_API res_T +scpr_is_component_in_component + (const struct scpr_polygon* polygon1, + const size_t icomponent1, + const struct scpr_polygon* polygon2, + const size_t icomponent2, + int* c1_is_in_c2); + SCPR_API res_T scpr_polygon_dump_to_obj (struct scpr_polygon* polygon, diff --git a/src/scpr_polygon.c b/src/scpr_polygon.c @@ -551,6 +551,53 @@ error: } res_T +scpr_get_vertex_in_component + (const struct scpr_polygon* polygon, + const size_t icomponent, + double vertex[2]) +{ + size_t i, p1sz; + Clipper2Lib::Point64 p0, c; + Clipper2Lib::PointInPolygonResult in; + res_T res = RES_OK; + + if(!polygon || !vertex || icomponent >= polygon->paths.size()) { + res = RES_BAD_ARG; + goto error; + } + + /* Find the center of the segment between vertex #0 and vertex #i + * If it is inside the polygon return it */ + p0 = polygon->paths[icomponent][0]; + p1sz = polygon->paths[icomponent].size(); + for(i = 2; i < polygon->paths[0].size(); i++) { + Clipper2Lib::Point64 pi = polygon->paths[icomponent][i]; + if(p1sz == 3) { + /* Special case of a triangle: get the barycenter */ + Clipper2Lib::Point64 p1 = polygon->paths[icomponent][1]; + c = (p0 + p1 + pi) * 0.3333333; + } else { + c = (p0 + pi) * 0.5; + } + TRY(in = Clipper2Lib::PointInPolygon(c, polygon->paths[icomponent])); + if(in == Clipper2Lib::PointInPolygonResult::IsOn) { + int64_t tmp64[2]; + tmp64[0] = c.x; tmp64[1] = c.y; + ERR(scpr_device_unscale(polygon->device, tmp64, 2, vertex)); + break; /* Found! */ + } + } + /* Should not be there: the component is either ill-formed or too thin to host + * a vertex in its inside! */ + res = RES_BAD_ARG; + +exit: + return res; +error: + goto exit; +} + +res_T scpr_is_vertex_in_component (const struct scpr_polygon* polygon, const size_t icomponent, @@ -570,7 +617,6 @@ scpr_is_vertex_in_component ERR(scpr_device_scale(polygon->device, vertex, 2, tmp64)); TRY(pt.Init(SPLIT2(tmp64))); TRY(in = Clipper2Lib::PointInPolygon(pt, polygon->paths[icomponent])); - enum class PointInPolygonResult { IsOn, IsInside, IsOutside }; switch(in) { case Clipper2Lib::PointInPolygonResult::IsOn: *situation = 0; @@ -590,6 +636,68 @@ error: } res_T +scpr_is_component_in_component + (const struct scpr_polygon* polygon1, + const size_t icomponent1, + const struct scpr_polygon* polygon2, + const size_t icomponent2, + int* c1_is_in_c2) +{ + size_t i, p1sz; + Clipper2Lib::Point64 p0, c; + Clipper2Lib::PointInPolygonResult in; + res_T res = RES_OK; + + if(!polygon1 || icomponent1 >= polygon1->paths.size() + || !polygon2 || icomponent2 >= polygon2->paths.size() + || ! c1_is_in_c2) + { + res = RES_BAD_ARG; + goto error; + } + + /* First find a vertex that is inside polygon1 */ + p0 = polygon1->paths[icomponent1][0]; + p1sz = polygon1->paths[icomponent1].size(); + for(i = 2; i < p1sz; i++) { + Clipper2Lib::Point64 pi = polygon1->paths[icomponent1][i]; + if(p1sz == 3) { + /* Special case of a triangle: get the barycenter */ + Clipper2Lib::Point64 p1 = polygon1->paths[icomponent1][1]; + c = (p0 + p1 + pi) * 0.3333333; + } else { + c = (p0 + pi) * 0.5; + } + TRY(in = Clipper2Lib::PointInPolygon(c, polygon1->paths[icomponent1])); + if(in != Clipper2Lib::PointInPolygonResult::IsInside) + continue; + /* c is in polygon1; check its situation against polygon2 */ + TRY(in = Clipper2Lib::PointInPolygon(c, polygon2->paths[icomponent2])); + switch(in) { + case Clipper2Lib::PointInPolygonResult::IsOn: + /* The 2 components overlap! */ + res = RES_BAD_ARG; + goto error; + case Clipper2Lib::PointInPolygonResult::IsOutside: + *c1_is_in_c2 = 0; + goto exit; + case Clipper2Lib::PointInPolygonResult::IsInside: + *c1_is_in_c2 = 1; + goto exit; + } + break; + } + /* Should not be there: component1 is either ill-formed or too thin to host + * a vertex in its inside! */ + res = RES_BAD_ARG; + +exit: + return res; +error: + goto exit; +} + +res_T scpr_polygon_dump_to_obj (struct scpr_polygon* polygon, FILE* stream)