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:
| M | src/scpr.h | | | 20 | +++++++++++++++++++- |
| M | src/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)