city_generator2

Generated conformal 3D meshes representing a city
git clone git://git.meso-star.fr/city_generator2.git
Log | Files | Refs | README | LICENSE

commit c7576e1b9fcbd86d10927be07f288ce801b14f1f
parent edbef1f867e2f1b75c5c2ff3d24fc4bf64573494
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri,  8 Sep 2023 17:57:21 +0200

Large debug step.

Change management of removed buildings. Improve output. Change
management of common parts between neighbour buildings.

Diffstat:
Mcmake/CMakeLists.txt | 4+++-
Msrc/cg.h | 29++++++++++++++++++++++++++++-
Msrc/cg_args.c | 34++++++++++++++++++++++++++++------
Msrc/cg_args.h | 3++-
Msrc/cg_building.c | 43++++++++++++++++++++++++++++++++++++++++++-
Msrc/cg_building.h | 36++++++++++++++++++++++++++----------
Msrc/cg_catalog_parsing.c | 13+++++++++----
Msrc/cg_city.c | 344++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/cg_city.h | 20+++++++++++---------
Msrc/cg_city_parsing.c | 11+++++++++--
Msrc/cg_construction_mode.c | 40+++++++++++++++-------------------------
Msrc/cg_construction_mode.h | 25++-----------------------
Msrc/cg_construction_mode_0.c | 412++++++++++++++++++++++++++++++++++---------------------------------------------
Msrc/cg_construction_mode_0.h | 11++++++++---
Msrc/cg_construction_mode_1.c | 1291+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/cg_construction_mode_1.h | 16++++++++--------
Msrc/cg_ground.c | 115++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/cg_ground.h | 26++++++++++++--------------
Msrc/cg_main.c | 15+++++++++++----
Asrc/cg_types.c | 39+++++++++++++++++++++++++++++++++++++++
Asrc/cg_types.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
21 files changed, 1449 insertions(+), 1126 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -114,7 +114,8 @@ set(CG2_FILES_SRC cg_construction_mode_0.c cg_construction_mode_1.c cg_ground.c - cg_main.c) + cg_main.c + cg_types.c) set(CG2_FILES_INC cg.h @@ -132,6 +133,7 @@ set(CG2_FILES_INC cg_construction_mode_1_parsing_schemas.h cg_default.h.in cg_ground.h + cg_types.h cg_version.h.in) set(CG2_FILES_DOC COPYING README.md) diff --git a/src/cg.h b/src/cg.h @@ -29,7 +29,7 @@ * Some constants used in city_generator */ -#define CLIPPER_PRECISON 3 /* Input footprints are rounded to mm */ +#define CLIPPER_PRECISON 2 /* Input footprints are rounded to cm */ /* Utility functions */ static INLINE void @@ -59,6 +59,33 @@ log_err_fn(const char* msg, void* ctx) fprintf(stderr, "\x1b[31merror:\x1b[0m %s", msg); } +static INLINE void +log_prt_fn_ne(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + + fprintf(stderr, "output: %s", msg); +} + +static INLINE void +log_warn_fn_ne(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + + fprintf(stderr, "warning: %s", msg); +} + +static INLINE void +log_err_fn_ne(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + + fprintf(stderr, "error: %s", msg); +} + static INLINE res_T cyaml_err_to_res_T(const cyaml_err_t err) { diff --git a/src/cg_args.c b/src/cg_args.c @@ -29,6 +29,7 @@ #include <rsys/cstr.h> #include <getopt.h> +#include <stdio.h> void print_version(void) @@ -43,7 +44,7 @@ short_help(void) { print_version(); printf("\nUsage:\n" - "city_generator2 -m <FILENAME> { -c <FILENAME> }+ -[%c] [-s] [-V verbosity] [-k] [-f <NAME>] [-F]\n" + "city_generator2 -m <FILENAME> { -c <FILENAME> }+ -[%c] [-s] [-V verbosity] [-k] [-f <NAME>] [-F][-E]\n" "city_generator2 [-h]\n" "city_generator2 [-v]\n", CG2_ARGS_CHANGE_BINARY_DEFAULT_OPTION @@ -65,12 +66,17 @@ short_help(void) " (default "STR(CG2_ARGS_STL_DEFAULT_STR)").\n" "-k\n" " Keep running on errors.\n" + "-E\n" + " Don't use escape characters in logs.\n" + " Use as first option to avoid escape characters in initial log messages.\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" + "-F <level>\n" + " Dump the footprint of some buildings, depending on level:\n" + " - With level 1 dump the footprint of any building not generated due to an error.\n" + " - With level 2 dump the footprint of any building.\n" + " Process the whole file regardless of errors, 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" @@ -104,7 +110,7 @@ parse_args int opt; int info_provided = 0, c_provided = 0, m_provided = 0; struct args* args; - char option_list[] = "?c:m:hkFf:vV:"; + char option_list[] = "?c:m:hkEF:f:svV:"; ASSERT(allocator && logger && argv && out_args); @@ -168,8 +174,24 @@ parse_args /* Optional */ + case 'E': + args->no_escape = 1; + /* Immediate effect on logs */ + logger_set_stream(logger, LOG_OUTPUT, log_prt_fn_ne, NULL); + logger_set_stream(logger, LOG_WARNING, log_warn_fn_ne, NULL); + logger_set_stream(logger, LOG_ERROR, log_err_fn_ne, NULL); + break; + case 'F': - args->dump_footprints_on_error = 1; + res = cstr_to_int(optarg, &args->dump_footprints_level); + if(res != RES_OK + || args->dump_footprints_level < 1 || args->dump_footprints_level > 2) + { + if(res == RES_OK) res = RES_BAD_ARG; + logger_print(logger, LOG_ERROR, "Invalid arg for option %c: '%s'.\n", + opt, optarg); + goto error; + } break; case 'f': diff --git a/src/cg_args.h b/src/cg_args.h @@ -42,7 +42,8 @@ struct args { int print_version; int single_thread; int keep_running_on_errors; - int dump_footprints_on_error; + int dump_footprints_level; + int no_escape; }; res_T diff --git a/src/cg_building.c b/src/cg_building.c @@ -69,9 +69,49 @@ adjoining_data_copy_and_release return RES_OK; } +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 +build_envelop + (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; + struct str name; + + str_init(building->city->allocator, &name); + + 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(str_printf(&name, "%s_envelop", str_cget(&building->name))); + ERR(scad_geometry_extrude(footprint, str_cget(&name), d, envelop)); + +exit: + str_release(&name); + if (footprint) SCAD(geometry_ref_put(footprint)); + return res; +error: + goto exit; +} + res_T build_adjoining (struct building* building, + struct darray_geometries* current_cad, struct darray_adjoining_data* adjoining) { res_T res = RES_OK; @@ -106,7 +146,8 @@ build_adjoining ASSERT(flags & CLOSE_PROXIMITY); (void)flags; close_building = *htable_building_iterator_key_get(&it); adj = darray_adjoining_data_data_get(adjoining) + prev + i; - ERR(close_building->functors->build_envelop(close_building, &adj->envelop)); + ERR(build_envelop(close_building, &adj->envelop)); + ERR(darray_geometries_push_back(current_cad, &adj->envelop)); adj->main_building = building; adj->adjoining_building = close_building; ERR(str_append_printf(&msg, " '%s'", str_cget(&close_building->name))); diff --git a/src/cg_building.h b/src/cg_building.h @@ -33,6 +33,8 @@ struct building; struct parsed_city_building; struct city; struct darray_adjoining_data; +struct darray_double; +struct darray_geometries; /* An htable to uniquely associate flags to buildings */ #define HTABLE_NAME building @@ -42,13 +44,16 @@ struct darray_adjoining_data; /* An enum to encode building events types. */ enum building_event { - BUILDING_NO_EVENT, + BUILDING_NO_EVENT = 0, BUILDING_WITH_OVERLAPPING = BIT(0), - BUILDING_WITH_CLOSE_NEIGHBOR = BIT(1), - BUILDING_OUT_OF_GROUND_EXTENT = BIT(2), - BUILDING_DUMPED_TO_OBJ = BIT(3), - BUILDING_CREATED = BIT(4), - BUILDING_CAD_EXPORTED_TO_STL = BIT(5) + BUILDING_OUT_OF_GROUND_EXTENT = BIT(1), + BUILDING_INSIDE_BUILDING = BIT(2), + BUILDING_REMOVED = BIT(5), + BUILDING_WITH_CLOSE_NEIGHBOR = BIT(6), + BUILDING_DUMPED_TO_OBJ = BIT(7), + BUILDING_CREATED = BIT(11), + BUILDING_CAD_EXPORTED_TO_STL = BIT(12), + BUILDING_ALREADY_UNREGISTRED = BIT(13) }; /* A type to store the functors of a construction mode */ @@ -67,13 +72,14 @@ struct construction_mode_functors { int dump_footprints_on_error, int keep_running_on_errors, struct darray_adjoining_data* adjoining_data, + struct darray_geometries* current_cad, void** cad); res_T (*build_footprint) (struct building* building, struct scad_geometry** footprint); - res_T (*build_envelop) - (struct building* building, - struct scad_geometry** envelop); + res_T (*save_ground_connection_triangles) + (void* cad, + struct darray_double* triangles); res_T (*export_stl) (void* cad, const int binary); @@ -109,6 +115,7 @@ struct building { /* specific data depending to the construction mode */ void* data; + void* data_cad; }; #define DARRAY_NAME pbuilding @@ -121,7 +128,7 @@ struct adjoining_data { /* Only valid for building save */ struct scad_geometry* envelop; struct scad_geometry* common_geometry; - int save; + int save, really_adjoining; }; static FINLINE void adjoining_data_init(struct mem_allocator* alloc, struct adjoining_data* data) @@ -146,9 +153,18 @@ res_T adjoining_data_copy_and_release #define DARRAY_FUNCTOR_COPY_AND_RELEASE adjoining_data_copy_and_release #include <rsys/dynamic_array.h> +void get_position_pg + (const size_t ivert, double pos[2], void* ctx); + +res_T +build_envelop + (struct building* building, + struct scad_geometry** envelop); + res_T build_adjoining (struct building* building, + struct darray_geometries* current_cad, struct darray_adjoining_data* adjoining); #endif /* BUILDING_H */ diff --git a/src/cg_catalog_parsing.c b/src/cg_catalog_parsing.c @@ -20,14 +20,13 @@ #include "cg.h" #include "cg_args.h" #include "cg_catalog_parsing.h" -#include "cg_construction_mode_0.h" #include "cg_construction_mode_0_parsing_schemas.h" #include "cg_construction_mode_1_parsing_schemas.h" #include "cg_city_parsing_schemas.h" -#include "cg_building.h" #include <rsys/logger.h> #include <rsys/str.h> +#include <rsys/clock_time.h> #include <cyaml/cyaml.h> @@ -60,6 +59,8 @@ parse_catalog struct parsed_cmode* parsed_cmode = NULL; const char* filename = NULL; FILE* f; + struct time t0, dt; + char buf[128]; (void)logger; ASSERT(files_array && allocator && logger && out_parsed); @@ -82,6 +83,7 @@ parse_catalog const struct cyaml_schema_value* schema; size_t set_count; + time_current(&t0); /* Parse construction mode only */ filename = darray_names_cdata_get(files_array)[i]; err = cyaml_load_file(filename, config, &construction_mode_schema, @@ -107,11 +109,14 @@ parse_catalog break; default: FATAL("Invalid enum value.\n"); } + time_sub(&dt, time_current(&dt), &t0); + time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); logger_print(logger, LOG_OUTPUT, - "Catalog file '%s' parsed: mode '%s', %zu dataset(s) read.\n", + "Catalog file '%s' parsed: mode '%s', %zu dataset(s) read. in %s\n", filename, city_building_types_strings[items[i].construction_mode].str, - set_count); + set_count, + buf); /* Free tmp struct */ err = cyaml_free(config, &construction_mode_schema, parsed_cmode, 1); diff --git a/src/cg_city.c b/src/cg_city.c @@ -29,17 +29,61 @@ #include "cg_args.h" #include "cg_city_parsing_schemas.h" +#include <rsys/rsys.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> #include <rsys/double4.h> #include <rsys/hash_table.h> #include <rsys/dynamic_array.h> - +#include <rsys/clock_time.h> #include <rsys/str.h> + #include <star/scad.h> #include <star/scpr.h> #include <string.h> + +static int +non_overlap_is_inside + (struct building* b1, + struct building* b2) +{ + size_t count, i; + double pt[2]; + int situation; + ASSERT(b1 && b2); + SCPR(polygon_get_components_count(b1->pg, &count)); + ASSERT(count == 1); + SCPR(polygon_get_components_count(b2->pg, &count)); + ASSERT(count == 1); + SCPR(polygon_get_vertices_count(b2->pg, 0, &count)); + for(i = 0; i < count; i++) { + SCPR(polygon_get_position(b2->pg, 0, i, pt)); + SCPR(point_in_component(b1->pg, 0, pt, &situation)); + if(situation != 0) break; + /* If vertex is shared test the next one */ + } + return (situation != -1); +} + +/* Unregister building from adjoining information of other buildings */ +static void +unregister_close_building + (struct city* city, + struct building* building) +{ + size_t i, n; + ASSERT(city && building); + for(i = 0; i < city->allocated_buildings_count; i++) { + struct building *b = city->buildings+i; + unsigned char *ptr; + ptr = htable_building_find(&b->close_buildings, &building); + if(!ptr) continue; /* No registered information */ + n = htable_building_erase(&b->close_buildings, &building); + ASSERT(n == 1); (void)n; + } +} + void make_b_pair (struct b_pair* pair, @@ -82,24 +126,6 @@ error: goto exit; } -/* Unregister building from adjoining information of other buildings */ -static void -unregister_close_building - (struct city* city, - struct building* building) -{ - size_t i, n; - ASSERT(city && building); - for(i = 0; i < city->allocated_buildings_count; i++) { - struct building *b = city->buildings+i; - unsigned char *ptr; - ptr = htable_building_find(&b->close_buildings, &building); - if(!ptr) continue; /* No registered information */ - n = htable_building_erase(&b->close_buildings, &building); - ASSERT(n == 1); (void)n; - } -} - #define STORE_CLOSE_INFO(Building1, Building2, Proximity) {\ unsigned char *ptr__, tmp__; \ ptr__ = htable_building_find(&(Building1)->close_buildings, &(Building2)); \ @@ -123,18 +149,17 @@ int overlapping_segments /* 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; const struct scpr_polygon* pg = ctx->alternate_polygons ? ctx->alternate_polygons[i] : building->pg; if(pg == segment1->polygon) { building1 = building; name1 = str_cget(&building->name); - building1->event_flags |= flag; + building1->event_flags |= BUILDING_WITH_CLOSE_NEIGHBOR; } if(pg == segment2->polygon) { building2 = building; name2 = str_cget(&building->name); - building2->event_flags |= flag; + building2->event_flags |= BUILDING_WITH_CLOSE_NEIGHBOR; } } CHK(name1 && name2); @@ -170,8 +195,8 @@ int simple_intersection 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; + const enum building_event flag = (ctx->search_type == OVERLAPPING_PROXIMITY) + ? BUILDING_WITH_OVERLAPPING | BUILDING_REMOVED : BUILDING_WITH_CLOSE_NEIGHBOR; struct logger* logger; struct mem_allocator* allocator; @@ -190,7 +215,8 @@ int simple_intersection building1 = building; name1 = str_cget(&building->name); building1->event_flags |= flag; - } else if(pg == segment2->polygon) { + } + if(pg == segment2->polygon) { building2 = building; name2 = str_cget(&building->name); building2->event_flags |= flag; @@ -198,33 +224,57 @@ int simple_intersection } CHK(name1 && name2); - switch(ctx->search_type) { - case OVERLAPPING_PROXIMITY: - if(ctx->keep_running_on_errors) { - logger_print(logger, LOG_WARNING, - "Intersection detected between buildings '%s' and '%s'.\n", - name1, name2); - logger_print(logger, LOG_WARNING, - "Buildings will not be part of the output.\n"); - } else { - logger_print(logger, LOG_ERROR, - "Intersection detected between buildings '%s' and '%s'.\n", + if(building1 == building2) { + switch(ctx->search_type) { + case OVERLAPPING_PROXIMITY: + if(ctx->keep_running_on_errors) { + logger_print(logger, LOG_WARNING, + "Self intersection detected for building '%s'.\n", name1); + logger_print(logger, LOG_WARNING, + "Building will not be part of the output.\n"); + } else { + logger_print(logger, LOG_ERROR, + "Self intersection detected for building '%s'.\n", name1); + } + /* Dump error polygons in OBJ files */ + if(ctx->dump_footprints_level == 1) { + ERR(dump_obj(allocator, building1, NULL)); + } + ERR(darray_pbuilding_push_back(&ctx->city->removed_buildings, &building1)); + break; + case CLOSE_PROXIMITY: + break; + default: FATAL("Invalid type."); + } + } else { + switch(ctx->search_type) { + case OVERLAPPING_PROXIMITY: + if(ctx->keep_running_on_errors) { + logger_print(logger, LOG_WARNING, + "Intersection detected between buildings '%s' and '%s'.\n", + name1, name2); + logger_print(logger, LOG_WARNING, + "Buildings will not be part of the output.\n"); + } else { + logger_print(logger, LOG_ERROR, + "Intersection detected between buildings '%s' and '%s'.\n", + name1, name2); + } + /* Dump error polygons in OBJ files */ + if(ctx->dump_footprints_level == 1) { + ERR(dump_obj(allocator, building1, NULL)); + ERR(dump_obj(allocator, building2, NULL)); + } + ERR(darray_pbuilding_push_back(&ctx->city->removed_buildings, &building1)); + ERR(darray_pbuilding_push_back(&ctx->city->removed_buildings, &building2)); + break; + case CLOSE_PROXIMITY: + logger_print(logger, LOG_OUTPUT, + "Buildings '%s' and '%s' are in close proximity.\n", name1, name2); - } - /* Dump the polygons in OBJ files */ - if(ctx->dump_footprints_on_error) { - ERR(dump_obj(allocator, building1, NULL)); - ERR(dump_obj(allocator, building2, NULL)); - } - ERR(darray_pbuilding_push_back(&ctx->city->removed_buildings, &building1)); - ERR(darray_pbuilding_push_back(&ctx->city->removed_buildings, &building2)); - break; - case CLOSE_PROXIMITY: - logger_print(logger, LOG_OUTPUT, - "Buildings '%s' and '%s' are in close proximity.\n", - name1, name2); - break; - default: FATAL("Invalid type."); + break; + default: FATAL("Invalid type."); + } } /* store other polygon on building information */ @@ -234,7 +284,7 @@ int simple_intersection /* Return 1 to stop the process unless whe are in proximity search or the user * asked to go further */ if(ctx->search_type == CLOSE_PROXIMITY - || ctx->keep_running_on_errors || ctx->dump_footprints_on_error) + || ctx->keep_running_on_errors || ctx->dump_footprints_level >= 1) return 0; return 1; error: @@ -267,9 +317,12 @@ create_city int error_occured = 0; struct building* building = NULL; struct darray_polygons offset_polygons; + struct time t0, dt; + char buf[128]; ASSERT(logger && allocator && args && parsed_city && catalog && out_city); + time_current(&t0); str_init(allocator, &name); darray_polygons_init(allocator, &offset_polygons); htable_names_init(allocator, &names); @@ -280,7 +333,6 @@ create_city goto error; } - darray_pbuilding_init(allocator, &city->removed_buildings); city->allocated_buildings_count = parsed_city->city_building_list_count; city->buildings = MEM_CALLOC(allocator, city->allocated_buildings_count, sizeof(*city->buildings)); @@ -299,10 +351,12 @@ create_city 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; + city->dump_footprints_level = args->dump_footprints_level; htable_names_init(allocator, &city->dump_footprint_names); - htable_common_triangles_init(allocator, &city->common_triangles); - city->tables_initialized = 1; + htable_common_init(allocator, &city->common); + darray_pbuilding_init(allocator, &city->removed_buildings); + ground_init(allocator, &city->ground); + city->array_and_tables_initialized = 1; /* Some specific building footprints will be dumped (command line request) */ for(i = 0; i < darray_names_size_get(&args->dump_footprint_names); i++) { char one = 1; @@ -340,7 +394,8 @@ create_city } /* Dump polygon if required */ dump = htable_names_find(&city->dump_footprint_names, &building->name) - || (tmp_res != RES_OK && city->dump_footprints_on_error); + || (tmp_res != RES_OK && city->dump_footprints_level == 1) + || city->dump_footprints_level == 2; if(dump) { ERR(dump_obj(allocator, building, NULL)); } @@ -349,6 +404,7 @@ create_city logger_print(city->logger, LOG_WARNING, "Building '%s' will not be part of the output.\n", str_cget(&building->name)); + ERR(darray_pbuilding_push_back(&city->removed_buildings, &building)); continue; } res = tmp_res; @@ -385,7 +441,7 @@ create_city 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.dump_footprints_level = city->dump_footprints_level; ctx.keep_running_on_errors = city->keep_running_on_errors; callbacks.simple_intersection = simple_intersection; callbacks.overlapping_segments = overlapping_segments; @@ -395,9 +451,63 @@ create_city res = RES_BAD_ARG; goto error; } + /* Check for polygons in polygons. + * As remaining polygons do not overlap, its enough to check a single vertex + * to detect a polygon is inside another */ + for(i = 0; i < city->allocated_buildings_count ; i++) { + struct building* b1 = city->buildings + i; + size_t j; + if(b1->event_flags & BUILDING_REMOVED) continue; + for(j = 0; j < i; j++) { + struct building* b2 = city->buildings + j; + int in = 0; + if((b2->event_flags & BUILDING_REMOVED)) continue; + /* b1 and b2 and 2 different valid buildings */ + if(non_overlap_is_inside(b1, b2)) { + ASSERT(!non_overlap_is_inside(b2, b1)); + ERR(darray_pbuilding_push_back(&city->removed_buildings, &b2)); + b2->event_flags |= BUILDING_INSIDE_BUILDING | BUILDING_REMOVED; + if(city->keep_running_on_errors) { + logger_print(logger, LOG_WARNING, + "Building '%s' is inside building '%s'.\n", + str_cget(&b2->name), str_cget(&b1->name)); + logger_print(logger, LOG_WARNING, + "Building '%s' will not be part of the output.\n", + str_cget(&b2->name)); + } else { + logger_print(logger, LOG_ERROR, + "Building '%s' is inside building '%s'.\n", + str_cget(&b2->name), str_cget(&b1->name)); + } + } + else if(non_overlap_is_inside(b2, b1)) { + ERR(darray_pbuilding_push_back(&city->removed_buildings, &b1)); + b1->event_flags |= BUILDING_INSIDE_BUILDING | BUILDING_REMOVED; + if(city->keep_running_on_errors) { + logger_print(logger, LOG_WARNING, + "Building '%s' is inside building '%s'.\n", + str_cget(&b1->name), str_cget(&b2->name)); + logger_print(logger, LOG_WARNING, + "Building '%s' will not be part of the output.\n", + str_cget(&b1->name)); + } else { + logger_print(logger, LOG_ERROR, + "Building '%s' is inside building '%s'.\n", + str_cget(&b1->name), str_cget(&b2->name)); + } + } + if(in && !city->keep_running_on_errors) { + res = RES_BAD_ARG; + goto error; + } + } + } /* Remove removed buildings from proximity information of other buildings */ for(i = 0; i < darray_pbuilding_size_get(&city->removed_buildings); i++) { struct building* b = darray_pbuilding_data_get(&city->removed_buildings)[i]; + if(b->event_flags & BUILDING_ALREADY_UNREGISTRED) + continue; /* Do not unregister twice! */ + b->event_flags |= BUILDING_ALREADY_UNREGISTRED; unregister_close_building(city, b); } @@ -415,6 +525,9 @@ exit: if(close_intersector) SCPR(intersector_ref_put(close_intersector)); htable_names_release(&names); *out_city = city; + time_sub(&dt, time_current(&dt), &t0); + time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); + logger_print(city->logger, LOG_OUTPUT, "Map implantation analyzed in %s.\n", buf); return res; error: if(building) { @@ -440,17 +553,19 @@ release_city(struct city* city) } if(city->scpr) SCPR(device_ref_put(city->scpr)); - if(city->tables_initialized) { - htable_common_triangles_release(&city->common_triangles); + if(city->array_and_tables_initialized) { + htable_common_release(&city->common); htable_names_release(&city->dump_footprint_names); + darray_pbuilding_release(&city->removed_buildings); } /* iterate on building */ for (i = 0; i < city->allocated_buildings_count; i++) { struct building* building = city->buildings + i; - ERR(building->functors->release(building)); + if(building->functors) { + ERR(building->functors->release(building)); + } } - darray_pbuilding_release(&city->removed_buildings); MEM_RM(city->allocator, city->buildings); MEM_RM(city->allocator, city); exit: @@ -468,47 +583,65 @@ city_cad_build(struct city* city) size_t i, a, generated_buildings_count = 0; struct building *building = NULL; struct darray_adjoining_data adjoining_data; - struct darray_double trg; - struct data_cad_cmode_0* cad = NULL; + struct darray_double common; + void* cad = NULL; + struct darray_geometries current_cad; + struct time t0, dt; + char buf[128]; ASSERT(city); + darray_geometries_init(city->allocator, &current_cad); darray_adjoining_data_init(city->allocator, &adjoining_data); - darray_double_init(city->allocator, &trg); + darray_double_init(city->allocator, &common); /* Initialize star-cad */ ERR(scad_initialize(city->logger, city->allocator, city->verbosisty_level)); scad_initialized = 1; options.Mesh.MeshSizeFromPoints = 0; - options.Misc.LogOpenCascadeTagsRefCounting = Scad_log_only_undeleted; +#ifdef NDEBUG + options.Misc.LogRefCounting = Scad_log_dimTags_only_undeleted; +#else + options.Misc.LogRefCounting = Scad_log_dimTags_all | Scad_log_geometry; +#endif ERR(scad_set_options(&options)); /* iterate on buildings */ for(i = 0; i < city->allocated_buildings_count; i++) { building = city->buildings + i; - if(building->event_flags & BUILDING_WITH_OVERLAPPING - || !(building->event_flags & BUILDING_CREATED)) - { - /* No fix for these problems */ - if(city->dump_footprints_on_error) { + if(city->dump_footprints_level == 2) { + ERR(dump_obj(city->allocator, building, NULL)); + } + if(building->event_flags & BUILDING_REMOVED) { + if(city->dump_footprints_level == 1) { ERR(dump_obj(city->allocator, building, NULL)); } } else { - /* create building */ + /* create building CAD */ struct adjoining_data* adj; - res = building->functors->build_cad(building, city->dump_footprints_on_error, - city->keep_running_on_errors, &adjoining_data, (void**)&cad); + time_current(&t0); + logger_print(city->logger, LOG_OUTPUT, + "Start processing building '%s'.\n", str_cget(&building->name)); + darray_geometries_clear(&current_cad); + res = building->functors->build_cad(building, city->dump_footprints_level, + city->keep_running_on_errors, &adjoining_data, &current_cad, + (void**)&cad); if(res != RES_OK) { - if(city->dump_footprints_on_error) { + if(city->dump_footprints_level == 1) { ERR(dump_obj(city->allocator, building, NULL)); } + time_sub(&dt, time_current(&dt), &t0); + time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); + logger_print(city->logger, LOG_OUTPUT, + "Building '%s': stopped after %s.\n", str_cget(&building->name), buf); if(city->keep_running_on_errors) { logger_print(city->logger, LOG_WARNING, "Building '%s' will not be part of the output.\n", str_cget(&building->name)); /* Unregister building from adjoining information of other buildings */ unregister_close_building(city, building); + darray_adjoining_data_clear(&adjoining_data); /* FIXME: adjoining buildings may have been built already, taking this * building into account. There is no simple way to undo this other * than rebuild them after this building removal. The visible effects @@ -521,6 +654,10 @@ city_cad_build(struct city* city) } ERR(res); ERR(scad_scene_mesh()); + /* Keep ground/building's boundary triangles now as the geometry will be + * released before ground is built */ + ERR(building->functors->save_ground_connection_triangles(cad, + &city->ground.ground_trg)); /* Keep the mesh of some geometry if planned */ adj = darray_adjoining_data_data_get(&adjoining_data); for(a = 0; a < darray_adjoining_data_size_get(&adjoining_data); a++) { @@ -536,16 +673,12 @@ city_cad_build(struct city* city) * (as geom lifetime is limited to a single iteration) */ continue; } - darray_double_clear(&trg); - /* Warning: one could think that reversing the triangles here would do - * the job of having them correctly oriented when reused from the - * other building's point of view. The fact is that this lead to a - * non-consistent orientation. As a consequence, triangle's orientation - * has to be set when the mesh is reused, based on the CAD normal. */ - ERR(scad_stl_get_data(adj[a].common_geometry, &trg)); + darray_double_clear(&common); + ERR(scad_stl_get_data(adj[a].common_geometry, &common)); make_b_pair(&pair, building, adj[a].adjoining_building); - ERR(htable_common_triangles_set(&building->city->common_triangles, - &pair, &trg)); + ASSERT(darray_double_size_get(&common) > 0 + && darray_double_size_get(&common) % 9 == 0); + ERR(htable_common_set(&city->common, &pair, &common)); } ERR(building->functors->export_stl(cad, city->binary_export)); building->event_flags |= BUILDING_CAD_EXPORTED_TO_STL; @@ -556,20 +689,24 @@ city_cad_build(struct city* city) ERR(building->functors->release_cad(cad)); cad = NULL; /* Avoid double release */ darray_adjoining_data_clear(&adjoining_data); + darray_geometries_clear(&current_cad); ERR(scad_scene_clear()); generated_buildings_count++; + time_sub(&dt, time_current(&dt), &t0); + time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); logger_print(city->logger, LOG_OUTPUT, - "Building '%s': done.\n", str_cget(&building->name)); + "Building '%s': done in %s.\n", str_cget(&building->name), buf); } } building = NULL; city->cad_generated_buildings_count = generated_buildings_count; exit: + darray_geometries_release(&current_cad); darray_adjoining_data_release(&adjoining_data); if(cad) CHK(RES_OK == building->functors->release_cad(cad)); if(scad_initialized) SCAD(finalize()); - darray_double_release(&trg); + darray_double_release(&common); return res; error: if(building) { @@ -585,42 +722,51 @@ city_ground_build(struct city* city) res_T res = RES_OK; struct scad_options options = SCAD_DEFAULT_OPTIONS__; int scad_initialized = 0; - struct ground ground = GROUND_NULL__; - size_t i = 0, g = 0; + size_t i = 0; struct building *building = NULL; + struct time t0, dt; + char buf[128]; - ERR(ground_init(city->allocator, city->logger, - city->cad_generated_buildings_count, &ground)); - + time_current(&t0); + logger_print(city->logger, LOG_OUTPUT, "Start processing ground.\n"); /* Initialize star-cad */ ERR(scad_initialize(city->logger, city->allocator, city->verbosisty_level)); scad_initialized = 1; options.Mesh.MeshSizeFromPoints = 0; - options.Misc.LogOpenCascadeTagsRefCounting = Scad_log_only_undeleted; +#ifdef NDEBUG + options.Misc.LogRefCounting = Scad_log_dimTags_only_undeleted; +#else + options.Misc.LogRefCounting = Scad_log_dimTags_all | Scad_log_geometry; +#endif ERR(scad_set_options(&options)); /* iterate on buildings */ + ERR(darray_geometries_reserve(&city->ground.footprints, + city->allocated_buildings_count)); for(i = 0; i < city->allocated_buildings_count; i++) { building = city->buildings + i; - struct scad_geometry** footprint; + struct scad_geometry* footprint; if(!(building->event_flags & BUILDING_CAD_EXPORTED_TO_STL)) continue; - footprint = ground.footprints + g++; - /* create building footprint */ - ERR(building->functors->build_footprint(building, footprint)); + ERR(building->functors->build_footprint(building, &footprint)); + ERR(darray_geometries_push_back(&city->ground.footprints, &footprint)); + ERR(scad_geometry_ref_put(footprint)); /* Ownership transfered */ } building = NULL; - ERR(ground_build_cad(city->allocator, city, &ground)); + ERR(ground_build_cad(city->allocator, city)); ERR(scad_scene_mesh()); - ERR(ground_export_stl(&ground, city->binary_export)); + ERR(ground_export_stl(&city->ground, city->binary_export)); exit: - ground_clear(city->allocator, &ground); + ground_clear(&city->ground); if(scad_initialized) SCAD(finalize()); + time_sub(&dt, time_current(&dt), &t0); + time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); + logger_print(city->logger, LOG_OUTPUT, "Ground done in %s.\n", buf); return res; error: if(building) { diff --git a/src/cg_city.h b/src/cg_city.h @@ -21,10 +21,12 @@ #define CITY_H #include "cg_building.h" +#include "cg_ground.h" #include <star/scpr.h> #include <star/scad.h> +#include <rsys/rsys.h> #include <rsys/str.h> #include <rsys/hash_table.h> #include <rsys/dynamic_array.h> @@ -93,9 +95,9 @@ ppoly_copy_and_release #define HTABLE_KEY_FUNCTOR_HASH str_hash #include <rsys/hash_table.h> -/* A table to link a bunch of triangles to a pair of buildings. - * Used to store the common triangles to ensure conformity despite the fact - * that buildings are meshed during differents star-cad sessions. */ +/* A table to link a bunch of triangles and their normals to a pair of buildings. + * Used to store the common triangles and normals to ensure conformity despite + * the fact that buildings are meshed during differents star-cad sessions. */ struct b_pair { struct building* b1; struct building* b2; @@ -110,13 +112,12 @@ make_b_pair (struct b_pair* pair, struct building* b1, struct building* b2); -#define HTABLE_NAME common_triangles +#define HTABLE_NAME common #define HTABLE_DATA struct darray_double #define HTABLE_DATA_FUNCTOR_INIT darray_double_init #define HTABLE_DATA_FUNCTOR_RELEASE darray_double_release #define HTABLE_DATA_FUNCTOR_COPY darray_double_copy #define HTABLE_DATA_FUNCTOR_COPY_AND_RELEASE darray_double_copy_and_release -#define HTABLE_DATA_FUNCTOR_COPY_AND_CLEAR darray_double_copy_and_clear #define HTABLE_KEY struct b_pair #define HTABLE_KEY_FUNCTOR_EQ b_pair_eq #include <rsys/hash_table.h> @@ -125,10 +126,11 @@ struct city { double lower[2], upper[2]; /* Bbox */ double ground_depth; struct building* buildings; /* list of buildings */ + struct ground ground; size_t cad_generated_buildings_count, allocated_buildings_count, initialized_buildings_count; struct htable_names dump_footprint_names; - struct htable_common_triangles common_triangles; + struct htable_common common; struct darray_pbuilding removed_buildings; struct mem_allocator* allocator; struct logger* logger; @@ -136,8 +138,8 @@ struct city { int binary_export; int verbosisty_level; int keep_running_on_errors; - int dump_footprints_on_error; - int tables_initialized; + int dump_footprints_level; + int array_and_tables_initialized; }; res_T @@ -181,7 +183,7 @@ struct callback_ctx { 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 dump_footprints_level; int keep_running_on_errors; }; diff --git a/src/cg_city_parsing.c b/src/cg_city_parsing.c @@ -25,8 +25,10 @@ #include <star/scpr.h> +#include <rsys/rsys.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> +#include <rsys/clock_time.h> #include <cyaml/cyaml.h> @@ -44,9 +46,12 @@ parse_city struct parsed_city *parsed = NULL; FILE* f; cyaml_err_t err; + struct time t0, dt; + char buf[128]; ASSERT(allocator && logger && filename && config && out_parsed); + time_current(&t0); err = cyaml_load_file(filename, config, &city_schema, (void**)&parsed, NULL); ERR(cyaml_err_to_res_T(err)); @@ -55,10 +60,12 @@ parse_city str_init(allocator, &parsed->filename); ERR(str_set(&parsed->filename, filename)); + time_sub(&dt, time_current(&dt), &t0); + time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); /* Log outcome */ logger_print(logger, LOG_OUTPUT, - "City map file '%s' parsed: %u building(s) read.\n", - filename, ((struct parsed_city*)parsed)->city_building_list_count); + "City map file '%s' parsed: %u building(s) read in %s.\n", + filename, ((struct parsed_city*)parsed)->city_building_list_count, buf); exit: *out_parsed = parsed; diff --git a/src/cg_construction_mode.c b/src/cg_construction_mode.c @@ -18,8 +18,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "cg.h" +#include "cg_types.h" #include "cg_building.h" -#include "cg_catalog.h" #include "cg_city.h" #include "cg_city_parsing_schemas.h" #include "cg_construction_mode.h" @@ -31,20 +31,6 @@ #include <star/scpr.h> void -pgeom_release(struct scad_geometry** data) { - ASSERT(data); - SCAD(geometry_ref_put(*data)); -} - -res_T -pgeom_copy(struct scad_geometry** dst, struct scad_geometry* const* src) { - ASSERT(dst && src); - *dst = *src; - SCAD(geometry_ref_get(*src)); - return RES_OK; -} - -void get_nverts(const size_t icomp, size_t* nverts, void* context) { struct parsed_city_building* parsed_data = context; @@ -61,14 +47,6 @@ get_pos(const size_t icomp, const size_t ivert, double pos[2], void* context) 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 building* building, @@ -77,7 +55,8 @@ init_building_base const double lower[2], const double upper[2]) { - int inside; + int inside, cw; + size_t count; res_T res = RES_OK; ASSERT(city && building && parsed_data && lower && upper); @@ -91,16 +70,27 @@ init_building_base ERR(scpr_polygon_create(city->scpr, &building->pg)); ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos, parsed_data)); + ERR(scpr_polygon_get_vertices_count(building->pg, 0, &count)); + if(parsed_data->vertice_count != count) { + logger_print(city->logger, LOG_WARNING, + "Building '%s' had quasi-identical vertices that have been merged.\n", + str_cget(&building->name)); + } ERR(scpr_polygon_in_bbox(building->pg, lower, upper, &inside)); if(!inside) { logger_print(city->logger, (city->keep_running_on_errors ? LOG_WARNING : LOG_ERROR), "Building '%s' is out of the ground extent.\n", str_cget(&building->name)); - building->event_flags |= BUILDING_OUT_OF_GROUND_EXTENT; + building->event_flags |= BUILDING_OUT_OF_GROUND_EXTENT | BUILDING_REMOVED; res = RES_BAD_ARG; goto error; } + /* Force orientation so that pg's normal is downward */ + ERR(scpr_polygon_is_component_cw(building->pg, 0, &cw)); + if(!cw) { + ERR(scpr_polygon_reverse_component(building->pg, 0)); + } exit: return res; diff --git a/src/cg_construction_mode.h b/src/cg_construction_mode.h @@ -21,6 +21,7 @@ #define Construction_MODE_H__ #include "cg_city_parsing_schemas.h" +#include "cg_city.h" #include <rsys/rsys.h> #include <star/scpr.h> @@ -36,26 +37,7 @@ struct scad_geometry; struct darray_double; #define DARRAY_NAME common_trg -#define DARRAY_DATA struct darray_double* -#include <rsys/dynamic_array.h> - -void -pgeom_release(struct scad_geometry** data); -res_T -pgeom_copy(struct scad_geometry** dst, struct scad_geometry* const* src); -static FINLINE res_T -pgeom_copy_and_release - (struct scad_geometry** dst, struct scad_geometry* const* src) -{ - ASSERT(dst && src); - *dst = *src; - return RES_OK; -} -#define DARRAY_NAME geometries -#define DARRAY_DATA struct scad_geometry* -#define DARRAY_FUNCTOR_RELEASE pgeom_release -#define DARRAY_FUNCTOR_COPY pgeom_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE pgeom_copy_and_release +#define DARRAY_DATA struct b_pair #include <rsys/dynamic_array.h> void @@ -64,9 +46,6 @@ 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 building* building, diff --git a/src/cg_construction_mode_0.c b/src/cg_construction_mode_0.c @@ -18,6 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "cg.h" +#include "cg_types.h" #include "cg_building.h" #include "cg_catalog.h" #include "cg_city.h" @@ -32,21 +33,20 @@ #include <star/scad.h> #include <star/scpr.h> -#include <star/sstl.h> - -#include <limits.h> static res_T -build_floor_footprint +build_footprint (struct scpr_polygon* pg, + const double z, struct scad_geometry** footprint) { res_T res = RES_OK; - size_t nverts; + 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)); + ERR(scad_add_polygon(NULL, get_position_pg, pg, z, nverts, footprint)); exit: return res; @@ -59,57 +59,33 @@ build_floor (const char* prefix, struct scpr_polygon* pg, struct building* b, + struct darray_geometries* current_cad, struct scad_geometry** floor) { res_T res = RES_OK; - double e; struct dataset_cmode_0* data; struct scad_geometry* footprint = NULL; double d[3] = {0, 0, 0}; char* floorname = NULL; struct str name; - int is_init = 0; - ASSERT(pg && b && floor); - - data = (struct dataset_cmode_0*)b->data; - e = data->floor_thickness; + ASSERT(prefix && pg && b && floor); str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_floor")); - floorname = str_get(&name); - } + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_floor")); + floorname = str_get(&name); - ERR(build_floor_footprint(pg, &footprint)); + ERR(build_footprint(pg, 0, &footprint)); - d[2] = e; + data = (struct dataset_cmode_0*)b->data; + d[2] = data->floor_thickness; ERR(scad_geometry_extrude(footprint, floorname, d, floor)); + ERR(darray_geometries_push_back(current_cad, floor)); exit: - SCAD(geometry_ref_put(footprint)); - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -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: + if(footprint) SCAD(geometry_ref_put(footprint)); + str_release(&name); return res; error: goto exit; @@ -126,12 +102,11 @@ build_fake_ground ASSERT(pg && fake_ground); - ERR(build_floor_footprint(pg, &footprint)); - - ERR(scad_geometry_extrude(footprint, NULL, d, fake_ground)); + ERR(build_footprint(pg, 0, &footprint)); + ERR(scad_geometry_extrude(footprint, "fake_ground", d, fake_ground)); exit: - SCAD(geometry_ref_put(footprint)); + if(footprint) SCAD(geometry_ref_put(footprint)); return res; error: goto exit; @@ -140,8 +115,9 @@ error: static res_T build_roof (const char* prefix, - const struct building* b, + struct building* b, const struct scad_geometry* floor, + struct darray_geometries* current_cad, struct scad_geometry** roof) { res_T res = RES_OK; @@ -151,28 +127,23 @@ build_roof struct dataset_cmode_0* data; char* roofname = NULL; struct str name; - int is_init = 0; - ASSERT(b && floor && roof); + ASSERT(prefix && b && floor && roof); str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_roof")); - roofname = str_get(&name); - } + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_roof")); + roofname = str_get(&name); height = b->height; data = (struct dataset_cmode_0*)b->data; e = data->floor_thickness; - - ERR(scad_geometry_copy(floor, roofname, roof)); d[2] = height - e ; - ERR(scad_geometry_translate(*roof, d)); + ERR(scad_geometry_translate(floor, d, roofname, roof)); + ERR(darray_geometries_push_back(current_cad, roof)); exit: - if (is_init) str_release(&name); + str_release(&name); return res; error: goto exit; @@ -180,23 +151,18 @@ error: static res_T build_wall_footprint - (struct scpr_polygon* pg, - struct scpr_polygon* pg_int, - struct scad_geometry** footprint) + (struct scpr_polygon* pg, + struct scpr_polygon* pg_int, + struct scad_geometry** footprint) { res_T res = RES_OK; struct scad_geometry* polygon = NULL; struct scad_geometry* polygon_int = NULL; - size_t nverts, nverts_int; ASSERT(pg && pg_int && footprint); - ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &polygon)); - - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts_int)); - ERR(scad_add_polygon(NULL, get_position_pg, pg_int, 0, nverts_int, &polygon_int)); - + ERR(build_footprint(pg, 0, &polygon)); + ERR(build_footprint(pg_int, 0, &polygon_int)); ERR(scad_cut_geometries(NULL, &polygon, 1, &polygon_int, 1, footprint)); exit: @@ -209,40 +175,35 @@ error: static res_T build_wall - (const char* prefix, - struct scpr_polygon* pg, - struct scpr_polygon* pg_int, - struct building* b, - struct scad_geometry** wall) + (const char* prefix, + struct scpr_polygon* pg, + struct scpr_polygon* pg_int, + struct building* b, + struct darray_geometries* current_cad, + struct scad_geometry** wall) { res_T res = RES_OK; - double height; struct scad_geometry* footprint = NULL; double d[3] = {0, 0, 0}; char* wallname = NULL; struct str name; - int is_init = 0; - - ASSERT(pg && pg_int && b && wall); - height = b->height; + ASSERT(prefix && pg && pg_int && b && wall); str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_walls")); - wallname = str_get(&name); - } + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_walls")); + wallname = str_get(&name); ERR(build_wall_footprint(pg, pg_int, &footprint)); - d[2] = height; + d[2] = b->height; ERR(scad_geometry_extrude(footprint, wallname, d, wall)); + ERR(darray_geometries_push_back(current_cad, wall)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); - if (is_init) str_release(&name); + str_release(&name); return res; error: goto exit; @@ -252,7 +213,8 @@ static res_T build_cavity (const char* prefix, struct scpr_polygon* pg, - const struct building* b, + struct building* b, + struct darray_geometries* current_cad, struct scad_geometry** cavity) { res_T res = RES_OK; @@ -262,32 +224,27 @@ build_cavity struct scad_geometry* polygon = NULL; char* cavityname = NULL; struct str name; - int is_init = 0; - size_t nverts; - ASSERT(pg && b && cavity); + ASSERT(prefix && pg && b && cavity); height = b->height; data = (struct dataset_cmode_0*)b->data; e = data->floor_thickness; str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_F_internal")); - cavityname = str_get(&name); - } + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_F_internal")); + cavityname = str_get(&name); - ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg, e, nverts, &polygon)); + ERR(build_footprint(pg, e, &polygon)); d[2] = height - 2*e; ERR(scad_geometry_extrude(polygon, cavityname, d, cavity)); + ERR(darray_geometries_push_back(current_cad, cavity)); exit: if(polygon) SCAD(geometry_ref_put(polygon)); - if (is_init) str_release(&name); + str_release(&name); return res; error: goto exit; @@ -304,7 +261,7 @@ build_connection struct str name; int is_init = 0; - ASSERT(allocator && cad); + ASSERT(prefix && allocator && cad); cad->connection = MEM_CALLOC(allocator, 3, sizeof(struct scad_geometry*)); if(!cad->connection) { @@ -316,37 +273,28 @@ build_connection /* cavity/floor connection */ str_init(allocator, &name); is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_C_internal_floor")); - cname = str_get(&name); - } - + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_C_internal_floor")); + cname = str_get(&name); ERR(scad_geometries_common_boundaries(cname, &cad->cavity, 1, &cad->floor, 1, &cad->connection[0])); /* cavity/wall connection */ - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_C_internal_walls")); - cname = str_get(&name); - } - + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_C_internal_walls")); + cname = str_get(&name); ERR(scad_geometries_common_boundaries(cname, &cad->cavity, 1, &cad->wall, 1, &cad->connection[1])); /* cavity/roof connection */ - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_C_internal_roof")); - cname = str_get(&name); - } - + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_C_internal_roof")); + cname = str_get(&name); ERR(scad_geometries_common_boundaries(cname, &cad->cavity, 1, &cad->roof, 1, &cad->connection[2])); exit: - if (is_init) str_release(&name); + if(is_init) str_release(&name); return res; error: goto exit; @@ -365,17 +313,17 @@ build_boundary struct str name; int is_init = 0; struct adjoining_data* adj; - size_t adjoining_n, i = 0, count = 0; + size_t adjoining_n, i = 0, maxc, count = 0; - ASSERT(allocator && prefix && adjoining_data && data_cad); + ASSERT(prefix && allocator && adjoining_data && data_cad); adjoining_n = darray_adjoining_data_size_get(adjoining_data); adj = darray_adjoining_data_data_get(adjoining_data); str_init(allocator, &name); is_init = 1; - count = 5 + adjoining_n; - list = MEM_CALLOC(allocator, count, sizeof(struct scad_geometry*)); + maxc = 5 + adjoining_n; + list = MEM_CALLOC(allocator, maxc, sizeof(struct scad_geometry*)); if(!list) { res = RES_MEM_ERR; goto error; @@ -384,12 +332,19 @@ build_boundary * of conformity wrt the adjoining building. The reason is that the common * part that could end to be not conformal is not part of the boundary. As a * consequence it cannot be part of the result. */ + count = 5; list[0] = data_cad->floor; list[1] = data_cad->roof; list[2] = data_cad->wall; list[3] = data_cad->cavity; list[4] = data_cad->fake_ground; - for (i=0; i<adjoining_n; i++) list[5+i] = adj[i].envelop; + for (i=0; i<adjoining_n; i++) { + if(adj[i].really_adjoining) { + list[count] = adj[i].envelop; + count++; + } + } + ASSERT(maxc >= count); ERR(str_set(&name, prefix)); ERR(str_append(&name, "_B_walls")); @@ -405,7 +360,7 @@ build_boundary exit: MEM_RM(allocator, list); - if (is_init) str_release(&name); + if(is_init) str_release(&name); return res; error: goto exit; @@ -437,6 +392,7 @@ building_ground_connection ERR(scad_geometries_common_boundaries(cname, list, 2, &cad->fake_ground, 1, connection)); + exit: if(is_init) str_release(&name); return res; @@ -461,13 +417,13 @@ init_cmode_0 struct str dataset_name; 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 + &init_cmode_0, + &release_cmode_0, + &build_cad_cmode_0, + &build_footprint_cmode_0, + &save_ground_connection_triangles_0, + &export_stl_cmode_0, + &release_cad_cmode_0 }; struct mem_allocator* allocator; struct logger* logger; @@ -516,9 +472,10 @@ release_cmode_0 res_T build_cad_cmode_0 (struct building* building, - int dump_footprints_on_error, + int dump_footprints_level, int keep_running_on_errors, struct darray_adjoining_data* adjoining_data, + struct darray_geometries* current_cad, void** cad) { res_T res = RES_OK; @@ -528,7 +485,6 @@ build_cad_cmode_0 struct data_cad_cmode_0* data_cad = NULL; double e_wall; const char* name; - struct scad_geometry *tmp = NULL; size_t adjoining_n = 0; struct scpr_intersector* overlapping_intersector = NULL; struct scpr_intersector_check_callbacks callbacks @@ -538,13 +494,16 @@ build_cad_cmode_0 struct scpr_device* scpr; struct mem_allocator* allocator; struct logger* logger = NULL; - size_t c; + size_t i, c, cad_count; + struct scad_geometry** cur_cad = NULL; + struct scad_geometry** partitioned = NULL; if (!building || !cad || !adjoining_data) { res = RES_BAD_ARG; goto error; } + name = str_cget(&building->name); scpr = building->city->scpr; allocator = building->city->allocator; logger = building->city->logger; @@ -561,7 +520,8 @@ build_cad_cmode_0 res = RES_MEM_ERR; goto error; } - data_cad->allocator = allocator; + building->data_cad = data_cad; + data_cad->building = building; darray_common_trg_init(allocator, &data_cad->common_trg); darray_geometries_init(allocator, &data_cad->adj_walls); @@ -572,11 +532,9 @@ build_cad_cmode_0 ERR(scpr_polygon_create_copy(scpr, building->pg, &pg_int)); ERR(scpr_offset_polygon(pg_int, -e_wall, SCPR_JOIN_MITER)); ERR(scpr_polygon_get_components_count(pg_int, &c)); - if(c == 0) { - /* Building is too small wrt wall thickness */ + if(c != 1) { logger_print(logger, (keep_running_on_errors ? LOG_WARNING : LOG_ERROR), - "Building '%s' is too small with respect to wall thickness.\n", - str_cget(&building->name)); + "Building '%s' is too small with respect to wall thickness.\n", name); error_msg_printed = 1; res = RES_BAD_ARG; goto error; @@ -589,14 +547,13 @@ build_cad_cmode_0 ctx.buildings_count = 1; ctx.intersection_found = &error_occured; ctx.search_type = OVERLAPPING_PROXIMITY; - ctx.dump_footprints_on_error = dump_footprints_on_error; + ctx.dump_footprints_level = dump_footprints_level; ctx.keep_running_on_errors = keep_running_on_errors; callbacks.simple_intersection = simple_intersection; ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx)); if(error_occured) { logger_print(logger, LOG_ERROR, - "Internal error building CAD for building '%s'.\n", - str_cget(&building->name)); + "Internal error building CAD for building '%s'.\n", name); ERR(darray_pbuilding_push_back(&building->city->removed_buildings, &building)); error_msg_printed = 1; res = RES_BAD_ARG; @@ -604,35 +561,46 @@ build_cad_cmode_0 } /* build floor with pg_int */ - name = str_cget(&building->name); - ERR(build_floor(name, pg_int, building, &data_cad->floor)); + ERR(build_floor(name, pg_int, building, current_cad, &data_cad->floor)); /* roof is a translated copy of floor */ - ERR(build_roof(name, building, data_cad->floor, &data_cad->roof)); + ERR(build_roof(name, building, data_cad->floor, current_cad, &data_cad->roof)); /* build wall with pg and pg_int */ - ERR(build_wall(name, building->pg, pg_int, building, &data_cad->wall)); + ERR(build_wall(name, building->pg, pg_int, building, current_cad, &data_cad->wall)); /* build cavity */ - ERR(build_cavity(name, pg_int, building, &data_cad->cavity)); + ERR(build_cavity(name, pg_int, building, current_cad, &data_cad->cavity)); /* build adjoining envelop */ adjoining_n = htable_building_size_get(&building->close_buildings); if (adjoining_n > 0) { - ERR(build_adjoining(building, adjoining_data)); + ERR(build_adjoining(building, current_cad, adjoining_data)); ASSERT(adjoining_n == darray_adjoining_data_size_get(adjoining_data)); } /* build fake ground */ ERR(build_fake_ground(building->pg, &data_cad->fake_ground)); + ERR(darray_geometries_push_back(current_cad, &data_cad->fake_ground)); - ERR(scad_scene_partition()); + /* Partition CAD */ + cad_count = darray_geometries_size_get(current_cad); + partitioned = MEM_CALLOC(allocator, cad_count, sizeof(*partitioned)); + if(!partitioned) { + res = RES_MEM_ERR; + goto error; + } + cur_cad = darray_geometries_data_get(current_cad); + ERR(scad_geometries_partition(cur_cad, cad_count, 0, partitioned)); + /* Swap original geometry and partitioned geometry in data_cad (was + * accumulated into current_cad) */ + ERR(scad_geometries_swap(cur_cad, partitioned, cad_count, Scad_swap_geometry)); /* After partitioning, manage common parts with other buildings */ if(adjoining_n > 0) { size_t a; struct b_pair pair; - struct darray_double* common_trg; + struct darray_double* common; struct adjoining_data* adjoining = darray_adjoining_data_data_get(adjoining_data); for(a = 0; a < adjoining_n; a++) { @@ -640,8 +608,8 @@ build_cad_cmode_0 ERR(scad_geometries_common_boundaries(NULL, &data_cad->wall, 1, &adj->envelop, 1, &adj->common_geometry)); ERR(scad_geometry_get_count(adj->common_geometry, &c)); - if(c == 0) { - /* Not really adjoining */ + adj->really_adjoining = (c != 0); + if(!adj->really_adjoining) { logger_print(logger, LOG_OUTPUT, "building '%s': neighbor '%s' not really adjoining.\n", str_cget(&building->name), @@ -649,20 +617,15 @@ build_cad_cmode_0 continue; } make_b_pair(&pair, building, adj->adjoining_building); - common_trg - = htable_common_triangles_find(&building->city->common_triangles, &pair); - if(common_trg) { - /* The common geometry has already been processed when creating a - * previous building, and the very same mesh must be used for this one. - * Keep track of the geometry to replace and the mesh to output instead */ - ERR(darray_geometries_push_back(&data_cad->adj_walls, - &adj->common_geometry)); - ERR(darray_common_trg_push_back(&data_cad->common_trg, &common_trg)); - } else { + /* Keep track of the geometry to replace and the mesh to output instead */ + ERR(darray_geometries_push_back(&data_cad->adj_walls, &adj->common_geometry)); + ERR(darray_common_trg_push_back(&data_cad->common_trg, &pair)); + common = htable_common_find(&building->city->common, &pair); + if(!common) { /* The mesh doesn't exist yet and won't be created until a further step. * We need to store the geometry id so that the mesh can be stored when * created. */ - adjoining[a].save = 1; + adj->save = 1; } } } @@ -678,7 +641,12 @@ build_cad_cmode_0 ERR(build_connection(name, allocator, data_cad)); exit: - if(tmp) SCAD(geometry_ref_put(tmp)); + if(partitioned) { + for(i = 0; i < cad_count; i++) { + if(partitioned[i]) SCAD(geometry_ref_put(partitioned[i])); + } + MEM_RM(allocator, partitioned); + } if(pg_int) SCPR(polygon_ref_put(pg_int)); if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector)); if(cad) *(struct data_cad_cmode_0**)cad = data_cad; @@ -706,7 +674,7 @@ build_footprint_cmode_0 goto error; } - ERR(build_footprint(building->pg, footprint)); + ERR(build_footprint(building->pg, 0, footprint)); exit: return res; @@ -714,26 +682,21 @@ error: goto exit; } -res_T -build_envelop_cmode_0 - (struct building* building, - struct scad_geometry** envelop) +res_T save_ground_connection_triangles_0 + (void* cad, + struct darray_double* triangles) { 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; + struct data_cad_cmode_0* data_cad = cad; - ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &footprint)); + if(!cad || !triangles) { + res = RES_BAD_ARG; + goto error; + } - d[2] = height; - ERR(scad_geometry_extrude(footprint, NULL, d, envelop)); + ERR(scad_stl_get_data(data_cad->ground_connection, triangles)); exit: - if (footprint) SCAD(geometry_ref_put(footprint)); return res; error: goto exit; @@ -746,87 +709,64 @@ export_stl_cmode_0 { res_T res = RES_OK; struct data_cad_cmode_0* data_cad = (struct data_cad_cmode_0*)cad; - size_t i, j, common_n = 0, coord_count = 0; + size_t i, j, coord_count = 0; struct darray_double trg; struct str name; int initialized = 0; - struct scad_geometry** list = NULL; + struct mem_allocator* allocator = NULL; if(!cad) { res = RES_BAD_ARG; goto error; } + allocator = data_cad->building->city->allocator; + /* floor export */ - ERR(scad_stl_export(data_cad->floor, NULL, binary)); + ERR(scad_stl_export(data_cad->floor, NULL, Scad_force_normals_outward, binary)); /* roof export */ - ERR(scad_stl_export(data_cad->roof, NULL, binary)); + ERR(scad_stl_export(data_cad->roof, NULL, Scad_force_normals_outward, binary)); /* wall export */ if(darray_geometries_size_get(&data_cad->adj_walls) == 0) { - ERR(scad_stl_export(data_cad->wall, NULL, binary)); + ERR(scad_stl_export(data_cad->wall, NULL, Scad_force_normals_outward, binary)); } else { /* There is some adjoining building(s) to manage */ - struct darray_double **common - = darray_common_trg_data_get(&data_cad->common_trg); size_t common_count = darray_common_trg_size_get(&data_cad->common_trg); const char* tmp; - darray_double_init(data_cad->allocator, &trg); - str_init(data_cad->allocator, &name); + darray_double_init(allocator, &trg); + str_init(allocator, &name); initialized = 1; /* Get the triangles that are not common with adjoining buildings */ ERR(scad_stl_get_data_partial(data_cad->wall, darray_geometries_data_get(&data_cad->adj_walls), - darray_geometries_size_get(&data_cad->adj_walls), - &trg)); + darray_geometries_size_get(&data_cad->adj_walls), &trg)); coord_count = darray_double_size_get(&trg); /* Add the triangles from adjoining buildings */ for(i = 0; i < common_count; i++) { size_t sz; - int found = 0; - const double* t9 = darray_double_cdata_get(common[i]); + struct b_pair* pair = darray_common_trg_data_get(&data_cad->common_trg)+ i; + const double *t9; double* tgt; - struct scad_geometry* common_g - = darray_geometries_data_get(&data_cad->adj_walls)[i]; - double n[3], e1[3], e2[3], reverse; - /* Determine the normal orientation for common triangles */ - d3_sub(e1, t9 + 3, t9); - d3_sub(e2, t9 + 6, t9); - d3_cross(n, e1, e2); - ERR(scad_geometry_explode(common_g, NULL, &list, &common_n)); - for(j = 0; j < common_n; j++) { - double center[3], N[3]; - struct scad_geometry* surface; - ERR(scad_geometry_get_centerofmass(list[j], center)); - ERR(scad_geometry_normal(list[j], center, N, NULL, &surface)); - ERR(scad_geometry_ref_put(surface)); - reverse = d3_dot(N, n); - if(fabs(reverse) > 0.99*d3_len(n)*d3_len(N)) { - found = 1; - break; - } - } - for(j = 0; j < common_n; j++) { - ERR(scad_geometry_ref_put(list[j])); - } - MEM_RM(data_cad->allocator, list); - common_n = 0; list = NULL; /* Avoid double free */ - if(!found) { + struct city* city = data_cad->building->city; + struct darray_double* common = NULL; + /* Get triangles */ + common = htable_common_find(&city->common, pair); + if(!common) { res = RES_BAD_ARG; goto error; } + t9 = darray_double_cdata_get(common); /* Add common triangles */ - sz = darray_double_size_get(common[i]); + sz = darray_double_size_get(common); ASSERT(sz % 9 == 0); ASSERT(coord_count == darray_double_size_get(&trg)); ERR(darray_double_resize(&trg, coord_count + sz)); tgt = darray_double_data_get(&trg); - for(j = 0; j < sz; j += 9) { - d3_set(tgt + coord_count + j+0, t9 + j+0); - d3_set(tgt + coord_count + j+3, t9 + j+(reverse>0 ? 3 : 6)); - d3_set(tgt + coord_count + j+6, t9 + j+(reverse>0 ? 6 : 3)); + for(j = 0; j < sz; j++) { + tgt[coord_count + j] = t9[j]; } coord_count += sz; ASSERT(coord_count % 9 == 0); @@ -834,30 +774,30 @@ export_stl_cmode_0 ERR(scad_geometry_get_name(data_cad->wall, &tmp)); ERR(str_set(&name, tmp)); ERR(str_append(&name, ".stl")); - ERR(scad_stl_data_write(&trg, str_cget(&name), binary)); + ERR(scad_stl_data_write(&trg, str_cget(&name), Scad_force_normals_outward, + binary)); } /* cavity export */ - ERR(scad_stl_export(data_cad->cavity, NULL, binary)); + ERR(scad_stl_export(data_cad->cavity, NULL, Scad_force_normals_outward, binary)); /* connection export */ for (i = 0; i < data_cad->n_connection; i++) { - ERR(scad_stl_export(data_cad->connection[i], NULL, binary)); + ERR(scad_stl_export(data_cad->connection[i], NULL, + Scad_keep_normals_unchanged, binary)); } /* boundary export */ - ERR(scad_stl_export(data_cad->boundary_wall, NULL, binary)); - ERR(scad_stl_export(data_cad->boundary_roof, NULL, binary)); + ERR(scad_stl_export(data_cad->boundary_wall, NULL, Scad_keep_normals_unchanged, + binary)); + ERR(scad_stl_export(data_cad->boundary_roof, NULL, Scad_keep_normals_unchanged, + binary)); /* footprint export */ - ERR(scad_geometry_reverse(data_cad->ground_connection)); - ERR(scad_stl_export(data_cad->ground_connection, NULL, binary)); + ERR(scad_stl_export(data_cad->ground_connection, NULL, + Scad_keep_normals_unchanged, binary)); exit: - for(j = 0; j < common_n; j++) { - if(list[j]) SCAD(geometry_ref_put(list[j])); - } - MEM_RM(data_cad->allocator, list); if(initialized) { darray_double_release(&trg); str_release(&name); @@ -881,7 +821,7 @@ release_cad_cmode_0 goto error; } - allocator = data_cad->allocator; + allocator = data_cad->building->city->allocator; darray_common_trg_release(&data_cad->common_trg); darray_geometries_release(&data_cad->adj_walls); diff --git a/src/cg_construction_mode_0.h b/src/cg_construction_mode_0.h @@ -54,9 +54,9 @@ struct dataset_cmode_0 { #include <rsys/hash_table.h> struct data_cad_cmode_0 { - struct mem_allocator* allocator; struct darray_common_trg common_trg; struct darray_geometries adj_walls; + struct building* building; struct scad_geometry* wall; struct scad_geometry* roof; struct scad_geometry* floor; @@ -88,6 +88,7 @@ build_cad_cmode_0 int dump_footprints_on_error, int keep_running_on_errors, struct darray_adjoining_data* adjoining_data, + struct darray_geometries* current_cad, void** cad); res_T @@ -96,9 +97,13 @@ build_footprint_cmode_0 struct scad_geometry** footprint); res_T -build_envelop_cmode_0 +get_ground_connection_0 (struct building* building, - struct scad_geometry** envelop); + struct scad_geometry** connection); + +res_T save_ground_connection_triangles_0 + (void* cad, + struct darray_double* triangles); res_T export_stl_cmode_0 diff --git a/src/cg_construction_mode_1.c b/src/cg_construction_mode_1.c @@ -18,6 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "cg.h" +#include "cg_types.h" #include "cg_default.h" #include "cg_building.h" #include "cg_catalog.h" @@ -26,25 +27,93 @@ #include "cg_construction_mode.h" #include "cg_construction_mode_1.h" +#include <rsys/rsys.h> #include <rsys/str.h> #include <rsys/logger.h> #include <rsys/hash_table.h> #include <rsys/double3.h> + #include <star/scad.h> #include <star/scpr.h> +STATIC_ASSERT((CG2_CLOSE_NEIGHBOR_DISTANCE > 0.1), Close_neighbor_distance_cannot_be_less_than_10cm); + +static res_T +build_footprint + (struct scpr_polygon* pg, + const double z, + 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, z, nverts, footprint)); + +exit: + return res; +error: + goto exit; +} + +/* Return a polygon with the given offset. + * Get a reference: do put a reference on the result! */ +static res_T +do_offset + (struct building* building, + struct htable_polygons* polygons, + struct scpr_intersector* overlapping_intersector, + int *error_msg_printed, + const double offset, + struct scpr_polygon** p_out) +{ + res_T res = RES_OK; + struct scpr_polygon** ptr_p; + + ASSERT(building && polygons && overlapping_intersector + && error_msg_printed && p_out); + + ptr_p = htable_polygons_find(polygons, &offset); + if(ptr_p) { + *p_out = *ptr_p; + ERR(scpr_polygon_ref_get(*p_out)); + } else { + size_t c; + ERR(scpr_polygon_create_copy(building->city->scpr, building->pg, p_out)); + ERR(scpr_offset_polygon(*p_out, offset, SCPR_JOIN_MITER)); + ERR(scpr_polygon_get_components_count(*p_out, &c)); + if(c != 1) { + ASSERT(offset < 0); + logger_print(building->city->logger, + (building->city->keep_running_on_errors ? LOG_WARNING : LOG_ERROR), + "Building '%s' is too small with respect to wall thickness.\n", + str_cget(&building->name)); + *error_msg_printed = 1; + res = RES_BAD_ARG; + goto error; + } + ERR(scpr_intersector_register_polygon(overlapping_intersector, *p_out)); + ERR(htable_polygons_set(polygons, &offset, p_out)); + } + +exit: + return res; +error: + if(!ptr_p) SCPR(polygon_ref_put(*p_out)); /* Created here */ + *p_out = NULL; + goto exit; +} + static res_T build_floor - (struct scpr_device* scpr, - struct mem_allocator* allocator, - struct logger* logger, + (struct building* building, int *error_msg_printed, - int keep_running_on_errors, - const char* prefix, - const struct scpr_polygon* pg, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** floor) { res_T res = RES_OK; @@ -53,58 +122,35 @@ build_floor double e_floor = data->floor_thickness; double offset = 0; struct scpr_polygon* pg_int = NULL; - struct scpr_polygon** ptr_p = NULL; - size_t nverts = 0; struct scad_geometry* footprint = NULL; double d[3] = {0, 0, 0}; char* floorname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && floor); + ASSERT(building && error_msg_printed && data && floor); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_floor")); - floorname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_floor")); + floorname = str_get(&name); offset = -(e_wall + e_insulation); - ptr_p = htable_polygons_find(polygons, &offset); - if(ptr_p) { - pg_int = *ptr_p; - } else { - size_t c; - ERR(scpr_polygon_create_copy(scpr, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, offset, SCPR_JOIN_MITER)); - ERR(scpr_polygon_get_components_count(pg_int, &c)); - if(c == 0) { - /* Building is too small wrt wall thickness */ - logger_print(logger, - (keep_running_on_errors ? LOG_WARNING : LOG_ERROR), - "Building '%s' is too small with respect to wall thickness.\n", - prefix); - *error_msg_printed = 1; - res = RES_BAD_ARG; - goto error; - } - ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int)); - htable_polygons_set(polygons, &offset, &pg_int); - } + ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg_int, 0, nverts, &footprint)); + ERR(build_footprint(pg_int, 0, &footprint)); d[2] = -e_floor; ERR(scad_geometry_extrude(footprint, floorname, d, floor)); + ERR(darray_geometries_push_back(current_cad, floor)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); - if(!ptr_p) SCPR(polygon_ref_put(pg_int)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -112,15 +158,15 @@ error: static res_T build_wall - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, + (struct building* building, + int *error_msg_printed, + const int is_foundation, const char* suffix, - const struct scpr_polygon* pg, const double height, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** wall) { res_T res = RES_OK; @@ -129,78 +175,53 @@ build_wall double offset = 0; struct scpr_polygon* pg_int = NULL; struct scpr_polygon* pg_ext = NULL; - struct scpr_polygon** ptr_pi = NULL; - struct scpr_polygon** ptr_pe = NULL; - size_t nverts = 0; struct scad_geometry* footprint = NULL; struct scad_geometry* footprint_int = NULL; struct scad_geometry* footprint_ext = NULL; double d[3] = {0, 0, 0}; char* wallname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && wall); + ASSERT(building && error_msg_printed && data && wall); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - if (suffix) { - ERR(str_append(&name, "_")); - ERR(str_append(&name, suffix)); - } - wallname = str_get(&name); + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + if (suffix) { + ERR(str_append(&name, "_")); + ERR(str_append(&name, suffix)); } + wallname = str_get(&name); - if (strcmp(suffix, "S_foundation") == 0) { + if(is_foundation) { offset = -(e_insulation + 0.1*e_wall); } else { offset = -e_insulation; } - ptr_pe = htable_polygons_find(polygons, &offset); - if(ptr_pe) { - pg_ext = *ptr_pe; - } else { - ERR(scpr_polygon_create_copy(scpr, pg, &pg_ext)); - ERR(scpr_offset_polygon(pg_ext, offset, SCPR_JOIN_MITER)); - ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_ext)); - htable_polygons_set(polygons, &offset, &pg_ext); - } + ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_ext)); offset = -(e_wall + e_insulation); - ptr_pi = htable_polygons_find(polygons, &offset); - if(ptr_pi) { - pg_int = *ptr_pi; - } 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)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); + ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); - - ERR(scad_cut_geometries( - NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); + /* wall footprint*/ + ERR(build_footprint(pg_int, 0, &footprint_int)); + ERR(build_footprint(pg_ext, 0, &footprint_ext)); + ERR(scad_cut_geometries(NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); d[2] = height; ERR(scad_geometry_extrude(footprint, wallname, d, wall)); + ERR(darray_geometries_push_back(current_cad, wall)); exit: - if(!ptr_pi) SCPR(polygon_ref_put(pg_int)); - if(!ptr_pe) SCPR(polygon_ref_put(pg_ext)); if(footprint) SCAD(geometry_ref_put(footprint)); if(footprint_int) SCAD(geometry_ref_put(footprint_int)); if(footprint_ext) SCAD(geometry_ref_put(footprint_ext)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_ext) SCPR(polygon_ref_put(pg_ext)); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -208,15 +229,14 @@ error: static res_T build_int_insulation - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const double height, const struct dataset_cmode_1* data, struct scad_geometry* inter_floor, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** insulation) { res_T res = RES_OK; @@ -229,9 +249,6 @@ build_int_insulation double offset = 0; struct scpr_polygon* pg_int = NULL; struct scpr_polygon* pg_ext = NULL; - struct scpr_polygon** ptr_pi = NULL; - struct scpr_polygon** ptr_pe = NULL; - size_t nverts = 0; struct scad_geometry* footprint = NULL; struct scad_geometry* footprint_int = NULL; struct scad_geometry* footprint_ext = NULL; @@ -239,48 +256,27 @@ build_int_insulation double d[3] = {0, 0, 0}; char* insulationname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && insulation); + ASSERT(building && error_msg_printed && data && insulation); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_internal_insulation")); - insulationname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_internal_insulation")); + insulationname = str_get(&name); offset = -(e_ext_insulation + e_wall); - ptr_pe = htable_polygons_find(polygons, &offset); - if(ptr_pe) { - pg_ext = *ptr_pe; - } else { - ERR(scpr_polygon_create_copy(scpr, pg, &pg_ext)); - ERR(scpr_offset_polygon(pg_ext, offset, SCPR_JOIN_MITER)); - ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_ext)); - htable_polygons_set(polygons, &offset, &pg_ext); - } + ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_ext)); offset = -(e_ext_insulation + e_wall + e_int_insulation); - ptr_pi = htable_polygons_find(polygons, &offset); - if(ptr_pi) { - pg_int = *ptr_pi; - } 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(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); /* insulation footprint */ - ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); - - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); - + ERR(build_footprint(pg_int, 0, &footprint_int)); + ERR(build_footprint(pg_ext, 0, &footprint_ext)); ERR(scad_cut_geometries(NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); d[2] = height - e_roof - attic - e_roof_insulation; @@ -291,15 +287,16 @@ build_int_insulation } else { ERR(scad_geometry_copy(geom, insulationname, insulation)); } + ERR(darray_geometries_push_back(current_cad, insulation)); exit: - if(!ptr_pi) SCPR(polygon_ref_put(pg_int)); - if(!ptr_pe) SCPR(polygon_ref_put(pg_ext)); if(footprint) SCAD(geometry_ref_put(footprint)); if(footprint_int) SCAD(geometry_ref_put(footprint_int)); if(footprint_ext) SCAD(geometry_ref_put(footprint_ext)); if(geom) SCAD(geometry_ref_put(geom)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_ext) SCPR(polygon_ref_put(pg_ext)); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -307,14 +304,13 @@ error: static res_T build_roof - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const double height, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** roof) { res_T res = RES_OK; @@ -324,46 +320,36 @@ 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}; char* roofname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && roof); + ASSERT(building && error_msg_printed && data && roof); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_roof")); - roofname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_roof")); + roofname = str_get(&name); 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(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); z_roof = height - e_roof; - ERR(scad_add_polygon(NULL, get_position_pg, pg_int, z_roof, nverts, &footprint)); + ERR(build_footprint(pg_int, z_roof, &footprint)); d[2] = e_roof; ERR(scad_geometry_extrude(footprint, roofname, d, roof)); + ERR(darray_geometries_push_back(current_cad, roof)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -371,14 +357,13 @@ error: static res_T build_roof_insulation - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const double height, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** insulation) { res_T res = RES_OK; @@ -390,47 +375,36 @@ 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}; char* insulationname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && insulation); + ASSERT(building && error_msg_printed && data && insulation); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_roof_insulation")); - insulationname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_roof_insulation")); + insulationname = str_get(&name); 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(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); z_insulation = height - e_roof - attic - e_roof_insulation; - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, z_insulation, nverts, &footprint)); + ERR(build_footprint(pg_int, z_insulation, &footprint)); d[2] = e_roof_insulation; ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); + ERR(darray_geometries_push_back(current_cad, insulation)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -438,13 +412,12 @@ error: static res_T build_floor_insulation - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** insulation) { res_T res = RES_OK; @@ -455,47 +428,36 @@ 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}; char* insulationname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && insulation); + ASSERT(building && error_msg_printed && data && insulation); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_floor_insulation")); - insulationname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_floor_insulation")); + insulationname = str_get(&name); 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(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); z_insulation = - e_floor - e_floor_insulation; - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, z_insulation, nverts, &footprint)); + ERR(build_footprint(pg_int, z_insulation, &footprint)); d[2] = e_floor_insulation; ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); + ERR(darray_geometries_push_back(current_cad, insulation)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -503,14 +465,13 @@ error: static res_T build_inter_floor - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const double height, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** inter_floor) { res_T res = RES_OK; @@ -526,7 +487,6 @@ 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; @@ -534,37 +494,28 @@ build_inter_floor double d[3] = {0, 0, 0}; char* floorname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && inter_floor); + ASSERT(building && error_msg_printed && data && inter_floor); - darray_geometries_init(allocator, &floor_array); + darray_geometries_init(building->city->allocator, &floor_array); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_intermediate_floors")); - floorname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_intermediate_floors")); + floorname = str_get(&name); 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(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + 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; z_floor = h_cavity/(double)(1 + floor_n); d[2] = e_floor; for (i = 0; i < floor_n; i++) { - ERR(scad_add_polygon( NULL, get_position_pg, pg_int, z_floor, nverts, + ERR(scad_add_polygon(NULL, get_position_pg, pg_int, z_floor, nverts, &footprint)); ERR(scad_geometry_extrude(footprint, NULL, d, &floor)); ERR(scad_geometry_ref_put(footprint)); @@ -579,12 +530,14 @@ build_inter_floor floor_list = darray_geometries_data_get(&floor_array); ERR(scad_fuse_geometries(floorname, floor_list, floor_n, floor_list, floor_n, inter_floor)); + ERR(darray_geometries_push_back(current_cad, inter_floor)); exit: - if (is_init) str_release(&name); + str_release(&name); if(footprint) SCAD(geometry_ref_put(footprint)); if(floor) SCAD(geometry_ref_put(floor)); if(floor_list) darray_geometries_release(&floor_array); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -592,14 +545,13 @@ error: static res_T build_ext_insulation - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const double height, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** insulation) { res_T res = RES_OK; @@ -608,35 +560,25 @@ build_ext_insulation 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; struct scad_geometry* footprint_ext = NULL; double d[3] = {0, 0, 0}; char* insulationname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && insulation); + ASSERT(building && data && polygons && insulation); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_S_external_insulation")); - insulationname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_S_external_insulation")); + insulationname = str_get(&name); 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); - } + ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); offset = 0; ptr_p = htable_polygons_find(polygons, &offset); @@ -644,25 +586,20 @@ build_ext_insulation pg_ext = *ptr_p; /*insulation footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); - - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); - - ERR(scad_cut_geometries( - NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); + ERR(build_footprint(pg_int, 0, &footprint_int)); + ERR(build_footprint(pg_ext, 0, &footprint_ext)); + ERR(scad_cut_geometries(NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); d[2] = height; ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); + ERR(darray_geometries_push_back(current_cad, insulation)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); if(footprint_int) SCAD(geometry_ref_put(footprint_int)); if(footprint_ext) SCAD(geometry_ref_put(footprint_ext)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -670,13 +607,12 @@ error: static res_T build_crawlspace - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** crawlspace) { res_T res = RES_OK; @@ -688,47 +624,36 @@ 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}; char* crawlname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && crawlspace); + ASSERT(building && error_msg_printed && data && crawlspace); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_F_crawlspace")); - crawlname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_F_crawlspace")); + crawlname = str_get(&name); 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(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); z_crawl = - e_floor - e_floor_insulation - e_crawl; - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, z_crawl, nverts, &footprint)); + ERR(build_footprint(pg_int, z_crawl, &footprint)); d[2] = e_crawl; ERR(scad_geometry_extrude(footprint, crawlname, d, crawlspace)); + ERR(darray_geometries_push_back(current_cad, crawlspace)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -736,15 +661,14 @@ error: static res_T build_habitable - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const double height, const struct dataset_cmode_1* data, struct scad_geometry* floor, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** cavity) { res_T res = RES_OK; @@ -756,40 +680,25 @@ 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; double d[3] = {0, 0, 0}; char* cavityname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && cavity); + ASSERT(building && error_msg_printed && data && cavity); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_F_levels")); - cavityname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_F_levels")); + cavityname = str_get(&name); 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)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, 0, nverts, &footprint)); + ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); + ERR(build_footprint(pg_int, 0, &footprint)); d[2] = height - e_roof - e_attic - e_roof_insulation; ERR(scad_geometry_extrude(footprint, NULL, d, &geom)); @@ -799,11 +708,13 @@ build_habitable } else { ERR(scad_geometry_copy(geom, cavityname, cavity)); } + ERR(darray_geometries_push_back(current_cad, cavity)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); if(geom) SCAD(geometry_ref_put(geom)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -811,14 +722,13 @@ error: static res_T build_attic - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - const struct scpr_polygon* pg, + (struct building* building, + int *error_msg_printed, const double height, const struct dataset_cmode_1* data, struct scpr_intersector* overlapping_intersector, struct htable_polygons* polygons, + struct darray_geometries* current_cad, struct scad_geometry** attic) { res_T res = RES_OK; @@ -829,47 +739,36 @@ 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}; char* atticname = NULL; struct str name; - int is_init = 0; + const char* prefix; - ASSERT(allocator && pg && data && attic); + ASSERT(building && error_msg_printed && data && attic); - if (prefix) { - str_init(allocator, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_F_attic")); - atticname = str_get(&name); - } + prefix = str_cget(&building->name); + str_init(building->city->allocator, &name); + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_F_attic")); + atticname = str_get(&name); 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(do_offset(building, polygons, overlapping_intersector, error_msg_printed, + offset, &pg_int)); /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); z_attic = height - e_roof - e_attic; - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, z_attic, nverts, &footprint)); + ERR(build_footprint(pg_int, z_attic, &footprint)); d[2] = e_attic; ERR(scad_geometry_extrude(footprint, atticname, d, attic)); + ERR(darray_geometries_push_back(current_cad, attic)); exit: if(footprint) SCAD(geometry_ref_put(footprint)); - if (is_init) str_release(&name); + str_release(&name); + if(pg_int) SCPR(polygon_ref_put(pg_int)); return res; error: goto exit; @@ -877,21 +776,24 @@ error: 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, + (const struct dataset_cmode_1* data, struct data_cad_cmode_1* data_cad, + struct darray_geometries* current_cad, struct darray_adjoining_data* adjoining_data) { res_T res = RES_OK; - size_t i, j, adjoining_n, removed_windows = 0; + size_t i, j, adjoining_n, removed_count, removed_hor = 0; + size_t removed_windows_sz = 0, removed_windows_adj = 0, removed_windows_self = 0; + size_t list_n = 0, array_n; + const char* prefix; double N[3]; double dir[3]; - double scale[3]; + double scale[3], scale_[3]; struct scad_geometry* surface = NULL; + struct scad_geometry* win_surface = NULL; + struct scad_geometry* surface_ = NULL; struct scad_geometry* hole = NULL; + struct scad_geometry* detect = NULL; struct scad_geometry** hole_list = NULL; struct darray_geometries hole_array; struct scad_geometry* geom = NULL; @@ -902,91 +804,191 @@ build_windows struct scad_geometry* glass = NULL; struct scad_geometry** glass_list = NULL; struct darray_geometries glass_array; - size_t list_n = 0, array_n; - struct str gname; - int is_init = 0; + struct scad_geometry* env = NULL; + struct scad_geometry* benv = NULL; + struct scad_geometry* problem = NULL; + struct str name; struct adjoining_data* adj; - (void)scpr; + struct mem_allocator* allocator; - ASSERT(scpr && allocator && logger && data && data_cad && adjoining_data); + ASSERT(data && data_cad && adjoining_data); + allocator = data_cad->building->city->allocator; adjoining_n = darray_adjoining_data_size_get(adjoining_data); adj = darray_adjoining_data_data_get(adjoining_data); darray_geometries_init(allocator, &hole_array); darray_geometries_init(allocator, &glass_array); + str_init(allocator, &name); d3_splat(scale, sqrt(data->glass_ratio)); + d3_splat(scale_, MMIN(1, 1.05 * sqrt(data->glass_ratio))); /* windows are build from the vertical faces of habitable cavities */ - ERR(scad_geometry_boundary(NULL, &data_cad->habitable_cavity, 1, &bcavity)); - ERR(scad_geometry_explode(bcavity, NULL, &list, &list_n)); - + ERR(scad_geometry_boundary("cavity_boundary", &data_cad->habitable_cavity, 1, + &bcavity)); + ERR(scad_geometry_explode(bcavity, "cavity_elt", &list, &list_n)); + ERR(scad_geometry_ref_put(bcavity)); + bcavity = NULL; + + /* The boundary of the envelop of the building. + * To be used for windows validation */ + ERR(build_envelop(data_cad->building, &env)); + ERR(scad_geometry_boundary("envelop_boundary", &env, 1, &benv)); + ERR(scad_geometry_ref_put(env)); + env = NULL; + + ERR(darray_geometries_reserve(&hole_array, list_n)); + ERR(darray_geometries_reserve(&glass_array, list_n)); for (i = 0; i < list_n; i++) { - double hsz, center[3]; + double hsz, mass, center[3]; size_t center_n; size_t count; + int removed = 0; ERR(scad_geometry_get_count(list[i], &center_n)); ASSERT(center_n == 1); ERR(scad_geometry_get_centerofmass(list[i], center)); - ERR(scad_geometry_normal(list[i], center, N, NULL, &surface)); + ERR(str_printf(&name, "surface_%lu", (long unsigned)i)); + ERR(scad_geometry_normal(list[i], center, N, str_cget(&name), &surface)); - if (N[2] != 0) { + if(N[2] != 0) { ERR(scad_geometry_ref_put(surface)); surface = NULL; + removed_hor++; continue; /* keep only vertical face */ } - ERR(scad_geometry_dilate(surface, center, scale)); + ERR(scad_geometry_get_mass(list[i], &mass)); + if(mass < 0.1) { + /* this window would be too small */ + ERR(scad_geometry_ref_put(surface)); + surface = NULL; + removed = 1; + removed_windows_sz++; + } + + if(!removed) { + /* Used to check for validity with a slitghly bigger size */ + ERR(str_printf(&name, "surface+_%lu", (long unsigned)i)); + ERR(scad_geometry_dilate(surface, center, scale_, str_cget(&name), + &surface_)); + } - /* Use the same distance used in early stages for close neighbor detection */ - hsz = CG2_CLOSE_NEIGHBOR_DISTANCE + data->wall_thickness + - data->internal_insulation_thickness + data->external_insulation_thickness; - d3_muld(dir, N, hsz); - ERR(scad_geometry_extrude(surface, NULL, dir, &hole)); + if(!removed && adjoining_n) { + /* Use the same distance used in early stages for close neighbor detection */ + hsz = CG2_CLOSE_NEIGHBOR_DISTANCE + data->wall_thickness + + data->internal_insulation_thickness + data->external_insulation_thickness; + d3_muld(dir, N, hsz); + ERR(str_printf(&name, "detect_adj_%lu", (long unsigned)i)); + ERR(scad_geometry_extrude(surface_, str_cget(&name), dir, &detect)); - /* Check if hole intersects adjoining envelops */ - /* Push only if don't intersect */ - if (adjoining_n) { + /* Check if detect intersects adjoining envelops */ + /* Push only if don't intersect */ adj_list = MEM_REALLOC(allocator, adj_list, adjoining_n * sizeof(struct scad_geometry*)); - for(j=0; j<adjoining_n; j++) adj_list[j] = adj[j].envelop; - ERR(scad_intersect_geometries(NULL, &hole, 1, adj_list, adjoining_n, - &hole_adjoining_intersect)); + for(j = 0; j < adjoining_n; j++) adj_list[j] = adj[j].envelop; + + ERR(str_printf(&name, "adj_intersect_%lu", (long unsigned)i)); + ERR(scad_intersect_geometries(str_cget(&name), &detect, 1, adj_list, + adjoining_n, &hole_adjoining_intersect)); + ERR(scad_geometry_ref_put(detect)); + detect = NULL; ERR(scad_geometry_get_count(hole_adjoining_intersect, &count)); ERR(scad_geometry_ref_put(hole_adjoining_intersect)); hole_adjoining_intersect = NULL; - } else { - count = 0; + if(count) { + removed = 1; + removed_windows_adj++; + } } - if (count == 0) { - ERR(darray_geometries_push_back(&hole_array, &hole)); + /* Check if the window intersects an unexpected wall of the building: + * - the window is too large wrt of external size of the wall (the window's + * size is a % of the internal size of the wall that can be larger than + * the external size due to angles). + * - another wall facing the current one at a too close distance (can be the + * prev/next with sharp angle, or not), + * - a tiny unwanted wall created by noise at the polygon level (mainly due + * to the offseting algorithm). */ + if(!removed) { + /* Use smaller distance than the one used for neighbor detection */ + hsz = 0.1 + data->wall_thickness + data->internal_insulation_thickness + + data->external_insulation_thickness; + d3_muld(dir, N, hsz); + ERR(str_printf(&name, "detect_self_%lu", (long unsigned)i)); + ERR(scad_geometry_extrude(surface_, str_cget(&name), dir, &detect)); + /* Compute intersection between detect and envelop: the number of + * components is expected to be 1, or the window is better removed */ + ERR(str_printf(&name, "self_intersect_%lu", (long unsigned)i)); + ERR(scad_intersect_geometries(str_cget(&name), &benv, 1, &detect, 1, + &problem)); + ERR(scad_geometry_ref_put(detect)); + detect = NULL; + ERR(scad_geometry_get_count(problem, &count)); + ERR(scad_geometry_ref_put(problem)); + problem = NULL; + if(count != 1) { + removed = 1; + removed_windows_self++; + } + } - 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)); + if(!removed) { + ERR(scad_geometry_dilate(surface, center, scale, NULL, &win_surface)); + ERR(str_printf(&name, "hole_%lu", (long unsigned)i)); + ERR(scad_geometry_extrude(win_surface, str_cget(&name), dir, &hole)); + ERR(darray_geometries_push_back(&hole_array, &hole)); + ERR(scad_geometry_ref_put(hole)); + hole = NULL; + d3_muld(dir, N, 0.024); + ERR(str_printf(&name, "glass_%lu", (long unsigned)i)); + ERR(scad_geometry_extrude(win_surface, str_cget(&name), dir, &glass)); ERR(darray_geometries_push_back(&glass_array, &glass)); + ERR(darray_geometries_push_back(current_cad, &glass)); ERR(scad_geometry_ref_put(glass)); glass = NULL; - } else { - removed_windows++; + + } + ASSERT(hole == NULL); + ASSERT(detect == NULL); + if(win_surface) { + ERR(scad_geometry_ref_put(win_surface)); + win_surface = NULL; + } + if(surface) { + ERR(scad_geometry_ref_put(surface)); + surface = NULL; + } + if(surface_) { + ERR(scad_geometry_ref_put(surface_)); + surface_ = NULL; } - ERR(scad_geometry_ref_put(hole)); - hole = NULL; - ERR(scad_geometry_ref_put(surface)); - surface = NULL; } - ASSERT(darray_geometries_size_get(&hole_array) - == darray_geometries_size_get(&glass_array)); - + removed_count = removed_windows_sz + removed_windows_adj + removed_windows_self; array_n = darray_geometries_size_get(&hole_array); - - if(removed_windows) { - logger_print(logger, LOG_OUTPUT, - "Building '%s' has %zu/%zu windows removed due to close neighbors.\n", - prefix, removed_windows, removed_windows+array_n); + ASSERT(array_n == darray_geometries_size_get(&glass_array)); + ASSERT(array_n + removed_hor + removed_count == list_n); + + prefix = str_cget(&data_cad->building->name); + if(removed_count != 0) { + logger_print(data_cad->building->city->logger, LOG_WARNING, + "Building '%s' has %zu/%zu windows removed:\n", + prefix, removed_count, removed_count + array_n); + if(removed_windows_sz != 0) { + logger_print(data_cad->building->city->logger, LOG_WARNING, + "- %zu windows removed due to too small size.\n", removed_windows_sz); + } + if(removed_windows_adj != 0) { + logger_print(data_cad->building->city->logger, LOG_WARNING, + "- %zu windows removed due to close neighbors.\n", removed_windows_adj); + } + if(removed_windows_self != 0) { + logger_print(data_cad->building->city->logger, LOG_WARNING, + "- %zu windows removed due to self conflicts.\n", removed_windows_self); + } + } else { + logger_print(data_cad->building->city->logger, LOG_OUTPUT, + "Building '%s' has no window removed (out of %zu).\n", prefix, array_n); } if (array_n > 0) { @@ -994,20 +996,18 @@ build_windows 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->wall, geom)); - ERR(scad_geometry_ref_put(data_cad->wall)); - data_cad->wall = geom; + ERR(scad_cut_geometries(NULL, &data_cad->wall, 1, hole_list, array_n, &geom)); + ERR(scad_geometries_swap(&data_cad->wall, &geom, 1, Scad_swap_geometry)); + ERR(scad_geometry_ref_put(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_ref_put(data_cad->internal_insulation)); - data_cad->internal_insulation = geom; + ERR(scad_geometries_swap(&data_cad->internal_insulation, &geom, 1, + Scad_swap_geometry)); + ERR(scad_geometry_ref_put(geom)); geom = NULL; } @@ -1015,38 +1015,37 @@ build_windows 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_ref_put(data_cad->external_insulation)); - data_cad->external_insulation = geom; + ERR(scad_geometries_swap(&data_cad->external_insulation, &geom, 1, + Scad_swap_geometry)); + ERR(scad_geometry_ref_put(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(str_set(&name, prefix)); + ERR(str_append(&name, "_S_glazing")); + ERR(scad_fuse_geometries(str_cget(&name), glass_list, 1, + glass_list+1, array_n - 1, &data_cad->glazing)); } exit: - for (i = 0 ; i < list_n; i++) { - if(list[i]) SCAD(geometry_ref_put(list[i])); - } + for(i = 0 ; i < list_n; i++) SCAD(geometry_ref_put(list[i])); darray_geometries_release(&hole_array); darray_geometries_release(&glass_array); - if (surface) SCAD(geometry_ref_put(surface)); - if (glass) SCAD(geometry_ref_put(glass)); - if (geom) SCAD(geometry_ref_put(geom)); - if (bcavity) SCAD(geometry_ref_put(bcavity)); - if (hole_adjoining_intersect) SCAD(geometry_ref_put(hole_adjoining_intersect)); + if(env) SCAD(geometry_ref_put(env)); + if(benv) SCAD(geometry_ref_put(benv)); + if(surface) SCAD(geometry_ref_put(surface)); + if(win_surface) SCAD(geometry_ref_put(win_surface)); + if(problem) SCAD(geometry_ref_put(problem)); + if(hole) SCAD(geometry_ref_put(hole)); + if(detect) SCAD(geometry_ref_put(detect)); + if(glass) SCAD(geometry_ref_put(glass)); + if(geom) SCAD(geometry_ref_put(geom)); + if(bcavity) SCAD(geometry_ref_put(bcavity)); + if(hole_adjoining_intersect) SCAD(geometry_ref_put(hole_adjoining_intersect)); MEM_RM(allocator, list); MEM_RM(allocator, adj_list); - if (is_init) str_release(&gname); + str_release(&name); return res; error: goto exit; @@ -1054,10 +1053,7 @@ error: static res_T build_boundary - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - struct data_cad_cmode_1* data_cad, + (struct data_cad_cmode_1* data_cad, struct darray_adjoining_data* adjoining_data, struct darray_geometries* boundary) { @@ -1067,18 +1063,17 @@ build_boundary struct scad_geometry* bound = NULL; char* boundaryname = NULL; struct str name; - int is_init = 0; struct adjoining_data* adj; size_t adjoining_n, i = 0, count = 0; - (void)scpr; + const char* prefix; - ASSERT(allocator && prefix && data_cad && adjoining_data && boundary); + ASSERT(data_cad && adjoining_data && boundary); + prefix = str_cget(&data_cad->building->name); adjoining_n = darray_adjoining_data_size_get(adjoining_data); adj = darray_adjoining_data_data_get(adjoining_data); - darray_geometries_init(allocator, &array); - str_init(allocator, &name); - is_init = 1; + darray_geometries_init(data_cad->building->city->allocator, &array); + str_init(data_cad->building->city->allocator, &name); /* Ensure enough room for all geometries without error nor mem move */ ERR(darray_geometries_reserve(&array, 14 + adjoining_n)); @@ -1115,11 +1110,13 @@ build_boundary if (data_cad->crawlspace_cavity) { ERR(darray_geometries_push_back(&array, &data_cad->crawlspace_cavity)); } - if (data_cad->glass) { - ERR(darray_geometries_push_back(&array, &data_cad->glass)); + if (data_cad->glazing) { + ERR(darray_geometries_push_back(&array, &data_cad->glazing)); } for (i=0; i<adjoining_n; i++) { - ERR(darray_geometries_push_back(&array, &adj[i].envelop)); + if(adj[i].really_adjoining) { + ERR(darray_geometries_push_back(&array, &adj[i].envelop)); + } } count = darray_geometries_size_get(&array); @@ -1146,12 +1143,12 @@ build_boundary ERR(scad_geometry_ref_put(bound)); bound = NULL; - if (data_cad->glass) { + if (data_cad->glazing) { ERR(str_set(&name, prefix)); ERR(str_append(&name, "_B_glazing")); boundaryname = str_get(&name); ERR(scad_geometries_common_boundaries(boundaryname, list, count, - &data_cad->glass, 1, &bound)); + &data_cad->glazing, 1, &bound)); ERR(darray_geometries_push_back(boundary, &bound)); ERR(scad_geometry_ref_put(bound)); bound = NULL; @@ -1185,7 +1182,7 @@ build_boundary exit: if(bound) SCAD(geometry_ref_put(bound)); - if (is_init) str_release(&name); + str_release(&name); darray_geometries_release(&array); return res; error: @@ -1194,10 +1191,7 @@ error: static res_T build_connection - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - struct data_cad_cmode_1* data_cad, + (struct data_cad_cmode_1* data_cad, struct darray_geometries* connection) { res_T res = RES_OK; @@ -1205,15 +1199,15 @@ build_connection size_t count = 0; char* cname = NULL; struct str name; - int is_init = 0; - (void)scpr; + const char* prefix; - ASSERT(allocator && prefix && data_cad && connection); + ASSERT(data_cad && connection); - str_init(allocator, &name); - is_init = 1; + prefix = str_cget(&data_cad->building->name); + str_init(data_cad->building->city->allocator, &name); -#define CREATE_CONNECT(G1,G2,SUFFIX) ERR(str_set(&name, prefix));\ +#define CREATE_CONNECT(G1,G2,SUFFIX) \ + ERR(str_set(&name, prefix));\ ERR(str_append(&name, SUFFIX));\ cname = str_get(&name);\ ERR(scad_geometries_common_boundaries(cname, &data_cad->G1, 1,\ @@ -1236,8 +1230,8 @@ build_connection CREATE_CONNECT(habitable_cavity,wall,"_C_levels_walls"); /* with glass */ - if (data_cad->glass) { - CREATE_CONNECT(habitable_cavity,glass,"_C_levels_glazing"); + if (data_cad->glazing) { + CREATE_CONNECT(habitable_cavity,glazing,"_C_levels_glazing"); } /* with internal insulation */ @@ -1296,26 +1290,7 @@ build_connection #undef CREATE_CONNECT exit: - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -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: + str_release(&name); return res; error: goto exit; @@ -1323,11 +1298,9 @@ error: static res_T build_fake_ground - (struct scpr_device* scpr, - struct mem_allocator* allocator, - struct data_cad_cmode_1* cad, - struct scpr_polygon* pg, + (struct data_cad_cmode_1* cad, const double depth, + struct darray_geometries* current_cad, struct scad_geometry** ground) { res_T res = RES_OK; @@ -1339,9 +1312,9 @@ build_fake_ground struct scad_geometry* footprint = NULL; struct scad_geometry* geom = NULL; - ASSERT(cad && pg && ground ); + ASSERT(cad && ground ); - darray_geometries_init(allocator, &array); + darray_geometries_init(cad->building->city->allocator, &array); /* Ensure enough room for all geometries without error nor mem move */ ERR(darray_geometries_reserve(&array, 4)); @@ -1361,15 +1334,16 @@ build_fake_ground count = darray_geometries_size_get(&array); list = darray_geometries_data_get(&array); - ERR(scpr_polygon_create_copy(scpr, pg, &pg_offset)); + ERR(scpr_polygon_create_copy(cad->building->city->scpr, cad->building->pg, &pg_offset)); ERR(scpr_offset_polygon(pg_offset, 0.1, SCPR_JOIN_MITER)); - ERR(build_footprint(pg_offset, &footprint)); + ERR(build_footprint(pg_offset, 0, &footprint)); dir[2] = -depth*1.1; ERR(scad_geometry_extrude(footprint, NULL, dir, &geom)); - ERR(scad_cut_geometries(NULL, &geom, 1, list, count, ground)); + ERR(scad_cut_geometries("fake_ground", &geom, 1, list, count, ground)); + ERR(darray_geometries_push_back(current_cad, ground)); exit: if (pg_offset) SCPR(polygon_ref_put(pg_offset)); @@ -1383,29 +1357,24 @@ error: static res_T building_ground_connection - (struct scpr_device* scpr, - struct mem_allocator* allocator, - const char* prefix, - struct data_cad_cmode_1* cad, + (struct data_cad_cmode_1* cad, struct scad_geometry** connection) { res_T res = RES_OK; char* cname = NULL; struct str name; - int is_init = 0; size_t count; struct darray_geometries array; struct scad_geometry** list = NULL; struct scad_geometry* list_boundary = NULL; struct scad_geometry* footprint = NULL; + const char* prefix; - (void)scpr; - ASSERT(scpr && allocator && prefix && cad && connection); - - darray_geometries_init(allocator, &array); + ASSERT(cad && connection); - str_init(allocator, &name); - is_init = 1; + prefix = str_cget(&cad->building->name); + darray_geometries_init(cad->building->city->allocator, &array); + str_init(cad->building->city->allocator, &name); ERR(str_set(&name, prefix)); ERR(str_append(&name, "_C_ground")); cname = str_get(&name); @@ -1439,7 +1408,7 @@ building_ground_connection exit: darray_geometries_release(&array); - if (is_init) str_release(&name); + str_release(&name); if (list_boundary) SCAD(geometry_ref_put(list_boundary)); if (footprint) SCAD(geometry_ref_put(footprint)); return res; @@ -1464,13 +1433,13 @@ init_cmode_1 struct str dataset_name; 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 + &init_cmode_1, + &release_cmode_1, + &build_cad_cmode_1, + &build_footprint_cmode_1, + &save_ground_connection_triangles_1, + &export_stl_cmode_1, + &release_cad_cmode_1 }; struct mem_allocator* allocator; struct logger* logger; @@ -1519,9 +1488,10 @@ release_cmode_1 res_T build_cad_cmode_1 (struct building* building, - int dump_footprints_on_error, + int dump_footprints_level, int keep_running_on_errors, struct darray_adjoining_data* adjoining_data, + struct darray_geometries* current_cad, void** cad) { res_T res = RES_OK; @@ -1539,16 +1509,18 @@ build_cad_cmode_1 struct htable_polygons polygons; int polygons_initialized = 0; double zero = 0; - struct scpr_device* scpr; struct mem_allocator* allocator; struct logger* logger = NULL; + size_t i, cad_count; + struct scad_geometry** cur_cad = NULL; + struct scad_geometry** partitioned = NULL; if (!building || !cad || !adjoining_data) { res = RES_BAD_ARG; goto error; } - scpr = building->city->scpr; + name = str_cget(&building->name); allocator = building->city->allocator; logger = building->city->logger; data_cad = MEM_CALLOC(allocator, 1, sizeof(struct data_cad_cmode_1)); @@ -1556,15 +1528,17 @@ build_cad_cmode_1 res = RES_MEM_ERR; goto error; } - data_cad->allocator = allocator; - darray_geometries_init(allocator, &data_cad->boundary); - darray_geometries_init(allocator, &data_cad->connection); + building->data_cad = data_cad; + data_cad->building = building; darray_common_trg_init(allocator, &data_cad->common_trg); darray_geometries_init(allocator, &data_cad->adj_walls); + 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)); + ERR(scpr_intersector_create(building->city->scpr, &overlapping_intersector)); ERR(scpr_intersector_register_polygon(overlapping_intersector, building->pg)); /* An htable to associate offset polygons to offsets. Not really for * performance, but to avoid considering the same polygon more than once when @@ -1577,16 +1551,15 @@ build_cad_cmode_1 - roof */ - name = str_cget(&building->name); - ERR(build_floor(scpr, allocator, logger, &error_msg_printed, - keep_running_on_errors, name, building->pg, data, overlapping_intersector, - &polygons, &data_cad->floor)); + ERR(build_floor(building, &error_msg_printed, data, overlapping_intersector, + &polygons, current_cad, &data_cad->floor)); - ERR(build_wall(scpr, allocator, name, "S_walls", building->pg, height, data, - overlapping_intersector, &polygons, &data_cad->wall)); + ERR(build_wall(building, &error_msg_printed, 0, "S_walls", height, data, + overlapping_intersector, &polygons, current_cad, &data_cad->wall)); - ERR(build_roof(scpr, allocator, name, building->pg, height, data, - overlapping_intersector, &polygons, &data_cad->roof)); + ERR(build_roof(building, &error_msg_printed, + height, data, + overlapping_intersector, &polygons, current_cad, &data_cad->roof)); /* build optionnal elements : - foundation @@ -1599,34 +1572,34 @@ build_cad_cmode_1 if (data->foundation_depth > 0) { depth = -data->foundation_depth; - ERR(build_wall(scpr, allocator, name, "S_foundation", building->pg, depth, data, - overlapping_intersector, &polygons, &data_cad->foundation)); + ERR(build_wall(building, &error_msg_printed, 1, "S_foundation", depth, + data, overlapping_intersector, &polygons, current_cad, &data_cad->foundation)); } if (data->inter_floor_count > 0) { - ERR(build_inter_floor(scpr, allocator, name, building->pg, height, data, - overlapping_intersector, &polygons, &data_cad->intermediate_floor)); + ERR(build_inter_floor(building, &error_msg_printed, height, data, + overlapping_intersector, &polygons, current_cad, &data_cad->intermediate_floor)); } if (data->external_insulation_thickness> 0) { - ERR(build_ext_insulation(scpr, allocator, name, building->pg, height, data, - overlapping_intersector, &polygons, &data_cad->external_insulation)); + ERR(build_ext_insulation(building, &error_msg_printed, height, data, + overlapping_intersector, &polygons, current_cad, &data_cad->external_insulation)); } if (data->internal_insulation_thickness> 0) { - ERR(build_int_insulation(scpr, allocator, name, building->pg, height, data, + ERR(build_int_insulation(building, &error_msg_printed, height, data, data_cad->intermediate_floor, overlapping_intersector, &polygons, - &data_cad->internal_insulation)); + current_cad, &data_cad->internal_insulation)); } if (data->roof_insulation_thickness > 0) { - ERR(build_roof_insulation(scpr, allocator, name, building->pg, height, data, - overlapping_intersector, &polygons, &data_cad->roof_insulation)); + ERR(build_roof_insulation(building, &error_msg_printed, height, data, + overlapping_intersector, &polygons, current_cad, &data_cad->roof_insulation)); } if (data->floor_insulation_thickness > 0) { - ERR(build_floor_insulation(scpr, allocator, name, building->pg, data, - overlapping_intersector, &polygons, &data_cad->floor_insulation)); + ERR(build_floor_insulation(building, &error_msg_printed, data, + overlapping_intersector, &polygons, current_cad, &data_cad->floor_insulation)); } /* build cavities : @@ -1636,17 +1609,17 @@ build_cad_cmode_1 */ if (data->attic_height > 0) { - ERR(build_attic(scpr, allocator, name, building->pg, height, data, - overlapping_intersector, &polygons, &data_cad->attic_cavity)); + ERR(build_attic(building, &error_msg_printed, height, data, + overlapping_intersector, &polygons, current_cad, &data_cad->attic_cavity)); } - ERR(build_habitable(scpr, allocator, name, building->pg, height, data, + ERR(build_habitable(building, &error_msg_printed, height, data, data_cad->intermediate_floor, overlapping_intersector, &polygons, - &data_cad->habitable_cavity)); + current_cad, &data_cad->habitable_cavity)); if (data->crawl_height > 0) { - ERR(build_crawlspace(scpr, allocator, name, building->pg, data, - overlapping_intersector, &polygons, &data_cad->crawlspace_cavity)); + ERR(build_crawlspace(building, &error_msg_printed, data, + overlapping_intersector, &polygons, current_cad, &data_cad->crawlspace_cavity)); } /* Check for registered polygons overlapping */ @@ -1655,14 +1628,14 @@ build_cad_cmode_1 ctx.buildings_count = 1; ctx.intersection_found = &error_occured; ctx.search_type = OVERLAPPING_PROXIMITY; - ctx.dump_footprints_on_error = dump_footprints_on_error; + ctx.dump_footprints_level = dump_footprints_level; ctx.keep_running_on_errors = keep_running_on_errors; callbacks.simple_intersection = simple_intersection; ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx)); if(error_occured) { logger_print(logger, LOG_ERROR, "Internal error building CAD for building '%s'.\n", - str_cget(&building->name)); + name); ERR(darray_pbuilding_push_back(&building->city->removed_buildings, &building)); error_msg_printed = 1; res = RES_BAD_ARG; @@ -1672,29 +1645,38 @@ build_cad_cmode_1 /* build adjoining envelop */ adjoining_n = htable_building_size_get(&building->close_buildings); if (adjoining_n > 0) { - ERR(build_adjoining(building, adjoining_data)); + ERR(build_adjoining(building, current_cad, adjoining_data)); ASSERT(adjoining_n == darray_adjoining_data_size_get(adjoining_data)); } /* windows */ if (data->glass_ratio > 0) { - ERR(build_windows(scpr, allocator, logger, name, data, data_cad, adjoining_data)); + ERR(build_windows(data, data_cad, current_cad, adjoining_data)); } /* fake ground */ depth = MMAX(data->foundation_depth, data->floor_thickness + data->floor_insulation_thickness + data->crawl_height); + ERR(build_fake_ground(data_cad, depth, current_cad, &data_cad->fake_ground)); - ERR(build_fake_ground(scpr, allocator, data_cad, building->pg, depth, - &data_cad->fake_ground)); - - ERR(scad_scene_partition()); + /* Partition CAD */ + cad_count = darray_geometries_size_get(current_cad); + partitioned = MEM_CALLOC(allocator, cad_count, sizeof(*partitioned)); + if(!partitioned) { + res = RES_MEM_ERR; + goto error; + } + cur_cad = darray_geometries_data_get(current_cad); + ERR(scad_geometries_partition(cur_cad, cad_count, 0, partitioned)); + /* Swap original geometry and partitioned geometry in data_cad (was + * accumulated into current_cad) */ + ERR(scad_geometries_swap(cur_cad, partitioned, cad_count, Scad_swap_geometry)); /* After partitioning, manage common parts with other buildings */ if(adjoining_n > 0) { size_t a, c; struct b_pair pair; - struct darray_double* common_trg; + struct darray_double* common; struct adjoining_data* adjoining = darray_adjoining_data_data_get(adjoining_data); struct scad_geometry* extern_most = data_cad->external_insulation @@ -1704,45 +1686,44 @@ build_cad_cmode_1 ERR(scad_geometries_common_boundaries(NULL, &extern_most, 1, &adj->envelop, 1, &adj->common_geometry)); ERR(scad_geometry_get_count(adj->common_geometry, &c)); - if(c == 0) { - /* Not really adjoining */ + adj->really_adjoining = (c != 0); + if(!adj->really_adjoining) { logger_print(logger, LOG_OUTPUT, "building '%s': neighbor '%s' not really adjoining.\n", - str_cget(&building->name), + name, str_cget(&adj->adjoining_building->name)); continue; } make_b_pair(&pair, building, adj->adjoining_building); - common_trg - = htable_common_triangles_find(&building->city->common_triangles, &pair); - if(common_trg) { - /* The common geometry has already been processed when creating a - * previous building, and the very same mesh must be used for this one. - * Keep track of the geometry to replace and the mesh to output instead */ - ERR(darray_geometries_push_back(&data_cad->adj_walls, - &adj->common_geometry)); - ERR(darray_common_trg_push_back(&data_cad->common_trg, &common_trg)); - } else { + /* Keep track of the geometry to replace and the mesh to output instead */ + ERR(darray_geometries_push_back(&data_cad->adj_walls, &adj->common_geometry)); + ERR(darray_common_trg_push_back(&data_cad->common_trg, &pair)); + common = htable_common_find(&building->city->common, &pair); + if(!common) { /* The mesh doesn't exist yet and won't be created until a further step. * We need to store the geometry id so that the mesh can be stored when * created. */ - adjoining[a].save = 1; + adj->save = 1; } } } /* build ground/building connection */ - ERR(building_ground_connection(scpr, allocator, name, data_cad, - &data_cad->ground_connection)); + ERR(building_ground_connection(data_cad, &data_cad->ground_connection)); /* build boundaries */ - ERR(build_boundary(scpr, allocator, name, data_cad, adjoining_data, - &data_cad->boundary)); + ERR(build_boundary(data_cad, adjoining_data, &data_cad->boundary)); /* build connections */ - ERR(build_connection(scpr, allocator, name, data_cad, &data_cad->connection)); + ERR(build_connection(data_cad, &data_cad->connection)); exit: + if(partitioned) { + for(i = 0; i < cad_count; i++) { + if(partitioned[i]) SCAD(geometry_ref_put(partitioned[i])); + } + MEM_RM(allocator, partitioned); + } if(polygons_initialized) htable_polygons_release(&polygons); if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector)); if(cad) *(struct data_cad_cmode_1**)cad = data_cad; @@ -1770,7 +1751,7 @@ build_footprint_cmode_1 goto error; } - ERR(build_footprint(building->pg, footprint)); + ERR(build_footprint(building->pg, 0, footprint)); exit: return res; @@ -1778,27 +1759,21 @@ error: goto exit; } -res_T -build_envelop_cmode_1 - (struct building* building, - struct scad_geometry** envelop) +res_T save_ground_connection_triangles_1 + (void* cad, + struct darray_double* triangles) { 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; + struct data_cad_cmode_1* data_cad = cad; - ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &footprint)); + if(!cad || !triangles) { + res = RES_BAD_ARG; + goto error; + } - /* wall envelop */ - d[2] = height; - ERR(scad_geometry_extrude(footprint, NULL, d, envelop)); + ERR(scad_stl_get_data(data_cad->ground_connection, triangles)); exit: - if (footprint) SCAD(geometry_ref_put(footprint)); return res; error: goto exit; @@ -1811,87 +1786,159 @@ export_stl_cmode_1 { res_T res = RES_OK; struct data_cad_cmode_1* data_cad = (struct data_cad_cmode_1 *)cad; - size_t i = 0; + size_t i = 0, j, common_n = 0, coord_count = 0; + struct darray_double trg; + struct str name; + int initialized = 0; + struct scad_geometry** list = NULL; + struct mem_allocator* allocator = NULL; if (!cad) { res = RES_BAD_ARG; goto error; } + allocator = data_cad->building->city->allocator; + /* floor export */ - ERR(scad_stl_export(data_cad->floor, NULL, binary)); + ERR(scad_stl_export(data_cad->floor, NULL, Scad_force_normals_outward, binary)); + + /* roof export */ + ERR(scad_stl_export(data_cad->roof, NULL, Scad_force_normals_outward, binary)); /* wall export */ - ERR(scad_stl_export(data_cad->wall, NULL, binary)); + if(darray_geometries_size_get(&data_cad->adj_walls) == 0) { + ERR(scad_stl_export(data_cad->wall, NULL, Scad_force_normals_outward, binary)); + } else { + /* There is some adjoining building(s) to manage */ + size_t common_count = darray_common_trg_size_get(&data_cad->common_trg); + const char* tmp; - /* roof export */ - ERR(scad_stl_export(data_cad->roof, NULL, binary)); + darray_double_init(allocator, &trg); + str_init(allocator, &name); + initialized = 1; + /* Get the triangles that are not common with adjoining buildings */ + ERR(scad_stl_get_data_partial(data_cad->wall, + darray_geometries_data_get(&data_cad->adj_walls), + darray_geometries_size_get(&data_cad->adj_walls), &trg)); + coord_count = darray_double_size_get(&trg); + /* Add the triangles from adjoining buildings */ + for(i = 0; i < common_count; i++) { + size_t sz; + struct b_pair* pair = darray_common_trg_data_get(&data_cad->common_trg)+ i; + const double *t9; + double* tgt; + struct city* city = data_cad->building->city; + struct darray_double* common = NULL; + /* Get triangles */ + common = htable_common_find(&city->common, pair); + if(!common) { + res = RES_BAD_ARG; + goto error; + } + t9 = darray_double_cdata_get(common); + /* Add common triangles */ + sz = darray_double_size_get(common); + ASSERT(sz % 9 == 0); + ASSERT(coord_count == darray_double_size_get(&trg)); + ERR(darray_double_resize(&trg, coord_count + sz)); + tgt = darray_double_data_get(&trg); + for(j = 0; j < sz; j++) { + tgt[coord_count + j] = t9[j]; + } + coord_count += sz; + ASSERT(coord_count % 9 == 0); + } + ERR(scad_geometry_get_name(data_cad->wall, &tmp)); + ERR(str_set(&name, tmp)); + ERR(str_append(&name, ".stl")); + ERR(scad_stl_data_write(&trg, str_cget(&name), Scad_force_normals_outward, + binary)); + } /* foundation export */ if (data_cad->foundation) { - ERR(scad_stl_export(data_cad->foundation, NULL, binary)); + ERR(scad_stl_export(data_cad->foundation, NULL, Scad_force_normals_outward, + binary)); } /* glass export */ - if (data_cad->glass) { - ERR(scad_stl_export(data_cad->glass, NULL, binary)); + if (data_cad->glazing) { + ERR(scad_stl_export(data_cad->glazing, NULL, Scad_force_normals_outward, + binary)); } /* intermediate floor export*/ if (data_cad->intermediate_floor) { - ERR(scad_stl_export(data_cad->intermediate_floor, NULL, binary)); + ERR(scad_stl_export(data_cad->intermediate_floor, NULL, + Scad_force_normals_outward, binary)); } /* internal insulation export*/ if (data_cad->internal_insulation) { - ERR(scad_stl_export(data_cad->internal_insulation, NULL, binary)); + ERR(scad_stl_export(data_cad->internal_insulation, NULL, + Scad_force_normals_outward, binary)); } /* external insulation export*/ if (data_cad->external_insulation) { - ERR(scad_stl_export(data_cad->external_insulation, NULL, binary)); + ERR(scad_stl_export(data_cad->external_insulation, NULL, + Scad_force_normals_outward, binary)); } /* roof insulation export*/ if (data_cad->roof_insulation) { - ERR(scad_stl_export(data_cad->roof_insulation, NULL, binary)); + ERR(scad_stl_export(data_cad->roof_insulation, NULL, + Scad_force_normals_outward, binary)); } /* floor insulation export*/ if (data_cad->floor_insulation) { - ERR(scad_stl_export(data_cad->floor_insulation, NULL, binary)); + ERR(scad_stl_export(data_cad->floor_insulation, NULL, + Scad_force_normals_outward, binary)); } /* attic cavity export*/ if (data_cad->attic_cavity) { - ERR(scad_stl_export(data_cad->attic_cavity, NULL, binary)); + ERR(scad_stl_export(data_cad->attic_cavity, NULL, + Scad_force_normals_outward, binary)); } /* habitable cavity export*/ - ERR(scad_stl_export(data_cad->habitable_cavity, NULL, binary)); + ERR(scad_stl_export(data_cad->habitable_cavity, NULL, + Scad_force_normals_outward, binary)); /* crawlspace cavity export*/ if (data_cad->crawlspace_cavity) { - ERR(scad_stl_export(data_cad->crawlspace_cavity, NULL, binary)); + ERR(scad_stl_export(data_cad->crawlspace_cavity, NULL, + Scad_force_normals_outward, binary)); } /* boundary export*/ 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_stl_export(b, NULL, binary)); + ERR(scad_stl_export(b, NULL, Scad_keep_normals_unchanged, binary)); } /* connections export*/ for(i = 0; i < darray_geometries_size_get(&data_cad->connection); i++) { struct scad_geometry* c = darray_geometries_data_get(&data_cad->connection)[i]; - ERR(scad_stl_export(c, NULL, binary)); + ERR(scad_stl_export(c, NULL, Scad_keep_normals_unchanged, binary)); } /* ground/building connection export*/ - ERR(scad_geometry_reverse(data_cad->ground_connection)); - ERR(scad_stl_export(data_cad->ground_connection, NULL, binary)); + ERR(scad_stl_export(data_cad->ground_connection, NULL, + Scad_keep_normals_unchanged, binary)); exit: + for(j = 0; j < common_n; j++) { + if(list[j]) SCAD(geometry_ref_put(list[j])); + } + MEM_RM(allocator, list); + if(initialized) { + darray_double_release(&trg); + str_release(&name); + } return res; error: goto exit; @@ -1910,7 +1957,7 @@ release_cad_cmode_1 goto error; } - allocator = data_cad->allocator; + allocator = data_cad->building->city->allocator; darray_geometries_release(&data_cad->boundary); darray_geometries_release(&data_cad->connection); darray_common_trg_release(&data_cad->common_trg); @@ -1927,7 +1974,7 @@ release_cad_cmode_1 GDEL(floor); GDEL(floor_insulation); GDEL(foundation); - GDEL(glass); + GDEL(glazing); GDEL(ground_connection); GDEL(habitable_cavity); GDEL(intermediate_floor); diff --git a/src/cg_construction_mode_1.h b/src/cg_construction_mode_1.h @@ -63,11 +63,11 @@ struct dataset_cmode_1 { #include <rsys/hash_table.h> struct data_cad_cmode_1 { - struct mem_allocator* allocator; - struct darray_geometries boundary; - struct darray_geometries connection; struct darray_common_trg common_trg; struct darray_geometries adj_walls; + struct darray_geometries boundary; + struct darray_geometries connection; + struct building* building; struct scad_geometry* wall; struct scad_geometry* roof; struct scad_geometry* floor; @@ -80,7 +80,7 @@ struct data_cad_cmode_1 { struct scad_geometry* external_insulation; /* can be NULL */ struct scad_geometry* floor_insulation; /* can be NULL */ struct scad_geometry* roof_insulation; /* can be NULL */ - struct scad_geometry* glass; + struct scad_geometry* glazing; struct scad_geometry* fake_ground;/*not exported, used for ground connection*/ struct scad_geometry* ground_connection; size_t n_connection; @@ -105,6 +105,7 @@ build_cad_cmode_1 int dump_footprints_on_error, int keep_running_on_errors, struct darray_adjoining_data* adjoining_data, + struct darray_geometries* current_cad, void** cad); res_T @@ -112,10 +113,9 @@ build_footprint_cmode_1 (struct building* building, struct scad_geometry** footprint); -res_T -build_envelop_cmode_1 - (struct building* building, - struct scad_geometry** envelop); +res_T save_ground_connection_triangles_1 + (void* cad, + struct darray_double* triangles); res_T export_stl_cmode_1 diff --git a/src/cg_ground.c b/src/cg_ground.c @@ -18,10 +18,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "cg_ground.h" +#include "cg_building.h" #include "cg_city.h" #include "cg.h" +#include <rsys/rsys.h> +#include <rsys/dynamic_array_double.h> #include <rsys/str.h> + #include <star/scad.h> #define GDEL(Tgt) \ @@ -29,17 +33,17 @@ /* To avoid double delete, set to NULL after deletion */ \ Tgt = NULL -#define GMV(Idx) \ - ASSERT(ground->boundary[Idx] == NULL); \ - ground->boundary[Idx] = surface; \ - /* To avoid unwanted delete, set to NULL after mv */ \ - surface = NULL +#define GPUSH(G) \ + ASSERT(G); \ + ERR(darray_geometries_push_back(&ground->boundaries, &(G))); \ + ERR(scad_geometry_ref_put(G)); /* Ownership is transfered to array */ \ + surface = NULL; \ + (G) = NULL; res_T ground_build_cad (struct mem_allocator* allocator, - struct city* city, - struct ground* ground) + struct city* city) { res_T res = RES_OK; double origin[3]; @@ -47,10 +51,13 @@ ground_build_cad struct scad_geometry* bound = NULL; struct scad_geometry** list; struct scad_geometry* surface = NULL; + struct scad_geometry* tmp = NULL; size_t i, count = 0; + struct ground* ground; - ASSERT(city && ground); + ASSERT(city); + ground = &city->ground; origin[0] = city->lower[0]; origin[1] = city->lower[1]; origin[2] = -city->ground_depth; @@ -59,7 +66,7 @@ ground_build_cad extent[1] = city->upper[1] - city->lower[1]; extent[2] = city->ground_depth; - if (origin[2] > 0 || extent[0] < 0 || extent[1] < 0 || extent[2] < 0 ) { + if(origin[2] > 0 || extent[0] < 0 || extent[1] < 0 || extent[2] < 0 ) { res = RES_BAD_ARG; goto error; } @@ -68,11 +75,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, count, sizeof(struct scad_geometry*)); + ERR(darray_geometries_reserve(&ground->boundaries, count)); - for (i = 0; i < count; i++) { + for(i = 0; i < count; i++) { double center[3]; size_t center_n; double N[3]; @@ -80,33 +85,41 @@ ground_build_cad ERR(scad_geometry_get_count(list[i], &center_n)); ASSERT(center_n == 1); ERR(scad_geometry_get_centerofmass(list[i], center)); - ERR(scad_geometry_normal(list[i], center, N, NULL, &surface)); if (N[0] == 0 && N[1] == 0 && N[2] == -1) { ERR(scad_geometry_rename(surface, "ground_B_bottom")); - GMV(0); + GPUSH(surface); } 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); + struct scad_geometry** footprints = + darray_geometries_data_get(&ground->footprints); + size_t fpcount = darray_geometries_size_get(&ground->footprints); + if(fpcount) { + ERR(scad_cut_geometries("ground_B_top", &surface, 1, footprints, fpcount, + &tmp)); + GDEL(surface); + GPUSH(tmp); + } else { + ERR(scad_geometry_rename(surface, "ground_B_top")); + GPUSH(surface); + } } else if (N[0] == -1 && N[1] == 0 && N[2] == 0) { ERR(scad_geometry_rename(surface, "ground_B_lateral_0")); - GMV(2); + GPUSH(surface); } else if (N[0] == 1 && N[1] == 0 && N[2] == 0) { ERR(scad_geometry_rename(surface, "ground_B_lateral_1")); - GMV(3); + GPUSH(surface); } else if (N[0] == 0 && N[1] == -1 && N[2] == 0) { ERR(scad_geometry_rename(surface, "ground_B_lateral_2")); - GMV(4); + GPUSH(surface); } else if (N[0] == 0 && N[1] == 1 && N[2] == 0) { ERR(scad_geometry_rename(surface, "ground_B_lateral_3")); - GMV(5); + GPUSH(surface); } else FATAL("Wrong ground box boundary."); } @@ -117,22 +130,33 @@ exit: } MEM_RM(allocator, list); GDEL(surface); + GDEL(tmp); GDEL(bound); return res; error: goto exit; } -#undef GMV +#undef GPUSH res_T -ground_export_stl(const struct ground* ground, const int binary) +ground_export_stl + (struct ground* ground, + const int binary) { res_T res = RES_OK; size_t i = 0; - for(i = 0; i < 6; i++) { - ERR(scad_stl_export(ground->boundary[i], NULL, binary)); + ASSERT(ground); + + for(i = 0; i < darray_geometries_size_get(&ground->boundaries); i++) { + struct scad_geometry* b = darray_geometries_data_get(&ground->boundaries)[i]; + /* Boundary files */ + ERR(scad_stl_export(b, NULL, Scad_keep_normals_unchanged, binary)); + /* Collect triangles */ + ERR(scad_stl_get_data(b, &ground->ground_trg)); } + ERR(scad_stl_data_write(&ground->ground_trg, "ground_body.stl", + Scad_force_normals_outward, binary)); exit: return res; @@ -140,48 +164,25 @@ error: goto exit; } -res_T +void ground_init (struct mem_allocator* allocator, - struct logger* logger, - const size_t count, struct ground* ground) { - res_T res = RES_OK; - (void)logger; - ground->box = NULL; - ground->boundary = NULL; - ground->footprints_count = count; - ground->footprints - = MEM_CALLOC(allocator, ground->footprints_count, sizeof(*ground->footprints)); - if(!ground->footprints) { - res = RES_MEM_ERR; - goto error; - } - -exit: - return res; -error: - goto exit; + darray_double_init(allocator, &ground->ground_trg); + darray_geometries_init(allocator, &ground->footprints); + darray_geometries_init(allocator, &ground->boundaries); } void ground_clear - (struct mem_allocator* allocator, - struct ground* ground) + (struct ground* ground) { - size_t i; GDEL(ground->box); - for(i = 0; i < 6; i++) { - GDEL(ground->boundary[i]); - } - MEM_RM(allocator, ground->boundary); - - for(i = 0; i < ground->footprints_count; i++) { - GDEL(ground->footprints[i]); - } - MEM_RM(allocator, ground->footprints); + darray_geometries_release(&ground->footprints); + darray_geometries_release(&ground->boundaries); + darray_double_release(&ground->ground_trg); } #undef GDEL diff --git a/src/cg_ground.h b/src/cg_ground.h @@ -20,7 +20,10 @@ #ifndef GROUND_H #define GROUND_H +#include "cg_types.h" + #include <rsys/rsys.h> +#include <rsys/dynamic_array_double.h> struct city; struct scad_geometry; @@ -30,33 +33,28 @@ struct logger; struct ground { /* cad representation */ struct scad_geometry* box; - struct scad_geometry** boundary; - struct scad_geometry** footprints; /* list of building footprint */ - size_t footprints_count; /* number of footprint */ + struct darray_geometries boundaries; + struct darray_geometries footprints; + struct darray_double ground_trg; }; -#define GROUND_NULL__ {NULL, NULL, NULL, 0} -static const struct ground GROUND_NULL = GROUND_NULL__; - res_T ground_build_cad (struct mem_allocator* allocator, - struct city* city, - struct ground* ground); + struct city* city); res_T -ground_export_stl(const struct ground* ground, const int binary); +ground_export_stl + (struct ground* ground, + const int binary); -res_T +void ground_init (struct mem_allocator* allocator, - struct logger* logger, - const size_t count, struct ground* ground); void ground_clear - (struct mem_allocator* allocator, - struct ground* ground); + (struct ground* ground); #endif /* GROUND */ diff --git a/src/cg_main.c b/src/cg_main.c @@ -24,12 +24,11 @@ #include "cg_city_parsing.h" #include "cg_catalog.h" #include "cg_catalog_parsing.h" -#include "cg_construction_mode_0_parsing_schemas.h" -#include "cg_construction_mode_1_parsing_schemas.h" #include <cyaml/cyaml.h> #include <rsys/rsys.h> +#include <rsys/clock_time.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> #include <star/scad.h> @@ -102,7 +101,10 @@ int main .log_level = CYAML_LOG_WARNING, /* Logging errors and warnings only. */ .flags = CYAML_CFG_DEFAULT, }; + struct time t0, dt; + char buf[128]; + time_current(&t0); /* init allocator and logger */ ERR(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); allocator_initialized = 1; @@ -166,8 +168,13 @@ int main exit: release_city(city); release_catalog(catalog); - if(logger_initialized) logger_release(&logger); if(args) release_args(args); + time_sub(&dt, time_current(&dt), &t0); + time_dump(&dt, TIME_MIN | TIME_SEC, NULL, buf, sizeof(buf)); + if(logger_initialized) { + logger_print(&logger, LOG_OUTPUT, "Total run time: %s.\n", buf); + logger_release(&logger); + } if(allocator_initialized) { if(check_memory_allocator(&allocator)) err = EXIT_FAILURE; mem_shutdown_proxy_allocator(&allocator); @@ -180,7 +187,7 @@ error: err = EXIT_FAILURE; if(logger_initialized) { logger_print(&logger, LOG_ERROR, "City generator failed.\n"); - if(!city->keep_running_on_errors) + if(city && !city->keep_running_on_errors) logger_print(&logger, LOG_ERROR, "Try to re-run with option -k.\n"); } goto exit; diff --git a/src/cg_types.c b/src/cg_types.c @@ -0,0 +1,39 @@ +/* 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_types.h" + +#include <rsys/rsys.h> +#include <star/scad.h> + +void +pgeom_release(struct scad_geometry** data) { + ASSERT(data); + SCAD(geometry_ref_put(*data)); +} + +res_T +pgeom_copy(struct scad_geometry** dst, struct scad_geometry* const* src) { + ASSERT(dst && src); + *dst = *src; + SCAD(geometry_ref_get(*src)); + return RES_OK; +} + + diff --git a/src/cg_types.h b/src/cg_types.h @@ -0,0 +1,48 @@ +/* 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/>. */ + +#ifndef TYPES_H +#define TYPES_H + +#include <rsys/rsys.h> +#include <rsys/dynamic_array_double.h> + +struct scad_geometry; + +void +pgeom_release(struct scad_geometry** data); +res_T +pgeom_copy(struct scad_geometry** dst, struct scad_geometry* const* src); +static FINLINE res_T +pgeom_copy_and_release + (struct scad_geometry** dst, struct scad_geometry* const* src) +{ + ASSERT(dst && src); + *dst = *src; + return RES_OK; +} +#define DARRAY_NAME geometries +#define DARRAY_DATA struct scad_geometry* +#define DARRAY_INIT adjoining_data_init +#define DARRAY_FUNCTOR_RELEASE pgeom_release +#define DARRAY_FUNCTOR_COPY pgeom_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE pgeom_copy_and_release +#include <rsys/dynamic_array.h> + +#endif /* TYPES */