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:
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,