commit 8d119ead1b2d001779fe6bfc65858eed86b52c63
parent b7726f0b2c4209707c77a1a66bee3e2b1dd6dd8f
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 10 Mar 2023 14:35:25 +0100
Merge branch 'feature_adjoining' into develop
Diffstat:
21 files changed, 1479 insertions(+), 342 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})
@@ -103,10 +103,12 @@ endif()
################################################################################
set(CG2_FILES_SRC
cg_args.c
+ cg_building.c
cg_catalog.c
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/example/catalog0.yaml b/example/catalog0.yaml
@@ -0,0 +1,8 @@
+construction_mode: Construction_Mode_0
+datasets:
+ - name: b0a
+ wall_thickness: 0.2
+ floor_thickness: 0.35
+ - name: b0b
+ wall_thickness: 0.15
+ floor_thickness: 0.2
diff --git a/example/catalog1.yaml b/example/catalog1.yaml
@@ -0,0 +1,30 @@
+construction_mode: Construction_Mode_1
+datasets:
+ - name: b1a
+ inter_floor_count: 0
+ wall_thickness: 0.2
+ floor_thickness: 0.3
+ inter_floor_thickness: 0.2
+ roof_thickness: 0.3
+ internal_insulation_thickness: 0.1
+ external_insulation_thickness: 0
+ floor_insulation_thickness: 0.1
+ roof_insulation_thickness: 0.2
+ foundation_depth: 2
+ crawl_height: 0.
+ attic_height: 0.
+ glass_ratio: 0.5
+ - name: b1b
+ inter_floor_count: 1
+ wall_thickness: 0.3
+ floor_thickness: 0.6
+ inter_floor_thickness: 0.2
+ roof_thickness: 0.3
+ internal_insulation_thickness: 0.
+ external_insulation_thickness: 0.1
+ floor_insulation_thickness: 0
+ roof_insulation_thickness: 0.1
+ foundation_depth: 2.5
+ crawl_height: 1
+ attic_height: 0
+ glass_ratio: 0.6
diff --git a/example/city.yaml b/example/city.yaml
@@ -0,0 +1,40 @@
+ground:
+ extent: [ -40, 40, -40, 40 ]
+ depth: 5
+
+buildings:
+ - name: bat_0
+ construction_mode: Construction_Mode_1
+ dataset: b1a
+ footprint: [ [0, 0], [10, 0], [10, 10], [0, 10] ]
+ height: 5.52056
+ - name: bat_1
+ construction_mode: Construction_Mode_1
+ dataset: b1a
+ footprint: [ [10, 0], [15, 0], [15, 15], [10, 15] ]
+ height: 4.66191
+ - name: bat_2
+ construction_mode: Construction_Mode_1
+ dataset: b1b
+ footprint: [ [20, 0], [30, 0], [30, 10], [20, 10] ]
+ height: 8
+ - name: bat_3
+ construction_mode: Construction_Mode_0
+ dataset: b0a
+ footprint: [ [20, 0], [20, -5], [25, -5], [25, 0] ]
+ height: 3.52056
+ - name: bat_4
+ construction_mode: Construction_Mode_1
+ dataset: b1a
+ footprint: [ [5, 0], [5, -5], [12, -5], [12, 0] ]
+ height: 3.52056
+ - name: bat_5
+ construction_mode: Construction_Mode_1
+ dataset: b1a
+ footprint: [ [22, -20], [22, -25], [27, -25], [27, -20] ]
+ height: 3.5
+ - name: bat_6
+ construction_mode: Construction_Mode_1
+ dataset: b1a
+ footprint: [ [20, -20], [30, -20], [30, -10], [20, -10] ]
+ height: 8
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
@@ -0,0 +1,89 @@
+/* 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_city.h"
+#include "cg_building.h"
+
+#include <rsys/str.h>
+#include <rsys/stretchy_array.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/logger.h>
+
+#include <star/scad.h>
+
+res_T
+build_adjoining
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building,
+ struct scad_geometry*** geom)
+{
+ res_T res = RES_OK;
+ size_t count, i = 0;
+ struct scad_geometry** envelop_list = NULL;
+ struct htable_building_iterator it, end;
+ struct htable_building* close_buildings;
+ struct str msg;
+
+ ASSERT(allocator && logger && building && geom);
+
+ str_init(allocator, &msg);
+ close_buildings = &building->close_buildings;
+ count = htable_building_size_get(close_buildings);
+
+ envelop_list = MEM_CALLOC(allocator, count, sizeof(struct scad_geometry*));
+ if(!envelop_list) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ ERR(str_printf(&msg,
+ "building '%s' considering close neighbor(s) when creating CAD:",
+ str_cget(&building->name)));
+
+ /* iterate over adjoining building */
+ 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); (void)flags;
+ close_building = *htable_building_iterator_key_get(&it);
+ ERR(close_building->functors->build_envelop(allocator, logger, close_building,
+ envelop_list + i++));
+ ERR(str_append_printf(&msg, " '%s'", str_cget(&close_building->name)));
+ htable_building_iterator_next(&it);
+ }
+ ASSERT(i == count);
+
+ logger_print(logger, LOG_OUTPUT, "%s.\n", str_cget(&msg));
+
+exit:
+ str_release(&msg);
+ *geom = envelop_list;
+ return res;
+error:
+ 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;
+ goto exit;
+}
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,
@@ -56,6 +81,11 @@ struct construction_mode_functors {
struct logger* logger,
struct building* building,
struct scad_geometry** footprint);
+ res_T (*build_envelop)
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building,
+ struct scad_geometry** envelop);
res_T (*export_stl)
(struct mem_allocator* allocator,
struct logger* logger,
@@ -83,13 +113,22 @@ 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 htable_building close_buildings; /* links to other buildings */
+ int structs_initialized;
+ unsigned int event_flags;
/* specific data depending to the construction mode */
void* data;
};
+res_T
+build_adjoining
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ 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 overlapping_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.overlapping_segments = overlapping_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,23 +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;
- /* 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());
+
+ 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++;
+ }
}
+ 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;
}
@@ -202,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));
@@ -214,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());
@@ -228,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 overlapping_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
@@ -92,6 +92,25 @@ error:
}
static res_T
+build_footprint
+ (struct scpr_polygon* pg,
+ struct scad_geometry** footprint)
+{
+ res_T res = RES_OK;
+ size_t nverts = 0;
+
+ ASSERT(pg && footprint);
+
+ ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts));
+ ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, footprint));
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
build_fake_ground
(struct scpr_polygon* pg,
struct scad_geometry** fake_ground)
@@ -332,6 +351,8 @@ static res_T
build_boundary
(const char* prefix,
struct mem_allocator* allocator,
+ struct scad_geometry** adjoining_cad,
+ size_t adjoining_n,
struct data_cad_cmode_0* data_cad)
{
res_T res = RES_OK;
@@ -340,14 +361,15 @@ build_boundary
char* boundaryname = NULL;
struct str name;
int is_init = 0;
+ size_t i = 0;
ASSERT(allocator && prefix && data_cad);
str_init(allocator, &name);
is_init = 1;
- count = 5;
- list = MEM_ALLOC(allocator, count * sizeof(struct scad_geometry*));
+ count = 5 + adjoining_n;
+ list = MEM_CALLOC(allocator, count, sizeof(struct scad_geometry*));
if(!list) {
res = RES_MEM_ERR;
goto error;
@@ -357,8 +379,15 @@ build_boundary
list[2] = data_cad->roof;
list[3] = data_cad->cavity;
list[4] = data_cad->fake_ground;
+ for (i=0; i<adjoining_n; i++) {
+ list[5+i] = adjoining_cad[i];
+ }
data_cad->boundary = MEM_ALLOC(allocator, 2 * sizeof(struct scad_geometry*));
+ if(!data_cad->boundary) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
ERR(str_set(&name, prefix));
ERR(str_append(&name, "_B_walls"));
@@ -382,43 +411,32 @@ error:
static res_T
building_ground_connection
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct scpr_polygon* pg,
+ (struct mem_allocator* allocator,
const char* prefix,
- const double e,
+ struct data_cad_cmode_0* cad,
struct scad_geometry** connection)
{
res_T res = RES_OK;
- struct scpr_polygon* pg_int = NULL;
- struct scad_geometry* geom[2] = { NULL, NULL };
+ struct scad_geometry* list[2] = { NULL, NULL };
char* cname = NULL;
struct str name;
int is_init = 0;
- ASSERT(scpr && allocator && pg && e > 0 && connection);
+ ASSERT(allocator && prefix && connection);
- if (prefix) {
- str_init(allocator, &name);
- is_init = 1;
- ERR(str_set(&name, prefix));
- ERR(str_append(&name, "_C_ground"));
- cname = str_get(&name);
- }
-
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
- ERR(scpr_offset_polygon(pg_int, -e, SCPR_JOIN_MITER));
+ str_init(allocator, &name);
+ is_init = 1;
+ ERR(str_set(&name, prefix));
+ ERR(str_append(&name, "_C_ground"));
+ cname = str_get(&name);
- ERR(build_wall_footprint(pg, pg_int, &geom[0]));
- ERR(build_floor_footprint(pg_int, &geom[1]));
+ list[0] = cad->wall;
+ list[1] = cad->floor;
- ERR(scad_fragment_geometries(cname, &geom[0], 1, &geom[1], 1, connection));
-
+ ERR(scad_geometries_common_boundaries(cname, list, 2, &cad->fake_ground, 1,
+ connection));
exit:
if(is_init) str_release(&name);
- if(geom[0]) SCAD(geometry_delete(geom[0]));
- if(geom[1]) SCAD(geometry_delete(geom[1]));
- if(pg_int) SCPR(polygon_ref_put(pg_int));
return res;
error:
goto exit;
@@ -434,51 +452,46 @@ 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,
&export_stl_cmode_0,
&release_cad_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)));
@@ -486,8 +499,6 @@ init_cmode_0
goto error;
}
- building->data = dataset;
-
exit:
if(name_initialized) str_release(&dataset_name);
return res;
@@ -496,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;
@@ -511,6 +545,14 @@ build_cad_cmode_0
struct data_cad_cmode_0* data_cad = NULL;
double e_wall;
const char* name;
+ struct scad_geometry** adjoining_cad = NULL;
+ size_t i = 0;
+ size_t adjoining_n = 0;
+ 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;
@@ -520,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;
@@ -532,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);
@@ -549,24 +608,37 @@ build_cad_cmode_0
/* build cavity */
ERR(build_cavity(name, pg_int, building, &data_cad->cavity));
+
+ /* build adjoining envelop */
+ if (adjoining_n > 0) {
+ ERR(build_adjoining(allocator, logger, building, &adjoining_cad));
+ }
+
/* build fake ground */
ERR(build_fake_ground(pg, &data_cad->fake_ground));
ERR(scad_scene_partition());
/* build ground/building connection */
- ERR(building_ground_connection(scpr, allocator, pg, name, e_wall,
+ ERR(building_ground_connection(allocator, name, data_cad,
&data_cad->ground_connection));
/* build boundary */
- ERR(build_boundary(name, allocator, data_cad));
+ ERR(build_boundary(name, allocator, adjoining_cad, adjoining_n, data_cad));
/* build cavity/floor connectiona*/
ERR(build_connection(name, allocator, data_cad));
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]) {
+ ERR(scad_geometry_delete(adjoining_cad[i]));
+ }
+ }
+ MEM_RM(allocator, adjoining_cad);
return res;
error:
if(data_cad) CHK(RES_OK == release_cad_cmode_0(allocator, logger, data_cad));
@@ -583,21 +655,45 @@ build_footprint_cmode_0
struct scad_geometry** footprint)
{
res_T res = RES_OK;
- struct dataset_cmode_0* data = (struct dataset_cmode_0 *)building->data;
- double e_wall;
- (void)allocator; (void)logger;
+ (void)scpr; (void)allocator; (void)logger;
if(!building || ! footprint) {
res = RES_BAD_ARG;
goto error;
}
- e_wall = data->wall_thickness;
+ ERR(build_footprint(building->pg, footprint));
- ERR(building_ground_connection(scpr, allocator, building->pg, NULL, e_wall,
- footprint));
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+build_envelop_cmode_0
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building,
+ struct scad_geometry** envelop)
+{
+ res_T res = RES_OK;
+ size_t nverts = 0;
+ double height = building->height;
+ double d[3] = {0, 0, 0};
+ struct scpr_polygon* pg = building->pg;
+ struct scad_geometry* footprint = NULL;
+
+ (void)allocator; (void)logger;
+
+ ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts));
+ ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &footprint));
+
+ d[2] = height;
+ ERR(scad_geometry_extrude(footprint, NULL, d, envelop));
exit:
+ if (footprint) scad_geometry_delete(footprint);
return res;
error:
goto exit;
@@ -642,7 +738,7 @@ export_stl_cmode_0
ERR(scad_stl_export(data_cad->boundary[1], NULL, 0, binary));
/* footprint export */
- ERR(scad_stl_export(data_cad->ground_connection, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->ground_connection, NULL, 1, binary));
exit:
return res;
@@ -666,18 +762,25 @@ release_cad_cmode_0
goto error;
}
- if(data_cad->cavity) SCAD(geometry_delete(data_cad->cavity));
- if(data_cad->floor) SCAD(geometry_delete(data_cad->floor));
- if(data_cad->ground_connection) SCAD(geometry_delete(data_cad->ground_connection));
- if(data_cad->roof) SCAD(geometry_delete(data_cad->roof));
- if(data_cad->wall) SCAD(geometry_delete(data_cad->wall));
- if(data_cad->fake_ground) SCAD(geometry_delete(data_cad->fake_ground));
+#define GDEL(Field) \
+ if(data_cad->Field) SCAD(geometry_delete(data_cad->Field)); \
+ /* To ease debugging, set to NULL after deletion */ \
+ data_cad->Field = NULL
+ GDEL(cavity);
+ GDEL(floor);
+ GDEL(ground_connection);
+ GDEL(roof);
+ GDEL(wall);
+ GDEL(fake_ground);
+ GDEL(boundary[0]);
+ GDEL(boundary[1]);
for(i = 0; i < data_cad->n_connection; i++) {
- SCAD(geometry_delete(data_cad->connection[i]));
+ GDEL(connection[i]);
}
MEM_RM(allocator, data_cad->boundary);
MEM_RM(allocator, data_cad->connection);
MEM_RM(allocator, data_cad);
+#undef GDEL
exit:
return res;
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
@@ -90,6 +99,13 @@ build_footprint_cmode_0
struct scad_geometry** footprint);
res_T
+build_envelop_cmode_0
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building,
+ struct scad_geometry** envelop);
+
+res_T
export_stl_cmode_0
(struct mem_allocator* allocator,
struct logger* logger,
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;
@@ -120,13 +158,31 @@ build_wall
wallname = str_get(&name);
}
- offset = e_insulation;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_ext));
- ERR(scpr_offset_polygon(pg_ext, -offset, SCPR_JOIN_MITER));
+ if (strcmp(suffix, "S_foundation") == 0) {
+ offset = -(e_insulation + 0.1*e_wall);
+ } else {
+ 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);
+ }
- 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));
@@ -148,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;
@@ -164,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;
@@ -176,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;
@@ -196,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));
@@ -229,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;
@@ -244,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;
@@ -253,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};
@@ -270,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));
@@ -285,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;
@@ -299,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;
@@ -310,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};
@@ -327,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));
@@ -343,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;
@@ -356,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;
@@ -366,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};
@@ -383,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));
@@ -399,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;
@@ -413,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;
@@ -428,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;
@@ -448,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;
@@ -475,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++) {
@@ -496,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;
@@ -503,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;
@@ -522,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));
@@ -547,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;
@@ -561,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;
@@ -572,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};
@@ -589,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));
@@ -605,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;
@@ -620,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;
@@ -631,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;
@@ -649,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));
@@ -671,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;
@@ -685,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;
@@ -695,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};
@@ -712,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));
@@ -728,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;
@@ -738,12 +882,15 @@ 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)
+ struct data_cad_cmode_1* data_cad,
+ struct scad_geometry** adjoining_cad,
+ 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];
@@ -752,6 +899,7 @@ build_windows
struct scad_geometry** hole_list = NULL;
struct darray_geometries hole_array;
struct scad_geometry* geom = NULL;
+ struct scad_geometry* hole_adjoining_intersect = NULL;
struct scad_geometry* bcavity = NULL;
struct scad_geometry** list = NULL;
struct scad_geometry* glass = NULL;
@@ -762,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);
@@ -778,6 +926,7 @@ build_windows
for (i = 0; i < list_n; i++) {
double center[3];
size_t center_n;
+ size_t count;
ERR(scad_geometry_get_count(list[i], ¢er_n));
ASSERT(center_n == 1);
@@ -800,62 +949,89 @@ build_windows
dir[2] = 1.1*N[2] * (data->wall_thickness
+ data->internal_insulation_thickness + data->external_insulation_thickness);
ERR(scad_geometry_extrude(surface, NULL, dir, &hole));
- ERR(darray_geometries_push_back(&hole_array, &hole));
- dir[0] = N[0] * 0.024;
- dir[1] = N[1] * 0.024;
- dir[2] = N[2] * 0.024;
- ERR(scad_geometry_extrude(surface, NULL, dir, &glass));
- ERR(darray_geometries_push_back(&glass_array, &glass));
+ /* check if hole intersect adjoining_cad */
+ /* push only if no intersect */
+ 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));
+ } else {
+ count = 0;
+ }
+ if (count == 0) {
+ ERR(darray_geometries_push_back(&hole_array, &hole));
+
+ dir[0] = N[0] * 0.024;
+ dir[1] = N[1] * 0.024;
+ dir[2] = N[2] * 0.024;
+ 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));
+ hole_adjoining_intersect = NULL;
+ }
ERR(scad_geometry_delete(surface));
surface = NULL;
}
ASSERT(darray_geometries_size_get(&hole_array)
== darray_geometries_size_get(&glass_array));
- hole_list = darray_geometries_data_get(&hole_array);
- glass_list = darray_geometries_data_get(&glass_array);
array_n = darray_geometries_size_get(&hole_array);
- /* wall perforation */
- ERR(scad_cut_geometries(NULL, &data_cad->wall, 1,
- hole_list, array_n, &geom));
- ERR(scad_geometry_swap_names(data_cad->wall, geom));
- ERR(scad_geometry_delete(data_cad->wall));
- data_cad->wall = geom;
- geom = NULL;
-
- /* internal insulation perforation */
- if (data_cad->internal_insulation) {
- ERR(scad_cut_geometries(NULL, &data_cad->internal_insulation, 1,
- hole_list, array_n, &geom));
- ERR(scad_geometry_swap_names(data_cad->internal_insulation, geom));
- ERR(scad_geometry_delete(data_cad->internal_insulation));
- data_cad->internal_insulation = geom;
- geom = NULL;
+ 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);
}
- /* external insulation perforation */
- if (data_cad->external_insulation) {
- ERR(scad_cut_geometries(NULL, &data_cad->external_insulation, 1,
+ if (array_n > 0) {
+ hole_list = darray_geometries_data_get(&hole_array);
+ glass_list = darray_geometries_data_get(&glass_array);
+
+ /* wall perforation */
+ ERR(scad_cut_geometries(NULL, &data_cad->wall, 1,
hole_list, array_n, &geom));
- ERR(scad_geometry_swap_names(data_cad->external_insulation, geom));
- ERR(scad_geometry_delete(data_cad->external_insulation));
- data_cad->external_insulation = geom;
+ ERR(scad_geometry_swap_names(data_cad->wall, geom));
+ ERR(scad_geometry_delete(data_cad->wall));
+ data_cad->wall = geom;
geom = NULL;
- }
- /* build glass */
- if (prefix) {
- str_init(allocator, &gname);
- is_init = 1;
- ERR(str_set(&gname, prefix));
- ERR(str_append(&gname, "_S_glazing"));
- }
+ /* internal insulation perforation */
+ if (data_cad->internal_insulation) {
+ ERR(scad_cut_geometries(NULL, &data_cad->internal_insulation, 1,
+ hole_list, array_n, &geom));
+ ERR(scad_geometry_swap_names(data_cad->internal_insulation, geom));
+ ERR(scad_geometry_delete(data_cad->internal_insulation));
+ data_cad->internal_insulation = geom;
+ geom = NULL;
+ }
+
+ /* external insulation perforation */
+ if (data_cad->external_insulation) {
+ ERR(scad_cut_geometries(NULL, &data_cad->external_insulation, 1,
+ hole_list, array_n, &geom));
+ ERR(scad_geometry_swap_names(data_cad->external_insulation, geom));
+ ERR(scad_geometry_delete(data_cad->external_insulation));
+ data_cad->external_insulation = geom;
+ geom = NULL;
+ }
+
+ /* build glass */
+ if (prefix) {
+ str_init(allocator, &gname);
+ is_init = 1;
+ ERR(str_set(&gname, prefix));
+ ERR(str_append(&gname, "_S_glazing"));
+ }
- ERR(scad_fuse_geometries(str_cget(&gname), glass_list, 1,
- glass_list+1, array_n - 1, &data_cad->glass));
+ ERR(scad_fuse_geometries(str_cget(&gname), glass_list, 1,
+ glass_list+1, array_n - 1, &data_cad->glass));
+ }
exit:
glass_list = darray_geometries_data_get(&glass_array);
@@ -875,6 +1051,7 @@ exit:
if (surface) SCAD(geometry_delete(surface));
if (geom) SCAD(geometry_delete(geom));
if (bcavity) SCAD(geometry_delete(bcavity));
+ if (hole_adjoining_intersect) SCAD(geometry_delete(hole_adjoining_intersect));
MEM_RM(allocator, list);
if (is_init) str_release(&gname);
return res;
@@ -888,6 +1065,8 @@ build_boundary
struct mem_allocator* allocator,
const char* prefix,
struct data_cad_cmode_1* data_cad,
+ struct scad_geometry** adjoining_cad,
+ size_t adjoining_n,
struct darray_geometries* boundary)
{
res_T res = RES_OK;
@@ -899,6 +1078,7 @@ build_boundary
char* boundaryname = NULL;
struct str name;
int is_init = 0;
+ size_t i = 0;
(void)scpr;
ASSERT(allocator && prefix && data_cad && boundary);
@@ -910,7 +1090,7 @@ build_boundary
is_init = 1;
/* Ensure enough room for all geometries without error nor mem move */
- ERR(darray_geometries_reserve(&array, 14));
+ ERR(darray_geometries_reserve(&array, 14 + adjoining_n));
ERR(darray_geometries_push_back(&array, &data_cad->wall));
ERR(darray_geometries_push_back(&array, &data_cad->roof));
ERR(darray_geometries_push_back(&array, &data_cad->floor));
@@ -943,6 +1123,9 @@ build_boundary
if (data_cad->glass) {
ERR(darray_geometries_push_back(&array, &data_cad->glass));
}
+ for (i=0; i<adjoining_n; i++) {
+ ERR(darray_geometries_push_back(&array, adjoining_cad + i));
+ }
count = darray_geometries_size_get(&array);
list = darray_geometries_data_get(&array);
@@ -1212,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);
@@ -1246,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:
@@ -1269,51 +1453,46 @@ 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,
&export_stl_cmode_1,
&release_cad_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)));
@@ -1321,8 +1500,6 @@ init_cmode_1
goto error;
}
- building->data = dataset;
-
exit:
if(name_initialized) str_release(&dataset_name);
return res;
@@ -1331,26 +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 = 0;
+ 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;
@@ -1358,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
@@ -1366,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
@@ -1384,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 :
@@ -1420,41 +1647,68 @@ 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 (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));
}
/* fake ground */
depth = MMAX(data->foundation_depth,
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(build_fake_ground(scpr, allocator, data_cad, pg, depth, &data_cad->fake_ground));
ERR(scad_scene_partition());
- /* build ground/buildind connection */
+ /* build ground/building connection */
ERR(building_ground_connection(scpr, allocator, name, data_cad,
&data_cad->ground_connection));
/* build boundaries */
- ERR(build_boundary(scpr, allocator, name, data_cad, &data_cad->boundary));
+ ERR(build_boundary(scpr, allocator, name, data_cad, adjoining_cad, adjoining_n,
+ &data_cad->boundary));
/* build connections */
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]);
+ }
+ if (adjoining_cad) MEM_RM(allocator, adjoining_cad);
return res;
error:
if(data_cad) CHK(RES_OK == release_cad_cmode_1(allocator, logger, data_cad));
@@ -1487,6 +1741,36 @@ error:
}
res_T
+build_envelop_cmode_1
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building,
+ struct scad_geometry** envelop)
+{
+ res_T res = RES_OK;
+ size_t nverts = 0;
+ double height = building->height;
+ double d[3] = {0, 0, 0};
+ struct scpr_polygon* pg = building->pg;
+ struct scad_geometry* footprint = NULL;
+
+ (void)allocator; (void)logger;
+
+ ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts));
+ ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &footprint));
+
+ /* wall envelop */
+ d[2] = height;
+ ERR(scad_geometry_extrude(footprint, NULL, d, envelop));
+
+exit:
+ if (footprint) scad_geometry_delete(footprint);
+ return res;
+error:
+ goto exit;
+}
+
+res_T
export_stl_cmode_1
(struct mem_allocator* allocator,
struct logger* logger,
@@ -1597,21 +1881,25 @@ release_cad_cmode_1
goto error;
}
- if(data_cad->attic_cavity) SCAD(geometry_delete(data_cad->attic_cavity));
- if(data_cad->crawlspace_cavity) SCAD(geometry_delete(data_cad->crawlspace_cavity));
- if(data_cad->external_insulation) SCAD(geometry_delete(data_cad->external_insulation));
- if(data_cad->fake_ground) SCAD(geometry_delete(data_cad->fake_ground));
- if(data_cad->floor) SCAD(geometry_delete(data_cad->floor));
- if(data_cad->floor_insulation) SCAD(geometry_delete(data_cad->floor_insulation));
- if(data_cad->foundation) SCAD(geometry_delete(data_cad->foundation));
- if(data_cad->glass) SCAD(geometry_delete(data_cad->glass));
- if(data_cad->ground_connection) SCAD(geometry_delete(data_cad->ground_connection));
- if(data_cad->habitable_cavity) SCAD(geometry_delete(data_cad->habitable_cavity));
- if(data_cad->intermediate_floor) SCAD(geometry_delete(data_cad->intermediate_floor));
- if(data_cad->internal_insulation) SCAD(geometry_delete(data_cad->internal_insulation));
- if(data_cad->roof) SCAD(geometry_delete(data_cad->roof));
- if(data_cad->roof_insulation) SCAD(geometry_delete(data_cad->roof_insulation));
- if(data_cad->wall) SCAD(geometry_delete(data_cad->wall));
+#define GDEL(Field) \
+ if(data_cad->Field) SCAD(geometry_delete(data_cad->Field)); \
+ /* To ease debugging, write NULL after deletion */ \
+ data_cad->Field = NULL
+ GDEL(attic_cavity);
+ GDEL(crawlspace_cavity);
+ GDEL(external_insulation);
+ GDEL(fake_ground);
+ GDEL(floor);
+ GDEL(floor_insulation);
+ GDEL(foundation);
+ GDEL(glass);
+ GDEL(ground_connection);
+ GDEL(habitable_cavity);
+ GDEL(intermediate_floor);
+ GDEL(internal_insulation);
+ GDEL(roof);
+ GDEL(roof_insulation);
+ GDEL(wall);
for(i = 0; i < darray_geometries_size_get(&data_cad->boundary); i++) {
struct scad_geometry* b = darray_geometries_data_get(&data_cad->boundary)[i];
ERR(scad_geometry_delete(b));
@@ -1623,6 +1911,7 @@ release_cad_cmode_1
darray_geometries_release(&data_cad->boundary);
darray_geometries_release(&data_cad->connection);
MEM_RM(allocator, data_cad);
+#undef GDEL
exit:
return res;
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
@@ -115,6 +124,13 @@ build_footprint_cmode_1
struct scad_geometry** footprint);
res_T
+build_envelop_cmode_1
+ (struct mem_allocator* allocator,
+ struct logger* logger,
+ struct building* building,
+ struct scad_geometry** envelop);
+
+res_T
export_stl_cmode_1
(struct mem_allocator* allocator,
struct logger* logger,
diff --git a/src/cg_ground.c b/src/cg_ground.c
@@ -24,6 +24,16 @@
#include <rsys/str.h>
#include <star/scad.h>
+#define GDEL(Tgt) \
+ if(Tgt) SCAD(geometry_delete(Tgt)); \
+ /* To avoid double delete, set to NULL after deletion */ \
+ Tgt = NULL
+
+#define GMV(Idx) \
+ ground->boundary[Idx] = surface; \
+ /* To avoid double delete, set to NULL after deletion */ \
+ surface = NULL
+
res_T
ground_build_cad
(struct mem_allocator* allocator,
@@ -57,8 +67,9 @@ ground_build_cad
ERR(scad_geometry_boundary(NULL, &ground->box, 1, &bound));
ERR(scad_geometry_explode(bound, NULL, &list, &count));
+ ASSERT(count == 6);
- ground->boundary = MEM_CALLOC(allocator, 6, sizeof(struct scad_geometry*));
+ ground->boundary = MEM_CALLOC(allocator, count, sizeof(struct scad_geometry*));
for (i = 0; i < count; i++) {
double center[3];
@@ -72,43 +83,45 @@ ground_build_cad
ERR(scad_geometry_normal(list[i], center, N, NULL, &surface));
if (N[0] == 0 && N[1] == 0 && N[2] == -1) {
- ERR(scad_geometry_copy(surface, "ground_B_bottom", &ground->boundary[0]));
+ ERR(scad_geometry_rename(surface, "ground_B_bottom"));
+ GMV(0);
}
-
- if (N[0] == 0 && N[1] == 0 && N[2] == 1) {
+ else if (N[0] == 0 && N[1] == 0 && N[2] == 1) {
ERR(scad_cut_geometries("ground_B_top", &surface, 1,
ground->footprints, ground->footprints_count, &ground->boundary[1]));
+ GDEL(surface);
}
-
- if (N[0] == -1 && N[1] == 0 && N[2] == 0) {
- ERR(scad_geometry_copy(surface, "ground_B_lateral_0", &ground->boundary[2]));
+ else if (N[0] == -1 && N[1] == 0 && N[2] == 0) {
+ ERR(scad_geometry_rename(surface, "ground_B_lateral_0"));
+ GMV(2);
}
-
- if (N[0] == 1 && N[1] == 0 && N[2] == 0) {
- ERR(scad_geometry_copy(surface, "ground_B_lateral_1", &ground->boundary[3]));
+ else if (N[0] == 1 && N[1] == 0 && N[2] == 0) {
+ ERR(scad_geometry_rename(surface, "ground_B_lateral_1"));
+ GMV(3);
}
-
- if (N[0] == 0 && N[1] == -1 && N[2] == 0) {
- ERR(scad_geometry_copy(surface, "ground_B_lateral_2", &ground->boundary[4]));
+ else if (N[0] == 0 && N[1] == -1 && N[2] == 0) {
+ ERR(scad_geometry_rename(surface, "ground_B_lateral_2"));
+ GMV(4);
}
-
- if (N[0] == 0 && N[1] == 1 && N[2] == 0) {
- ERR(scad_geometry_copy(surface, "ground_B_lateral_3", &ground->boundary[5]));
+ else if (N[0] == 0 && N[1] == 1 && N[2] == 0) {
+ ERR(scad_geometry_rename(surface, "ground_B_lateral_3"));
+ GMV(5);
}
+ else FATAL("Wrong ground box boundary.");
}
-
exit:
for (i = 0; i < count; i++) {
- scad_geometry_delete(list[i]);
+ GDEL(list[i]);
}
- if (surface) scad_geometry_delete(surface);
MEM_RM(allocator, list);
- if (bound) SCAD(geometry_delete(bound));
+ GDEL(surface);
+ GDEL(bound);
return res;
error:
goto exit;
}
+#undef GMV
res_T
ground_export_stl(const struct ground* ground, const int binary)
@@ -158,14 +171,16 @@ ground_clear
struct ground* ground)
{
size_t i;
- SCAD(geometry_delete(ground->box));
+ GDEL(ground->box);
for(i = 0; i < 6; i++) {
- SCAD(geometry_delete(ground->boundary[i]));
+ GDEL(ground->boundary[i]);
}
MEM_RM(allocator, ground->boundary);
for(i = 0; i < ground->footprints_count; i++) {
- SCAD(geometry_delete(ground->footprints[i]));
+ GDEL(ground->footprints[i]);
}
MEM_RM(allocator, ground->footprints);
}
+
+#undef GDEL
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;