commit 942645ffc51ca1b49ebff77b4cfd13e15a92f22c
parent 51b00620d8f6aae71415dff12f2ee916cdc68da6
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 3 Mar 2023 16:53:10 +0100
Use new star-cpr features to detect buildings neighbors
Used both for error detection and for adjoining construction
Diffstat:
18 files changed, 1041 insertions(+), 266 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -72,7 +72,7 @@ configure_file(${CG2_SOURCE_DIR}/cg_version.h.in
find_package(RCMake 0.4.1 REQUIRED)
find_package(RSys 0.12.1 REQUIRED)
find_package(StarCAD 0.1 REQUIRED)
-find_package(StarCPR 0.1.3 REQUIRED)
+find_package(StarCPR 0.3 REQUIRED)
find_package(libcyaml 1.3 REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
@@ -108,6 +108,7 @@ set(CG2_FILES_SRC
cg_catalog_parsing.c
cg_city.c
cg_city_parsing.c
+ cg_construction_mode.c
cg_construction_mode_0.c
cg_construction_mode_1.c
cg_ground.c
diff --git a/src/cg.h b/src/cg.h
@@ -25,6 +25,14 @@
#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0
+/*
+ * Some constants used in city_generator
+ */
+
+#define CLIPPER_PRECISON 3 /* Input footprints are rounded to mm */
+#define CLOSE_NEIGHBOR_DISTANCE 0.1 /* Neighbors are considered close <= 0.1 m */
+
+/* Utility functions */
static INLINE void
log_prt_fn(const char* msg, void* ctx)
{
diff --git a/src/cg_args.c b/src/cg_args.c
@@ -43,7 +43,7 @@ short_help(void)
{
print_version();
printf("\nUsage:\n"
- "city_generator2 -m <FILENAME> { -c <FILENAME> }+ -[%c] [-s] [-V verbosity]\n"
+ "city_generator2 -m <FILENAME> { -c <FILENAME> }+ -[%c] [-s] [-V verbosity] [-k] [-f <NAME>] [-F]\n"
"city_generator2 [-h]\n"
"city_generator2 [-v]\n",
CG2_ARGS_CHANGE_BINARY_DEFAULT_OPTION
@@ -63,6 +63,14 @@ short_help(void)
"-%c\n"
" Set the format of output files to "STR(CG2_ARGS_STL_NON_DEFAULT_STR)
" (default "STR(CG2_ARGS_STL_DEFAULT_STR)").\n"
+ "-k\n"
+ " Keep running on errors.\n"
+ "-f <NAME>.\n"
+ " Dump the footprint of the building with the given name.\n"
+ " Can be used more than once.\n"
+ "-F\n"
+ " Dump the footprint of any building not generated due to an error.\n"
+ " Process the whole file and exit if any error was found unless -k is used.\n"
"-s\n"
" Force single threaded execution. By default use as many threads as available.\n"
"-v\n"
@@ -96,32 +104,31 @@ parse_args
int opt;
int info_provided = 0, c_provided = 0, m_provided = 0;
struct args* args;
- char option_list[] = "?c:m:hvV:";
+ char option_list[] = "?c:m:hkFf:vV:";
ASSERT(allocator && logger && argv && out_args);
/* Patch option_list[] according to stl format default */
option_list[0] = CG2_ARGS_CHANGE_BINARY_DEFAULT_OPTION;
- args = MEM_ALLOC(allocator, sizeof(*args));
+ args = MEM_CALLOC(allocator, 1, sizeof(*args));
if(!args) {
res = RES_MEM_ERR;
goto error;
}
+
args->allocator = allocator;
args->logger = logger;
+ darray_names_init(allocator, &args->catalog_files);
+ darray_names_init(allocator, &args->dump_footprint_names);
- /* Set default values */
- args->city_filename = NULL;
- darray_catalog_filenames_init(allocator, &args->catalog_filenames);
+ /* Set non-zero default values */
args->binary_export = CG2_ARGS_BINARY_STL_DEFAULT;
args->verbosity_level = CG2_ARGS_DEFAULT_VERBOSITY_LEVEL;
- args->single_thread = 0;
- args->print_help = 0;
- args->print_version = 0;
opterr = 0; /* No default error messages */
while((opt = getopt(argc, argv, option_list)) != -1) {
+ const char* name;
switch (opt) {
case '?': /* Unrecognized option */
@@ -141,7 +148,8 @@ parse_args
case 'c':
c_provided = 1;
- ERR(darray_catalog_filenames_push_back(&args->catalog_filenames, &optarg));
+ name = optarg;
+ ERR(darray_names_push_back(&args->catalog_files, &name));
break;
case 'm':
@@ -158,11 +166,26 @@ parse_args
args->binary_export = !CG2_ARGS_BINARY_STL_DEFAULT;
break;
+ /* Optional */
+
+ case 'F':
+ args->dump_footprints_on_error = 1;
+ break;
+
+ case 'f':
+ name = optarg;
+ ERR(darray_names_push_back(&args->dump_footprint_names, &name));
+ break;
+
case 'h':
info_provided = 1;
args->print_help = 1;
break;
+ case 'k':
+ args->keep_running_on_errors = 1;
+ break;
+
case 's':
info_provided = 1;
args->single_thread = 1;
@@ -228,6 +251,7 @@ release_args
{
if(!args) return;
- darray_catalog_filenames_release(&args->catalog_filenames);
+ darray_names_release(&args->catalog_files);
+ darray_names_release(&args->dump_footprint_names);
MEM_RM(args->allocator, args);
}
diff --git a/src/cg_args.h b/src/cg_args.h
@@ -26,20 +26,23 @@
struct logger;
struct mem_allocator;
-#define DARRAY_NAME catalog_filenames
-#define DARRAY_DATA char*
+#define DARRAY_NAME names
+#define DARRAY_DATA const char*
#include <rsys/dynamic_array.h>
struct args {
struct mem_allocator* allocator;
struct logger* logger;
char* city_filename;
- struct darray_catalog_filenames catalog_filenames;
+ struct darray_names catalog_files;
+ struct darray_names dump_footprint_names;
int binary_export;
int verbosity_level;
int print_help;
int print_version;
int single_thread;
+ int keep_running_on_errors;
+ int dump_footprints_on_error;
};
res_T
diff --git a/src/cg_building.c b/src/cg_building.c
@@ -18,47 +18,63 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "cg.h"
+#include "cg_city.h"
#include "cg_building.h"
#include <rsys/stretchy_array.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/logger.h>
+
#include <star/scad.h>
-res_T
+res_T
build_adjoining
(struct mem_allocator* allocator,
struct logger* logger,
- struct building** adjoining,
- const size_t adjoining_n,
+ struct building* building,
struct scad_geometry*** geom)
{
res_T res = RES_OK;
- size_t i = 0;
+ size_t count, i = 0;
struct scad_geometry** envelop_list = NULL;
+ struct htable_building_iterator it, end;
+ struct htable_building* close_buildings;
- if (!adjoining || adjoining_n < 1 || !geom) {
- res = RES_BAD_ARG;
- goto error;
- }
+ ASSERT(allocator && logger && building && geom);
+
+ close_buildings = &building->close_buildings;
+ count = htable_building_size_get(close_buildings);
- envelop_list = MEM_CALLOC(allocator, adjoining_n, sizeof(struct scad_geometry*));
+ logger_print(logger, LOG_OUTPUT,
+ "building '%s' considering %zu close neighbor(s) when creating CAD.\n",
+ str_cget(&building->name), count);
+
+ envelop_list = MEM_CALLOC(allocator, count, sizeof(struct scad_geometry*));
if(!envelop_list) {
res = RES_MEM_ERR;
goto error;
}
/* iterate over adjoining building */
- for (i=0; i<adjoining_n; i++) {
-
- ERR(adjoining[i]->functors->build_envelop(allocator, logger,
- adjoining[i], envelop_list + i));
+ htable_building_begin(close_buildings, &it);
+ htable_building_end(close_buildings, &end);
+ while(!htable_building_iterator_eq(&it, &end)) {
+ unsigned char flags = *htable_building_iterator_data_get(&it);
+ struct building* close_building;
+ ASSERT(flags & CLOSE_PROXIMITY);
+ close_building = *htable_building_iterator_key_get(&it);
+ ERR(close_building->functors->build_envelop(allocator, logger, close_building,
+ envelop_list + i++));
+ htable_building_iterator_next(&it);
}
-
+ ASSERT(i == count);
+
exit:
- if (envelop_list) *geom = envelop_list;
+ *geom = envelop_list;
return res;
error:
- for (i=0; i<adjoining_n; i++) {
- if (envelop_list[i]) scad_geometry_delete(envelop_list[i]);
+ for (i = 0; i < count; i++) {
+ if(envelop_list[i]) SCAD(geometry_delete(envelop_list[i]));
}
if (envelop_list) MEM_RM(allocator, envelop_list);
envelop_list = NULL;
diff --git a/src/cg_building.h b/src/cg_building.h
@@ -32,6 +32,24 @@ struct catalog;
struct building;
struct parsed_city_building;
struct scpr_device;
+struct building;
+
+/* An htable to uniquely associate flags to buildings */
+#define HTABLE_NAME building
+#define HTABLE_KEY struct building*
+#define HTABLE_DATA unsigned char
+#include <rsys/hash_table.h>
+
+/* An enum to encode building events types. */
+enum building_event {
+ BUILDING_NO_EVENT,
+ BUILDING_WITH_OVERLAPPING = BIT(0),
+ BUILDING_WITH_CLOSE_NEIGHBOR = BIT(1),
+ BUILDING_WITH_INTERNAL_ERROR = BIT(2),
+ BUILDING_OUT_OF_GROUND_EXTENT = BIT(3),
+ BUILDING_REMOVED = BIT(4),
+ BUILDING_DUMPED_TO_OBJ = BIT(5)
+};
/* A type to store the functors of a construction mode */
struct construction_mode_functors {
@@ -40,15 +58,22 @@ struct construction_mode_functors {
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int keep_running_on_error,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
const double upper[2]);
+ res_T (*release)
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building);
res_T (*build_cad)
(struct scpr_device* scpr,
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int dump_footprints_on_error,
+ int keep_running_on_errors,
void** cad);
res_T (*build_footprint)
(struct scpr_device* scpr,
@@ -88,12 +113,12 @@ struct building {
enum construction_mode_type construction_mode;
/* generic construction mode data */
- int name_initialized;
struct str name;
double height;
struct scpr_polygon* pg;
- struct building** adjoining;
- size_t adjoining_n;
+ struct htable_building close_buildings; /* links to other buildings */
+ int structs_initialized;
+ unsigned int event_flags;
/* specific data depending to the construction mode */
void* data;
@@ -103,8 +128,7 @@ res_T
build_adjoining
(struct mem_allocator* allocator,
struct logger* logger,
- struct building** adjoining,
- const size_t adjoining_n,
+ struct building* building,
struct scad_geometry*** geom);
#endif /* BUILDING_H */
diff --git a/src/cg_catalog_parsing.c b/src/cg_catalog_parsing.c
@@ -45,7 +45,7 @@ get_schema_from_parsed_cmode
res_T
parse_catalog
- (const struct darray_catalog_filenames* files_array,
+ (const struct darray_names* files_array,
struct mem_allocator* allocator,
struct logger* logger,
const struct cyaml_config* config,
@@ -57,7 +57,7 @@ parse_catalog
struct parsed_catalog_items* items;
struct parsed_catalog* parsed;
struct parsed_cmode* parsed_cmode = NULL;
- char* filename = NULL;
+ const char* filename = NULL;
(void)logger;
ASSERT(files_array && allocator && logger && out_parsed);
@@ -71,7 +71,7 @@ parse_catalog
parsed->allocator = allocator;
parsed->logger = logger;
- files_count = darray_catalog_filenames_size_get(files_array);
+ files_count = darray_names_size_get(files_array);
darray_parsed_catalog_items_init(allocator, &parsed->catalog);
ERR(darray_parsed_catalog_items_resize(&parsed->catalog, files_count));
@@ -80,7 +80,7 @@ parse_catalog
const struct cyaml_schema_value* schema;
/* Parse construction mode only */
- filename = darray_catalog_filenames_cdata_get(files_array)[i];
+ filename = darray_names_cdata_get(files_array)[i];
err = cyaml_load_file(filename, config, &construction_mode_schema,
(void**)&parsed_cmode, NULL);
ERR(cyaml_err_to_res_T(err));
diff --git a/src/cg_catalog_parsing.h b/src/cg_catalog_parsing.h
@@ -28,11 +28,11 @@
struct logger;
struct mem_allocator;
struct cyaml_config;
-struct darray_catalog_filenames;
+struct darray_names;
struct parsed_catalog_items {
enum parsed_cmode_type construction_mode;
- char* filename;
+ const char* filename;
void* parsed_data;
};
@@ -48,7 +48,7 @@ struct parsed_catalog {
res_T
parse_catalog
- (const struct darray_catalog_filenames* files,
+ (const struct darray_names* files,
struct mem_allocator* allocator,
struct logger* logger,
const struct cyaml_config* config,
diff --git a/src/cg_city.c b/src/cg_city.c
@@ -33,21 +33,169 @@
#include <rsys/double4.h>
#include <rsys/hash_table.h>
+#include <rsys/str.h>
#include <star/scpr.h>
#include <string.h>
-#define HTABLE_NAME names
-#define HTABLE_DATA char
-#define HTABLE_KEY struct str
-#define HTABLE_KEY_FUNCTOR_INIT str_init
-#define HTABLE_KEY_FUNCTOR_RELEASE str_release
-#define HTABLE_KEY_FUNCTOR_COPY str_copy
-#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release
-#define HTABLE_KEY_FUNCTOR_COPY_AND_CLEAR str_copy_and_clear
-#define HTABLE_KEY_FUNCTOR_EQ str_eq
-#define HTABLE_KEY_FUNCTOR_HASH str_hash
-#include <rsys/hash_table.h>
+res_T
+dump_obj
+ (struct mem_allocator* allocator,
+ struct building* building)
+{
+ res_T res = RES_OK;
+ FILE* stream = NULL;
+ struct str filename;
+
+ ASSERT(allocator && building);
+
+ /* No need to dump twice */
+ if(building->event_flags & BUILDING_DUMPED_TO_OBJ) return res;
+
+ str_init(allocator, &filename);
+ ERR(str_copy(&filename, &building->name));
+ ERR(str_append(&filename, ".obj"));
+ stream = fopen(str_cget(&filename), "w");
+ ERR(scpr_polygon_dump_to_obj(building->pg, stream));
+ building->event_flags |= BUILDING_DUMPED_TO_OBJ;
+exit:
+ if(stream) fclose(stream);
+ str_release(&filename);
+ return res;
+error:
+ goto exit;
+}
+
+#define STORE_CLOSE_INFO(Building1, Building2, Proximity) {\
+ unsigned char *ptr__, tmp__; \
+ ptr__ = htable_building_find(&(Building1)->close_buildings, &(Building2)); \
+ tmp__ = (unsigned char)(ptr__ ? ((Proximity) | *ptr__) : (Proximity)); \
+ ERR(htable_building_set(&(Building1)->close_buildings, &(Building2), &tmp__)); \
+}
+
+int collinear_segments
+ (struct scpr_callback_segment* segment1,
+ struct scpr_callback_segment* segment2,
+ void* ctx__)
+{
+ res_T res = RES_OK;
+ size_t i;
+ struct callback_ctx* ctx = (struct callback_ctx*)ctx__;
+ const char *name1 = NULL, *name2 = NULL;
+ struct building *building1 = NULL, *building2 = NULL;
+
+ ASSERT(segment1 && segment2 && ctx);
+
+ /* Search polygons in the city (slow, but OK) */
+ for(i = 0; i < ctx->buildings_count; i++) {
+ struct building* building = ctx->buildings + i;
+ enum building_event flag = BUILDING_WITH_CLOSE_NEIGHBOR;
+ if(building->pg == segment1->polygon) {
+ building1 = building;
+ name1 = str_cget(&building->name);
+ building1->event_flags |= flag;
+ } else if(building->pg == segment2->polygon) {
+ building2 = building;
+ name2 = str_cget(&building->name);
+ building2->event_flags |= flag;
+ }
+ }
+ CHK(name1 && name2);
+
+ switch(ctx->search_type) {
+ case OVERLAPPING_PROXIMITY:
+ /* store other polygon on building information */
+ STORE_CLOSE_INFO(building1, building2, CLOSE_PROXIMITY);
+ STORE_CLOSE_INFO(building2, building1, CLOSE_PROXIMITY);
+ logger_print(ctx->logger, LOG_OUTPUT,
+ "Common segments detected between buildings '%s' and '%s'.\n",
+ name1, name2);
+ break;
+ case CLOSE_PROXIMITY:
+ /* No action required */
+ break;
+ default: FATAL("Invalid type.");
+ }
+
+ return 0;
+error:
+ /* True errors are not recoverable */
+ return 1;
+}
+
+int simple_intersection
+ (struct scpr_callback_segment* segment1,
+ struct scpr_callback_segment* segment2,
+ void* ctx__)
+{
+ res_T res = RES_OK;
+ size_t i;
+ struct callback_ctx* ctx = (struct callback_ctx*)ctx__;
+ const char *name1 = NULL, *name2 = NULL;
+ struct building *building1 = NULL, *building2 = NULL;
+ enum building_event flag = ctx->search_type == OVERLAPPING_PROXIMITY
+ ? BUILDING_WITH_OVERLAPPING : BUILDING_WITH_CLOSE_NEIGHBOR;
+
+ ASSERT(segment1 && segment2 && ctx);
+
+ if(ctx->intersection_found) *ctx->intersection_found = 1;
+
+ /* Search polygons in the city (slow, but OK) */
+ for(i = 0; i < ctx->buildings_count; i++) {
+ struct building* building = ctx->buildings + i;
+ if(building->pg == segment1->polygon) {
+ building1 = building;
+ name1 = str_cget(&building->name);
+ building1->event_flags |= flag;
+ } else if(building->pg == segment2->polygon) {
+ building2 = building;
+ name2 = str_cget(&building->name);
+ building2->event_flags |= flag;
+ }
+ }
+ CHK(name1 && name2);
+
+ switch(ctx->search_type) {
+ case OVERLAPPING_PROXIMITY:
+ logger_print(ctx->logger,
+ (ctx->keep_running_on_errors ? LOG_WARNING : LOG_ERROR),
+ "Intersection detected between buildings '%s' and '%s'.\n",
+ name1, name2);
+ /* Dump the polygons in OBJ files */
+ ERR(dump_obj(ctx->allocator, building1));
+ ERR(dump_obj(ctx->allocator, building2));
+ break;
+ case CLOSE_PROXIMITY:
+ logger_print(ctx->logger, LOG_OUTPUT,
+ "Buildings '%s' and '%s' are in close proximity.\n",
+ name1, name2);
+ break;
+ default: FATAL("Invalid type.");
+ }
+
+ /* 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 user asked to go further */
+ if(ctx->keep_running_on_errors || ctx->dump_footprints_on_error)
+ return 0;
+ return 1;
+error:
+ /* True errors are not recoverable */
+ return 1;
+}
+#undef STORE_CLOSE_INFO
+
+#define ERRtmp(Expr) \
+if((error_occured |= ((res_tmp = (Expr)) != RES_OK)) \
+ && !city->dump_footprints_on_error) \
+{ \
+ logger_print(logger, LOG_ERROR, \
+ "Error initializing building '%s'.\n", str_cget(&building->name)); \
+ res = res_tmp; \
+ goto error;\
+} else (void)0
res_T
create_city
@@ -64,10 +212,20 @@ create_city
struct htable_names names;
int initialized = 0;
struct scpr_device_create_args scpr_args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
- (void)logger;
+ struct scpr_intersector* overlapping_intersector = NULL;
+ struct scpr_intersector* close_intersector = NULL;
+ struct scpr_intersector_check_callbacks callbacks
+ = SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__;
+ struct callback_ctx ctx;
+ struct scpr_polygon* tmp_polygon = NULL;
+ struct str name;
+ int error_occured = 0;
+ struct building* building = NULL;
ASSERT(logger && allocator && args && parsed_city && catalog && out_city);
+ str_init(allocator, &name);
+
city = MEM_CALLOC(allocator, 1, sizeof(*city));
if(!city) {
res = RES_MEM_ERR;
@@ -77,8 +235,8 @@ create_city
htable_names_init(allocator, &names);
initialized = 1;
- city->buildings_count = parsed_city->city_building_list_count;
- city->buildings = MEM_CALLOC(allocator, city->buildings_count,
+ city->allocated_buildings_count = parsed_city->city_building_list_count;
+ city->buildings = MEM_CALLOC(allocator, city->allocated_buildings_count,
sizeof(*city->buildings));
if(!city->buildings) {
res = RES_MEM_ERR;
@@ -90,9 +248,20 @@ create_city
scpr_args.allocator = allocator;
scpr_args.logger = logger;
scpr_args.verbosity_level = args->verbosity_level;
+ scpr_args.precision = CLIPPER_PRECISON;
ERR(scpr_device_create(&scpr_args, &city->scpr));
city->verbosisty_level = args->verbosity_level;
city->binary_export = args->binary_export;
+ city->keep_running_on_errors = args->keep_running_on_errors;
+ city->dump_footprints_on_error = args->dump_footprints_on_error;
+ htable_names_init(allocator, &city->dump_footprint_names);
+ city->names_initialized = 1;
+ for(i = 0; i < darray_names_size_get(&args->dump_footprint_names); i++) {
+ char one = 1;
+ const char* pname = darray_names_cdata_get(&args->dump_footprint_names)[i];
+ ERR(str_set(&name, pname));
+ ERR(htable_names_set(&city->dump_footprint_names, &name, &one));
+ }
city->ground_depth = parsed_city->ground.depth;
city->lower[0] = parsed_city->ground.extent[0];
@@ -100,63 +269,122 @@ create_city
city->upper[0] = parsed_city->ground.extent[1];
city->upper[1] = parsed_city->ground.extent[3];
+ ERR(scpr_intersector_create(city->scpr, &overlapping_intersector));
+ ERR(scpr_intersector_create(city->scpr, &close_intersector));
/* create buildings depending on their construction modes */
- for (i = 0; i < city->buildings_count ; i++) {
+ for (i = 0; i < city->allocated_buildings_count ; i++) {
struct parsed_city_building* parsed_data = parsed_city->city_building_list + i;
- struct building* building = city->buildings + i;
+ building = city->buildings + i;
char one = 1;
+ res_T res_tmp = RES_OK;
+ city->initialized_buildings_count++;
switch(parsed_data->cmode_type) {
case PARSED_CMODE_0:
- ERR(init_cmode_0(city->scpr, allocator, logger, building, parsed_data,
- catalog, city->lower, city->upper));
+ ERRtmp(init_cmode_0(city->scpr, allocator, logger, building,
+ city->keep_running_on_errors, parsed_data, catalog,
+ city->lower, city->upper));
break;
case PARSED_CMODE_1:
- ERR(init_cmode_1(city->scpr, allocator, logger, building, parsed_data,
- catalog, city->lower, city->upper));
+ ERRtmp(init_cmode_1(city->scpr, allocator, logger, building,
+ city->keep_running_on_errors, parsed_data, catalog,
+ city->lower, city->upper));
break;
- default:
- res = RES_BAD_ARG;
- goto error;
+ default: FATAL("Unknown construction mode");
}
- /* Check name unicity. The error case is Not supposed to happen: can be
+ /* Check name unicity. The error case is not supposed to happen: can be
* tested after building creation as this simplifies the process */
if(htable_names_find(&names, &building->name)) {
logger_print(logger, LOG_ERROR,
"Duplicate building name: '%s' in file '%s'.\n",
- parsed_data->name, str_cget(&parsed_city->filename));
+ str_cget(&building->name), str_cget(&parsed_city->filename));
res = RES_BAD_ARG;
goto error;
}
ERR(htable_names_set(&names, &building->name, &one));
+ /* Dump polygon if in the list */
+ if(htable_names_find(&city->dump_footprint_names, &building->name)) {
+ ERR(dump_obj(allocator, building));
+ }
+ /* Register the exterior building polygon for further overlapping detection */
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, building->pg));
+ /* Register offset exterior building polygon for further proximity detection */
+ ERR(scpr_polygon_create_copy(city->scpr, building->pg, &tmp_polygon));
+ ERR(scpr_offset_polygon(tmp_polygon, CLOSE_NEIGHBOR_DISTANCE,
+ SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(close_intersector, tmp_polygon));
+ ERR(scpr_polygon_ref_put(tmp_polygon));
+ tmp_polygon = NULL;
+ }
+ building = NULL;
+ ASSERT(city->initialized_buildings_count == city->allocated_buildings_count);
+
+ /* Check for polygons overlapping and proximity */
+ ctx.allocator = allocator;
+ ctx.logger = logger;
+ ctx.buildings = city->buildings;
+ ctx.buildings_count = city->initialized_buildings_count;
+ ctx.intersection_found = &error_occured;
+ ctx.search_type = OVERLAPPING_PROXIMITY;
+ ctx.dump_footprints_on_error = city->dump_footprints_on_error;
+ ctx.keep_running_on_errors = city->keep_running_on_errors;
+ callbacks.simple_intersection = simple_intersection;
+ callbacks.collinear_segments = collinear_segments;
+ ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx));
+ ctx.search_type = CLOSE_PROXIMITY;
+ ctx.intersection_found = NULL; /* Not an error in this case */
+ ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx));
+
+ if(error_occured && !city->keep_running_on_errors) {
+ res = RES_BAD_ARG;
+ goto error;
}
exit:
+ str_release(&name);
+ if(tmp_polygon) SCPR(polygon_ref_put(tmp_polygon));
+ if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector));
+ if(close_intersector) SCPR(intersector_ref_put(close_intersector));
if(initialized) htable_names_release(&names);
*out_city = city;
return res;
error:
- release_city(city);
+ if(building) {
+ logger_print(logger, LOG_ERROR,
+ "Error creating building '%s'.\n", str_cget(&building->name));
+ } else {
+ logger_print(logger, LOG_ERROR, "Error creating city.\n");
+ }
+ CHK(RES_OK == release_city(city));
city = NULL;
goto exit;
}
+#undef ERRtmp
-void
+res_T
release_city(struct city* city)
{
size_t i;
+ res_T res = RES_OK;
- if(!city) return;
+ if(!city) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
if(city->scpr) SCPR(device_ref_put(city->scpr));
+ if(city->names_initialized) htable_names_release(&city->dump_footprint_names);
/* iterate on building */
- for (i = 0; i < city->buildings_count; i++) {
+ for (i = 0; i < city->initialized_buildings_count; i++) {
struct building* building = city->buildings + i;
- if(building->pg) SCPR(polygon_ref_put(building->pg));
- if(building->name_initialized) str_release(&building->name);
+ ERR(building->functors->release(city->allocator, city->logger, building));
}
MEM_RM(city->allocator, city->buildings);
MEM_RM(city->allocator, city);
+exit:
+ return res;
+error:
+ goto exit;
}
res_T
@@ -165,7 +393,10 @@ city_cad_build(struct city* city)
res_T res = RES_OK;
struct scad_options options = SCAD_DEFAULT_OPTIONS__;
int scad_initialized = 0;
- size_t i;
+ size_t i, generated_buildings_count = 0;
+ struct building *building = NULL;
+
+ ASSERT(city);
/* Initialize star-cad */
ERR(scad_initialize(city->logger, city->allocator, city->verbosisty_level));
@@ -175,37 +406,42 @@ city_cad_build(struct city* city)
ERR(scad_set_options(&options));
/* iterate on buildings */
- for(i = 0; i < city->buildings_count; i++) {
- struct building* building = city->buildings + i;
+ for(i = 0; i < city->allocated_buildings_count; i++) {
+ building = city->buildings + i;
struct data_cad_cmode_0* cad = NULL;
- size_t j = 0;
- size_t count = 0;
-
- /* TEMPORARY HARD CODED DATA */
- /* all building are considered as adjoining */
- building->adjoining_n = city->buildings_count - 1;
- building->adjoining = malloc(building->adjoining_n * sizeof(struct building*));
- for (j=0; j < city->buildings_count; j++) {
- if (i != j) {
- building->adjoining[count] = city->buildings + j;
- count++;
+
+ if(building->event_flags & BUILDING_OUT_OF_GROUND_EXTENT
+ || building->event_flags & BUILDING_WITH_OVERLAPPING)
+ {
+ /* No fix for these problems */
+ building->event_flags |= BUILDING_REMOVED;
+ if(city->dump_footprints_on_error) {
+ ERR(dump_obj(city->allocator, building));
}
+ } else {
+ /* create building */
+ ERR(building->functors->build_cad(city->scpr, city->allocator,
+ city->logger, building, city->dump_footprints_on_error,
+ city->keep_running_on_errors, (void**)&cad));
+ ERR(scad_scene_mesh());
+ ERR(building->functors->export_stl(city->allocator, city->logger, cad,
+ city->binary_export));
+ ERR(building->functors->release_cad(city->allocator, city->logger, cad));
+ ERR(scad_scene_clear());
+ generated_buildings_count++;
}
-
- /* create building */
- ERR(building->functors->build_cad(city->scpr, city->allocator, city->logger,
- building, (void**)&cad));
- ERR(scad_scene_mesh());
- ERR(building->functors->export_stl(city->allocator, city->logger, cad,
- city->binary_export));
- ERR(building->functors->release_cad(city->allocator, city->logger, cad));
- ERR(scad_scene_clear());
}
+ building = NULL;
+ city->cad_generated_buildings_count = generated_buildings_count;
exit:
- if(scad_initialized) CHK(RES_OK == scad_finalize());
+ if(scad_initialized) SCAD(finalize());
return res;
error:
+ if(building) {
+ logger_print(city->logger, LOG_ERROR,
+ "Error generating CAD for building '%s'.\n", str_cget(&building->name));
+ }
goto exit;
}
@@ -216,9 +452,11 @@ city_ground_build(struct city* city)
struct scad_options options = SCAD_DEFAULT_OPTIONS__;
int scad_initialized = 0;
struct ground ground = GROUND_NULL__;
- size_t i;
+ size_t i = 0, g = 0;
+ struct building *building = NULL;
- ERR(ground_init(city->allocator, city->logger, city->buildings_count, &ground));
+ ERR(ground_init(city->allocator, city->logger,
+ city->cad_generated_buildings_count, &ground));
/* Initialize star-cad */
ERR(scad_initialize(city->logger, city->allocator, city->verbosisty_level));
@@ -228,13 +466,20 @@ city_ground_build(struct city* city)
ERR(scad_set_options(&options));
/* iterate on buildings */
- for(i = 0; i < ground.footprints_count ; i++) {
- struct building* building = city->buildings + i;
- struct scad_geometry** footprint = ground.footprints + i;
+ for(i = 0; i < city->allocated_buildings_count; i++) {
+ building = city->buildings + i;
+ struct scad_geometry** footprint;
+
+ if(building->event_flags & BUILDING_REMOVED)
+ continue;
+
+ footprint = ground.footprints + g++;
+
/* create building footprint */
ERR(building->functors->build_footprint(city->scpr, city->allocator,
city->logger, building, footprint));
}
+ building = NULL;
ERR(ground_build_cad(city->allocator, city, &ground));
ERR(scad_scene_mesh());
@@ -242,8 +487,17 @@ city_ground_build(struct city* city)
exit:
ground_clear(city->allocator, &ground);
- if(scad_initialized) CHK(RES_OK == scad_finalize());
+ if(scad_initialized) SCAD(finalize());
return res;
error:
+ if(building) {
+ logger_print(city->logger, LOG_ERROR,
+ "Error generating ground footprint for building '%s'.\n",
+ str_cget(&building->name));
+ }
+ else if(i == city->allocated_buildings_count) {
+ logger_print(city->logger, LOG_ERROR,
+ "Error generating ground.\n");
+ }
goto exit;
}
diff --git a/src/cg_city.h b/src/cg_city.h
@@ -22,6 +22,9 @@
#include <star/scad.h>
+#include <rsys/hash_table.h>
+#include <rsys/str.h>
+
struct logger;
struct mem_allocator;
struct building;
@@ -29,18 +32,35 @@ struct args;
struct parsed_city;
struct catalog;
struct scpr_device;
+struct scpr_callback_segment;
+
+#define HTABLE_NAME names
+#define HTABLE_DATA char
+#define HTABLE_KEY struct str
+#define HTABLE_KEY_FUNCTOR_INIT str_init
+#define HTABLE_KEY_FUNCTOR_RELEASE str_release
+#define HTABLE_KEY_FUNCTOR_COPY str_copy
+#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release
+#define HTABLE_KEY_FUNCTOR_COPY_AND_CLEAR str_copy_and_clear
+#define HTABLE_KEY_FUNCTOR_EQ str_eq
+#define HTABLE_KEY_FUNCTOR_HASH str_hash
+#include <rsys/hash_table.h>
struct city {
double lower[2], upper[2]; /* Bbox */
double ground_depth;
struct building* buildings; /* list of buildings */
- size_t buildings_count;
- int binary_export;
-
+ size_t cad_generated_buildings_count, allocated_buildings_count,
+ initialized_buildings_count;
+ struct htable_names dump_footprint_names;
struct mem_allocator* allocator;
struct logger* logger;
struct scpr_device* scpr;
+ int binary_export;
int verbosisty_level;
+ int keep_running_on_errors;
+ int dump_footprints_on_error;
+ int names_initialized;
};
res_T
@@ -60,7 +80,41 @@ res_T
city_ground_build
(struct city* city);
-void
+res_T
release_city(struct city* city);
+res_T
+dump_obj
+ (struct mem_allocator* allocator,
+ struct building* building);
+
+/* An enum to encode type of proximity of buildings. */
+enum building_proximity {
+ NO_PROXIMITY,
+ CLOSE_PROXIMITY = BIT(0),
+ OVERLAPPING_PROXIMITY = BIT(1)
+};
+
+/* the type of context expected by simple_intersection */
+struct callback_ctx {
+ struct mem_allocator* allocator;
+ struct logger* logger;
+ struct building* buildings;
+ size_t buildings_count;
+ int* intersection_found; /* Can be NULL if not to be registered */
+ enum building_proximity search_type;
+ int dump_footprints_on_error;
+ int keep_running_on_errors;
+};
+
+int collinear_segments
+ (struct scpr_callback_segment* segment1,
+ struct scpr_callback_segment* segment2,
+ void* ctx__);
+
+int simple_intersection
+ (struct scpr_callback_segment* segment1,
+ struct scpr_callback_segment* segment2,
+ void* ctx__);
+
#endif /*CITY_H*/
diff --git a/src/cg_construction_mode.c b/src/cg_construction_mode.c
@@ -0,0 +1,123 @@
+/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA
+ * Copyright (C) 2022 CNRS
+ * Copyright (C) 2022 Sorbonne Université
+ * Copyright (C) 2022 Université Paul Sabatier
+ * Copyright (C) 2022 |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/>. */
+
+#include "cg.h"
+#include "cg_building.h"
+#include "cg_catalog.h"
+#include "cg_city.h"
+#include "cg_city_parsing_schemas.h"
+#include "cg_construction_mode.h"
+
+#include <rsys/rsys.h>
+#include <rsys/str.h>
+#include <rsys/logger.h>
+#include <star/scad.h>
+#include <star/scpr.h>
+
+void
+get_nverts(const size_t icomp, size_t* nverts, void* context)
+{
+ struct parsed_city_building* parsed_data = context;
+ ASSERT(icomp == 0); (void)icomp;
+ *nverts = parsed_data->vertice_count;
+}
+
+void
+get_pos(const size_t icomp, const size_t ivert, double pos[2], void* context)
+{
+ struct parsed_city_building* parsed_data = context;
+ ASSERT(icomp == 0); (void)icomp;
+ pos[0] = parsed_data->vertice[ivert*2 + 0];
+ pos[1] = parsed_data->vertice[ivert*2 + 1];
+}
+
+void get_position_pg
+ (const size_t ivert, double pos[2], void* ctx)
+{
+ struct scpr_polygon* pg = ctx;
+ ASSERT(pos && pg);
+ CHK(scpr_polygon_get_position(pg, 0, ivert, pos) == RES_OK);
+}
+
+res_T
+init_building_base
+ (struct scpr_device* scpr,
+ struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building,
+ int keep_running_on_error,
+ struct parsed_city_building* parsed_data,
+ const double lower[2],
+ const double upper[2])
+{
+ int inside;
+ res_T res = RES_OK;
+
+ ASSERT(scpr && allocator && logger && building && parsed_data && lower && upper);
+
+ building->height = parsed_data->height;
+ str_init(allocator, &building->name);
+ htable_building_init(allocator, &building->close_buildings);
+ building->structs_initialized = 1;
+ ERR(str_set(&building->name, parsed_data->name));
+ ERR(scpr_polygon_create(scpr, &building->pg));
+ ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos,
+ parsed_data));
+ ERR(scpr_polygon_in_bbox(building->pg, lower, upper, &inside));
+ if(!inside) {
+ logger_print(logger, LOG_ERROR,
+ "Building '%s' is out of the ground extent.\n",
+ str_cget(&building->name));
+ building->event_flags |= BUILDING_OUT_OF_GROUND_EXTENT;
+ if(!keep_running_on_error) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+release_building_base
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building)
+{
+ res_T res = RES_OK;
+ (void) allocator; (void)logger;
+
+ ASSERT(allocator && logger && building);
+
+ if(building->structs_initialized) {
+ str_release(&building->name);
+ htable_building_release(&building->close_buildings);
+ }
+ if(building->pg) {
+ ERR(scpr_polygon_ref_put(building->pg));
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
diff --git a/src/cg_construction_mode.h b/src/cg_construction_mode.h
@@ -25,30 +25,38 @@
#include <rsys/rsys.h>
#include <star/scpr.h>
-static void
-get_nverts(const size_t icomp, size_t* nverts, void* context)
-{
- struct parsed_city_building* parsed_data = context;
- ASSERT(icomp == 0); (void)icomp;
- *nverts = parsed_data->vertice_count;
-}
-
-static void
-get_pos(const size_t icomp, const size_t ivert, double pos[2], void* context)
-{
- struct parsed_city_building* parsed_data = context;
- ASSERT(icomp == 0); (void)icomp;
- pos[0] = parsed_data->vertice[ivert*2 + 0];
- pos[1] = parsed_data->vertice[ivert*2 + 1];
-}
-
-static void get_position_pg
- (const size_t ivert, double pos[2], void* ctx)
-{
- struct scpr_polygon* pg = ctx;
- ASSERT(pos && pg);
- CHK(scpr_polygon_get_position(pg, 0, ivert, pos) == RES_OK);
-}
+struct scpr_device;
+struct mem_allocator;
+struct logger;
+struct building;
+struct parsed_city_building;
+struct catalog;
+
+void
+get_nverts(const size_t icomp, size_t* nverts, void* context);
+
+void
+get_pos(const size_t icomp, const size_t ivert, double pos[2], void* context);
+
+void get_position_pg
+ (const size_t ivert, double pos[2], void* ctx);
+
+res_T
+init_building_base
+ (struct scpr_device* scpr,
+ struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building,
+ int keep_running_on_error,
+ struct parsed_city_building* parsed_data,
+ const double lower[2],
+ const double upper[2]);
+
+res_T
+release_building_base
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building);
#endif
diff --git a/src/cg_construction_mode_0.c b/src/cg_construction_mode_0.c
@@ -369,7 +369,7 @@ build_boundary
is_init = 1;
count = 5 + adjoining_n;
- list = MEM_ALLOC(allocator, count * sizeof(struct scad_geometry*));
+ list = MEM_CALLOC(allocator, count, sizeof(struct scad_geometry*));
if(!list) {
res = RES_MEM_ERR;
goto error;
@@ -429,10 +429,10 @@ building_ground_connection
ERR(str_set(&name, prefix));
ERR(str_append(&name, "_C_ground"));
cname = str_get(&name);
-
+
list[0] = cad->wall;
list[1] = cad->floor;
-
+
ERR(scad_geometries_common_boundaries(cname, list, 2, &cad->fake_ground, 1,
connection));
exit:
@@ -452,18 +452,19 @@ init_cmode_0
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int keep_running_on_error,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
const double upper[2])
{
res_T res = RES_OK;
- struct dataset_cmode_0* dataset;
struct str dataset_name;
- int name_initialized = 0, inside;
+ int name_initialized = 0;
static struct construction_mode_functors functors_0
= {
&init_cmode_0,
+ &release_cmode_0,
&build_cad_cmode_0,
&build_footprint_cmode_0,
&build_envelop_cmode_0,
@@ -472,32 +473,25 @@ init_cmode_0
};
(void)parsed_data;
- if(!building || !allocator || !parsed_data || !catalog) {
+ if(!scpr || !allocator || !logger || !building || !parsed_data || !catalog
+ || !lower || !upper)
+ {
res = RES_BAD_ARG;
goto error;
}
building->construction_mode = mode_0;
building->functors = &functors_0;
- building->height = parsed_data->height;
- str_init(allocator, &building->name);
- building->name_initialized = 1;
+
+ ERR(init_building_base(scpr, allocator, logger, building, keep_running_on_error,
+ parsed_data, lower, upper));
+
str_init(allocator, &dataset_name);
name_initialized = 1;
- ERR(str_set(&building->name, parsed_data->name));
ERR(str_set(&dataset_name, parsed_data->dataset_name));
- ERR(scpr_polygon_create(scpr, &building->pg));
- ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos,
- parsed_data));
- ERR(scpr_polygon_in_bbox(building->pg, lower, upper, &inside));
- if(!inside) {
- logger_print(logger, LOG_ERROR,
- "Building '%s' is out of the ground extent.\n",
- str_cget(&building->name));
- }
- dataset = htable_dataset_cmode_0_find(&catalog->catalog_0, &dataset_name);
- if (dataset == NULL) {
+ building->data = htable_dataset_cmode_0_find(&catalog->catalog_0, &dataset_name);
+ if (building->data == NULL) {
ERR(logger_print(logger, LOG_ERROR,
"Unknown dataset name: '%s' used by building '%s'.\n",
str_cget(&dataset_name), str_cget(&building->name)));
@@ -505,8 +499,6 @@ init_cmode_0
goto error;
}
- building->data = dataset;
-
exit:
if(name_initialized) str_release(&dataset_name);
return res;
@@ -515,11 +507,34 @@ error:
}
res_T
+release_cmode_0
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building)
+{
+ res_T res = RES_OK;
+
+ if(!allocator || !logger || !building) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(release_building_base(allocator, logger, building));
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
build_cad_cmode_0
(struct scpr_device* scpr,
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int dump_footprints_on_error,
+ int keep_running_on_errors,
void** cad)
{
res_T res = RES_OK;
@@ -532,7 +547,12 @@ build_cad_cmode_0
const char* name;
struct scad_geometry** adjoining_cad = NULL;
size_t i = 0;
- size_t adjoining_n = building->adjoining_n;
+ size_t adjoining_n;
+ struct scpr_intersector* overlapping_intersector = NULL;
+ struct scpr_intersector_check_callbacks callbacks
+ = SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__;
+ struct callback_ctx ctx;
+ int error_occured = 0;
if (!building || !allocator || !cad) {
res = RES_BAD_ARG;
@@ -542,6 +562,7 @@ build_cad_cmode_0
height = building->height;
pg = building->pg;
data = (struct dataset_cmode_0 *)building->data;
+ adjoining_n = htable_building_size_get(&building->close_buildings);
if (height <= 0 || data->wall_thickness <= 0 || data->floor_thickness <= 0) {
res = RES_BAD_ARG;
@@ -554,9 +575,25 @@ build_cad_cmode_0
goto error;
}
+ ERR(scpr_intersector_create(scpr, &overlapping_intersector));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, building->pg));
+
e_wall = data->wall_thickness;
ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
ERR(scpr_offset_polygon(pg_int, -e_wall, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+
+ /* Check for polygons overlapping */
+ ctx.allocator = allocator;
+ ctx.logger = logger;
+ ctx.buildings = building;
+ ctx.buildings_count = 1;
+ ctx.intersection_found = &error_occured;
+ ctx.search_type = OVERLAPPING_PROXIMITY;
+ ctx.dump_footprints_on_error = dump_footprints_on_error;
+ ctx.keep_running_on_errors = keep_running_on_errors;
+ callbacks.simple_intersection = simple_intersection;
+ ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx));
/* build floor with pg_int */
name = str_cget(&building->name);
@@ -574,8 +611,7 @@ build_cad_cmode_0
/* build adjoining envelop */
if (adjoining_n > 0) {
- ERR(build_adjoining(allocator, logger,
- building->adjoining, adjoining_n, &adjoining_cad));
+ ERR(build_adjoining(allocator, logger, building, &adjoining_cad));
}
/* build fake ground */
@@ -595,11 +631,14 @@ build_cad_cmode_0
exit:
if(pg_int) SCPR(polygon_ref_put(pg_int));
+ if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector));
*(struct data_cad_cmode_0**)cad = data_cad;
for (i=0 ; i<adjoining_n; i++) {
- if (adjoining_cad[i]) scad_geometry_delete(adjoining_cad[i]);
+ if (adjoining_cad[i]) {
+ ERR(scad_geometry_delete(adjoining_cad[i]));
+ }
}
- if (adjoining_cad) MEM_RM(allocator, adjoining_cad);
+ MEM_RM(allocator, adjoining_cad);
return res;
error:
if(data_cad) CHK(RES_OK == release_cad_cmode_0(allocator, logger, data_cad));
diff --git a/src/cg_construction_mode_0.h b/src/cg_construction_mode_0.h
@@ -68,17 +68,26 @@ init_cmode_0
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int keep_running_on_error,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
const double upper[2]);
res_T
+release_cmode_0
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building);
+
+res_T
build_cad_cmode_0
(struct scpr_device* scpr,
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int dump_footprints_on_error,
+ int keep_running_on_errors,
void** cad);
res_T
diff --git a/src/cg_construction_mode_1.c b/src/cg_construction_mode_1.c
@@ -20,15 +20,41 @@
#include "cg.h"
#include "cg_building.h"
#include "cg_catalog.h"
+#include "cg_city.h"
#include "cg_city_parsing_schemas.h"
#include "cg_construction_mode.h"
#include "cg_construction_mode_1.h"
#include <rsys/str.h>
#include <rsys/logger.h>
+#include <rsys/hash_table.h>
#include <star/scad.h>
#include <star/scpr.h>
+/* An htable to associate offset polygons to offsets.
+ * Not really to avoid offseting more than once to the same offset, but to avoid
+ * considering the same polygon more than once when checking for polygon
+ * intersections (that are internal errors). */
+static FINLINE void
+ptr_polygon_init
+ (struct mem_allocator* alloc, struct scpr_polygon** data)
+{
+ ASSERT(data); (void)alloc;
+ *data = NULL;
+}
+static FINLINE void
+ptr_polygon_release(struct scpr_polygon** data)
+{
+ ASSERT(data);
+ if(*data) SCPR(polygon_ref_put(*data));
+}
+#define HTABLE_NAME polygons
+#define HTABLE_KEY double
+#define HTABLE_DATA struct scpr_polygon*
+#define HTABLE_DATA_FUNCTOR_INIT ptr_polygon_init
+#define HTABLE_DATA_FUNCTOR_RELEASE ptr_polygon_release
+#include <rsys/hash_table.h>
+
static res_T
build_floor
(struct scpr_device* scpr,
@@ -36,6 +62,8 @@ build_floor
const char* prefix,
const struct scpr_polygon* pg,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** floor)
{
res_T res = RES_OK;
@@ -44,6 +72,7 @@ build_floor
double e_floor = data->floor_thickness;
double offset = 0;
struct scpr_polygon* pg_int = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
double d[3] = {0, 0, 0};
@@ -61,9 +90,16 @@ build_floor
floorname = str_get(&name);
}
- offset = e_wall + e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/*footprint*/
ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts));
@@ -75,7 +111,6 @@ build_floor
exit:
SCAD(geometry_delete(footprint));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
return res;
error:
goto exit;
@@ -90,6 +125,8 @@ build_wall
const struct scpr_polygon* pg,
const double height,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** wall)
{
res_T res = RES_OK;
@@ -98,6 +135,7 @@ build_wall
double offset = 0;
struct scpr_polygon* pg_int = NULL;
struct scpr_polygon* pg_ext = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
struct scad_geometry* footprint_int = NULL;
@@ -121,17 +159,30 @@ build_wall
}
if (strcmp(suffix, "S_foundation") == 0) {
- offset = e_insulation + 0.1*e_wall;
+ offset = -(e_insulation + 0.1*e_wall);
} else {
- offset = e_insulation;
+ offset = -e_insulation;
+ }
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_ext = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_ext));
+ ERR(scpr_offset_polygon(pg_ext, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_ext));
+ htable_polygons_set(polygons, &offset, &pg_ext);
}
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_ext));
- ERR(scpr_offset_polygon(pg_ext, -offset, SCPR_JOIN_MITER));
-
- offset = e_wall + e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/*wall footprint*/
ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts));
@@ -153,8 +204,6 @@ exit:
SCAD(geometry_delete(footprint_int));
SCAD(geometry_delete(footprint_ext));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
- if (pg_ext) SCPR(polygon_ref_put(pg_ext));
return res;
error:
goto exit;
@@ -169,6 +218,8 @@ build_int_insulation
const double height,
const struct dataset_cmode_1* data,
struct scad_geometry* inter_floor,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** insulation)
{
res_T res = RES_OK;
@@ -181,6 +232,7 @@ build_int_insulation
double offset = 0;
struct scpr_polygon* pg_int = NULL;
struct scpr_polygon* pg_ext = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
struct scad_geometry* footprint_int = NULL;
@@ -201,13 +253,27 @@ build_int_insulation
insulationname = str_get(&name);
}
- offset = e_ext_insulation + e_wall;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_ext));
- ERR(scpr_offset_polygon(pg_ext, -offset, SCPR_JOIN_MITER));
+ offset = -(e_ext_insulation + e_wall);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_ext = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_ext));
+ ERR(scpr_offset_polygon(pg_ext, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_ext));
+ htable_polygons_set(polygons, &offset, &pg_ext);
+ }
- offset = e_ext_insulation + e_wall + e_int_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_ext_insulation + e_wall + e_int_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/* insulation footprint */
ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts));
@@ -234,8 +300,6 @@ exit:
SCAD(geometry_delete(footprint_ext));
SCAD(geometry_delete(geom));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
- if (pg_ext) SCPR(polygon_ref_put(pg_ext));
return res;
error:
goto exit;
@@ -249,6 +313,8 @@ build_roof
const struct scpr_polygon* pg,
const double height,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** roof)
{
res_T res = RES_OK;
@@ -258,6 +324,7 @@ build_roof
double offset = 0;
double z_roof = 0;
struct scpr_polygon* pg_int = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
double d[3] = {0, 0, 0};
@@ -275,9 +342,16 @@ build_roof
roofname = str_get(&name);
}
- offset = e_wall + e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/*footprint*/
ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts));
@@ -290,7 +364,6 @@ build_roof
exit:
SCAD(geometry_delete(footprint));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
return res;
error:
goto exit;
@@ -304,6 +377,8 @@ build_roof_insulation
const struct scpr_polygon* pg,
const double height,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** insulation)
{
res_T res = RES_OK;
@@ -315,6 +390,7 @@ build_roof_insulation
double offset = 0;
double z_insulation = 0;
struct scpr_polygon* pg_int = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
double d[3] = {0, 0, 0};
@@ -332,9 +408,16 @@ build_roof_insulation
insulationname = str_get(&name);
}
- offset = e_wall + e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/*footprint*/
ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts));
@@ -348,7 +431,6 @@ build_roof_insulation
exit:
SCAD(geometry_delete(footprint));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
return res;
error:
goto exit;
@@ -361,6 +443,8 @@ build_floor_insulation
const char* prefix,
const struct scpr_polygon* pg,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** insulation)
{
res_T res = RES_OK;
@@ -371,6 +455,7 @@ build_floor_insulation
double offset = 0;
double z_insulation = 0;
struct scpr_polygon* pg_int = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
double d[3] = {0, 0, 0};
@@ -388,9 +473,16 @@ build_floor_insulation
insulationname = str_get(&name);
}
- offset = e_wall + e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/*footprint*/
ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts));
@@ -404,7 +496,6 @@ build_floor_insulation
exit:
SCAD(geometry_delete(footprint));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
return res;
error:
goto exit;
@@ -418,6 +509,8 @@ build_inter_floor
const struct scpr_polygon* pg,
const double height,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** inter_floor)
{
res_T res = RES_OK;
@@ -433,6 +526,7 @@ build_inter_floor
double z_floor = 0;
double h_cavity = 0;
struct scpr_polygon* pg_int = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry** floor_list = NULL;
struct darray_geometries floor_array;
@@ -453,9 +547,16 @@ build_inter_floor
floorname = str_get(&name);
}
- offset = e_wall + e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts));
h_cavity = height - e_roof - attic - e_roof_ins - (double)floor_n*e_floor;
@@ -480,7 +581,6 @@ build_inter_floor
exit:
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
floor_list = darray_geometries_data_get(&floor_array);
if(floor_list) {
for (i = 0; i < floor_n; i++) {
@@ -501,6 +601,8 @@ build_ext_insulation
const struct scpr_polygon* pg,
const double height,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** insulation)
{
res_T res = RES_OK;
@@ -508,6 +610,7 @@ build_ext_insulation
double offset = 0;
struct scpr_polygon* pg_int = NULL;
struct scpr_polygon* pg_ext = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
struct scad_geometry* footprint_int = NULL;
@@ -527,10 +630,21 @@ build_ext_insulation
insulationname = str_get(&name);
}
- offset = e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_ext));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -e_insulation;
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
+
+ offset = 0;
+ ptr_p = htable_polygons_find(polygons, &offset);
+ ASSERT(ptr_p); /* Offset 0 is the first to be inserted in polygons */
+ pg_ext = *ptr_p;
/*insulation footprint*/
ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts));
@@ -552,8 +666,6 @@ exit:
SCAD(geometry_delete(footprint_int));
SCAD(geometry_delete(footprint_ext));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
- if (pg_ext) SCPR(polygon_ref_put(pg_ext));
return res;
error:
goto exit;
@@ -566,6 +678,8 @@ build_crawlspace
const char* prefix,
const struct scpr_polygon* pg,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** crawlspace)
{
res_T res = RES_OK;
@@ -577,6 +691,7 @@ build_crawlspace
double offset = 0;
double z_crawl= 0;
struct scpr_polygon* pg_int = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
double d[3] = {0, 0, 0};
@@ -594,9 +709,16 @@ build_crawlspace
crawlname = str_get(&name);
}
- offset = e_wall + e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/*footprint*/
ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts));
@@ -610,7 +732,6 @@ build_crawlspace
exit:
SCAD(geometry_delete(footprint));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
return res;
error:
goto exit;
@@ -625,6 +746,8 @@ build_habitable
const double height,
const struct dataset_cmode_1* data,
struct scad_geometry* floor,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** cavity)
{
res_T res = RES_OK;
@@ -636,6 +759,7 @@ build_habitable
double e_attic = data->attic_height;
double offset = 0;
struct scpr_polygon* pg_int = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
struct scad_geometry* geom = NULL;
@@ -654,9 +778,16 @@ build_habitable
cavityname = str_get(&name);
}
- offset = e_wall + e_ext_insulation + e_int_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_ext_insulation + e_int_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/*footprint*/
ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts));
@@ -676,7 +807,6 @@ exit:
SCAD(geometry_delete(footprint));
SCAD(geometry_delete(geom));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
return res;
error:
goto exit;
@@ -690,6 +820,8 @@ build_attic
const struct scpr_polygon* pg,
const double height,
const struct dataset_cmode_1* data,
+ struct scpr_intersector* overlapping_intersector,
+ struct htable_polygons* polygons,
struct scad_geometry** attic)
{
res_T res = RES_OK;
@@ -700,6 +832,7 @@ build_attic
double offset = 0;
double z_attic = 0;
struct scpr_polygon* pg_int = NULL;
+ struct scpr_polygon** ptr_p;
size_t nverts = 0;
struct scad_geometry* footprint = NULL;
double d[3] = {0, 0, 0};
@@ -717,9 +850,16 @@ build_attic
atticname = str_get(&name);
}
- offset = e_wall + e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER));
+ offset = -(e_wall + e_insulation);
+ ptr_p = htable_polygons_find(polygons, &offset);
+ if(ptr_p) {
+ pg_int = *ptr_p;
+ } else {
+ ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
+ htable_polygons_set(polygons, &offset, &pg_int);
+ }
/*footprint*/
ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts));
@@ -733,7 +873,6 @@ build_attic
exit:
SCAD(geometry_delete(footprint));
if (is_init) str_release(&name);
- if (pg_int) SCPR(polygon_ref_put(pg_int));
return res;
error:
goto exit;
@@ -743,6 +882,7 @@ static res_T
build_windows
(struct scpr_device* scpr,
struct mem_allocator* allocator,
+ struct logger* logger,
const char* prefix,
const struct dataset_cmode_1* data,
struct data_cad_cmode_1* data_cad,
@@ -750,7 +890,7 @@ build_windows
size_t adjoining_n)
{
res_T res = RES_OK;
- size_t i = 0;
+ size_t i, removed_windows = 0;
double N[3];
double dir[3];
double scale[3];
@@ -770,7 +910,7 @@ build_windows
int is_init = 0;
(void)scpr;
- ASSERT(allocator && data && data_cad);
+ ASSERT(scpr && allocator && logger && data && data_cad);
darray_geometries_init(allocator, &hole_array);
darray_geometries_init(allocator, &glass_array);
@@ -815,7 +955,7 @@ build_windows
if (adjoining_cad) {
ERR(scad_intersect_geometries(NULL, &hole, 1, adjoining_cad, adjoining_n,
&hole_adjoining_intersect));
- ERR(scad_geometry_get_count(hole_adjoining_intersect, &count));
+ ERR(scad_geometry_get_count(hole_adjoining_intersect, &count));
} else {
count = 0;
}
@@ -829,6 +969,7 @@ build_windows
ERR(scad_geometry_extrude(surface, NULL, dir, &glass));
ERR(darray_geometries_push_back(&glass_array, &glass));
} else {
+ removed_windows++;
ERR(scad_geometry_delete(hole));
hole = NULL;
ERR(scad_geometry_delete(hole_adjoining_intersect));
@@ -842,6 +983,12 @@ build_windows
array_n = darray_geometries_size_get(&hole_array);
+ if(removed_windows) {
+ logger_print(logger, LOG_OUTPUT,
+ "Building '%s' has %zu/%zu windows removed due to close neighbors.\n",
+ prefix, removed_windows, removed_windows+array_n);
+ }
+
if (array_n > 0) {
hole_list = darray_geometries_data_get(&hole_array);
glass_list = darray_geometries_data_get(&glass_array);
@@ -1248,6 +1395,7 @@ building_ground_connection
struct scad_geometry* list_boundary = NULL;
struct scad_geometry* footprint = NULL;
+ (void)scpr;
ASSERT(scpr && allocator && prefix && cad && connection);
darray_geometries_init(allocator, &array);
@@ -1282,7 +1430,7 @@ building_ground_connection
count = darray_geometries_size_get(&array);
list = darray_geometries_data_get(&array);
- ERR(scad_geometries_common_boundaries(cname, list,count, &cad->fake_ground, 1,
+ ERR(scad_geometries_common_boundaries(cname, list, count, &cad->fake_ground, 1,
connection));
exit:
@@ -1305,18 +1453,19 @@ init_cmode_1
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int keep_running_on_error,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
const double upper[2])
{
res_T res = RES_OK;
- struct dataset_cmode_1* dataset;
struct str dataset_name;
- int name_initialized = 0, inside;
+ int name_initialized = 0;
static struct construction_mode_functors functors_1
= {
&init_cmode_1,
+ &release_cmode_1,
&build_cad_cmode_1,
&build_footprint_cmode_1,
&build_envelop_cmode_1,
@@ -1325,32 +1474,25 @@ init_cmode_1
};
(void) parsed_data;
- if(!building || !allocator || !parsed_data ||!catalog) {
+ if(!scpr || !allocator || !logger || !building || !parsed_data || !catalog
+ || !lower || !upper)
+ {
res = RES_BAD_ARG;
goto error;
}
building->construction_mode = mode_1;
building->functors = &functors_1;
- building->height = parsed_data->height;
- str_init(allocator, &building->name);
- building->name_initialized = 1;
+
+ ERR(init_building_base(scpr, allocator, logger, building,
+ keep_running_on_error, parsed_data, lower, upper));
+
str_init(allocator, &dataset_name);
name_initialized = 1;
- ERR(str_set(&building->name, parsed_data->name));
ERR(str_set(&dataset_name, parsed_data->dataset_name));
- ERR(scpr_polygon_create(scpr, &building->pg));
- ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos,
- parsed_data));
- ERR(scpr_polygon_in_bbox(building->pg, lower, upper, &inside));
- if(!inside) {
- logger_print(logger, LOG_ERROR,
- "Building '%s' is out of the ground extent.\n",
- str_cget(&building->name));
- }
- dataset = htable_dataset_cmode_1_find(&catalog->catalog_1, &dataset_name);
- if (dataset == NULL) {
+ building->data = htable_dataset_cmode_1_find(&catalog->catalog_1, &dataset_name);
+ if (building->data == NULL) {
ERR(logger_print(logger, LOG_ERROR,
"Unknown dataset name: '%s' used by building '%s'.\n",
str_cget(&dataset_name), str_cget(&building->name)));
@@ -1358,8 +1500,6 @@ init_cmode_1
goto error;
}
- building->data = dataset;
-
exit:
if(name_initialized) str_release(&dataset_name);
return res;
@@ -1368,29 +1508,62 @@ error:
}
res_T
+release_cmode_1
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building)
+{
+ res_T res = RES_OK;
+
+ if(!allocator || !logger || !building) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(release_building_base(allocator, logger, building));
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+
+res_T
build_cad_cmode_1
(struct scpr_device* scpr,
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int dump_footprints_on_error,
+ int keep_running_on_errors,
void** cad)
{
res_T res = RES_OK;
double height = building->height;
double depth = 0;
- struct scpr_polygon* pg = building->pg;
+ struct scpr_polygon* pg = NULL;
struct dataset_cmode_1* data = (struct dataset_cmode_1 *)building->data;
struct data_cad_cmode_1* data_cad = NULL;
const char* name;
+ struct scpr_intersector* overlapping_intersector = NULL;
+ struct scpr_intersector_check_callbacks callbacks
+ = SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__;
struct scad_geometry** adjoining_cad = NULL;
size_t i = 0;
- size_t adjoining_n = building->adjoining_n;
+ size_t adjoining_n;
+ struct callback_ctx ctx;
+ int error_occured = 0;
+ struct htable_polygons polygons;
+ int polygons_initialized = 0;
+ double zero = 0;
if (!building || !allocator || !cad) {
res = RES_BAD_ARG;
goto error;
}
+ adjoining_n = htable_building_size_get(&building->close_buildings);
data_cad = MEM_CALLOC(allocator, 1, sizeof(struct data_cad_cmode_1));
if(!data_cad) {
res = RES_MEM_ERR;
@@ -1398,6 +1571,16 @@ build_cad_cmode_1
}
darray_geometries_init(allocator, &data_cad->boundary);
darray_geometries_init(allocator, &data_cad->connection);
+ htable_polygons_init(allocator, &polygons);
+ polygons_initialized = 1;
+
+ ERR(scpr_intersector_create(scpr, &overlapping_intersector));
+
+ /* Register the original polygon with offset 0; as polygons in the htable are
+ * ref_put, register a copy! */
+ ERR(scpr_polygon_create_copy(scpr, building->pg, &pg));
+ ERR(scpr_intersector_register_polygon(overlapping_intersector, pg));
+ ERR(htable_polygons_set(&polygons, &zero, &pg));
/* build mandatories elements :
- floor
@@ -1406,11 +1589,14 @@ build_cad_cmode_1
*/
name = str_cget(&building->name);
- ERR(build_floor(scpr, allocator, name, pg, data, &data_cad->floor));
+ ERR(build_floor(scpr, allocator, name, pg, data, overlapping_intersector,
+ &polygons, &data_cad->floor));
- ERR(build_wall(scpr, allocator, name, "S_walls", pg, height, data, &data_cad->wall));
+ ERR(build_wall(scpr, allocator, name, "S_walls", pg, height, data,
+ overlapping_intersector, &polygons, &data_cad->wall));
- ERR(build_roof(scpr, allocator, name, pg, height, data, &data_cad->roof));
+ ERR(build_roof(scpr, allocator, name, pg, height, data,
+ overlapping_intersector, &polygons, &data_cad->roof));
/* build optionnal elements :
- foundation
@@ -1424,32 +1610,33 @@ build_cad_cmode_1
if (data->foundation_depth > 0) {
depth = -data->foundation_depth;
ERR(build_wall(scpr, allocator, name, "S_foundation", pg, depth, data,
- &data_cad->foundation));
+ overlapping_intersector, &polygons, &data_cad->foundation));
}
if (data->inter_floor_count > 0) {
ERR(build_inter_floor(scpr, allocator, name, pg, height, data,
- &data_cad->intermediate_floor));
+ overlapping_intersector, &polygons, &data_cad->intermediate_floor));
}
if (data->external_insulation_thickness> 0) {
ERR(build_ext_insulation(scpr, allocator, name, pg, height, data,
- &data_cad->external_insulation));
+ overlapping_intersector, &polygons, &data_cad->external_insulation));
}
if (data->internal_insulation_thickness> 0) {
ERR(build_int_insulation(scpr, allocator, name, pg, height, data,
- data_cad->intermediate_floor, &data_cad->internal_insulation));
+ data_cad->intermediate_floor, overlapping_intersector, &polygons,
+ &data_cad->internal_insulation));
}
if (data->roof_insulation_thickness > 0) {
ERR(build_roof_insulation(scpr, allocator, name, pg, height, data,
- &data_cad->roof_insulation));
+ overlapping_intersector, &polygons, &data_cad->roof_insulation));
}
if (data->floor_insulation_thickness > 0) {
ERR(build_floor_insulation(scpr, allocator, name, pg, data,
- &data_cad->floor_insulation));
+ overlapping_intersector, &polygons, &data_cad->floor_insulation));
}
/* build cavities :
@@ -1460,25 +1647,38 @@ build_cad_cmode_1
if (data->attic_height > 0) {
ERR(build_attic(scpr, allocator, name, pg, height, data,
- &data_cad->attic_cavity));
+ overlapping_intersector, &polygons, &data_cad->attic_cavity));
}
ERR(build_habitable(scpr, allocator, name, pg, height, data,
- data_cad->intermediate_floor, &data_cad->habitable_cavity));
+ data_cad->intermediate_floor, overlapping_intersector, &polygons,
+ &data_cad->habitable_cavity));
if (data->crawl_height > 0) {
- ERR(build_crawlspace(scpr, allocator, name, pg, data, &data_cad->crawlspace_cavity));
+ ERR(build_crawlspace(scpr, allocator, name, pg, data,
+ overlapping_intersector, &polygons, &data_cad->crawlspace_cavity));
}
+ /* Check for polygons overlapping */
+ ctx.allocator = allocator;
+ ctx.logger = logger;
+ ctx.buildings = building;
+ ctx.buildings_count = 1;
+ ctx.intersection_found = &error_occured;
/* build adjoining envelop */
- if (building->adjoining_n > 0) {
- ERR(build_adjoining(allocator, logger,
- building->adjoining, building->adjoining_n, &adjoining_cad));
+ if (adjoining_n > 0) {
+ ERR(build_adjoining(allocator, logger, building, &adjoining_cad));
}
+ ctx.search_type = OVERLAPPING_PROXIMITY;
+ ctx.dump_footprints_on_error = dump_footprints_on_error;
+ ctx.keep_running_on_errors = keep_running_on_errors;
+ callbacks.simple_intersection = simple_intersection;
+ ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx));
+
/* windows */
if (data->glass_ratio > 0) {
- ERR(build_windows(scpr, allocator, name, data, data_cad,
+ ERR(build_windows(scpr, allocator, logger, name, data, data_cad,
adjoining_cad, adjoining_n));
}
@@ -1487,7 +1687,7 @@ build_cad_cmode_1
data->floor_thickness + data->floor_insulation_thickness + data->crawl_height);
ERR(build_fake_ground(scpr, allocator, data_cad, pg, depth, &data_cad->fake_ground));
-
+
ERR(scad_scene_partition());
/* build ground/building connection */
@@ -1502,6 +1702,8 @@ build_cad_cmode_1
ERR(build_connection(scpr, allocator, name, data_cad, &data_cad->connection));
exit:
+ if(polygons_initialized) htable_polygons_release(&polygons);
+ if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector));
*(struct data_cad_cmode_1**)cad = data_cad;
for (i=0; i<adjoining_n; i++) {
if (adjoining_cad[i]) scad_geometry_delete(adjoining_cad[i]);
diff --git a/src/cg_construction_mode_1.h b/src/cg_construction_mode_1.h
@@ -93,17 +93,26 @@ init_cmode_1
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int keep_running_on_error,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
const double upper[2]);
res_T
+release_cmode_1
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building);
+
+res_T
build_cad_cmode_1
(struct scpr_device* scpr,
struct mem_allocator* allocator,
struct logger* logger,
struct building* building,
+ int dump_footprints_on_error,
+ int keep_running_on_errors,
void** cad);
res_T
diff --git a/src/cg_ground.c b/src/cg_ground.c
@@ -97,7 +97,6 @@ ground_build_cad
}
}
-
exit:
for (i = 0; i < count; i++) {
scad_geometry_delete(list[i]);
diff --git a/src/cg_main.c b/src/cg_main.c
@@ -135,7 +135,7 @@ int main
/* Parse catalog.
* No semantic validation is done at this stage */
- ERR(parse_catalog(&args->catalog_filenames, &allocator, &logger, &config,
+ ERR(parse_catalog(&args->catalog_files, &allocator, &logger, &config,
&parsed_catalog));
/* Create catalog from parsed data.
@@ -158,15 +158,14 @@ int main
release_args(args);
args = NULL;
- ERR(city_ground_build(city));
ERR(city_cad_build(city));
+ /* As buildings can be removed at the CAD generation step, ground CAD must be
+ * generated after buildings CAD */
+ ERR(city_ground_build(city));
exit:
- release_args(args);
release_city(city);
release_catalog(catalog);
- release_parsed_catalog(&config, parsed_catalog);
- release_parsed_city(&config, parsed_city);
if(logger_initialized) logger_release(&logger);
if(allocator_initialized) {
if(check_memory_allocator(&allocator)) err = EXIT_FAILURE;
@@ -175,6 +174,9 @@ exit:
}
return err;
error:
+ release_args(args);
+ release_parsed_catalog(&config, parsed_catalog);
+ release_parsed_city(&config, parsed_city);
err = EXIT_FAILURE;
printf("City generator failed.\n");
goto exit;