commit 83d8067fcaa072ea83bab5f395cc26438357e09f
parent 5384651a6e8acb89d89b605af98c441c754e41d4
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 21 Apr 2023 16:03:18 +0200
Fix non-conforming meshes in some adjoining configurations
Also make various improvements
Diffstat:
18 files changed, 1063 insertions(+), 604 deletions(-)
diff --git a/README.md b/README.md
@@ -23,6 +23,19 @@ resulting project can be edited, built, tested and installed as any CMake
project. Refer to the [CMake documentation](https://cmake.org/documentation)
for further informations on CMake.
+Some parameters that change the program behaviour can be set at the cmake stage.
+To set them one can use the -D<VAR>=<VAL> pattern. The parameters are:
+
+- `CG2_ARGS_DEFAULT_VERBOSITY_LEVEL`: the default verbosity level if the `-V`
+ option is not used. Default is 1 (errors only).
+
+- `STL_OUTPUT_DEFAULT_IS_BINARY`: The default format for output STL files.
+ Default is ascii. Depending of this option, the command line options allow
+ either -a the change the type to ascii, or -b to change it to binary.
+
+- `CG2_CLOSE_NEIGHBOR_DISTANCE`: The distance up to which a close neighbor
+ building prevents windows to be generated. Default is 2 meters.
+
## Copyright notice
Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -20,7 +20,9 @@ enable_testing()
set(CG2_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
option(NO_TEST "Disable the test" OFF)
option(STL_OUTPUT_DEFAULT_IS_BINARY
- "Default is to use binary format for output STL files" ON)
+ "Default is to use binary format for output STL files" OFF)
+set(CG2_CLOSE_NEIGHBOR_DISTANCE "2" CACHE STRING
+ "Distance up to which windows are not generated")
if(CMAKE_HOST_UNIX)
set(CG2_DOC "TROFF" CACHE STRING
diff --git a/src/cg.h b/src/cg.h
@@ -30,7 +30,6 @@
*/
#define CLIPPER_PRECISON 3 /* Input footprints are rounded to mm */
-#define CLOSE_NEIGHBOR_DISTANCE 0.1 /* Neighbors are considered close <= 0.1 m */
/* Utility functions */
static INLINE void
diff --git a/src/cg_building.c b/src/cg_building.c
@@ -22,38 +22,74 @@
#include "cg_building.h"
#include <rsys/str.h>
-#include <rsys/stretchy_array.h>
#include <rsys/mem_allocator.h>
#include <rsys/logger.h>
#include <star/scad.h>
+void
+adjoining_data_release(struct adjoining_data* data)
+{
+ ASSERT(data);
+ if(data->envelop) {
+ SCAD(geometry_ref_put(data->envelop));
+ data->envelop = NULL;
+ }
+ if(data->common_geometry) {
+ SCAD(geometry_ref_put(data->common_geometry));
+ data->common_geometry = NULL;
+ }
+}
+
+res_T
+adjoining_data_copy
+ (struct adjoining_data* dst, const struct adjoining_data* src)
+{
+ ASSERT(dst && src);
+ dst->adjoining_building = src->adjoining_building;
+ dst->main_building = src->main_building;
+ dst->common_geometry = src->common_geometry;
+ if(dst->common_geometry) SCAD(geometry_ref_get(dst->common_geometry));
+ dst->envelop = src->envelop;
+ if(dst->envelop) SCAD(geometry_ref_get(dst->envelop));
+ dst->save = src->save;
+ return RES_OK;
+}
+
+res_T
+adjoining_data_copy_and_release
+ (struct adjoining_data* dst, const struct adjoining_data* src)
+{
+ ASSERT(dst && src);
+ dst->adjoining_building = src->adjoining_building;
+ dst->main_building = src->main_building;
+ dst->common_geometry = src->common_geometry;
+ dst->envelop = src->envelop;
+ dst->save = src->save;
+ return RES_OK;
+}
+
res_T
build_adjoining
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- struct scad_geometry*** geom)
+ (struct building* building,
+ struct darray_adjoining_data* adjoining)
{
res_T res = RES_OK;
- size_t count, i = 0;
- struct scad_geometry** envelop_list = NULL;
+ size_t count, prev, i = 0;
struct htable_building_iterator it, end;
struct htable_building* close_buildings;
struct str msg;
+ struct mem_allocator* allocator;
+ struct logger* logger;
- ASSERT(allocator && logger && building && geom);
+ ASSERT(building && adjoining);
+ allocator = building->city->allocator;
+ logger = building->city->logger;
str_init(allocator, &msg);
close_buildings = &building->close_buildings;
count = htable_building_size_get(close_buildings);
- envelop_list = MEM_CALLOC(allocator, count, sizeof(struct scad_geometry*));
- if(!envelop_list) {
- res = RES_MEM_ERR;
- goto error;
- }
-
ERR(str_printf(&msg,
"building '%s' considering close neighbor(s) when creating CAD:",
str_cget(&building->name)));
@@ -61,29 +97,29 @@ build_adjoining
/* iterate over adjoining building */
htable_building_begin(close_buildings, &it);
htable_building_end(close_buildings, &end);
+ prev = darray_adjoining_data_size_get(adjoining);
+ ERR(darray_adjoining_data_resize(adjoining, prev + count));
while(!htable_building_iterator_eq(&it, &end)) {
unsigned char flags = *htable_building_iterator_data_get(&it);
struct building* close_building;
+ struct adjoining_data* adj;
ASSERT(flags & CLOSE_PROXIMITY); (void)flags;
close_building = *htable_building_iterator_key_get(&it);
- ERR(close_building->functors->build_envelop(allocator, logger, close_building,
- envelop_list + i++));
+ adj = darray_adjoining_data_data_get(adjoining) + prev + i;
+ ERR(close_building->functors->build_envelop(close_building, &adj->envelop));
+ adj->main_building = building;
+ adj->adjoining_building = close_building;
ERR(str_append_printf(&msg, " '%s'", str_cget(&close_building->name)));
htable_building_iterator_next(&it);
+ i++;
}
- ASSERT(i == count);
logger_print(logger, LOG_OUTPUT, "%s.\n", str_cget(&msg));
exit:
str_release(&msg);
- *geom = envelop_list;
return res;
error:
- for (i = 0; i < count; i++) {
- if(envelop_list[i]) SCAD(geometry_delete(envelop_list[i]));
- }
- if (envelop_list) MEM_RM(allocator, envelop_list);
- envelop_list = NULL;
+ darray_adjoining_data_clear(adjoining);
goto exit;
}
diff --git a/src/cg_building.h b/src/cg_building.h
@@ -22,17 +22,17 @@
#include <rsys/rsys.h>
#include <rsys/str.h>
+#include <rsys/dynamic_array.h>
+#include <rsys/dynamic_array.h>
#include <rsys/hash_table.h>
struct scpr_polygon;
struct scad_geometry;
-struct mem_allocator;
-struct logger;
struct catalog;
struct building;
struct parsed_city_building;
-struct scpr_device;
-struct building;
+struct city;
+struct darray_adjoining_data;
/* An htable to uniquely associate flags to buildings */
#define HTABLE_NAME building
@@ -45,54 +45,40 @@ enum building_event {
BUILDING_NO_EVENT,
BUILDING_WITH_OVERLAPPING = BIT(0),
BUILDING_WITH_CLOSE_NEIGHBOR = BIT(1),
- BUILDING_WITH_INTERNAL_ERROR = BIT(2),
- BUILDING_OUT_OF_GROUND_EXTENT = BIT(3),
- BUILDING_REMOVED = BIT(4),
- BUILDING_DUMPED_TO_OBJ = BIT(5)
+ BUILDING_OUT_OF_GROUND_EXTENT = BIT(2),
+ BUILDING_DUMPED_TO_OBJ = BIT(3),
+ BUILDING_CREATED = BIT(4),
+ BUILDING_CAD_EXPORTED_TO_STL = BIT(5)
};
/* A type to store the functors of a construction mode */
struct construction_mode_functors {
res_T (*init)
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- int keep_running_on_error,
+ (struct building* building,
+ struct city* city,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
const double upper[2]);
res_T (*release)
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building);
+ (struct building* building);
res_T (*build_cad)
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
int dump_footprints_on_error,
int keep_running_on_errors,
+ struct darray_adjoining_data* adjoining_data,
void** cad);
res_T (*build_footprint)
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** footprint);
res_T (*build_envelop)
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** envelop);
res_T (*export_stl)
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad,
+ (void* cad,
const int binary);
res_T (*release_cad)
- (struct mem_allocator* allocator, struct logger* logger, void* cad);
+ (void* cad);
};
/* A type to give an ID to construction modes.
@@ -114,6 +100,7 @@ struct building {
/* generic construction mode data */
struct str name;
+ struct city* city;
double height;
struct scpr_polygon* pg;
struct htable_building close_buildings; /* links to other buildings */
@@ -124,11 +111,44 @@ struct building {
void* data;
};
+#define DARRAY_NAME pbuilding
+#define DARRAY_DATA struct building*
+#include <rsys/dynamic_array.h>
+
+struct adjoining_data {
+ struct building* adjoining_building;
+ struct building* main_building;
+ /* Only valid for building save */
+ struct scad_geometry* envelop;
+ struct scad_geometry* common_geometry;
+ int save;
+};
+static FINLINE void
+adjoining_data_init(struct mem_allocator* alloc, struct adjoining_data* data)
+{
+ ASSERT(data); (void)alloc;
+ data->adjoining_building = NULL;
+ data->main_building = NULL;
+ data->envelop = NULL;
+ data->common_geometry = NULL;
+ data->save = 0;
+}
+void adjoining_data_release(struct adjoining_data* data);
+res_T adjoining_data_copy
+ (struct adjoining_data* dst, const struct adjoining_data* src);
+res_T adjoining_data_copy_and_release
+ (struct adjoining_data* dst, const struct adjoining_data* src);
+#define DARRAY_NAME adjoining_data
+#define DARRAY_DATA struct adjoining_data
+#define DARRAY_FUNCTOR_INIT adjoining_data_init
+#define DARRAY_FUNCTOR_COPY adjoining_data_copy
+#define DARRAY_FUNCTOR_RELEASE adjoining_data_release
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE adjoining_data_copy_and_release
+#include <rsys/dynamic_array.h>
+
res_T
build_adjoining
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- struct scad_geometry*** geom);
+ (struct building* building,
+ struct darray_adjoining_data* adjoining);
#endif /* BUILDING_H */
diff --git a/src/cg_catalog_parsing.c b/src/cg_catalog_parsing.c
@@ -20,6 +20,7 @@
#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"
@@ -79,6 +80,7 @@ parse_catalog
items = darray_parsed_catalog_items_data_get(&parsed->catalog);
for(i = 0; i < files_count; i++) {
const struct cyaml_schema_value* schema;
+ size_t set_count;
/* Parse construction mode only */
filename = darray_names_cdata_get(files_array)[i];
@@ -95,6 +97,22 @@ parse_catalog
items[i].filename = filename;
items[i].construction_mode = parsed_cmode->cmode_type;
+ /* Log outcome */
+ switch(items[i].construction_mode) {
+ case PARSED_CMODE_0:
+ set_count = ((struct parsed_catalog_cmode_0*)items[i].parsed_data)->datasets_count;
+ break;
+ case PARSED_CMODE_1:
+ set_count = ((struct parsed_catalog_cmode_1*)items[i].parsed_data)->datasets_count;
+ break;
+ default: FATAL("Invalid enum value.\n");
+ }
+ logger_print(logger, LOG_OUTPUT,
+ "Catalog file '%s' parsed: mode '%s', %zu dataset(s) read.\n",
+ filename,
+ city_building_types_strings[items[i].construction_mode].str,
+ set_count);
+
/* Free tmp struct */
err = cyaml_free(config, &construction_mode_schema, parsed_cmode, 1);
CHK(RES_OK == cyaml_err_to_res_T(err));
diff --git a/src/cg_city.c b/src/cg_city.c
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "cg.h"
+#include "cg_default.h"
#include "cg_city.h"
#include "cg_construction_mode_0.h"
#include "cg_construction_mode_1.h"
@@ -32,20 +33,34 @@
#include <rsys/mem_allocator.h>
#include <rsys/double4.h>
#include <rsys/hash_table.h>
+#include <rsys/dynamic_array.h>
#include <rsys/str.h>
+#include <star/scad.h>
#include <star/scpr.h>
#include <string.h>
+void
+make_b_pair
+ (struct b_pair* pair,
+ struct building* b1,
+ struct building* b2)
+{
+ ASSERT(pair && b1 && b2 && b1 != b2);
+ pair->b1 = MMIN(b1, b2);
+ pair->b2 = MMAX(b1, b2);
+}
res_T
dump_obj
(struct mem_allocator* allocator,
- struct building* building)
+ struct building* building,
+ struct scpr_polygon* alternate_polygon) /* Can be NULL */
{
res_T res = RES_OK;
FILE* stream = NULL;
struct str filename;
+ struct scpr_polygon* p;
ASSERT(allocator && building);
@@ -56,7 +71,8 @@ dump_obj
ERR(str_copy(&filename, &building->name));
ERR(str_append(&filename, ".obj"));
stream = fopen(str_cget(&filename), "w");
- ERR(scpr_polygon_dump_to_obj(building->pg, stream));
+ p = alternate_polygon ? alternate_polygon : building->pg;
+ ERR(scpr_polygon_dump_to_obj(p, stream));
building->event_flags |= BUILDING_DUMPED_TO_OBJ;
exit:
if(stream) fclose(stream);
@@ -66,6 +82,24 @@ 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);
+ }
+}
+
#define STORE_CLOSE_INFO(Building1, Building2, Proximity) {\
unsigned char *ptr__, tmp__; \
ptr__ = htable_building_find(&(Building1)->close_buildings, &(Building2)); \
@@ -90,11 +124,14 @@ int overlapping_segments
for(i = 0; i < ctx->buildings_count; i++) {
struct building* building = ctx->buildings + i;
enum building_event flag = BUILDING_WITH_CLOSE_NEIGHBOR;
- if(building->pg == segment1->polygon) {
+ 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;
- } else if(building->pg == segment2->polygon) {
+ }
+ if(pg == segment2->polygon) {
building2 = building;
name2 = str_cget(&building->name);
building2->event_flags |= flag;
@@ -107,8 +144,8 @@ int overlapping_segments
/* store other polygon on building information */
STORE_CLOSE_INFO(building1, building2, CLOSE_PROXIMITY);
STORE_CLOSE_INFO(building2, building1, CLOSE_PROXIMITY);
- logger_print(ctx->logger, LOG_OUTPUT,
- "Common segments detected between buildings '%s' and '%s'.\n",
+ logger_print(ctx->city->logger, LOG_OUTPUT,
+ "Overlapping segment detected between buildings '%s' and '%s'.\n",
name1, name2);
break;
case CLOSE_PROXIMITY:
@@ -135,19 +172,25 @@ int simple_intersection
struct building *building1 = NULL, *building2 = NULL;
enum building_event flag = ctx->search_type == OVERLAPPING_PROXIMITY
? BUILDING_WITH_OVERLAPPING : BUILDING_WITH_CLOSE_NEIGHBOR;
+ struct logger* logger;
+ struct mem_allocator* allocator;
ASSERT(segment1 && segment2 && ctx);
+ logger = ctx->city->logger;
+ allocator = ctx->city->allocator;
if(ctx->intersection_found) *ctx->intersection_found = 1;
/* Search polygons in the city (slow, but OK) */
for(i = 0; i < ctx->buildings_count; i++) {
struct building* building = ctx->buildings + i;
- if(building->pg == segment1->polygon) {
+ 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;
- } else if(building->pg == segment2->polygon) {
+ } else if(pg == segment2->polygon) {
building2 = building;
name2 = str_cget(&building->name);
building2->event_flags |= flag;
@@ -157,16 +200,27 @@ int simple_intersection
switch(ctx->search_type) {
case OVERLAPPING_PROXIMITY:
- logger_print(ctx->logger,
- (ctx->keep_running_on_errors ? LOG_WARNING : LOG_ERROR),
- "Intersection detected between buildings '%s' and '%s'.\n",
- name1, name2);
+ 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 the polygons in OBJ files */
- ERR(dump_obj(ctx->allocator, building1));
- ERR(dump_obj(ctx->allocator, building2));
+ 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(ctx->logger, LOG_OUTPUT,
+ logger_print(logger, LOG_OUTPUT,
"Buildings '%s' and '%s' are in close proximity.\n",
name1, name2);
break;
@@ -177,8 +231,10 @@ int simple_intersection
STORE_CLOSE_INFO(building1, building2, ctx->search_type);
STORE_CLOSE_INFO(building2, building1, ctx->search_type);
- /* Return 1 to stop the process unless user asked to go further */
- if(ctx->keep_running_on_errors || ctx->dump_footprints_on_error)
+ /* Return 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)
return 0;
return 1;
error:
@@ -187,16 +243,6 @@ error:
}
#undef STORE_CLOSE_INFO
-#define ERRtmp(Expr) \
-if((error_occured |= ((res_tmp = (Expr)) != RES_OK)) \
- && !city->dump_footprints_on_error) \
-{ \
- logger_print(logger, LOG_ERROR, \
- "Error initializing building '%s'.\n", str_cget(&building->name)); \
- res = res_tmp; \
- goto error;\
-} else (void)0
-
res_T
create_city
(struct mem_allocator* allocator,
@@ -210,7 +256,6 @@ create_city
size_t i = 0;
struct city* city = NULL;
struct htable_names names;
- int initialized = 0;
struct scpr_device_create_args scpr_args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
struct scpr_intersector* overlapping_intersector = NULL;
struct scpr_intersector* close_intersector = NULL;
@@ -221,10 +266,13 @@ create_city
struct str name;
int error_occured = 0;
struct building* building = NULL;
+ struct darray_polygons offset_polygons;
ASSERT(logger && allocator && args && parsed_city && catalog && out_city);
str_init(allocator, &name);
+ darray_polygons_init(allocator, &offset_polygons);
+ htable_names_init(allocator, &names);
city = MEM_CALLOC(allocator, 1, sizeof(*city));
if(!city) {
@@ -232,9 +280,7 @@ create_city
goto error;
}
- htable_names_init(allocator, &names);
- initialized = 1;
-
+ 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));
@@ -255,7 +301,9 @@ create_city
city->keep_running_on_errors = args->keep_running_on_errors;
city->dump_footprints_on_error = args->dump_footprints_on_error;
htable_names_init(allocator, &city->dump_footprint_names);
- city->names_initialized = 1;
+ htable_common_triangles_init(allocator, &city->common_triangles);
+ city->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;
const char* pname = darray_names_cdata_get(&args->dump_footprint_names)[i];
@@ -271,26 +319,41 @@ create_city
ERR(scpr_intersector_create(city->scpr, &overlapping_intersector));
ERR(scpr_intersector_create(city->scpr, &close_intersector));
+ ERR(darray_polygons_reserve(&offset_polygons, city->allocated_buildings_count));
/* create buildings depending on their construction modes */
- for (i = 0; i < city->allocated_buildings_count ; i++) {
+ for(i = 0; i < city->allocated_buildings_count ; i++) {
+ res_T tmp_res;
struct parsed_city_building* parsed_data = parsed_city->city_building_list + i;
- building = city->buildings + i;
char one = 1;
- res_T res_tmp = RES_OK;
- city->initialized_buildings_count++;
+ int dump;
+ building = city->buildings + i;
switch(parsed_data->cmode_type) {
case PARSED_CMODE_0:
- ERRtmp(init_cmode_0(city->scpr, allocator, logger, building,
- city->keep_running_on_errors, parsed_data, catalog,
- city->lower, city->upper));
+ tmp_res = init_cmode_0(building, city, parsed_data, catalog,
+ city->lower, city->upper);
break;
case PARSED_CMODE_1:
- ERRtmp(init_cmode_1(city->scpr, allocator, logger, building,
- city->keep_running_on_errors, parsed_data, catalog,
- city->lower, city->upper));
+ tmp_res = init_cmode_1(building, city, parsed_data, catalog,
+ city->lower, city->upper);
break;
default: FATAL("Unknown construction mode");
}
+ /* Dump polygon if required */
+ dump = htable_names_find(&city->dump_footprint_names, &building->name)
+ || (tmp_res != RES_OK && city->dump_footprints_on_error);
+ if(dump) {
+ ERR(dump_obj(allocator, building, NULL));
+ }
+ if(tmp_res != RES_OK) {
+ 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));
+ continue;
+ }
+ res = tmp_res;
+ goto error;
+ }
/* Check name unicity. The error case is not supposed to happen: can be
* tested after building creation as this simplifies the process */
if(htable_names_find(&names, &building->name)) {
@@ -301,26 +364,23 @@ create_city
goto error;
}
ERR(htable_names_set(&names, &building->name, &one));
- /* Dump polygon if in the list */
- if(htable_names_find(&city->dump_footprint_names, &building->name)) {
- ERR(dump_obj(allocator, building));
- }
/* Register the exterior building polygon for further overlapping detection */
ERR(scpr_intersector_register_polygon(overlapping_intersector, building->pg));
/* Register offset exterior building polygon for further proximity detection */
ERR(scpr_polygon_create_copy(city->scpr, building->pg, &tmp_polygon));
- ERR(scpr_offset_polygon(tmp_polygon, CLOSE_NEIGHBOR_DISTANCE,
+ ERR(scpr_offset_polygon(tmp_polygon, CG2_CLOSE_NEIGHBOR_DISTANCE,
SCPR_JOIN_MITER));
ERR(scpr_intersector_register_polygon(close_intersector, tmp_polygon));
+ ERR(darray_polygons_push_back(&offset_polygons, &tmp_polygon));
ERR(scpr_polygon_ref_put(tmp_polygon));
tmp_polygon = NULL;
+ building->event_flags |= BUILDING_CREATED;
+ city->initialized_buildings_count++;
}
building = NULL;
- ASSERT(city->initialized_buildings_count == city->allocated_buildings_count);
- /* Check for polygons overlapping and proximity */
- ctx.allocator = allocator;
- ctx.logger = logger;
+ /* Check for polygons overlapping */
+ ctx.city = city;
ctx.buildings = city->buildings;
ctx.buildings_count = city->initialized_buildings_count;
ctx.intersection_found = &error_occured;
@@ -329,22 +389,31 @@ create_city
ctx.keep_running_on_errors = city->keep_running_on_errors;
callbacks.simple_intersection = simple_intersection;
callbacks.overlapping_segments = overlapping_segments;
+ ctx.alternate_polygons = NULL;
ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx));
- ctx.search_type = CLOSE_PROXIMITY;
- ctx.intersection_found = NULL; /* Not an error in this case */
- ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx));
-
if(error_occured && !city->keep_running_on_errors) {
res = RES_BAD_ARG;
goto error;
}
+ /* 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];
+ unregister_close_building(city, b);
+ }
+
+ /* Check for polygons proximity */
+ ctx.search_type = CLOSE_PROXIMITY;
+ ctx.alternate_polygons = darray_polygons_data_get(&offset_polygons);
+ ctx.intersection_found = NULL; /* Not an error in this case */
+ ERR(scpr_intersector_check(close_intersector, &callbacks, &ctx));
exit:
str_release(&name);
+ darray_polygons_release(&offset_polygons);
if(tmp_polygon) SCPR(polygon_ref_put(tmp_polygon));
if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector));
if(close_intersector) SCPR(intersector_ref_put(close_intersector));
- if(initialized) htable_names_release(&names);
+ htable_names_release(&names);
*out_city = city;
return res;
error:
@@ -358,7 +427,6 @@ error:
city = NULL;
goto exit;
}
-#undef ERRtmp
res_T
release_city(struct city* city)
@@ -372,13 +440,17 @@ release_city(struct city* city)
}
if(city->scpr) SCPR(device_ref_put(city->scpr));
- if(city->names_initialized) htable_names_release(&city->dump_footprint_names);
+ if(city->tables_initialized) {
+ htable_common_triangles_release(&city->common_triangles);
+ htable_names_release(&city->dump_footprint_names);
+ }
/* iterate on building */
- for (i = 0; i < city->initialized_buildings_count; i++) {
+ for (i = 0; i < city->allocated_buildings_count; i++) {
struct building* building = city->buildings + i;
- ERR(building->functors->release(city->allocator, city->logger, building));
+ ERR(building->functors->release(building));
}
+ darray_pbuilding_release(&city->removed_buildings);
MEM_RM(city->allocator, city->buildings);
MEM_RM(city->allocator, city);
exit:
@@ -393,11 +465,17 @@ city_cad_build(struct city* city)
res_T res = RES_OK;
struct scad_options options = SCAD_DEFAULT_OPTIONS__;
int scad_initialized = 0;
- size_t i, generated_buildings_count = 0;
+ 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;
ASSERT(city);
+ darray_adjoining_data_init(city->allocator, &adjoining_data);
+ darray_double_init(city->allocator, &trg);
+
/* Initialize star-cad */
ERR(scad_initialize(city->logger, city->allocator, city->verbosisty_level));
scad_initialized = 1;
@@ -408,34 +486,90 @@ city_cad_build(struct city* city)
/* iterate on buildings */
for(i = 0; i < city->allocated_buildings_count; i++) {
building = city->buildings + i;
- struct data_cad_cmode_0* cad = NULL;
- if(building->event_flags & BUILDING_OUT_OF_GROUND_EXTENT
- || building->event_flags & BUILDING_WITH_OVERLAPPING)
+ if(building->event_flags & BUILDING_WITH_OVERLAPPING
+ || !(building->event_flags & BUILDING_CREATED))
{
/* No fix for these problems */
- building->event_flags |= BUILDING_REMOVED;
if(city->dump_footprints_on_error) {
- ERR(dump_obj(city->allocator, building));
+ ERR(dump_obj(city->allocator, building, NULL));
}
} else {
/* create building */
- ERR(building->functors->build_cad(city->scpr, city->allocator,
- city->logger, building, city->dump_footprints_on_error,
- city->keep_running_on_errors, (void**)&cad));
+ struct adjoining_data* adj;
+ res = building->functors->build_cad(building, city->dump_footprints_on_error,
+ city->keep_running_on_errors, &adjoining_data, (void**)&cad);
+ if(res != RES_OK) {
+ if(city->dump_footprints_on_error) {
+ ERR(dump_obj(city->allocator, building, NULL));
+ }
+ 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);
+ /* 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
+ * are on walls' meshes being uselessly refined due to conformity with
+ * the now-removed building, and possible window removal that should
+ * now be reversed. */
+ res = RES_OK;
+ continue;
+ }
+ }
+ ERR(res);
ERR(scad_scene_mesh());
- ERR(building->functors->export_stl(city->allocator, city->logger, cad,
- city->binary_export));
- ERR(building->functors->release_cad(city->allocator, city->logger, cad));
+ /* 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++) {
+ struct b_pair pair;
+ size_t c;
+ ERR(scad_geometry_get_count(adj->common_geometry, &c));
+ if(c == 0) {
+ /* Not really adjoining */
+ continue;
+ }
+ if(!adj[a].save || building != adj[a].main_building) {
+ /* Only the building that created the record can do the job
+ * (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));
+ make_b_pair(&pair, building, adj[a].adjoining_building);
+ ERR(htable_common_triangles_set(&building->city->common_triangles,
+ &pair, &trg));
+ }
+ ERR(building->functors->export_stl(cad, city->binary_export));
+ building->event_flags |= BUILDING_CAD_EXPORTED_TO_STL;
+ logger_print(city->logger, LOG_OUTPUT,
+ "Building '%s': %s STL files created.\n",
+ str_cget(&building->name), (city->binary_export ? "binary" : "ascii"));
+ /* Cannot keep any geometry from one building to the other */
+ ERR(building->functors->release_cad(cad));
+ cad = NULL; /* Avoid double release */
+ darray_adjoining_data_clear(&adjoining_data);
ERR(scad_scene_clear());
generated_buildings_count++;
+ logger_print(city->logger, LOG_OUTPUT,
+ "Building '%s': done.\n", str_cget(&building->name));
}
}
building = NULL;
city->cad_generated_buildings_count = generated_buildings_count;
exit:
+ 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);
return res;
error:
if(building) {
@@ -470,14 +604,13 @@ city_ground_build(struct city* city)
building = city->buildings + i;
struct scad_geometry** footprint;
- if(building->event_flags & BUILDING_REMOVED)
+ if(!(building->event_flags & BUILDING_CAD_EXPORTED_TO_STL))
continue;
footprint = ground.footprints + g++;
/* create building footprint */
- ERR(building->functors->build_footprint(city->scpr, city->allocator,
- city->logger, building, footprint));
+ ERR(building->functors->build_footprint(building, footprint));
}
building = NULL;
ERR(ground_build_cad(city->allocator, city, &ground));
diff --git a/src/cg_city.h b/src/cg_city.h
@@ -20,20 +20,67 @@
#ifndef CITY_H
#define CITY_H
+#include "cg_building.h"
+
+#include <star/scpr.h>
#include <star/scad.h>
-#include <rsys/hash_table.h>
#include <rsys/str.h>
+#include <rsys/hash_table.h>
+#include <rsys/dynamic_array.h>
+#include <rsys/dynamic_array_double.h>
struct logger;
struct mem_allocator;
-struct building;
struct args;
struct parsed_city;
struct catalog;
struct scpr_device;
struct scpr_callback_segment;
+static FINLINE void
+ppoly_init
+ (struct mem_allocator* alloc, struct scpr_polygon** data)
+{
+ ASSERT(data); (void)alloc;
+ *data = NULL;
+}
+static INLINE void
+ppoly_release(struct scpr_polygon** data) {
+ ASSERT(data);
+ if(*data) SCPR(polygon_ref_put(*data));
+}
+static INLINE res_T
+ppoly_copy(struct scpr_polygon** dst, struct scpr_polygon* const* src) {
+ ASSERT(dst && src);
+ *dst = *src;
+ SCPR(polygon_ref_get(*src));
+ return RES_OK;
+}
+static FINLINE res_T
+ppoly_copy_and_release
+ (struct scpr_polygon** dst, struct scpr_polygon* const* src)
+{
+ ASSERT(dst && src);
+ *dst = *src;
+ return RES_OK;
+}
+#define DARRAY_NAME polygons
+#define DARRAY_DATA struct scpr_polygon*
+#define DARRAY_FUNCTOR_RELEASE ppoly_release
+#define DARRAY_FUNCTOR_COPY ppoly_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE ppoly_copy_and_release
+#include <rsys/dynamic_array.h>
+
+#define HTABLE_NAME polygons
+#define HTABLE_KEY double
+#define HTABLE_DATA struct scpr_polygon*
+#define HTABLE_DATA_FUNCTOR_INIT ppoly_init
+#define HTABLE_DATA_FUNCTOR_RELEASE ppoly_release
+#define HTABLE_DATA_FUNCTOR_COPY ppoly_copy
+#define HTABLE_DATA_FUNCTOR_COPY_AND_RELEASE ppoly_copy_and_release
+#include <rsys/hash_table.h>
+
#define HTABLE_NAME names
#define HTABLE_DATA char
#define HTABLE_KEY struct str
@@ -46,6 +93,34 @@ struct scpr_callback_segment;
#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. */
+struct b_pair {
+ struct building* b1;
+ struct building* b2;
+};
+static INLINE char
+b_pair_eq(const struct b_pair* p0, const struct b_pair* p1)
+{
+ return p0->b1 == p1->b1 && p0->b2 == p1->b2;
+}
+void
+make_b_pair
+ (struct b_pair* pair,
+ struct building* b1,
+ struct building* b2);
+#define HTABLE_NAME common_triangles
+#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>
+
struct city {
double lower[2], upper[2]; /* Bbox */
double ground_depth;
@@ -53,6 +128,8 @@ struct city {
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 darray_pbuilding removed_buildings;
struct mem_allocator* allocator;
struct logger* logger;
struct scpr_device* scpr;
@@ -60,7 +137,7 @@ struct city {
int verbosisty_level;
int keep_running_on_errors;
int dump_footprints_on_error;
- int names_initialized;
+ int tables_initialized;
};
res_T
@@ -86,7 +163,8 @@ release_city(struct city* city);
res_T
dump_obj
(struct mem_allocator* allocator,
- struct building* building);
+ struct building* building,
+ struct scpr_polygon* alternate_polygon); /* Can be NULL */
/* An enum to encode type of proximity of buildings. */
enum building_proximity {
@@ -97,9 +175,9 @@ enum building_proximity {
/* the type of context expected by simple_intersection */
struct callback_ctx {
- struct mem_allocator* allocator;
- struct logger* logger;
+ struct city* city;
struct building* buildings;
+ struct scpr_polygon** alternate_polygons;
size_t buildings_count;
int* intersection_found; /* Can be NULL if not to be registered */
enum building_proximity search_type;
diff --git a/src/cg_city_parsing.c b/src/cg_city_parsing.c
@@ -55,6 +55,11 @@ parse_city
str_init(allocator, &parsed->filename);
ERR(str_set(&parsed->filename, filename));
+ /* 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);
+
exit:
*out_parsed = parsed;
return res;
diff --git a/src/cg_construction_mode.c b/src/cg_construction_mode.c
@@ -31,6 +31,20 @@
#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;
@@ -57,11 +71,8 @@ void get_position_pg
res_T
init_building_base
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- int keep_running_on_error,
+ (struct building* building,
+ struct city* city,
struct parsed_city_building* parsed_data,
const double lower[2],
const double upper[2])
@@ -69,26 +80,26 @@ init_building_base
int inside;
res_T res = RES_OK;
- ASSERT(scpr && allocator && logger && building && parsed_data && lower && upper);
+ ASSERT(city && building && parsed_data && lower && upper);
+ building->city = city;
building->height = parsed_data->height;
- str_init(allocator, &building->name);
- htable_building_init(allocator, &building->close_buildings);
+ str_init(city->allocator, &building->name);
+ htable_building_init(city->allocator, &building->close_buildings);
building->structs_initialized = 1;
ERR(str_set(&building->name, parsed_data->name));
- ERR(scpr_polygon_create(scpr, &building->pg));
+ ERR(scpr_polygon_create(city->scpr, &building->pg));
ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos,
parsed_data));
ERR(scpr_polygon_in_bbox(building->pg, lower, upper, &inside));
if(!inside) {
- logger_print(logger, LOG_ERROR,
+ 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;
- if(!keep_running_on_error) {
- res = RES_BAD_ARG;
- goto error;
- }
+ res = RES_BAD_ARG;
+ goto error;
}
exit:
@@ -99,14 +110,11 @@ error:
res_T
release_building_base
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building)
+ (struct building* building)
{
res_T res = RES_OK;
- (void) allocator; (void)logger;
- ASSERT(allocator && logger && building);
+ ASSERT(building);
if(building->structs_initialized) {
str_release(&building->name);
diff --git a/src/cg_construction_mode.h b/src/cg_construction_mode.h
@@ -24,13 +24,39 @@
#include <rsys/rsys.h>
#include <star/scpr.h>
+#include <rsys/dynamic_array.h>
-struct scpr_device;
+struct city;
struct mem_allocator;
struct logger;
struct building;
struct parsed_city_building;
struct catalog;
+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
+#include <rsys/dynamic_array.h>
void
get_nverts(const size_t icomp, size_t* nverts, void* context);
@@ -43,20 +69,15 @@ void get_position_pg
res_T
init_building_base
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- int keep_running_on_error,
+ (struct building* building,
+ struct city* city,
struct parsed_city_building* parsed_data,
const double lower[2],
const double upper[2]);
res_T
release_building_base
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building);
+ (struct building* building);
#endif
diff --git a/src/cg_construction_mode_0.c b/src/cg_construction_mode_0.c
@@ -28,8 +28,13 @@
#include <rsys/rsys.h>
#include <rsys/str.h>
#include <rsys/logger.h>
+#include <rsys/double3.h>
+
#include <star/scad.h>
#include <star/scpr.h>
+#include <star/sstl.h>
+
+#include <limits.h>
static res_T
build_floor_footprint
@@ -84,7 +89,7 @@ build_floor
ERR(scad_geometry_extrude(footprint, floorname, d, floor));
exit:
- SCAD(geometry_delete(footprint));
+ SCAD(geometry_ref_put(footprint));
if (is_init) str_release(&name);
return res;
error:
@@ -126,7 +131,7 @@ build_fake_ground
ERR(scad_geometry_extrude(footprint, NULL, d, fake_ground));
exit:
- SCAD(geometry_delete(footprint));
+ SCAD(geometry_ref_put(footprint));
return res;
error:
goto exit;
@@ -195,8 +200,8 @@ build_wall_footprint
ERR(scad_cut_geometries(NULL, &polygon, 1, &polygon_int, 1, footprint));
exit:
- if(polygon) SCAD(geometry_delete(polygon));
- if(polygon_int) SCAD(geometry_delete(polygon_int));
+ if(polygon) SCAD(geometry_ref_put(polygon));
+ if(polygon_int) SCAD(geometry_ref_put(polygon_int));
return res;
error:
goto exit;
@@ -236,7 +241,7 @@ build_wall
ERR(scad_geometry_extrude(footprint, wallname, d, wall));
exit:
- if(footprint) SCAD(geometry_delete(footprint));
+ if(footprint) SCAD(geometry_ref_put(footprint));
if (is_init) str_release(&name);
return res;
error:
@@ -281,7 +286,7 @@ build_cavity
ERR(scad_geometry_extrude(polygon, cavityname, d, cavity));
exit:
- if(polygon) SCAD(geometry_delete(polygon));
+ if(polygon) SCAD(geometry_ref_put(polygon));
if (is_init) str_release(&name);
return res;
error:
@@ -351,20 +356,21 @@ static res_T
build_boundary
(const char* prefix,
struct mem_allocator* allocator,
- struct scad_geometry** adjoining_cad,
- size_t adjoining_n,
+ struct darray_adjoining_data* adjoining_data,
struct data_cad_cmode_0* data_cad)
{
res_T res = RES_OK;
- size_t count = 0;
struct scad_geometry** list = NULL;
char* boundaryname = NULL;
struct str name;
int is_init = 0;
- size_t i = 0;
+ struct adjoining_data* adj;
+ size_t adjoining_n, i = 0, count = 0;
- ASSERT(allocator && prefix && data_cad);
+ ASSERT(allocator && prefix && 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;
@@ -374,32 +380,28 @@ build_boundary
res = RES_MEM_ERR;
goto error;
}
+ /* Using wall here to compute boundary_wall is OK even if it doesn't take care
+ * 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. */
list[0] = data_cad->floor;
- list[1] = data_cad->wall;
- list[2] = data_cad->roof;
+ 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] = adjoining_cad[i];
- }
-
- data_cad->boundary = MEM_ALLOC(allocator, 2 * sizeof(struct scad_geometry*));
- if(!data_cad->boundary) {
- res = RES_MEM_ERR;
- goto error;
- }
+ for (i=0; i<adjoining_n; i++) list[5+i] = adj[i].envelop;
ERR(str_set(&name, prefix));
ERR(str_append(&name, "_B_walls"));
boundaryname = str_get(&name);
ERR(scad_geometries_common_boundaries(boundaryname, list, count,
- &data_cad->wall, 1, &data_cad->boundary[0]));
+ &data_cad->wall, 1, &data_cad->boundary_wall));
ERR(str_set(&name, prefix));
ERR(str_append(&name, "_B_roof"));
boundaryname = str_get(&name);
ERR(scad_geometries_common_boundaries(boundaryname, list, count,
- &data_cad->roof, 1, &data_cad->boundary[1]));
+ &data_cad->roof, 1, &data_cad->boundary_roof));
exit:
MEM_RM(allocator, list);
@@ -448,11 +450,8 @@ error:
res_T
init_cmode_0
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- int keep_running_on_error,
+ (struct building* building,
+ struct city* city,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
@@ -461,8 +460,7 @@ init_cmode_0
res_T res = RES_OK;
struct str dataset_name;
int name_initialized = 0;
- static struct construction_mode_functors functors_0
- = {
+ static struct construction_mode_functors functors_0 = {
&init_cmode_0,
&release_cmode_0,
&build_cad_cmode_0,
@@ -471,20 +469,21 @@ init_cmode_0
&export_stl_cmode_0,
&release_cad_cmode_0
};
+ struct mem_allocator* allocator;
+ struct logger* logger;
(void)parsed_data;
- if(!scpr || !allocator || !logger || !building || !parsed_data || !catalog
- || !lower || !upper)
- {
+ if(!city || !building || !parsed_data || !catalog || !lower || !upper) {
res = RES_BAD_ARG;
goto error;
}
+ allocator = city->allocator;
+ logger = city->logger;
building->construction_mode = mode_0;
building->functors = &functors_0;
- ERR(init_building_base(scpr, allocator, logger, building, keep_running_on_error,
- parsed_data, lower, upper));
+ ERR(init_building_base(building, city, parsed_data, lower, upper));
str_init(allocator, &dataset_name);
name_initialized = 1;
@@ -508,61 +507,49 @@ error:
res_T
release_cmode_0
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building)
+ (struct building* building)
{
- res_T res = RES_OK;
-
- if(!allocator || !logger || !building) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- ERR(release_building_base(allocator, logger, building));
-
-exit:
- return res;
-error:
- goto exit;
+ if(!building) return RES_BAD_ARG;
+ return release_building_base(building);
}
res_T
build_cad_cmode_0
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
int dump_footprints_on_error,
int keep_running_on_errors,
+ struct darray_adjoining_data* adjoining_data,
void** cad)
{
res_T res = RES_OK;
double height;
- struct scpr_polygon* pg = NULL;
struct scpr_polygon* pg_int = NULL;
struct dataset_cmode_0* data = NULL;
struct data_cad_cmode_0* data_cad = NULL;
double e_wall;
const char* name;
- struct scad_geometry** adjoining_cad = NULL;
- size_t i = 0;
+ struct scad_geometry *tmp = NULL;
size_t adjoining_n = 0;
struct scpr_intersector* overlapping_intersector = NULL;
struct scpr_intersector_check_callbacks callbacks
= SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__;
struct callback_ctx ctx;
- int error_occured = 0;
+ int error_occured = 0, error_msg_printed = 0;
+ struct scpr_device* scpr;
+ struct mem_allocator* allocator;
+ struct logger* logger;
+ size_t c;
- if (!building || !allocator || !cad) {
+ if (!building || !cad || !adjoining_data) {
res = RES_BAD_ARG;
goto error;
}
+ scpr = building->city->scpr;
+ allocator = building->city->allocator;
+ logger = building->city->logger;
height = building->height;
- pg = building->pg;
data = (struct dataset_cmode_0 *)building->data;
- adjoining_n = htable_building_size_get(&building->close_buildings);
if (height <= 0 || data->wall_thickness <= 0 || data->floor_thickness <= 0) {
res = RES_BAD_ARG;
@@ -574,18 +561,30 @@ build_cad_cmode_0
res = RES_MEM_ERR;
goto error;
}
+ data_cad->allocator = allocator;
+ darray_common_trg_init(allocator, &data_cad->common_trg);
+ darray_geometries_init(allocator, &data_cad->adj_walls);
ERR(scpr_intersector_create(scpr, &overlapping_intersector));
ERR(scpr_intersector_register_polygon(overlapping_intersector, building->pg));
e_wall = data->wall_thickness;
- ERR(scpr_polygon_create_copy(scpr, pg, &pg_int));
+ ERR(scpr_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 */
+ 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));
+ error_msg_printed = 1;
+ res = RES_BAD_ARG;
+ goto error;
+ }
ERR(scpr_intersector_register_polygon(overlapping_intersector, pg_int));
- /* Check for polygons overlapping */
- ctx.allocator = allocator;
- ctx.logger = logger;
+ /* Check for registered polygons overlapping */
+ ctx.city = building->city;
ctx.buildings = building;
ctx.buildings_count = 1;
ctx.intersection_found = &error_occured;
@@ -594,6 +593,15 @@ build_cad_cmode_0
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));
+ ERR(darray_pbuilding_push_back(&building->city->removed_buildings, &building));
+ error_msg_printed = 1;
+ res = RES_BAD_ARG;
+ goto error;
+ }
/* build floor with pg_int */
name = str_cget(&building->name);
@@ -603,59 +611,95 @@ build_cad_cmode_0
ERR(build_roof(name, building, data_cad->floor, &data_cad->roof));
/* build wall with pg and pg_int */
- ERR(build_wall(name, pg, pg_int, building, &data_cad->wall));
+ ERR(build_wall(name, building->pg, pg_int, building, &data_cad->wall));
/* build cavity */
ERR(build_cavity(name, pg_int, building, &data_cad->cavity));
-
/* build adjoining envelop */
+ adjoining_n = htable_building_size_get(&building->close_buildings);
if (adjoining_n > 0) {
- ERR(build_adjoining(allocator, logger, building, &adjoining_cad));
+ ERR(build_adjoining(building, adjoining_data));
+ ASSERT(adjoining_n == darray_adjoining_data_size_get(adjoining_data));
}
/* build fake ground */
- ERR(build_fake_ground(pg, &data_cad->fake_ground));
+ ERR(build_fake_ground(building->pg, &data_cad->fake_ground));
ERR(scad_scene_partition());
+ /* 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 adjoining_data* adjoining
+ = darray_adjoining_data_data_get(adjoining_data);
+ for(a = 0; a < adjoining_n; a++) {
+ struct adjoining_data* adj = adjoining + a;
+ 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 */
+ logger_print(logger, LOG_OUTPUT,
+ "building '%s': neighbor '%s' not really adjoining.\n",
+ str_cget(&building->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 {
+ /* 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;
+ }
+ }
+ }
+
/* build ground/building connection */
ERR(building_ground_connection(allocator, name, data_cad,
&data_cad->ground_connection));
/* build boundary */
- ERR(build_boundary(name, allocator, adjoining_cad, adjoining_n, data_cad));
+ ERR(build_boundary(name, allocator, adjoining_data, data_cad));
/* build cavity/floor connectiona*/
ERR(build_connection(name, allocator, data_cad));
exit:
+ if(tmp) SCAD(geometry_ref_put(tmp));
if(pg_int) SCPR(polygon_ref_put(pg_int));
if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector));
- *(struct data_cad_cmode_0**)cad = data_cad;
- for (i=0 ; i<adjoining_n; i++) {
- if (adjoining_cad[i]) {
- ERR(scad_geometry_delete(adjoining_cad[i]));
- }
- }
- MEM_RM(allocator, adjoining_cad);
+ if(cad) *(struct data_cad_cmode_0**)cad = data_cad;
return res;
error:
- if(data_cad) CHK(RES_OK == release_cad_cmode_0(allocator, logger, data_cad));
+ if(building && !error_msg_printed) {
+ logger_print(logger, LOG_ERROR,
+ "Unknown error building CAD for building '%s'.\n",
+ str_cget(&building->name));
+ }
+ if(data_cad) CHK(RES_OK == release_cad_cmode_0(data_cad));
data_cad = NULL;
goto exit;
}
res_T
build_footprint_cmode_0
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** footprint)
{
res_T res = RES_OK;
- (void)scpr; (void)allocator; (void)logger;
if(!building || ! footprint) {
res = RES_BAD_ARG;
@@ -672,9 +716,7 @@ error:
res_T
build_envelop_cmode_0
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** envelop)
{
res_T res = RES_OK;
@@ -684,8 +726,6 @@ build_envelop_cmode_0
struct scpr_polygon* pg = building->pg;
struct scad_geometry* footprint = NULL;
- (void)allocator; (void)logger;
-
ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts));
ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &footprint));
@@ -693,7 +733,7 @@ build_envelop_cmode_0
ERR(scad_geometry_extrude(footprint, NULL, d, envelop));
exit:
- if (footprint) scad_geometry_delete(footprint);
+ if (footprint) SCAD(geometry_ref_put(footprint));
return res;
error:
goto exit;
@@ -701,15 +741,16 @@ error:
res_T
export_stl_cmode_0
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad,
+ (void* cad,
const int binary)
{
res_T res = RES_OK;
struct data_cad_cmode_0* data_cad = (struct data_cad_cmode_0*)cad;
- size_t i;
- (void)allocator; (void)logger;
+ size_t i, j, common_n = 0, coord_count = 0;
+ struct darray_double trg;
+ struct str name;
+ int initialized = 0;
+ struct scad_geometry** list = NULL;
if(!cad) {
res = RES_BAD_ARG;
@@ -717,30 +758,110 @@ export_stl_cmode_0
}
/* floor export */
- ERR(scad_stl_export(data_cad->floor, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->floor, NULL, binary));
/* roof export */
- ERR(scad_stl_export(data_cad->roof, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->roof, NULL, binary));
/* wall export */
- ERR(scad_stl_export(data_cad->wall, NULL, 0, binary));
+ if(darray_geometries_size_get(&data_cad->adj_walls) == 0) {
+ ERR(scad_stl_export(data_cad->wall, NULL, 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);
+ 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;
+ int found = 0;
+ const double* t9 = darray_double_cdata_get(common[i]);
+ 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) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ /* Add common triangles */
+ sz = darray_double_size_get(common[i]);
+ 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));
+ }
+ 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), binary));
+ }
/* cavity export */
- ERR(scad_stl_export(data_cad->cavity, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->cavity, NULL, binary));
/* connection export */
for (i = 0; i < data_cad->n_connection; i++) {
- ERR(scad_stl_export(data_cad->connection[i], NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->connection[i], NULL, binary));
}
/* boundary export */
- ERR(scad_stl_export(data_cad->boundary[0], NULL, 0, binary));
- ERR(scad_stl_export(data_cad->boundary[1], NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->boundary_wall, NULL, binary));
+ ERR(scad_stl_export(data_cad->boundary_roof, NULL, binary));
/* footprint export */
- ERR(scad_stl_export(data_cad->ground_connection, NULL, 1, binary));
+ ERR(scad_geometry_reverse(data_cad->ground_connection));
+ ERR(scad_stl_export(data_cad->ground_connection, NULL, 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);
+ }
return res;
error:
goto exit;
@@ -748,22 +869,24 @@ error:
res_T
release_cad_cmode_0
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad)
+ (void* cad)
{
res_T res = RES_OK;
struct data_cad_cmode_0* data_cad = (struct data_cad_cmode_0 *)cad;
+ struct mem_allocator* allocator;
size_t i;
- (void)logger;
- if(!allocator || ! cad) {
+ if(!cad) {
res = RES_BAD_ARG;
goto error;
}
+ allocator = data_cad->allocator;
+ darray_common_trg_release(&data_cad->common_trg);
+ darray_geometries_release(&data_cad->adj_walls);
+
#define GDEL(Field) \
- if(data_cad->Field) SCAD(geometry_delete(data_cad->Field)); \
+ if(data_cad->Field) SCAD(geometry_ref_put(data_cad->Field)); \
/* To ease debugging, set to NULL after deletion */ \
data_cad->Field = NULL
GDEL(cavity);
@@ -772,15 +895,14 @@ release_cad_cmode_0
GDEL(roof);
GDEL(wall);
GDEL(fake_ground);
- GDEL(boundary[0]);
- GDEL(boundary[1]);
+ GDEL(boundary_wall);
+ GDEL(boundary_roof);
for(i = 0; i < data_cad->n_connection; i++) {
GDEL(connection[i]);
}
- MEM_RM(allocator, data_cad->boundary);
+#undef GDEL
MEM_RM(allocator, data_cad->connection);
MEM_RM(allocator, data_cad);
-#undef GDEL
exit:
return res;
diff --git a/src/cg_construction_mode_0.h b/src/cg_construction_mode_0.h
@@ -20,17 +20,20 @@
#ifndef Construction_MODE_0_H
#define Construction_MODE_0_H
+#include "cg_construction_mode.h"
+
#include <rsys/rsys.h>
#include <rsys/str.h>
+#include <rsys/dynamic_array.h>
#include <rsys/hash_table.h>
struct scad_geometry;
struct building;
-struct mem_allocator;
-struct logger;
struct parsed_city_building;
struct catalog;
-struct scpr_device;
+struct city;
+struct darray_double;
+struct darray_adjoining_data;
/* specific data for construction mode 0 */
struct dataset_cmode_0 {
@@ -51,12 +54,16 @@ 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 scad_geometry* wall;
struct scad_geometry* roof;
struct scad_geometry* floor;
struct scad_geometry* cavity;
struct scad_geometry* fake_ground;
- struct scad_geometry** boundary;
+ struct scad_geometry* boundary_wall;
+ struct scad_geometry* boundary_roof;
struct scad_geometry** connection;
struct scad_geometry* ground_connection;
size_t n_connection;
@@ -64,11 +71,8 @@ struct data_cad_cmode_0 {
res_T
init_cmode_0
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- int keep_running_on_error,
+ (struct building* building,
+ struct city* city,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
@@ -76,46 +80,33 @@ init_cmode_0
res_T
release_cmode_0
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building);
+ (struct building* building);
res_T
build_cad_cmode_0
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
int dump_footprints_on_error,
int keep_running_on_errors,
+ struct darray_adjoining_data* adjoining_data,
void** cad);
res_T
build_footprint_cmode_0
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** footprint);
res_T
build_envelop_cmode_0
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** envelop);
res_T
export_stl_cmode_0
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad,
+ (void* cad,
const int binary);
res_T
release_cad_cmode_0
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad);
+ (void* cad);
#endif /* Construction_MODE_0_H */
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_default.h"
#include "cg_building.h"
#include "cg_catalog.h"
#include "cg_city.h"
@@ -28,37 +29,17 @@
#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>
-/* An htable to associate offset polygons to offsets.
- * Not really to avoid offseting more than once to the same offset, but to avoid
- * considering the same polygon more than once when checking for polygon
- * intersections (that are internal errors). */
-static FINLINE void
-ptr_polygon_init
- (struct mem_allocator* alloc, struct scpr_polygon** data)
-{
- ASSERT(data); (void)alloc;
- *data = NULL;
-}
-static FINLINE void
-ptr_polygon_release(struct scpr_polygon** data)
-{
- ASSERT(data);
- if(*data) SCPR(polygon_ref_put(*data));
-}
-#define HTABLE_NAME polygons
-#define HTABLE_KEY double
-#define HTABLE_DATA struct scpr_polygon*
-#define HTABLE_DATA_FUNCTOR_INIT ptr_polygon_init
-#define HTABLE_DATA_FUNCTOR_RELEASE ptr_polygon_release
-#include <rsys/hash_table.h>
-
static res_T
build_floor
(struct scpr_device* scpr,
struct mem_allocator* allocator,
+ struct logger* logger,
+ int *error_msg_printed,
+ int keep_running_on_errors,
const char* prefix,
const struct scpr_polygon* pg,
const struct dataset_cmode_1* data,
@@ -95,8 +76,20 @@ build_floor
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);
}
@@ -109,7 +102,8 @@ build_floor
ERR(scad_geometry_extrude(footprint, floorname, d, floor));
exit:
- SCAD(geometry_delete(footprint));
+ if(footprint) SCAD(geometry_ref_put(footprint));
+ if(!ptr_p) SCPR(polygon_ref_put(pg_int));
if (is_init) str_release(&name);
return res;
error:
@@ -135,7 +129,8 @@ build_wall
double offset = 0;
struct scpr_polygon* pg_int = NULL;
struct scpr_polygon* pg_ext = NULL;
- struct scpr_polygon** ptr_p;
+ 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;
@@ -163,9 +158,9 @@ build_wall
} else {
offset = -e_insulation;
}
- ptr_p = htable_polygons_find(polygons, &offset);
- if(ptr_p) {
- pg_ext = *ptr_p;
+ 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));
@@ -174,9 +169,9 @@ build_wall
}
offset = -(e_wall + e_insulation);
- ptr_p = htable_polygons_find(polygons, &offset);
- if(ptr_p) {
- pg_int = *ptr_p;
+ 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));
@@ -200,9 +195,11 @@ build_wall
ERR(scad_geometry_extrude(footprint, wallname, d, wall));
exit:
- SCAD(geometry_delete(footprint));
- SCAD(geometry_delete(footprint_int));
- SCAD(geometry_delete(footprint_ext));
+ 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);
return res;
error:
@@ -232,7 +229,8 @@ build_int_insulation
double offset = 0;
struct scpr_polygon* pg_int = NULL;
struct scpr_polygon* pg_ext = NULL;
- struct scpr_polygon** ptr_p;
+ 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;
@@ -254,9 +252,9 @@ build_int_insulation
}
offset = -(e_ext_insulation + e_wall);
- ptr_p = htable_polygons_find(polygons, &offset);
- if(ptr_p) {
- pg_ext = *ptr_p;
+ 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));
@@ -265,9 +263,9 @@ build_int_insulation
}
offset = -(e_ext_insulation + e_wall + e_int_insulation);
- ptr_p = htable_polygons_find(polygons, &offset);
- if(ptr_p) {
- pg_int = *ptr_p;
+ 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));
@@ -295,10 +293,12 @@ build_int_insulation
}
exit:
- SCAD(geometry_delete(footprint));
- SCAD(geometry_delete(footprint_int));
- SCAD(geometry_delete(footprint_ext));
- SCAD(geometry_delete(geom));
+ 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);
return res;
error:
@@ -362,7 +362,7 @@ build_roof
ERR(scad_geometry_extrude(footprint, roofname, d, roof));
exit:
- SCAD(geometry_delete(footprint));
+ if(footprint) SCAD(geometry_ref_put(footprint));
if (is_init) str_release(&name);
return res;
error:
@@ -429,7 +429,7 @@ build_roof_insulation
ERR(scad_geometry_extrude(footprint, insulationname, d, insulation));
exit:
- SCAD(geometry_delete(footprint));
+ if(footprint) SCAD(geometry_ref_put(footprint));
if (is_init) str_release(&name);
return res;
error:
@@ -494,7 +494,7 @@ build_floor_insulation
ERR(scad_geometry_extrude(footprint, insulationname, d, insulation));
exit:
- SCAD(geometry_delete(footprint));
+ if(footprint) SCAD(geometry_ref_put(footprint));
if (is_init) str_release(&name);
return res;
error:
@@ -530,6 +530,7 @@ build_inter_floor
size_t nverts = 0;
struct scad_geometry** floor_list = NULL;
struct darray_geometries floor_array;
+ struct scad_geometry *footprint = NULL, *floor = NULL;
double d[3] = {0, 0, 0};
char* floorname = NULL;
struct str name;
@@ -563,14 +564,14 @@ build_inter_floor
z_floor = h_cavity/(double)(1 + floor_n);
d[2] = e_floor;
for (i = 0; i < floor_n; i++) {
- struct scad_geometry* floor = NULL;
- struct scad_geometry* footprint = NULL;
-
- ERR(scad_add_polygon(
- NULL, get_position_pg, pg_int, z_floor, nverts, &footprint));
+ 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));
+ footprint = NULL; /* Avoid double free */
ERR(darray_geometries_push_back(&floor_array, &floor));
- ERR(scad_geometry_delete(footprint));
+ ERR(scad_geometry_ref_put(floor));
+ floor = NULL; /* Avoid double free */
z_floor += h_cavity/(double)(1 + floor_n) + e_floor;
}
ASSERT(darray_geometries_size_get(&floor_array) == floor_n);
@@ -581,13 +582,9 @@ build_inter_floor
exit:
if (is_init) str_release(&name);
- floor_list = darray_geometries_data_get(&floor_array);
- if(floor_list) {
- for (i = 0; i < floor_n; i++) {
- SCAD(geometry_delete(floor_list[i]));
- }
- darray_geometries_release(&floor_array);
- }
+ if(footprint) SCAD(geometry_ref_put(footprint));
+ if(floor) SCAD(geometry_ref_put(floor));
+ if(floor_list) darray_geometries_release(&floor_array);
return res;
error:
goto exit;
@@ -662,9 +659,9 @@ build_ext_insulation
ERR(scad_geometry_extrude(footprint, insulationname, d, insulation));
exit:
- SCAD(geometry_delete(footprint));
- SCAD(geometry_delete(footprint_int));
- SCAD(geometry_delete(footprint_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);
return res;
error:
@@ -730,7 +727,7 @@ build_crawlspace
ERR(scad_geometry_extrude(footprint, crawlname, d, crawlspace));
exit:
- SCAD(geometry_delete(footprint));
+ if(footprint) SCAD(geometry_ref_put(footprint));
if (is_init) str_release(&name);
return res;
error:
@@ -804,8 +801,8 @@ build_habitable
}
exit:
- SCAD(geometry_delete(footprint));
- SCAD(geometry_delete(geom));
+ if(footprint) SCAD(geometry_ref_put(footprint));
+ if(geom) SCAD(geometry_ref_put(geom));
if (is_init) str_release(&name);
return res;
error:
@@ -871,7 +868,7 @@ build_attic
ERR(scad_geometry_extrude(footprint, atticname, d, attic));
exit:
- SCAD(geometry_delete(footprint));
+ if(footprint) SCAD(geometry_ref_put(footprint));
if (is_init) str_release(&name);
return res;
error:
@@ -886,11 +883,10 @@ build_windows
const char* prefix,
const struct dataset_cmode_1* data,
struct data_cad_cmode_1* data_cad,
- struct scad_geometry** adjoining_cad,
- size_t adjoining_n)
+ struct darray_adjoining_data* adjoining_data)
{
res_T res = RES_OK;
- size_t i, removed_windows = 0;
+ size_t i, j, adjoining_n, removed_windows = 0;
double N[3];
double dir[3];
double scale[3];
@@ -902,60 +898,64 @@ build_windows
struct scad_geometry* hole_adjoining_intersect = NULL;
struct scad_geometry* bcavity = NULL;
struct scad_geometry** list = NULL;
+ struct scad_geometry** adj_list = NULL;
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 adjoining_data* adj;
(void)scpr;
- ASSERT(scpr && allocator && logger && data && data_cad);
+ ASSERT(scpr && allocator && logger && data && data_cad && adjoining_data);
+ 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);
- scale[0] = sqrt(data->glass_ratio);
- scale[1] = scale[0];
- scale[2] = scale[0];
+ d3_splat(scale, 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));
for (i = 0; i < list_n; i++) {
- double center[3];
+ double hsz, center[3];
size_t center_n;
size_t count;
ERR(scad_geometry_get_count(list[i], ¢er_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[2] != 0) {
- ERR(scad_geometry_delete(surface));
+ ERR(scad_geometry_ref_put(surface));
surface = NULL;
continue; /* keep only vertical face */
}
ERR(scad_geometry_dilate(surface, center, scale));
- dir[0] = 1.1*N[0] * (data->wall_thickness
- + data->internal_insulation_thickness + data->external_insulation_thickness);
- dir[1] = 1.1*N[1] * (data->wall_thickness
- + data->internal_insulation_thickness + data->external_insulation_thickness);
- dir[2] = 1.1*N[2] * (data->wall_thickness
- + data->internal_insulation_thickness + data->external_insulation_thickness);
+ /* 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));
- /* check if hole intersect adjoining_cad */
- /* push only if no intersect */
- if (adjoining_cad) {
- ERR(scad_intersect_geometries(NULL, &hole, 1, adjoining_cad, adjoining_n,
+ /* Check if hole intersects adjoining envelops */
+ /* Push only if don't intersect */
+ if (adjoining_n) {
+ 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));
ERR(scad_geometry_get_count(hole_adjoining_intersect, &count));
+ ERR(scad_geometry_ref_put(hole_adjoining_intersect));
+ hole_adjoining_intersect = NULL;
} else {
count = 0;
}
@@ -968,14 +968,14 @@ build_windows
dir[2] = N[2] * 0.024;
ERR(scad_geometry_extrude(surface, NULL, dir, &glass));
ERR(darray_geometries_push_back(&glass_array, &glass));
+ ERR(scad_geometry_ref_put(glass));
+ glass = NULL;
} else {
removed_windows++;
- ERR(scad_geometry_delete(hole));
- hole = NULL;
- ERR(scad_geometry_delete(hole_adjoining_intersect));
- hole_adjoining_intersect = NULL;
}
- ERR(scad_geometry_delete(surface));
+ ERR(scad_geometry_ref_put(hole));
+ hole = NULL;
+ ERR(scad_geometry_ref_put(surface));
surface = NULL;
}
ASSERT(darray_geometries_size_get(&hole_array)
@@ -997,7 +997,7 @@ build_windows
ERR(scad_cut_geometries(NULL, &data_cad->wall, 1,
hole_list, array_n, &geom));
ERR(scad_geometry_swap_names(data_cad->wall, geom));
- ERR(scad_geometry_delete(data_cad->wall));
+ ERR(scad_geometry_ref_put(data_cad->wall));
data_cad->wall = geom;
geom = NULL;
@@ -1006,7 +1006,7 @@ build_windows
ERR(scad_cut_geometries(NULL, &data_cad->internal_insulation, 1,
hole_list, array_n, &geom));
ERR(scad_geometry_swap_names(data_cad->internal_insulation, geom));
- ERR(scad_geometry_delete(data_cad->internal_insulation));
+ ERR(scad_geometry_ref_put(data_cad->internal_insulation));
data_cad->internal_insulation = geom;
geom = NULL;
}
@@ -1016,7 +1016,7 @@ build_windows
ERR(scad_cut_geometries(NULL, &data_cad->external_insulation, 1,
hole_list, array_n, &geom));
ERR(scad_geometry_swap_names(data_cad->external_insulation, geom));
- ERR(scad_geometry_delete(data_cad->external_insulation));
+ ERR(scad_geometry_ref_put(data_cad->external_insulation));
data_cad->external_insulation = geom;
geom = NULL;
}
@@ -1034,25 +1034,18 @@ build_windows
}
exit:
- glass_list = darray_geometries_data_get(&glass_array);
for (i = 0 ; i < list_n; i++) {
- SCAD(geometry_delete(list[i]));
- }
- for (i = 0 ; i < darray_geometries_size_get(&hole_array); i++) {
- struct scad_geometry* h = darray_geometries_data_get(&hole_array)[i];
- SCAD(geometry_delete(h));
- }
- for (i = 0 ; i <darray_geometries_size_get(&glass_array); i++) {
- struct scad_geometry* g = darray_geometries_data_get(&glass_array)[i];
- SCAD(geometry_delete(g));
+ if(list[i]) SCAD(geometry_ref_put(list[i]));
}
darray_geometries_release(&hole_array);
darray_geometries_release(&glass_array);
- if (surface) SCAD(geometry_delete(surface));
- if (geom) SCAD(geometry_delete(geom));
- if (bcavity) SCAD(geometry_delete(bcavity));
- if (hole_adjoining_intersect) SCAD(geometry_delete(hole_adjoining_intersect));
+ 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));
MEM_RM(allocator, list);
+ MEM_RM(allocator, adj_list);
if (is_init) str_release(&gname);
return res;
error:
@@ -1065,32 +1058,34 @@ build_boundary
struct mem_allocator* allocator,
const char* prefix,
struct data_cad_cmode_1* data_cad,
- struct scad_geometry** adjoining_cad,
- size_t adjoining_n,
+ struct darray_adjoining_data* adjoining_data,
struct darray_geometries* boundary)
{
res_T res = RES_OK;
- size_t count;
struct darray_geometries array;
struct scad_geometry** list = NULL;
- struct darray_geometries bound_array;
struct scad_geometry* bound = NULL;
char* boundaryname = NULL;
struct str name;
int is_init = 0;
- size_t i = 0;
+ struct adjoining_data* adj;
+ size_t adjoining_n, i = 0, count = 0;
(void)scpr;
- ASSERT(allocator && prefix && data_cad && boundary);
+ ASSERT(allocator && prefix && data_cad && adjoining_data && boundary);
+ adjoining_n = darray_adjoining_data_size_get(adjoining_data);
+ adj = darray_adjoining_data_data_get(adjoining_data);
darray_geometries_init(allocator, &array);
- darray_geometries_init(allocator, &bound_array);
-
str_init(allocator, &name);
is_init = 1;
/* Ensure enough room for all geometries without error nor mem move */
ERR(darray_geometries_reserve(&array, 14 + adjoining_n));
+ /* Using wall here to compute boundary_wall is OK even if it doesn't take care
+ * 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. */
ERR(darray_geometries_push_back(&array, &data_cad->wall));
ERR(darray_geometries_push_back(&array, &data_cad->roof));
ERR(darray_geometries_push_back(&array, &data_cad->floor));
@@ -1124,7 +1119,7 @@ build_boundary
ERR(darray_geometries_push_back(&array, &data_cad->glass));
}
for (i=0; i<adjoining_n; i++) {
- ERR(darray_geometries_push_back(&array, adjoining_cad + i));
+ ERR(darray_geometries_push_back(&array, &adj[i].envelop));
}
count = darray_geometries_size_get(&array);
@@ -1139,6 +1134,8 @@ build_boundary
ERR(scad_geometries_common_boundaries(boundaryname, list, count,
&data_cad->wall, 1, &bound));
ERR(darray_geometries_push_back(boundary, &bound));
+ ERR(scad_geometry_ref_put(bound));
+ bound = NULL;
ERR(str_set(&name, prefix));
ERR(str_append(&name, "_B_roof"));
@@ -1146,6 +1143,8 @@ build_boundary
ERR(scad_geometries_common_boundaries(boundaryname, list, count,
&data_cad->roof, 1, &bound));
ERR(darray_geometries_push_back(boundary, &bound));
+ ERR(scad_geometry_ref_put(bound));
+ bound = NULL;
if (data_cad->glass) {
ERR(str_set(&name, prefix));
@@ -1154,6 +1153,8 @@ build_boundary
ERR(scad_geometries_common_boundaries(boundaryname, list, count,
&data_cad->glass, 1, &bound));
ERR(darray_geometries_push_back(boundary, &bound));
+ ERR(scad_geometry_ref_put(bound));
+ bound = NULL;
}
if (data_cad->external_insulation) {
@@ -1163,6 +1164,8 @@ build_boundary
ERR(scad_geometries_common_boundaries(boundaryname, list, count,
&data_cad->external_insulation, 1, &bound));
ERR(darray_geometries_push_back(boundary, &bound));
+ ERR(scad_geometry_ref_put(bound));
+ bound = NULL;
}
if (data_cad->internal_insulation) {
@@ -1175,12 +1178,13 @@ build_boundary
ERR(scad_geometry_get_count(bound, &bcount));
if (bcount > 0) {
ERR(darray_geometries_push_back(boundary, &bound));
- } else {
- SCAD(geometry_delete(bound));
}
+ ERR(scad_geometry_ref_put(bound));
+ bound = NULL;
}
exit:
+ if(bound) SCAD(geometry_ref_put(bound));
if (is_init) str_release(&name);
darray_geometries_release(&array);
return res;
@@ -1217,9 +1221,9 @@ build_connection
ERR(scad_geometry_get_count(connect, &count)); \
if (count > 0) { \
ERR(darray_geometries_push_back(connection, &connect)); \
- } else { \
- SCAD(geometry_delete(connect)); \
- }
+ } \
+ ERR(scad_geometry_ref_put(connect)); \
+ connect = NULL;
/* -------------------------------------------------------------------------*/
/* habitable cavity connections */
@@ -1370,8 +1374,8 @@ build_fake_ground
exit:
if (pg_offset) SCPR(polygon_ref_put(pg_offset));
darray_geometries_release(&array);
- if (footprint) SCAD(geometry_delete(footprint));
- if (geom) SCAD(geometry_delete(geom));
+ if (footprint) SCAD(geometry_ref_put(footprint));
+ if (geom) SCAD(geometry_ref_put(geom));
return res;
error:
goto exit;
@@ -1436,8 +1440,8 @@ building_ground_connection
exit:
darray_geometries_release(&array);
if (is_init) str_release(&name);
- if (list_boundary) SCAD(geometry_delete(list_boundary));
- if (footprint) SCAD(geometry_delete(footprint));
+ if (list_boundary) SCAD(geometry_ref_put(list_boundary));
+ if (footprint) SCAD(geometry_ref_put(footprint));
return res;
error:
goto exit;
@@ -1449,11 +1453,8 @@ error:
res_T
init_cmode_1
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- int keep_running_on_error,
+ (struct building* building,
+ struct city* city,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
@@ -1462,8 +1463,7 @@ init_cmode_1
res_T res = RES_OK;
struct str dataset_name;
int name_initialized = 0;
- static struct construction_mode_functors functors_1
- = {
+ static struct construction_mode_functors functors_1 = {
&init_cmode_1,
&release_cmode_1,
&build_cad_cmode_1,
@@ -1472,20 +1472,21 @@ init_cmode_1
&export_stl_cmode_1,
&release_cad_cmode_1
};
+ struct mem_allocator* allocator;
+ struct logger* logger;
(void) parsed_data;
- if(!scpr || !allocator || !logger || !building || !parsed_data || !catalog
- || !lower || !upper)
- {
+ if(!building || !city || !parsed_data || !catalog || !lower || !upper) {
res = RES_BAD_ARG;
goto error;
}
+ allocator = city->allocator;
+ logger = city->logger;
building->construction_mode = mode_1;
building->functors = &functors_1;
- ERR(init_building_base(scpr, allocator, logger, building,
- keep_running_on_error, parsed_data, lower, upper));
+ ERR(init_building_base(building, city, parsed_data, lower, upper));
str_init(allocator, &dataset_name);
name_initialized = 1;
@@ -1509,78 +1510,66 @@ error:
res_T
release_cmode_1
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building)
+ (struct building* building)
{
- res_T res = RES_OK;
-
- if(!allocator || !logger || !building) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- ERR(release_building_base(allocator, logger, building));
-
-exit:
- return res;
-error:
- goto exit;
+ if(!building) return RES_BAD_ARG;
+ return release_building_base(building);
}
-
res_T
build_cad_cmode_1
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
int dump_footprints_on_error,
int keep_running_on_errors,
+ struct darray_adjoining_data* adjoining_data,
void** cad)
{
res_T res = RES_OK;
double height = building->height;
double depth = 0;
- struct scpr_polygon* pg = NULL;
struct dataset_cmode_1* data = (struct dataset_cmode_1 *)building->data;
struct data_cad_cmode_1* data_cad = NULL;
const char* name;
struct scpr_intersector* overlapping_intersector = NULL;
struct scpr_intersector_check_callbacks callbacks
= SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__;
- struct scad_geometry** adjoining_cad = NULL;
- size_t i = 0;
size_t adjoining_n = 0;
struct callback_ctx ctx;
- int error_occured = 0;
+ int error_occured = 0, error_msg_printed = 0;;
struct htable_polygons polygons;
int polygons_initialized = 0;
double zero = 0;
+ struct scpr_device* scpr;
+ struct mem_allocator* allocator;
+ struct logger* logger;
- if (!building || !allocator || !cad) {
+ if (!building || !cad || !adjoining_data) {
res = RES_BAD_ARG;
goto error;
}
- adjoining_n = htable_building_size_get(&building->close_buildings);
+ scpr = building->city->scpr;
+ allocator = building->city->allocator;
+ logger = building->city->logger;
data_cad = MEM_CALLOC(allocator, 1, sizeof(struct data_cad_cmode_1));
if(!data_cad) {
res = RES_MEM_ERR;
goto error;
}
+ data_cad->allocator = allocator;
darray_geometries_init(allocator, &data_cad->boundary);
darray_geometries_init(allocator, &data_cad->connection);
+ darray_common_trg_init(allocator, &data_cad->common_trg);
+ darray_geometries_init(allocator, &data_cad->adj_walls);
htable_polygons_init(allocator, &polygons);
polygons_initialized = 1;
ERR(scpr_intersector_create(scpr, &overlapping_intersector));
-
- /* Register the original polygon with offset 0; as polygons in the htable are
- * ref_put, register a copy! */
- ERR(scpr_polygon_create_copy(scpr, building->pg, &pg));
- ERR(scpr_intersector_register_polygon(overlapping_intersector, pg));
- ERR(htable_polygons_set(&polygons, &zero, &pg));
+ 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
+ * checking for polygon intersections (that would be an error). */
+ ERR(htable_polygons_set(&polygons, &zero, &building->pg));
/* build mandatories elements :
- floor
@@ -1589,13 +1578,14 @@ build_cad_cmode_1
*/
name = str_cget(&building->name);
- ERR(build_floor(scpr, allocator, name, pg, data, overlapping_intersector,
+ 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_wall(scpr, allocator, name, "S_walls", pg, height, data,
+ ERR(build_wall(scpr, allocator, name, "S_walls", building->pg, height, data,
overlapping_intersector, &polygons, &data_cad->wall));
- ERR(build_roof(scpr, allocator, name, pg, height, data,
+ ERR(build_roof(scpr, allocator, name, building->pg, height, data,
overlapping_intersector, &polygons, &data_cad->roof));
/* build optionnal elements :
@@ -1609,33 +1599,33 @@ build_cad_cmode_1
if (data->foundation_depth > 0) {
depth = -data->foundation_depth;
- ERR(build_wall(scpr, allocator, name, "S_foundation", pg, depth, data,
+ ERR(build_wall(scpr, allocator, name, "S_foundation", building->pg, depth, data,
overlapping_intersector, &polygons, &data_cad->foundation));
}
if (data->inter_floor_count > 0) {
- ERR(build_inter_floor(scpr, allocator, name, pg, height, data,
+ ERR(build_inter_floor(scpr, allocator, name, building->pg, height, data,
overlapping_intersector, &polygons, &data_cad->intermediate_floor));
}
if (data->external_insulation_thickness> 0) {
- ERR(build_ext_insulation(scpr, allocator, name, pg, height, data,
+ ERR(build_ext_insulation(scpr, allocator, name, building->pg, height, data,
overlapping_intersector, &polygons, &data_cad->external_insulation));
}
if (data->internal_insulation_thickness> 0) {
- ERR(build_int_insulation(scpr, allocator, name, pg, height, data,
+ ERR(build_int_insulation(scpr, allocator, name, building->pg, height, data,
data_cad->intermediate_floor, overlapping_intersector, &polygons,
&data_cad->internal_insulation));
}
if (data->roof_insulation_thickness > 0) {
- ERR(build_roof_insulation(scpr, allocator, name, pg, height, data,
+ ERR(build_roof_insulation(scpr, allocator, name, building->pg, height, data,
overlapping_intersector, &polygons, &data_cad->roof_insulation));
}
if (data->floor_insulation_thickness > 0) {
- ERR(build_floor_insulation(scpr, allocator, name, pg, data,
+ ERR(build_floor_insulation(scpr, allocator, name, building->pg, data,
overlapping_intersector, &polygons, &data_cad->floor_insulation));
}
@@ -1646,56 +1636,107 @@ build_cad_cmode_1
*/
if (data->attic_height > 0) {
- ERR(build_attic(scpr, allocator, name, pg, height, data,
+ ERR(build_attic(scpr, allocator, name, building->pg, height, data,
overlapping_intersector, &polygons, &data_cad->attic_cavity));
}
- ERR(build_habitable(scpr, allocator, name, pg, height, data,
+ ERR(build_habitable(scpr, allocator, name, building->pg, height, data,
data_cad->intermediate_floor, overlapping_intersector, &polygons,
&data_cad->habitable_cavity));
if (data->crawl_height > 0) {
- ERR(build_crawlspace(scpr, allocator, name, pg, data,
+ ERR(build_crawlspace(scpr, allocator, name, building->pg, data,
overlapping_intersector, &polygons, &data_cad->crawlspace_cavity));
}
- /* Check for polygons overlapping */
- ctx.allocator = allocator;
- ctx.logger = logger;
+ /* Check for registered polygons overlapping */
+ ctx.city = building->city;
ctx.buildings = building;
ctx.buildings_count = 1;
ctx.intersection_found = &error_occured;
- /* build adjoining envelop */
- if (adjoining_n > 0) {
- ERR(build_adjoining(allocator, logger, building, &adjoining_cad));
- }
-
ctx.search_type = OVERLAPPING_PROXIMITY;
ctx.dump_footprints_on_error = dump_footprints_on_error;
ctx.keep_running_on_errors = keep_running_on_errors;
callbacks.simple_intersection = simple_intersection;
ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx));
+ if(error_occured) {
+ logger_print(logger, LOG_ERROR,
+ "Internal error building CAD for building '%s'.\n",
+ str_cget(&building->name));
+ ERR(darray_pbuilding_push_back(&building->city->removed_buildings, &building));
+ error_msg_printed = 1;
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* build adjoining envelop */
+ adjoining_n = htable_building_size_get(&building->close_buildings);
+ if (adjoining_n > 0) {
+ ERR(build_adjoining(building, 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_cad, adjoining_n));
+ ERR(build_windows(scpr, allocator, logger, name, data, data_cad, adjoining_data));
}
/* fake ground */
depth = MMAX(data->foundation_depth,
data->floor_thickness + data->floor_insulation_thickness + data->crawl_height);
- ERR(build_fake_ground(scpr, allocator, data_cad, pg, depth, &data_cad->fake_ground));
+ ERR(build_fake_ground(scpr, allocator, data_cad, building->pg, depth,
+ &data_cad->fake_ground));
ERR(scad_scene_partition());
+ /* 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 adjoining_data* adjoining
+ = darray_adjoining_data_data_get(adjoining_data);
+ struct scad_geometry* extern_most = data_cad->external_insulation
+ ? data_cad->external_insulation : data_cad->wall;
+ for(a = 0; a < adjoining_n; a++) {
+ struct adjoining_data* adj = adjoining + a;
+ 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 */
+ logger_print(logger, LOG_OUTPUT,
+ "building '%s': neighbor '%s' not really adjoining.\n",
+ str_cget(&building->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 {
+ /* 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;
+ }
+ }
+ }
+
/* build ground/building connection */
ERR(building_ground_connection(scpr, allocator, name, data_cad,
&data_cad->ground_connection));
/* build boundaries */
- ERR(build_boundary(scpr, allocator, name, data_cad, adjoining_cad, adjoining_n,
+ ERR(build_boundary(scpr, allocator, name, data_cad, adjoining_data,
&data_cad->boundary));
/* build connections */
@@ -1704,28 +1745,25 @@ build_cad_cmode_1
exit:
if(polygons_initialized) htable_polygons_release(&polygons);
if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector));
- *(struct data_cad_cmode_1**)cad = data_cad;
- for (i=0; i<adjoining_n; i++) {
- if (adjoining_cad[i]) scad_geometry_delete(adjoining_cad[i]);
- }
- if (adjoining_cad) MEM_RM(allocator, adjoining_cad);
+ if(cad) *(struct data_cad_cmode_1**)cad = data_cad;
return res;
error:
- if(data_cad) CHK(RES_OK == release_cad_cmode_1(allocator, logger, data_cad));
+ if(building && !error_msg_printed) {
+ logger_print(logger, LOG_ERROR,
+ "Unknown error building CAD for building '%s'.\n",
+ str_cget(&building->name));
+ }
+ if(data_cad) CHK(RES_OK == release_cad_cmode_1(data_cad));
data_cad = NULL;
goto exit;
}
res_T
build_footprint_cmode_1
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** footprint)
{
res_T res = RES_OK;
- (void)scpr; (void)allocator; (void)logger;
if (!building || !footprint) {
res = RES_BAD_ARG;
@@ -1742,9 +1780,7 @@ error:
res_T
build_envelop_cmode_1
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** envelop)
{
res_T res = RES_OK;
@@ -1754,8 +1790,6 @@ build_envelop_cmode_1
struct scpr_polygon* pg = building->pg;
struct scad_geometry* footprint = NULL;
- (void)allocator; (void)logger;
-
ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts));
ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &footprint));
@@ -1764,7 +1798,7 @@ build_envelop_cmode_1
ERR(scad_geometry_extrude(footprint, NULL, d, envelop));
exit:
- if (footprint) scad_geometry_delete(footprint);
+ if (footprint) SCAD(geometry_ref_put(footprint));
return res;
error:
goto exit;
@@ -1772,15 +1806,12 @@ error:
res_T
export_stl_cmode_1
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad,
+ (void* cad,
const int binary)
{
res_T res = RES_OK;
struct data_cad_cmode_1* data_cad = (struct data_cad_cmode_1 *)cad;
size_t i = 0;
- (void)allocator; (void)logger;
if (!cad) {
res = RES_BAD_ARG;
@@ -1788,76 +1819,77 @@ export_stl_cmode_1
}
/* floor export */
- ERR(scad_stl_export(data_cad->floor, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->floor, NULL, binary));
/* wall export */
- ERR(scad_stl_export(data_cad->wall, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->wall, NULL, binary));
/* roof export */
- ERR(scad_stl_export(data_cad->roof, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->roof, NULL, binary));
/* foundation export */
if (data_cad->foundation) {
- ERR(scad_stl_export(data_cad->foundation, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->foundation, NULL, binary));
}
/* glass export */
if (data_cad->glass) {
- ERR(scad_stl_export(data_cad->glass, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->glass, NULL, binary));
}
/* intermediate floor export*/
if (data_cad->intermediate_floor) {
- ERR(scad_stl_export(data_cad->intermediate_floor, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->intermediate_floor, NULL, binary));
}
/* internal insulation export*/
if (data_cad->internal_insulation) {
- ERR(scad_stl_export(data_cad->internal_insulation, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->internal_insulation, NULL, binary));
}
/* external insulation export*/
if (data_cad->external_insulation) {
- ERR(scad_stl_export(data_cad->external_insulation, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->external_insulation, NULL, binary));
}
/* roof insulation export*/
if (data_cad->roof_insulation) {
- ERR(scad_stl_export(data_cad->roof_insulation, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->roof_insulation, NULL, binary));
}
/* floor insulation export*/
if (data_cad->floor_insulation) {
- ERR(scad_stl_export(data_cad->floor_insulation, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->floor_insulation, NULL, binary));
}
/* attic cavity export*/
if (data_cad->attic_cavity) {
- ERR(scad_stl_export(data_cad->attic_cavity, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->attic_cavity, NULL, binary));
}
/* habitable cavity export*/
- ERR(scad_stl_export(data_cad->habitable_cavity, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->habitable_cavity, NULL, binary));
/* crawlspace cavity export*/
if (data_cad->crawlspace_cavity) {
- ERR(scad_stl_export(data_cad->crawlspace_cavity, NULL, 0, binary));
+ ERR(scad_stl_export(data_cad->crawlspace_cavity, NULL, 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, 0, binary));
+ ERR(scad_stl_export(b, NULL, 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, 0, binary));
+ ERR(scad_stl_export(c, NULL, binary));
}
/* ground/building connection export*/
- ERR(scad_stl_export(data_cad->ground_connection, NULL, 1, binary));
+ ERR(scad_geometry_reverse(data_cad->ground_connection));
+ ERR(scad_stl_export(data_cad->ground_connection, NULL, binary));
exit:
return res;
@@ -1867,22 +1899,25 @@ error:
res_T
release_cad_cmode_1
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad)
+ (void* cad)
{
res_T res = RES_OK;
struct data_cad_cmode_1* data_cad = (struct data_cad_cmode_1 *)cad;
- size_t i;
- (void)logger;
+ struct mem_allocator* allocator;
- if (!allocator || !cad) {
+ if (!cad) {
res = RES_BAD_ARG;
goto error;
}
+ allocator = data_cad->allocator;
+ darray_geometries_release(&data_cad->boundary);
+ darray_geometries_release(&data_cad->connection);
+ darray_common_trg_release(&data_cad->common_trg);
+ darray_geometries_release(&data_cad->adj_walls);
+
#define GDEL(Field) \
- if(data_cad->Field) SCAD(geometry_delete(data_cad->Field)); \
+ if(data_cad->Field) SCAD(geometry_ref_put(data_cad->Field)); \
/* To ease debugging, write NULL after deletion */ \
data_cad->Field = NULL
GDEL(attic_cavity);
@@ -1900,18 +1935,8 @@ release_cad_cmode_1
GDEL(roof);
GDEL(roof_insulation);
GDEL(wall);
- for(i = 0; i < darray_geometries_size_get(&data_cad->boundary); i++) {
- struct scad_geometry* b = darray_geometries_data_get(&data_cad->boundary)[i];
- ERR(scad_geometry_delete(b));
- }
- 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_geometry_delete(c));
- }
- darray_geometries_release(&data_cad->boundary);
- darray_geometries_release(&data_cad->connection);
- MEM_RM(allocator, data_cad);
#undef GDEL
+ MEM_RM(allocator, data_cad);
exit:
return res;
diff --git a/src/cg_construction_mode_1.h b/src/cg_construction_mode_1.h
@@ -20,6 +20,8 @@
#ifndef Construction_MODE_1_H
#define Construction_MODE_1_H
+#include "cg_construction_mode.h"
+
#include <rsys/rsys.h>
#include <rsys/str.h>
#include <rsys/hash_table.h>
@@ -27,15 +29,9 @@
struct scad_geometry;
struct building;
-struct mem_allocator;
-struct logger;
+struct city;
struct parsed_city_building;
struct catalog;
-struct scpr_device;
-
-#define DARRAY_NAME geometries
-#define DARRAY_DATA struct scad_geometry*
-#include <rsys/dynamic_array.h>
/* specific data for construction mode 1 */
struct dataset_cmode_1 {
@@ -67,6 +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 scad_geometry* wall;
struct scad_geometry* roof;
struct scad_geometry* floor;
@@ -82,18 +83,13 @@ struct data_cad_cmode_1 {
struct scad_geometry* glass;
struct scad_geometry* fake_ground;/*not exported, used for ground connection*/
struct scad_geometry* ground_connection;
- struct darray_geometries boundary;
- struct darray_geometries connection;
size_t n_connection;
};
res_T
init_cmode_1
- (struct scpr_device* device,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
- int keep_running_on_error,
+ (struct building* building,
+ struct city* city,
struct parsed_city_building* parsed_data,
struct catalog* catalog,
const double lower[2],
@@ -101,46 +97,33 @@ init_cmode_1
res_T
release_cmode_1
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building);
+ (struct building* building);
res_T
build_cad_cmode_1
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
int dump_footprints_on_error,
int keep_running_on_errors,
+ struct darray_adjoining_data* adjoining_data,
void** cad);
res_T
build_footprint_cmode_1
- (struct scpr_device* scpr,
- struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** footprint);
res_T
build_envelop_cmode_1
- (struct mem_allocator* allocator,
- struct logger* logger,
- struct building* building,
+ (struct building* building,
struct scad_geometry** envelop);
res_T
export_stl_cmode_1
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad,
+ (void* cad,
const int binary);
res_T
release_cad_cmode_1
- (struct mem_allocator* allocator,
- struct logger* logger,
- void* cad);
+ (void* cad);
#endif /* Construction_MODE_1_H */
diff --git a/src/cg_default.h.in b/src/cg_default.h.in
@@ -21,5 +21,6 @@
#define CG2_ARGS_STL_DEFAULT_STR @CG2_ARGS_STL_DEFAULT_STR@
#define CG2_ARGS_STL_NON_DEFAULT_STR @CG2_ARGS_STL_NON_DEFAULT_STR@
#define CG2_ARGS_CHANGE_BINARY_DEFAULT_OPTION '@CG2_ARGS_CHANGE_BINARY_DEFAULT_OPTION@'
+#define CG2_CLOSE_NEIGHBOR_DISTANCE @CG2_CLOSE_NEIGHBOR_DISTANCE@
#endif
diff --git a/src/cg_ground.c b/src/cg_ground.c
@@ -25,7 +25,7 @@
#include <star/scad.h>
#define GDEL(Tgt) \
- if(Tgt) SCAD(geometry_delete(Tgt)); \
+ if(Tgt) SCAD(geometry_ref_put(Tgt)); \
/* To avoid double delete, set to NULL after deletion */ \
Tgt = NULL
@@ -45,7 +45,7 @@ ground_build_cad
double origin[3];
double extent[3];
struct scad_geometry* bound = NULL;
- struct scad_geometry** list = NULL;
+ struct scad_geometry** list;
struct scad_geometry* surface = NULL;
size_t i, count = 0;
@@ -131,7 +131,7 @@ ground_export_stl(const struct ground* ground, const int binary)
size_t i = 0;
for(i = 0; i < 6; i++) {
- ERR(scad_stl_export(ground->boundary[i], NULL, 0, binary));
+ ERR(scad_stl_export(ground->boundary[i], NULL, binary));
}
exit:
diff --git a/src/cg_main.c b/src/cg_main.c
@@ -93,7 +93,7 @@ int main
struct parsed_city* parsed_city = NULL;
struct parsed_catalog* parsed_catalog = NULL;
struct catalog* catalog = NULL;
- int logger_initialized = 0, allocator_initialized = 0;
+ int keep, logger_initialized = 0, allocator_initialized = 0;
const struct cyaml_config config = {
.log_fn = cg_log,
.log_ctx = &logger,
@@ -124,6 +124,7 @@ int main
print_version();
goto exit;
}
+ keep = args->keep_running_on_errors;
/* Deactivate some logging according to the -V arg */
if(args->verbosity_level < 1)
@@ -178,6 +179,9 @@ error:
release_parsed_catalog(&config, parsed_catalog);
release_parsed_city(&config, parsed_city);
err = EXIT_FAILURE;
- printf("City generator failed.\n");
+ if(logger_initialized) {
+ logger_print(&logger, LOG_ERROR, "City generator failed.\n");
+ if(!keep) logger_print(&logger, LOG_ERROR, "Try to re-run with option -k.\n");
+ }
goto exit;
}