commit c2a2f7858b5249a3810394e44ed331d2227adc53
parent 35c7196ae6de64e2ff368d4d220dad06110b0956
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 13 Sep 2024 16:26:29 +0200
Fix a rare crash
It can occur that Clipper2 fails to detect polygon self intersection (if
it barely intersects). When this occurs during CAO creation steps it
could lead to some assertion failure (the configuration that allowed to
discover the problem was the CAO generation of a mode1 building, with an
undetected self-intersection on an inner polygon).
The fix is to change the code managing polygon intersections so that the
specific case of checking CAO validity does not fail, but detect that
something went wrong and reject the building.
Diffstat:
4 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/src/cg_city.c b/src/cg_city.c
@@ -115,6 +115,7 @@ error:
#define STORE_CLOSE_INFO(Building1, Building2, Proximity) {\
unsigned char *ptr__, tmp__; \
+ ASSERT((Building1) != (Building2)); \
ptr__ = htable_building_find(&(Building1)->close_buildings, &(Building2)); \
tmp__ = (unsigned char)(ptr__ ? ((Proximity) | *ptr__) : (Proximity)); \
ERR(htable_building_set(&(Building1)->close_buildings, &(Building2), &tmp__)); \
@@ -203,6 +204,13 @@ int simple_intersection
if(ctx->intersection_found) *ctx->intersection_found = 1;
+ if(ctx->search_type == TESTING_1_BUILDING_INTERNALS) {
+ /* There is no point in searching which building is involved.
+ * We noted the fact that an intersection was found, thats all. */
+ ASSERT(ctx->buildings_count == 1);
+ return 0;
+ }
+
/* Search polygons in the city (slow, but OK) */
for(i = 0; i < ctx->buildings_count; i++) {
struct building* building = ctx->buildings + i;
@@ -266,6 +274,9 @@ int simple_intersection
building2->event_flags |= BUILDING_REMOVED_EARLY;
break;
case CLOSE_PROXIMITY:
+ /* store other polygon on building information */
+ STORE_CLOSE_INFO(building1, building2, ctx->search_type);
+ STORE_CLOSE_INFO(building2, building1, ctx->search_type);
logger_print(logger, LOG_OUTPUT,
"Buildings '%s' and '%s' are in close proximity.\n", name1, name2);
break;
@@ -273,10 +284,6 @@ int simple_intersection
}
}
- /* store other polygon on building information */
- STORE_CLOSE_INFO(building1, building2, ctx->search_type);
- STORE_CLOSE_INFO(building2, building1, ctx->search_type);
-
/* Return 1 to stop the process unless whe are in proximity search or the user
* asked to go further */
if(ctx->search_type == CLOSE_PROXIMITY
@@ -374,7 +381,7 @@ create_city
struct scpr_intersector* close_intersector = NULL;
struct scpr_intersector_check_callbacks callbacks
= SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__;
- struct callback_ctx ctx;
+ struct callback_ctx ctx = CB_CTX_NULL__;
struct scpr_polygon* tmp_polygon = NULL;
struct str name;
int error_occured = 0;
@@ -515,7 +522,6 @@ create_city
ctx.keep_running_on_errors = city->keep_running_on_errors;
callbacks.simple_intersection = simple_intersection;
callbacks.overlapping_segments = overlapping_segments;
- ctx.alternate_polygons = NULL;
ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx));
if(error_occured && !city->keep_running_on_errors) {
res = RES_BAD_ARG;
diff --git a/src/cg_city.h b/src/cg_city.h
@@ -179,7 +179,8 @@ dump_footprint_to_obj
enum building_proximity {
NO_PROXIMITY,
CLOSE_PROXIMITY = BIT(0),
- OVERLAPPING_PROXIMITY = BIT(1)
+ OVERLAPPING_PROXIMITY = BIT(1),
+ TESTING_1_BUILDING_INTERNALS = BIT(2)
};
/* the type of context expected by simple_intersection */
@@ -193,6 +194,7 @@ struct callback_ctx {
int dump_footprints_level;
int keep_running_on_errors;
};
+#define CB_CTX_NULL__ { NULL, NULL, NULL, 0, NULL, NO_PROXIMITY, 0, 0 }
int overlapping_segments
(struct scpr_callback_segment* segment1,
diff --git a/src/cg_construction_mode_0.c b/src/cg_construction_mode_0.c
@@ -495,7 +495,7 @@ build_cad_cmode_0
struct scpr_intersector* overlapping_intersector = NULL;
struct scpr_intersector_check_callbacks callbacks
= SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__;
- struct callback_ctx ctx;
+ struct callback_ctx ctx = CB_CTX_NULL__;
int error_occured = 0, error_msg_printed = 0;
struct scpr_device* scpr;
struct mem_allocator* allocator;
@@ -555,7 +555,7 @@ build_cad_cmode_0
ctx.buildings = building;
ctx.buildings_count = 1;
ctx.intersection_found = &error_occured;
- ctx.search_type = OVERLAPPING_PROXIMITY;
+ ctx.search_type = TESTING_1_BUILDING_INTERNALS;
ctx.dump_footprints_level = dump_footprints_level;
ctx.keep_running_on_errors = keep_running_on_errors;
callbacks.simple_intersection = simple_intersection;
diff --git a/src/cg_construction_mode_1.c b/src/cg_construction_mode_1.c
@@ -1527,7 +1527,7 @@ build_cad_cmode_1
struct scpr_intersector_check_callbacks callbacks
= SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__;
size_t adjoining_n = 0;
- struct callback_ctx ctx;
+ struct callback_ctx ctx = CB_CTX_NULL__;
int error_occured = 0, error_msg_printed = 0;;
struct htable_polygons polygons;
int polygons_initialized = 0;
@@ -1658,7 +1658,7 @@ build_cad_cmode_1
ctx.buildings = building;
ctx.buildings_count = 1;
ctx.intersection_found = &error_occured;
- ctx.search_type = OVERLAPPING_PROXIMITY;
+ ctx.search_type = TESTING_1_BUILDING_INTERNALS;
ctx.dump_footprints_level = dump_footprints_level;
ctx.keep_running_on_errors = keep_running_on_errors;
callbacks.simple_intersection = simple_intersection;