commit b38528debac9ddb735f6eacc99c27d26e119e758
parent 9d29d87dc27d1b2bf5b7f503f2bee5bb0a71e2c4
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Mon, 6 Nov 2023 16:46:52 +0100
BugFix in component in component test
Diffstat:
4 files changed, 134 insertions(+), 33 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -99,6 +99,7 @@ if(NOT NO_TEST)
new_test(test_scpr_clip)
new_test(test_scpr_device)
new_test(test_scpr_intersector)
+ new_test(test_scpr_is_in)
new_test(test_scpr_offset)
new_test(test_scpr_mesh)
new_test(test_scpr_polygon)
diff --git a/src/scpr.h b/src/scpr.h
@@ -268,9 +268,9 @@ 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. */
+/* Check if a component is inside a component, given the 2 components are not
+ * equal and do not overlap (they can be adjoining).
+ * Only meaningful for simple components. */
SCPR_API res_T
scpr_is_component_in_component
(const struct scpr_polygon* polygon1,
diff --git a/src/scpr_polygon.c b/src/scpr_polygon.c
@@ -644,8 +644,10 @@ scpr_is_component_in_component
int* c1_is_in_c2)
{
size_t i, p1sz;
- Clipper2Lib::Point64 p0, c;
+ int is_in = -1;
Clipper2Lib::PointInPolygonResult in;
+ const Clipper2Lib::Path64* comp1;
+ const Clipper2Lib::Path64* comp2;
res_T res = RES_OK;
if(!polygon1 || icomponent1 >= polygon1->paths.size()
@@ -656,40 +658,41 @@ scpr_is_component_in_component
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]));
+ /* comp1 == comp2 is reported as bad arg.
+ * This API requires comp1 and comp2 to not overlap (they can be adjoining),
+ * this allows to exit early as soon as 1 vertex is either inside or outside */
+ comp1 = &polygon1->paths[icomponent1];
+ comp2 = &polygon2->paths[icomponent2];
+ p1sz = comp1->size();
+ for(i = 0; i < p1sz; i++) {
+ Clipper2Lib::Point64 p = (*comp1)[i];
+ TRY(in = Clipper2Lib::PointInPolygon(p, (*comp2)));
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;
+ is_in = 0;
+ break;
+ case Clipper2Lib::PointInPolygonResult::IsOn:
+ /* Cannot decide based on this */
+ break;
case Clipper2Lib::PointInPolygonResult::IsInside:
- *c1_is_in_c2 = 1;
- goto exit;
+ is_in = 1;
+ break;
+ }
+ if(is_in >= 0) break; /* Early exit */
+ }
+ if(is_in == -1) {
+ /* Every vertex of comp1 is on comp2: comp1 is either equal to comp2, or it
+ * is inside */
+ int is_eq = path_is_eq(comp1, comp2);
+ if(!is_eq) {
+ is_in = 1;
+ } else {
+ res = RES_BAD_ARG;
+ goto error;
}
- break;
}
- /* Should not be there: component1 is either ill-formed or too thin to host
- * a vertex in its inside! */
- res = RES_BAD_ARG;
+
+ * c1_is_in_c2 = is_in;
exit:
return res;
diff --git a/src/test_scpr_is_in.c b/src/test_scpr_is_in.c
@@ -0,0 +1,97 @@
+/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#define _POSIX_C_SOURCE 200112L
+
+#include "scpr.h"
+#include "test_scpr_utils.h"
+
+#include <rsys/rsys.h>
+#include <rsys/mem_allocator.h>
+
+#include <memory.h>
+
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
+ struct scpr_device* dev;
+ double c0[] = {0, 5, 8, 5, 8, 9, 0, 9 };
+ double c1[] = {1, 1, 3, 1, 3, 9, 1, 9 };
+ double c2[] = {3, 6, 5, 6, 5, 8, 4, 7, 3, 8 };
+ size_t n0[] = { 4 };
+ size_t n1[] = { 4 };
+ size_t n2[] = { 5 };
+ struct scpr_polygon* p0 = NULL;
+ struct scpr_polygon* p1 = NULL;
+ struct scpr_polygon* p2 = NULL;
+ struct polygon_context context;
+ double** pos;
+ int in;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ pos = (double**)MEM_CALLOC(&allocator, 1, sizeof(*pos));
+ *pos = (double*)MEM_CALLOC(&allocator, 10, sizeof(**pos));
+
+ args.allocator = &allocator;
+ args.precision = 2;
+ OK(scpr_device_create(&args, &dev));
+
+ OK(scpr_polygon_create(dev, &p0));
+ OK(scpr_polygon_create(dev, &p1));
+ OK(scpr_polygon_create(dev, &p2));
+
+ context.ncomps = 1;
+ context.coords = pos;
+
+ context.nverts = n0;
+ memcpy(*pos, c0, 2*n0[0]*sizeof(**pos));
+ OK(scpr_polygon_setup_indexed_vertices(p0, 1, pget_nverts, pget_pos, &context));
+
+ context.nverts = n1;
+ memcpy(*pos, c1, 2*n1[0]*sizeof(**pos));
+ OK(scpr_polygon_setup_indexed_vertices(p1, 1, pget_nverts, pget_pos, &context));
+
+ context.nverts = n2;
+ memcpy(*pos, c2, 2*n2[0]*sizeof(**pos));
+ OK(scpr_polygon_setup_indexed_vertices(p2, 1, pget_nverts, pget_pos, &context));
+
+ BAD(scpr_is_component_in_component(NULL, 0, NULL, 0, NULL));
+ OK(scpr_is_component_in_component(p1, 0, p2, 0, &in));
+ CHK(in == 0);
+ OK(scpr_is_component_in_component(p2, 0, p1, 0, &in));
+ CHK(in == 0);
+ OK(scpr_is_component_in_component(p2, 0, p0, 0, &in));
+ CHK(in == 1);
+ OK(scpr_is_component_in_component(p0, 0, p2, 0, &in));
+ CHK(in == 0);
+
+ OK(scpr_device_ref_put(dev));
+ OK(scpr_polygon_ref_put(p0));
+ OK(scpr_polygon_ref_put(p1));
+ OK(scpr_polygon_ref_put(p2));
+
+ MEM_RM(&allocator, *pos);
+ MEM_RM(&allocator, pos);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}