city_generator2

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

commit 46a23365ddb007729c2a792bb6719566ef7254a2
parent a8d710a27a463624b953ef5cb8bb13c450a11246
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed, 15 Jan 2025 10:47:33 +0100

First step in defining heigths in the mode 2 way

Mode 2 defines buildings heights by levels, enabling different heights
by level and by building.
At this stage levels height parsing is done, but levels are still
created with equal heights.

Diffstat:
Msrc/cg_building.c | 2+-
Msrc/cg_building.h | 6+++---
Msrc/cg_catalog.c | 1-
Msrc/cg_city_parsing_schemas.h | 8+++++++-
Msrc/cg_construction_mode.c | 4+++-
Msrc/cg_construction_mode_0.c | 27+++++++++++++++++++++++----
Msrc/cg_construction_mode_1.c | 23+++++++++++++++++++++--
Msrc/cg_construction_mode_2.c | 136++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/cg_construction_mode_2.h | 1-
Msrc/cg_construction_mode_2_parsing_schemas.h | 3---
10 files changed, 145 insertions(+), 66 deletions(-)

diff --git a/src/cg_building.c b/src/cg_building.c @@ -84,7 +84,7 @@ build_envelop { res_T res = RES_OK; size_t nverts = 0; - double height = building->height; + double height = building->total_height; double d[3] = {0, 0, 0}; struct scpr_polygon* pg = building->pg; struct scad_geometry* footprint = NULL; diff --git a/src/cg_building.h b/src/cg_building.h @@ -23,7 +23,7 @@ #include <rsys/rsys.h> #include <rsys/str.h> #include <rsys/dynamic_array.h> -#include <rsys/dynamic_array.h> +#include <rsys/dynamic_array_double.h> #include <rsys/hash_table.h> struct scpr_polygon; @@ -33,7 +33,6 @@ struct building; struct parsed_city_building; struct city; struct darray_adjoining_data; -struct darray_double; struct darray_geometries; /* An htable to uniquely associate flags to buildings */ @@ -116,7 +115,8 @@ struct building { struct str name; struct str external_layer_name; struct city* city; - double height; + double total_height; + struct darray_double levels_height; struct scpr_polygon* pg; struct htable_building close_buildings; /* links to other buildings */ int structs_initialized; diff --git a/src/cg_catalog.c b/src/cg_catalog.c @@ -197,7 +197,6 @@ create_catalog goto error; } /* Setup item */ - item.inter_floor_count = parsed_item->inter_floor_count; item.wall_thickness = parsed_item->wall_thickness; item.floor_thickness = parsed_item->floor_thickness; item.inter_floor_thickness = parsed_item->inter_floor_thickness; diff --git a/src/cg_city_parsing_schemas.h b/src/cg_city_parsing_schemas.h @@ -37,7 +37,9 @@ struct parsed_city_building { enum parsed_cmode_type cmode_type; char* dataset_name; double* vertice; /* flat array of vertice: { x0 y0 x1 y1 x2 y2... } */ + double* levels_height; double height; + unsigned levels_height_count; unsigned vertice_count; }; @@ -108,8 +110,12 @@ static const cyaml_schema_field_t city_building_fields_schema[] = { .count_size = sizeof(((struct parsed_city_building*)0)->vertice_count), .count_offset = offsetof(struct parsed_city_building, vertice_count), }, - CYAML_FIELD_FLOAT("height", CYAML_FLAG_DEFAULT, struct parsed_city_building, + CYAML_FIELD_FLOAT("height", CYAML_FLAG_OPTIONAL, struct parsed_city_building, height), + CYAML_FIELD_SEQUENCE("levels_height", + CYAML_FLAG_OPTIONAL | CYAML_FLAG_POINTER | CYAML_FLAG_FLOW, + struct parsed_city_building, levels_height, &entry_schema_double, + 1, CYAML_UNLIMITED), CYAML_FIELD_END }; diff --git a/src/cg_construction_mode.c b/src/cg_construction_mode.c @@ -63,11 +63,12 @@ init_building_base ASSERT(city && building && parsed_data); building->city = city; - building->height = parsed_data->height; str_init(city->allocator, &building->name); str_init(city->allocator, &building->external_layer_name); htable_building_init(city->allocator, &building->close_buildings); + darray_double_init(city->allocator, &building->levels_height); building->structs_initialized = 1; + ERR(str_set(&building->name, parsed_data->name)); ERR(scpr_polygon_create(city->scpr, &building->pg)); ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos, @@ -121,6 +122,7 @@ release_building_base str_release(&building->name); str_release(&building->external_layer_name); htable_building_release(&building->close_buildings); + darray_double_release(&building->levels_height); } if(building->pg) { ERR(scpr_polygon_ref_put(building->pg)); diff --git a/src/cg_construction_mode_0.c b/src/cg_construction_mode_0.c @@ -136,7 +136,7 @@ build_roof ERR(str_append(&name, "_S_roof")); roofname = str_get(&name); - height = b->height; + height = b->total_height; data = (struct dataset_cmode_0*)b->data; e = data->floor_thickness; d[2] = height - e ; @@ -198,7 +198,7 @@ build_wall ERR(build_wall_footprint(pg, pg_int, &footprint)); - d[2] = b->height; + d[2] = b->total_height; ERR(scad_geometry_extrude(footprint, wallname, d, wall)); ERR(darray_geometries_push_back(current_cad, wall)); @@ -228,7 +228,7 @@ build_cavity ASSERT(prefix && pg && b && cavity); - height = b->height; + height = b->total_height; data = (struct dataset_cmode_0*)b->data; e = data->floor_thickness; @@ -446,6 +446,25 @@ init_cmode_0 ERR(init_building_base(building, city, parsed_data)); + if(parsed_data->levels_height_count != 0) { + ERR(logger_print(city->logger, LOG_ERROR, + "Building '%s' defines 'levels_height' " + "(feature not available in construction mode 0).\n", + str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + + if(parsed_data->height <= 0) { + ERR(logger_print(city->logger, LOG_ERROR, + "Building '%s' height definition is invalid " + "(construction mode 0 should define a positive height through the 'height' field).\n", + str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + building->total_height = parsed_data->height; + str_init(allocator, &dataset_name); name_initialized = 1; ERR(str_set(&dataset_name, parsed_data->dataset_name)); @@ -513,7 +532,7 @@ build_cad_cmode_0 scpr = building->city->scpr; allocator = building->city->allocator; logger = building->city->logger; - height = building->height; + height = building->total_height; data = (struct dataset_cmode_0 *)building->data; logger_print(logger, LOG_OUTPUT, "Building '%s' construction mode 0.\n", name); diff --git a/src/cg_construction_mode_1.c b/src/cg_construction_mode_1.c @@ -832,7 +832,7 @@ build_windows e_roof_ins = data->roof_insulation_thickness; attic = data->attic_height; e_floor = data->inter_floor_thickness; - h_wall = (data_cad->building->height- e_roof - attic - e_roof_ins + h_wall = (data_cad->building->total_height- e_roof - attic - e_roof_ins - (double)floor_n*e_floor) / (double)(floor_n + 1); d3_splat(scale, sqrt(data->glass_ratio)); @@ -1477,6 +1477,25 @@ init_cmode_1 ERR(init_building_base(building, city, parsed_data)); + if(parsed_data->levels_height_count != 0) { + ERR(logger_print(city->logger, LOG_ERROR, + "Building '%s' defines 'levels_height' " + "(feature not available in construction mode 1).\n", + str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + + if(parsed_data->height <= 0) { + ERR(logger_print(city->logger, LOG_ERROR, + "Building '%s' height definition is invalid " + "(construction mode 1 should define a positive height through the 'height' field).\n", + str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + building->total_height = parsed_data->height; + str_init(allocator, &dataset_name); name_initialized = 1; ERR(str_set(&dataset_name, parsed_data->dataset_name)); @@ -1518,7 +1537,7 @@ build_cad_cmode_1 void** cad) { res_T res = RES_OK; - double height = building->height; + double height = building->total_height; double depth = 0; struct dataset_cmode_1* data = (struct dataset_cmode_1 *)building->data; struct data_cad_cmode_1* data_cad = NULL; diff --git a/src/cg_construction_mode_2.c b/src/cg_construction_mode_2.c @@ -477,7 +477,7 @@ build_inter_floor { res_T res = RES_OK; size_t i = 0; - size_t floor_n = data->inter_floor_count; + size_t levels_n = darray_double_size_get(&building->levels_height); double e_roof = data->roof_thickness; double e_roof_ins = data->roof_insulation_thickness; double attic = data->attic_height; @@ -512,10 +512,10 @@ build_inter_floor offset, &pg_int)); ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - h_cavity = height - e_roof - attic - e_roof_ins - (double)floor_n*e_floor; - z_floor = h_cavity/(double)(1 + floor_n); + h_cavity = height - e_roof - attic - e_roof_ins - (double)(levels_n - 1)*e_floor; + z_floor = h_cavity/(double)levels_n; d[2] = e_floor; - for(i = 0; i < floor_n; i++) { + for(i = 0; i < levels_n - 1; i++) { ERR(scad_add_polygon(NULL, get_position_pg, pg_int, z_floor, nverts, &footprint)); ERR(scad_geometry_extrude(footprint, NULL, d, &floor)); @@ -524,13 +524,13 @@ build_inter_floor ERR(darray_geometries_push_back(&floor_array, &floor)); ERR(scad_geometry_ref_put(floor)); floor = NULL; /* Avoid double free */ - z_floor += h_cavity/(double)(1 + floor_n) + e_floor; + z_floor += h_cavity/(double)levels_n + e_floor; } - ASSERT(darray_geometries_size_get(&floor_array) == floor_n); + ASSERT(darray_geometries_size_get(&floor_array) == levels_n - 1); floor_list = darray_geometries_data_get(&floor_array); - ERR(scad_fuse_geometries(floorname, floor_list, floor_n, floor_list, floor_n, - inter_floor)); + ERR(scad_fuse_geometries(floorname, floor_list, levels_n - 1, + floor_list, levels_n - 1, inter_floor)); ERR(darray_geometries_push_back(current_cad, inter_floor)); exit: @@ -704,8 +704,7 @@ build_habitable d[2] = height - e_roof - e_attic - e_roof_insulation; ERR(scad_geometry_extrude(footprint, NULL, d, &geom)); if(floor) { - ERR(scad_cut_geometries( - cavityname, &geom, 1, &floor, 1, cavity)); + ERR(scad_cut_geometries(cavityname, &geom, 1, &floor, 1, cavity)); } else { ERR(scad_geometry_copy(geom, cavityname, cavity)); } @@ -811,7 +810,7 @@ build_windows struct scad_geometry* env = NULL; struct scad_geometry* benv = NULL; struct scad_geometry* problem = NULL; - size_t floor_n; + size_t levels_n; double e_roof, e_roof_ins, attic, wall_height, e_floor; struct str name; struct adjoining_data* adj; @@ -829,13 +828,13 @@ build_windows str_init(allocator, &name); /* Compute wall height to help compute the minimum for windows area */ - floor_n = data->inter_floor_count; + levels_n = darray_double_size_get(&data_cad->building->levels_height); e_roof = data->roof_thickness; e_roof_ins = data->roof_insulation_thickness; attic = data->attic_height; e_floor = data->inter_floor_thickness; - wall_height = (data_cad->building->height - e_roof - attic - e_roof_ins - - (double)floor_n*e_floor) / (double)(floor_n + 1); + wall_height = (data_cad->building->total_height - e_roof - attic - e_roof_ins + - (double)(levels_n -1)*e_floor) / (double)levels_n; /* windows are build from the vertical faces of habitable cavities */ ERR(scad_geometry_boundary("cavity_boundary", &data_cad->habitable_cavity, 1, @@ -1573,7 +1572,8 @@ init_cmode_2 struct mem_allocator* allocator; struct logger* logger; int has_external_insulation; - (void) parsed_data; + double *lh; + unsigned count; if(!building || !city || !parsed_data || !catalog || !lower || !upper) { res = RES_BAD_ARG; @@ -1587,14 +1587,32 @@ init_cmode_2 ERR(init_building_base(building, city, parsed_data)); + if(parsed_data->height != 0) { + ERR(logger_print(city->logger, LOG_ERROR, + "Building '%s' defines 'height' " + "(feature not available in construction mode 2).\n", + str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + + if(parsed_data->levels_height_count <= 0) { + ERR(logger_print(city->logger, LOG_ERROR, + "Building '%s' height definition is invalid " + "(construction mode 2 should define the 'levels_height' field).\n", + str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + str_init(allocator, &dataset_name); name_initialized = 1; ERR(str_set(&dataset_name, parsed_data->dataset_name)); building->data = htable_dataset_cmode_2_find(&catalog->catalog_2, &dataset_name); if(building->data == NULL) { ERR(logger_print(logger, LOG_ERROR, - "Unknown dataset name: '%s' used by building '%s'.\n", - str_cget(&dataset_name), str_cget(&building->name))); + "Unknown dataset name: '%s' used by building '%s'.\n", + str_cget(&dataset_name), str_cget(&building->name))); res = RES_BAD_ARG; goto error; } @@ -1603,6 +1621,25 @@ init_cmode_2 ERR(str_set(&building->external_layer_name, (has_external_insulation ? "external_insulation" : "walls"))); + ERR(darray_double_resize(&building->levels_height, + parsed_data->levels_height_count)); + lh = darray_double_data_get(&building->levels_height); + + building->total_height = data->attic_height + + data->roof_thickness + data->roof_insulation_thickness; + for(count = 0; count < parsed_data->levels_height_count; count++) { + lh[count] = parsed_data->levels_height[count]; + if(lh[count] <= 0) { + ERR(logger_print(city->logger, LOG_ERROR, + "Building '%s' height definition is invalid " + "(level heights should be positive).\n", + str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + building->total_height += lh[count]; + } + exit: if(name_initialized) str_release(&dataset_name); return res; @@ -1611,24 +1648,24 @@ error: } res_T -release_cmode_2 - (struct building* building) + release_cmode_2 +(struct building* building) { if(!building) return RES_BAD_ARG; return release_building_base(building); } res_T -build_cad_cmode_2 - (struct building* building, - int dump_footprints_level, - int keep_running_on_errors, - struct darray_adjoining_data* adjoining_data, - struct darray_geometries* current_cad, - void** cad) + build_cad_cmode_2 +(struct building* building, + int dump_footprints_level, + int keep_running_on_errors, + struct darray_adjoining_data* adjoining_data, + struct darray_geometries* current_cad, + void** cad) { res_T res = RES_OK; - double height = building->height; + double height = building->total_height; double depth = 0; struct dataset_cmode_2* data = (struct dataset_cmode_2 *)building->data; struct data_cad_cmode_2* data_cad = NULL; @@ -1636,7 +1673,7 @@ build_cad_cmode_2 struct scpr_intersector* overlapping_intersector = NULL; struct scpr_intersector_check_callbacks callbacks = SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__; - size_t adjoining_n = 0; + size_t adjoining_n = 0, levels_n; struct callback_ctx ctx = CB_CTX_NULL__; int error_occured = 0, error_msg_printed = 0;; struct htable_polygons polygons; @@ -1659,10 +1696,11 @@ build_cad_cmode_2 name = str_cget(&building->name); allocator = building->city->allocator; logger = building->city->logger; + levels_n = darray_double_size_get(&building->levels_height); logger_print(logger, LOG_OUTPUT, - "Building '%s' construction mode 2, with %lu levels.\n", - name, 1 + data->inter_floor_count); + "Building '%s' construction mode 2, %g m tall, with %lu levels.\n", + name, building->total_height, levels_n); data_cad = MEM_CALLOC(allocator, 1, sizeof(struct data_cad_cmode_2)); if(!data_cad) { @@ -1687,10 +1725,10 @@ build_cad_cmode_2 ERR(htable_polygons_set(&polygons, &zero, &building->pg)); /* build mandatories elements : - - floor - - wall - - roof - */ + - floor + - wall + - roof + */ ERR(build_floor(building, &error_msg_printed, data, overlapping_intersector, &polygons, current_cad, &data_cad->floor)); @@ -1703,13 +1741,13 @@ build_cad_cmode_2 overlapping_intersector, &polygons, current_cad, &data_cad->roof)); /* build optionnal elements : - - foundation - - intermediate floor - - external insulation - - internal insulation - - roof insulation - - floor insulation - */ + - foundation + - intermediate floor + - external insulation + - internal insulation + - roof insulation + - floor insulation + */ if(data->foundation_depth > 0) { depth = -data->foundation_depth; @@ -1717,7 +1755,7 @@ build_cad_cmode_2 data, overlapping_intersector, &polygons, current_cad, &data_cad->foundation)); } - if(data->inter_floor_count > 0) { + if(levels_n > 1) { ERR(build_inter_floor(building, &error_msg_printed, height, data, overlapping_intersector, &polygons, current_cad, &data_cad->intermediate_floor)); } @@ -1744,10 +1782,10 @@ build_cad_cmode_2 } /* build cavities : - - attic - - habitable - - crawlspace - */ + - attic + - habitable + - crawlspace + */ if(data->attic_height > 0) { ERR(build_attic(building, &error_msg_printed, height, data, @@ -1798,7 +1836,7 @@ build_cad_cmode_2 /* fake ground */ depth = MMAX(data->foundation_depth, - data->floor_thickness + data->floor_insulation_thickness + data->crawl_height); + data->floor_thickness + data->floor_insulation_thickness + data->crawl_height); ERR(build_fake_ground(data_cad, depth, current_cad, &data_cad->fake_ground)); /* print partial computation time */ @@ -1840,8 +1878,8 @@ build_cad_cmode_2 /* print partial computation time */ time_sub(&dt, time_current(&dt), &t0); time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); - logger_print(logger, LOG_OUTPUT, - "Building '%s' partitioning stage done in %s.\n", name, buf); + logger_print(logger, LOG_OUTPUT, + "Building '%s' partitioning stage done in %s.\n", name, buf); time_current(&t0); /* After partitioning, manage common parts with other buildings */ diff --git a/src/cg_construction_mode_2.h b/src/cg_construction_mode_2.h @@ -35,7 +35,6 @@ struct catalog; /* specific data for construction mode 1 */ struct dataset_cmode_2 { - size_t inter_floor_count; /* can be 0 */ double wall_thickness; /* must be > 0 */ double floor_thickness; /* must be > 0 */ double inter_floor_thickness; /* must be > 0 */ diff --git a/src/cg_construction_mode_2_parsing_schemas.h b/src/cg_construction_mode_2_parsing_schemas.h @@ -26,7 +26,6 @@ struct parsed_dataset_cmode_2 { char* name; - size_t inter_floor_count; /* can be 0 */ double wall_thickness; /* must be > 0 */ double floor_thickness; /* must be > 0 */ double inter_floor_thickness; /* must be > 0 */ @@ -57,8 +56,6 @@ struct parsed_catalog_cmode_2 { static const cyaml_schema_field_t dataset_cmode_2_fields_schema[] = { CYAML_FIELD_STRING_PTR("name", CYAML_FLAG_POINTER, struct parsed_dataset_cmode_2, name, 0, CYAML_UNLIMITED), - CYAML_FIELD_INT("inter_floor_count", CYAML_FLAG_DEFAULT, - struct parsed_dataset_cmode_2, inter_floor_count), CYAML_FIELD_FLOAT("wall_thickness", CYAML_FLAG_DEFAULT, struct parsed_dataset_cmode_2, wall_thickness), CYAML_FIELD_FLOAT("floor_thickness", CYAML_FLAG_DEFAULT,