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 6f43c1eb62dd77e8c902ce5b18b1171b5e80634e
parent 1f83d75b99cfbf46a96a129b3436b6b3618b8c18
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon,  9 Jan 2023 16:07:48 +0100

Merge branch 'feature_yaml_data' into develop

Diffstat:
Mcmake/CMakeLists.txt | 31+++++++++++++++++++++----------
Msrc/cg.h | 44++++++++++++++++++++++++++++++++++++++++++++
Msrc/cg_args.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/cg_args.h | 28+++++++++++++++++++---------
Msrc/cg_building.h | 96+++++++++++++++++++++++++++++++++++--------------------------------------------
Dsrc/cg_building_model0.c | 572-------------------------------------------------------------------------------
Dsrc/cg_building_model0.h | 68--------------------------------------------------------------------
Dsrc/cg_building_model1.c | 1526-------------------------------------------------------------------------------
Dsrc/cg_building_model1.h | 89-------------------------------------------------------------------------------
Asrc/cg_catalog.c | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_catalog.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_catalog_parsing.c | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_catalog_parsing.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/cg_city.c | 168++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/cg_city.h | 67+++++++++++++++++++++++++++----------------------------------------
Asrc/cg_city_parsing.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_city_parsing.h | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_city_parsing_schemas.h | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_constructive_mode.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_constructive_mode_0.c | 634+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_constructive_mode_0.h | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_constructive_mode_0_parsing_schemas.h | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_constructive_mode_1.c | 1486+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_constructive_mode_1.h | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_constructive_mode_1_parsing_schemas.h | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cg_constructive_modes_parsing_schemas.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/cg_ground.c | 61++++++++++++++++++++++++++++++++++++-------------------------
Msrc/cg_ground.h | 29++++++++++++++++++-----------
Msrc/cg_main.c | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Dsrc/cg_parsing.c | 465-------------------------------------------------------------------------------
Dsrc/cg_parsing.h | 48------------------------------------------------
31 files changed, 3815 insertions(+), 3035 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -27,6 +27,7 @@ find_package(RCMake 0.4.1 REQUIRED) find_package(RSys 0.12.1 REQUIRED) find_package(StarCAD 0.1 REQUIRED) find_package(StarCPR 0.1.3 REQUIRED) +find_package(libcyaml 1.3 REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) include(rcmake) @@ -36,10 +37,11 @@ include_directories( ${StarCAD_INCLUDE_DIR} ${RSys_INCLUDE_DIR} ${StarCPR_INCLUDE_DIR} + ${LIBCYAML_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") endif() ################################################################################ @@ -51,24 +53,32 @@ set(CG2_VERSION_PATCH 0) set(CG2_VERSION ${CG2_VERSION_MAJOR}.${CG2_VERSION_MINOR}.${CG2_VERSION_PATCH}) set(CG2_FILES_SRC - cg_main.c + cg_args.c + cg_catalog.c + cg_catalog_parsing.c cg_city.c - cg_building_model0.c - cg_building_model1.c + cg_city_parsing.c + cg_constructive_mode_0.c + cg_constructive_mode_1.c cg_ground.c - cg_args.c - cg_parsing.c) + cg_main.c) set(CG2_FILES_INC cg.h cg_args.h cg_building.h - cg_building_model0.h - cg_building_model1.h + cg_catalog.h + cg_catalog_parsing.h cg_city.h + cg_city_parsing.h + cg_city_parsing_schemas.h + cg_constructive_mode.h + cg_constructive_mode_0.h + cg_constructive_mode_0_parsing_schemas.h + cg_constructive_mode_1.h + cg_constructive_mode_1_parsing_schemas.h cg_default.h.in cg_ground.h - cg_parsing.h cg_version.h.in) set(CG2_ARGS_DEFAULT_VERBOSE_LEVEL "1") @@ -95,7 +105,8 @@ add_executable(city_generator2 ${CG2_FILES_SRC} ${CG2_FILES_INC}) -target_link_libraries(city_generator2 RSys StarCAD StarCPR ${MATH_LIB}) +target_link_libraries(city_generator2 + RSys StarCAD StarCPR ${LIBCYAML_LIBRARY} ${MATH_LIB}) set_target_properties(city_generator2 PROPERTIES VERSION ${CG2_VERSION}) diff --git a/src/cg.h b/src/cg.h @@ -20,7 +20,51 @@ #ifndef CG_H #define CG_H +#include <rsys/rsys.h> +#include <cyaml/cyaml.h> + #define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0 +static INLINE void +log_prt_fn(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + + fprintf(stderr, "\x1b[32moutput:\x1b[0m %s", msg); +} + +static INLINE void +log_warn_fn(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + + fprintf(stderr, "\x1b[33mwarning:\x1b[0m %s", msg); +} + +static INLINE void +log_err_fn(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; + + fprintf(stderr, "\x1b[31merror:\x1b[0m %s", msg); +} + +static INLINE res_T +cyaml_err_to_res_T(const cyaml_err_t err) +{ + res_T res = RES_OK; + + switch(err) { + case CYAML_OK: res = RES_OK; break; + case CYAML_ERR_OOM: res = RES_MEM_ERR; break; + case CYAML_ERR_FILE_OPEN: res = RES_IO_ERR; break; + default: res = RES_UNKNOWN_ERR; break; + } + return res; +} + #endif /*CG_H*/ diff --git a/src/cg_args.c b/src/cg_args.c @@ -18,6 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "cg_args.h" +#include "cg_catalog_parsing.h" #include "cg_version.h" #include "cg_default.h" #include "cg.h" @@ -41,17 +42,18 @@ short_help(void) { print_version(); printf("\nUsage:\n" - "city_generator2 [-a] -b <FILE> -c <FILE> [-V verbosity]\n" + "city_generator2 -m <FILENAME> -c <FILENAME> [-V verbosity]\n" "city_generator2 [-h]\n" "city_generator2 [-v]\n" ); printf( "\nMandatory options\n" "-----------------\n" - "-b <building_model_file>\n" - " Read a yaml text file that describes the building.\n" - "-c <city_model_file>\n" - " Read a yaml text file that describes the city.\n" + "-c <filename>\n" + " Read a yaml text file containing datasets for a given constructive mode.\n" + " Can be used more than once.\n" + "-m <city_map_filename>\n" + " Read a yaml text file that describes the city map.\n" "\nOther options\n" "-------------\n" "-h\n" @@ -80,19 +82,35 @@ short_help(void) res_T parse_args - (struct logger* logger, + (struct mem_allocator* allocator, + struct logger* logger, int argc, char** argv, - struct args* args) + struct args** out_args) { res_T res = RES_OK; int opt; - int info_provided = 0, b_provided = 0, c_provided = 0; - struct args aaa = ARGS_NULL__; - const char option_list[] = "b:c:f:hvV:"; + int info_provided = 0, c_provided = 0, m_provided = 0; + struct args* args; + const char option_list[] = "c:m:f:hvV:"; + + ASSERT(allocator && logger && argv && out_args); + + args = MEM_ALLOC(allocator, sizeof(*args)); + if(!args) { + res = RES_MEM_ERR; + goto error; + } + args->allocator = allocator; + args->logger = logger; /* Set default values */ - *args = aaa; + args->city_filename = NULL; + darray_catalog_filenames_init(allocator, &args->catalog_filenames); + args->binary_export = CG2_BINARY_EXPORT_DEFAULT; + args->verbosity_level = CG2_DEFAULT_VERBOSE_LEVEL; + args->print_help = 0; + args->print_version = 0; opterr = 0; /* No default error messages */ while((opt = getopt(argc, argv, option_list)) != -1) { @@ -113,14 +131,19 @@ parse_args goto error; } - case 'b': - if(b_provided) { + case 'c': + c_provided = 1; + ERR(darray_catalog_filenames_push_back(&args->catalog_filenames, &optarg)); + break; + + case 'm': + if(m_provided) { logger_print(logger, LOG_ERROR, "Option -%c provided twice.\n", opt); res = RES_BAD_ARG; goto error; } - args->building_model_file = optarg; - b_provided = 1; + args->city_filename = optarg; + m_provided = 1; break; case 'f': @@ -142,26 +165,16 @@ parse_args args->print_help = 1; break; - case 'c': - if(c_provided) { - logger_print(logger, LOG_ERROR, "Option -%c provided twice.\n", opt); - res = RES_BAD_ARG; - goto error; - } - args->city_model_file = optarg; - c_provided = 1; - break; - case 'v': info_provided = 1; args->print_version = 1; break; case 'V': - res = cstr_to_int(optarg, &args->verbose); + res = cstr_to_int(optarg, &args->verbosity_level); if(res != RES_OK - || args->verbose < 0 - || args->verbose > 3) + || args->verbosity_level < 0 + || args->verbosity_level > 3) { if(res == RES_OK) res = RES_BAD_ARG; logger_print(logger, LOG_ERROR, @@ -183,22 +196,35 @@ parse_args goto error; } - if(!b_provided && !info_provided) { + if(!c_provided && !info_provided) { ERR(logger_print(logger, LOG_ERROR, - "Missing mandatory argument: -b <building_model_file>\n")); + "Missing mandatory argument: -b <construction_mode_filename>\n")); res = RES_BAD_ARG; goto error; } - if(!c_provided && !info_provided) { + if(!m_provided && !info_provided) { ERR(logger_print(logger, LOG_ERROR, - "Missing mandatory argument: -c <city_model_file>\n")); + "Missing mandatory argument: -c <city_filename>\n")); res = RES_BAD_ARG; goto error; } exit: + *out_args = args; return res; error: + release_args(args); + args = NULL; goto exit; } + +void +release_args + (struct args* args) +{ + if(!args) return; + + darray_catalog_filenames_release(&args->catalog_filenames); + MEM_RM(args->allocator, args); +} diff --git a/src/cg_args.h b/src/cg_args.h @@ -20,27 +20,37 @@ #ifndef PARSE_ARGS_H #define PARSE_ARGS_H -#include "cg_default.h" - #include <rsys/rsys.h> +#include <rsys/dynamic_array.h> struct logger; -struct args; +#define DARRAY_NAME catalog_filenames +#define DARRAY_DATA char* +#include <rsys/dynamic_array.h> struct args { - char* city_model_file; - char* building_model_file; + struct mem_allocator* allocator; + struct logger* logger; + char* city_filename; + struct darray_catalog_filenames catalog_filenames; int binary_export; - int verbose; + int verbosity_level; int print_help; int print_version; }; -#define ARGS_NULL__ \ - { NULL, NULL, CG2_BINARY_EXPORT_DEFAULT, CG2_DEFAULT_VERBOSE_LEVEL, 0, 0 } res_T -parse_args(struct logger* logger, int argc, char** argv, struct args* args); +parse_args + (struct mem_allocator* allocator, + struct logger* logger, + int argc, + char** argv, + struct args** out_args); + +void +release_args + (struct args* args); void print_version(void); diff --git a/src/cg_building.h b/src/cg_building.h @@ -24,73 +24,61 @@ #include <rsys/str.h> #include <rsys/hash_table.h> +#include "cg_constructive_mode_0.h" +#include "cg_constructive_mode_1.h" + struct scpr_polygon; struct scad_geometry; +struct mem_allocator; +struct logger; +struct catalog; -enum model_type { - model0, - model1, - MODEL_COUNT_ +/* A type to store the functors of a constructive mode */ +struct constructive_mode_functors { + res_T (*init) + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct parsed_city_building* parsed_data, + struct catalog* catalog); + res_T (*build_cad) + (struct building* building, struct mem_allocator* allocator, + struct logger* logger, void** cad); + res_T (*build_footprint) + (struct building* building, struct mem_allocator* allocator, + struct logger* logger, struct scad_geometry** footprint); + res_T (*export_stl) + (void* cad, struct mem_allocator* allocator, struct logger* logger, + const int binary); + res_T (*release_cad) + (struct mem_allocator* allocator, struct logger* logger, void* cad); }; -extern char const* model_str[1]; - -struct building_params { - enum model_type model; - struct str name; - void* data; +/* A type to give an ID to constructive modes. + * Add a new entry for each new constructive mode. */ +enum constructive_mode_type { + mode_0, + mode_1, + CONSTRUCTIVE_MODES_COUNT__ }; +/* The name of the constructive modes, as expected in the city description. */ +extern char const* constructive_mode_name[CONSTRUCTIVE_MODES_COUNT__]; -static INLINE char -eq_str(const struct str* a, const struct str* b) -{ - return !strcmp(str_cget(a), str_cget(b)); -} - -static INLINE size_t -hash_str(const struct str* a) -{ - return hash_fnv32(str_cget(a), str_len(a)); -} - -#define HTABLE_NAME building_params -#define HTABLE_DATA struct building_params -#define HTABLE_KEY struct str -#define HTABLE_KEY_FUNCTOR_INIT str_init -#define HTABLE_KEY_FUNCTOR_RELEASE str_release -#define HTABLE_KEY_FUNCTOR_COPY str_copy -#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release -#define HTABLE_KEY_FUNCTOR_EQ eq_str -#define HTABLE_KEY_FUNCTOR_HASH hash_str -#include <rsys/hash_table.h> - - -/* the specific building model functors headers must be included here */ -#include "cg_building_model0.h" -#include "cg_building_model1.h" - +/* The type of buildings as described in the city description */ struct building { - /* generic building data */ - size_t id; - enum model_type model; - struct str* data_name; + /* constructive mode */ + struct constructive_mode_functors* functors; + enum constructive_mode_type constructive_mode; + + /* generic constructive mode data */ + int name_initialized; + struct str name; double height; struct scpr_polygon* pg; - /* specific data depending model */ + /* specific data depending to the constructive mode */ void* data; - void* data_cad; - - /* functors depending model */ - res_T (*init) - (struct building* building, struct htable_building_params* htparams); - res_T (*build_cad)(struct building* building); - res_T (*build_footprint) - (struct building* building, - struct scad_geometry** footprint); - res_T (*export_stl)(const struct building* building, const int binary); - res_T (*release)(struct building* building); }; #endif /* BUILDING_H */ diff --git a/src/cg_building_model0.c b/src/cg_building_model0.c @@ -1,572 +0,0 @@ -/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA - * Copyright (C) 2022 CNRS - * Copyright (C) 2022 Sorbonne Université - * Copyright (C) 2022 Université Paul Sabatier - * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "cg.h" -#include "cg_building.h" - -#include <rsys/str.h> -#include <star/scad.h> -#include <star/scpr.h> - -static void get_position_pg - (const size_t ivert, double pos[2], void* ctx) -{ - struct scpr_polygon* pg = ctx; - ASSERT(pos && pg); - CHK(scpr_polygon_get_position(pg, 0, ivert, pos) == RES_OK); -} - -static res_T -build_floor_footprint - (struct scpr_polygon* pg, - struct scad_geometry** footprint) -{ - res_T res = RES_OK; - size_t nverts; - ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, footprint)); - -exit: - return res; -error: - goto exit; -} - -static res_T -build_floor - (const char* prefix, - struct scpr_polygon* pg, - struct building* b, - struct scad_geometry** floor) -{ - res_T res = RES_OK; - double e; - struct data_model0* data; - struct scad_geometry* footprint = NULL; - double d[3] = {0, 0, 0}; - char* floorname = NULL; - struct str name; - int is_init = 0; - - data = (struct data_model0*)b->data; - e = data->floor; - - str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_floor")); - floorname = str_get(&name); - } - - ERR(build_floor_footprint(pg, &footprint)); - - d[2] = e; - ERR(scad_geometry_extrude(footprint, floorname, d, floor)); - -exit: - scad_geometry_delete(footprint); - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -static res_T -build_roof - (const char* prefix, - const struct building* b, - const struct scad_geometry* floor, - struct scad_geometry** roof) -{ - res_T res = RES_OK; - double height; - double e; - double d[3] = {0, 0, 0}; - struct data_model0* data; - /*struct data_cad_model0* data_cad;*/ - char* roofname = NULL; - struct str name; - int is_init = 0; - - str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_roof")); - roofname = str_get(&name); - } - - height = b->height; - data = (struct data_model0*)b->data; - /*data_cad = (struct data_cad_model0*)b->data_cad;*/ - e = data->floor; - - ERR(scad_geometry_copy(floor, roofname, roof)); - d[2] = height - e ; - ERR(scad_geometry_translate(*roof, d)); - -exit: - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -static res_T -build_wall_footprint - (struct scpr_polygon* pg, - struct scpr_polygon* pg_int, - struct scad_geometry** footprint) -{ - res_T res = RES_OK; - /*struct data_cad_model0* data_cad;*/ - struct scad_geometry* polygon = NULL; - struct scad_geometry* polygon_int = NULL; - size_t nverts, nverts_int; - - ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &polygon)); - - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts_int)); - ERR(scad_add_polygon(NULL, get_position_pg, pg_int, 0, nverts_int, &polygon_int)); - - ERR(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); - return res; -error: - goto exit; -} - -static res_T -build_wall - (const char* prefix, - struct scpr_polygon* pg, - struct scpr_polygon* pg_int, - struct building* b, - struct scad_geometry** wall) -{ - res_T res = RES_OK; - double height; - struct scad_geometry* footprint = NULL; - double d[3] = {0, 0, 0}; - char* wallname = NULL; - struct str name; - int is_init = 0; - - height = b->height; - - str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_wall")); - wallname = str_get(&name); - } - - ERR(build_wall_footprint(pg, pg_int, &footprint)); - - d[2] = height; - ERR(scad_geometry_extrude(footprint, wallname, d, wall)); - -exit: - if(footprint) scad_geometry_delete(footprint); - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -static res_T -build_cavity - (const char* prefix, - struct scpr_polygon* pg, - const struct building* b, - struct scad_geometry** cavity) -{ - res_T res = RES_OK; - double e, height; - struct data_model0* data; - double d[3] = {0, 0, 0}; - struct scad_geometry* polygon = NULL; - char* cavityname = NULL; - struct str name; - int is_init = 0; - size_t nverts; - - height = b->height; - data = (struct data_model0*)b->data; - e = data->floor; - - str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_cavity")); - cavityname = str_get(&name); - } - - ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg, e, nverts, &polygon)); - - d[2] = height - e; - ERR(scad_geometry_extrude(polygon, cavityname, d, cavity)); - -exit: - if(polygon) scad_geometry_delete(polygon); - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -static res_T -build_connection - (const char* prefix, - struct data_cad_model0* cad) -{ - res_T res = RES_OK; - char* cname = NULL; - struct str name; - int is_init = 0; - - cad->connection = malloc(3 * sizeof(struct scad_geometry*)); - cad->n_connection = 3; - - /* cavity/floor connection */ - str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_C_cavity_floor")); - cname = str_get(&name); - } - - ERR(scad_geometries_common_boundaries - (cname, - &cad->cavity, 1, - &cad->floor, 1, - &cad->connection[0])); - - /* cavity/wall connection */ - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_C_cavity_wall")); - cname = str_get(&name); - } - - ERR(scad_geometries_common_boundaries - (cname, - &cad->cavity, 1, - &cad->wall, 1, - &cad->connection[1])); - - /* cavity/roof connection */ - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_C_cavity_roof")); - cname = str_get(&name); - } - - ERR(scad_geometries_common_boundaries - (cname, - &cad->cavity, 1, - &cad->roof, 1, - &cad->connection[2])); - -exit: - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -static res_T -build_boundary - (const char* prefix, - struct data_cad_model0* cad) -{ - res_T res = RES_OK; - struct scad_geometry** list = NULL; - struct scad_geometry* boundary = NULL; - /*struct scad_geometry* footprint = NULL;*/ - char* cname = NULL; - struct str name; - int is_init = 0; - - list = malloc(4 * sizeof(struct scad_geometry*)); - list[0] = cad->floor; - list[1] = cad->wall; - list[2] = cad->roof; - list[3] = cad->cavity; - - str_init(NULL, &name); - is_init = 1; - if (prefix) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_boundary")); - cname = str_get(&name); - } - - ERR(scad_geometry_boundary(NULL, list, 4, &boundary)); - - ERR(scad_cut_geometries(cname, &boundary, 1, &cad->ground_connection, 1, - &cad->boundary)); - -exit: - if(boundary) scad_geometry_delete(boundary); - /*if(footprint) scad_geometry_delete(footprint);*/ - if (list) free(list); - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -static res_T -building_ground_connection - (const char* prefix, - struct scpr_polygon* pg, - const double e, - struct scad_geometry** connection) -{ - res_T res = RES_OK; - struct scpr_polygon* pg_int = NULL; - struct scad_geometry* geom[2]; - char* cname = NULL; - struct str name; - int is_init = 0; - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_C_building_ground")); - cname = str_get(&name); - } - - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -e, SCPR_JOIN_MITER)); - - ERR(build_wall_footprint(pg, pg_int, &geom[0])); - ERR(build_floor_footprint(pg, &geom[1])); - - ERR(scad_fragment_geometries(cname, &geom[0], 1, &geom[1], 1, connection)); - -exit: - if(is_init) str_release(&name); - if(geom[0]) scad_geometry_delete(geom[0]); - if(geom[1]) scad_geometry_delete(geom[1]); - if(pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - -res_T -init_model0 - (struct building* building, struct htable_building_params* htparams) -{ - res_T res = RES_OK; - struct data_model0 data; - struct building_params* params; - - params = htable_building_params_find(htparams, building->data_name); - if (params == NULL) { - res = RES_BAD_ARG; - goto error; - } - - if (params->model != building->model) { - res = RES_BAD_ARG; - goto error; - } - - data = *(struct data_model0*)params->data; - building->data = malloc(sizeof(struct data_model0)); - if (!building->data) { - res = RES_MEM_ERR; - goto error; - } - *(struct data_model0*)(building->data) = data; - building->build_cad = &build_cad_model0; - building->export_stl = &export_stl_model0; - building->release = &release_model0; - building->build_footprint = &build_footprint_model0; - -exit: - return res; -error: - goto exit; -} - -res_T -build_cad_model0(struct building* building) -{ - res_T res = RES_OK; - size_t id = building->id; - enum model_type model = building->model; - double height = building->height; - struct scpr_polygon* pg = building->pg; - struct scpr_polygon* pg_int = NULL; - struct data_model0* data = (struct data_model0 *)building->data; - struct data_cad_model0* data_cad; - double e_wall; - struct str prefix; - int is_init = 0; - - if (!building) { - res = RES_BAD_ARG; - goto error; - } - - if (height <= 0 || data->wall <= 0 || data->floor <= 0) { - res = RES_BAD_ARG; - goto error; - } - - str_init(NULL, &prefix); - is_init = 1; - ERR(str_set(&prefix, "building_")); - ERR(str_append_printf(&prefix, "%lu_", (unsigned long)id)); - ERR(str_append(&prefix, model_str[model])); - - data_cad = malloc(sizeof(struct data_cad_model0)); - building->data_cad = (struct data_cad_model0*)data_cad; - - e_wall = data->wall; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -e_wall, SCPR_JOIN_MITER)); - - /* build floor with pg_int */ - ERR(build_floor(str_cget(&prefix), pg_int, building, &data_cad->floor)); - - /* roof is a translated copy of floor */ - ERR(build_roof(str_cget(&prefix), building, data_cad->floor, &data_cad->roof)); - - /* build wall with pg and pg_int */ - ERR(build_wall(str_cget(&prefix), pg, pg_int, building, &data_cad->wall)); - - /* build cavity */ - ERR(build_cavity(str_cget(&prefix), pg_int, building, &data_cad->cavity)); - - ERR(scad_scene_partition()); - - /* build ground/building connection */ - ERR(building_ground_connection(str_cget(&prefix), pg, e_wall, - &data_cad->ground_connection)); - - /* build boundary */ - ERR(build_boundary(str_cget(&prefix), building->data_cad)); - - /* build cavity/floor connectiona*/ - ERR(build_connection(str_cget(&prefix), building->data_cad)); - - -exit: - if(is_init) str_release(&prefix); - if(pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} - -res_T -build_footprint_model0 - (struct building* building, - struct scad_geometry** footprint) -{ - res_T res = RES_OK; - struct scpr_polygon* pg = building->pg; - struct data_model0* data = (struct data_model0 *)building->data; - double e_wall; - - e_wall = data->wall; - - ERR(building_ground_connection(NULL, pg, e_wall, footprint)); - -exit: - return res; -error: - goto exit; -} - -res_T -export_stl_model0 - (const struct building* building, const int binary) -{ - res_T res = RES_OK; - struct data_cad_model0* data_cad = (struct data_cad_model0 *)building->data_cad; - size_t i; - - /* floor export */ - ERR(scad_stl_export(data_cad->floor, NULL, binary)); - - /* roof export */ - ERR(scad_stl_export(data_cad->roof, NULL, binary)); - - /* wall export */ - ERR(scad_stl_export(data_cad->wall, NULL, binary)); - - /* cavity export */ - 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, binary)); - } - - /* boundary export */ - ERR(scad_stl_export(data_cad->boundary, NULL, binary)); - - /* footprint export */ - ERR(scad_stl_export(data_cad->ground_connection, NULL, binary)); - -exit: - return res; -error: - goto exit; -} - -res_T -release_model0 - (struct building* building) -{ - res_T res = RES_OK; - - struct data_model0* data = (struct data_model0 *)building->data; - struct data_cad_model0* data_cad = (struct data_cad_model0 *)building->data_cad; - - scpr_polygon_ref_put(building->pg); - - str_release(building->data_name); - - if (data_cad->connection) free(data_cad->connection); - if (data) free(data); - if (data_cad) free(data_cad); - - return res; -} diff --git a/src/cg_building_model0.h b/src/cg_building_model0.h @@ -1,68 +0,0 @@ -/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA - * Copyright (C) 2022 CNRS - * Copyright (C) 2022 Sorbonne Université - * Copyright (C) 2022 Université Paul Sabatier - * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef BUILDING_MODEL0_H -#define BUILDING_MODEL0_H - -#include <rsys/rsys.h> - -struct scad_geometry; - -struct building; -struct htable_building_params; -struct building_params; - -/* specific data for model 0 */ -struct data_model0 { - double wall; /* wall thickness */ - double floor; /* floor thickness */ -}; - -struct data_cad_model0 { - struct scad_geometry* wall; - struct scad_geometry* roof; - struct scad_geometry* floor; - struct scad_geometry* cavity; - struct scad_geometry* boundary; - struct scad_geometry** connection; - struct scad_geometry* ground_connection; - size_t n_connection; -}; - -res_T -init_model0 - (struct building* building, struct htable_building_params* htparams); - -res_T -build_cad_model0(struct building* building); - -res_T -build_footprint_model0 - (struct building* building, - struct scad_geometry** footprint); - -res_T -export_stl_model0 - (const struct building* building, const int binary); - -res_T -release_model0 - (struct building* building); - -#endif /* BUILDING_MODEL0_H */ diff --git a/src/cg_building_model1.c b/src/cg_building_model1.c @@ -1,1526 +0,0 @@ -/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA - * Copyright (C) 2022 CNRS - * Copyright (C) 2022 Sorbonne Université - * Copyright (C) 2022 Université Paul Sabatier - * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "cg.h" -#include "cg_building.h" - -#include <rsys/str.h> -#include <rsys/stretchy_array.h> -#include <star/scad.h> -#include <star/scpr.h> - -static void get_position_pg - (const size_t ivert, double pos[2], void* ctx) -{ - struct scpr_polygon* pg = ctx; - ASSERT(pos && pg); - CHK(scpr_polygon_get_position(pg, 0, ivert, pos) == RES_OK); -} - -static res_T -build_floor - (const char* prefix, - const struct scpr_polygon* pg, - const struct data_model1* data, - struct scad_geometry** floor) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_insulation = data->ext_insulation; - double e_floor = data->floor; - double offset = 0; - struct scpr_polygon* pg_int = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - double d[3] = {0, 0, 0}; - char* floorname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !floor) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_floor")); - floorname = str_get(&name); - } - - offset = e_wall + e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon(NULL, get_position_pg, pg_int, 0, nverts, &footprint)); - - d[2] = -e_floor; - ERR(scad_geometry_extrude(footprint, floorname, d, floor)); - -exit: - scad_geometry_delete(footprint); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} - -static res_T -build_wall - (const char* prefix, - const char* suffix, - const struct scpr_polygon* pg, - const double height, - const struct data_model1* data, - struct scad_geometry** wall) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_insulation = data->ext_insulation; - double offset = 0; - struct scpr_polygon* pg_int = NULL; - struct scpr_polygon* pg_ext = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - struct scad_geometry* footprint_int = NULL; - struct scad_geometry* footprint_ext = NULL; - double d[3] = {0, 0, 0}; - char* wallname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !wall) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - if (suffix) { - ERR(str_append(&name, "_")); - ERR(str_append(&name, suffix)); - } - wallname = str_get(&name); - } - - offset = e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_ext)); - ERR(scpr_offset_polygon(pg_ext, -offset, SCPR_JOIN_MITER)); - - offset = e_wall + e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*wall footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); - - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); - - ERR(scad_cut_geometries( - NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); - - d[2] = height; - ERR(scad_geometry_extrude(footprint, wallname, d, wall)); - -exit: - scad_geometry_delete(footprint); - scad_geometry_delete(footprint_int); - scad_geometry_delete(footprint_ext); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - if (pg_ext) scpr_polygon_ref_put(pg_ext); - return res; -error: - goto exit; -} - -static res_T -build_int_insulation - (const char* prefix, - const struct scpr_polygon* pg, - const double height, - const struct data_model1* data, - struct scad_geometry* inter_floor, - struct scad_geometry** insulation) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_roof = data->roof; - double e_roof_insulation = data->roof_insulation; - double attic = data->attic; - double e_ext_insulation = data->ext_insulation; - double e_int_insulation = data->int_insulation; - double offset = 0; - struct scpr_polygon* pg_int = NULL; - struct scpr_polygon* pg_ext = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - struct scad_geometry* footprint_int = NULL; - struct scad_geometry* footprint_ext = NULL; - struct scad_geometry* geom = NULL; - double d[3] = {0, 0, 0}; - char* insulationname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !insulation) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_int_insulation")); - insulationname = str_get(&name); - } - - offset = e_ext_insulation + e_wall; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_ext)); - ERR(scpr_offset_polygon(pg_ext, -offset, SCPR_JOIN_MITER)); - - offset = e_ext_insulation + e_wall + e_int_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /* insulation footprint */ - ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); - - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); - - ERR(scad_cut_geometries( - NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); - - d[2] = height - e_roof - attic - e_roof_insulation; - ERR(scad_geometry_extrude(footprint, NULL, d, &geom)); - - if (inter_floor) { - ERR(scad_cut_geometries( - insulationname, &geom, 1, &inter_floor, 1, insulation)); - } else { - ERR(scad_geometry_copy(geom, insulationname, insulation)); - } - - -exit: - scad_geometry_delete(footprint); - scad_geometry_delete(footprint_int); - scad_geometry_delete(footprint_ext); - scad_geometry_delete(geom); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - if (pg_ext) scpr_polygon_ref_put(pg_ext); - return res; -error: - goto exit; -} - -static res_T -build_roof - (const char* prefix, - const struct scpr_polygon* pg, - const double height, - const struct data_model1* data, - struct scad_geometry** roof) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_insulation = data->ext_insulation; - double e_roof = data->roof; - double offset = 0; - double z_roof = 0; - struct scpr_polygon* pg_int = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - double d[3] = {0, 0, 0}; - char* roofname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !roof) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_roof")); - roofname = str_get(&name); - } - - offset = e_wall + e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - z_roof = height - e_roof; - ERR(scad_add_polygon(NULL, get_position_pg, pg_int, z_roof, nverts, &footprint)); - - d[2] = e_roof; - ERR(scad_geometry_extrude(footprint, roofname, d, roof)); - -exit: - scad_geometry_delete(footprint); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} - -static res_T -build_roof_insulation - (const char* prefix, - const struct scpr_polygon* pg, - const double height, - const struct data_model1* data, - struct scad_geometry** insulation) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_insulation = data->ext_insulation; - double e_roof = data->roof; - double attic = data->attic; - double e_roof_insulation = data->roof_insulation; - double offset = 0; - double z_insulation = 0; - struct scpr_polygon* pg_int = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - double d[3] = {0, 0, 0}; - char* insulationname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !insulation) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_roof_insulation")); - insulationname = str_get(&name); - } - - offset = e_wall + e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - z_insulation = height - e_roof - attic - e_roof_insulation; - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, z_insulation, nverts, &footprint)); - - d[2] = e_roof_insulation; - ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); - -exit: - scad_geometry_delete(footprint); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} - -static res_T -build_floor_insulation - (const char* prefix, - const struct scpr_polygon* pg, - const struct data_model1* data, - struct scad_geometry** insulation) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_insulation = data->ext_insulation; - double e_floor = data->floor; - double e_floor_insulation = data->floor_insulation; - double offset = 0; - double z_insulation = 0; - struct scpr_polygon* pg_int = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - double d[3] = {0, 0, 0}; - char* insulationname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !insulation) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_floor_insulation")); - insulationname = str_get(&name); - } - - offset = e_wall + e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - z_insulation = - e_floor - e_floor_insulation; - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, z_insulation, nverts, &footprint)); - - d[2] = e_floor_insulation; - ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); - -exit: - scad_geometry_delete(footprint); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} -static res_T -build_inter_floor - (const char* prefix, - const struct scpr_polygon* pg, - const double height, - const struct data_model1* data, - struct scad_geometry** inter_floor) -{ - res_T res = RES_OK; - size_t i = 0; - size_t floor_n = data->inter_floor_n; - double e_roof = data->roof; - double e_roof_ins = data->roof_insulation; - double attic = data->attic; - double e_floor = data->inter_floor; - double e_wall = data->wall; - double e_insulation = data->ext_insulation; - double offset = 0; - double z_floor = 0; - double h_cavity = 0; - struct scpr_polygon* pg_int = NULL; - size_t nverts = 0; - struct scad_geometry** floor_list = NULL; - double d[3] = {0, 0, 0}; - char* floorname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !inter_floor) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_inter_floor")); - floorname = str_get(&name); - } - - offset = e_wall + e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - - h_cavity = height - e_roof - attic - e_roof_ins - (double)floor_n*e_floor; - z_floor = h_cavity/(double)(1 + floor_n); - d[2] = e_floor; - for (i=0; i< floor_n; ++i) { - 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_geometry_extrude(footprint, NULL, d, &floor)); - sa_push(floor_list, floor); - ERR(scad_geometry_delete(footprint)); - z_floor += h_cavity/(double)(1 + floor_n) + e_floor; - } - - ERR(scad_fuse_geometries( - floorname, - floor_list, sa_size(floor_list), - floor_list, sa_size(floor_list), - inter_floor)); - -exit: - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - if (floor_list) { - for (i=0; i< floor_n; ++i) { - scad_geometry_delete(floor_list[i]); - } - sa_release(floor_list); - } - return res; -error: - goto exit; -} -static res_T -build_ext_insulation - (const char* prefix, - const struct scpr_polygon* pg, - const double height, - const struct data_model1* data, - struct scad_geometry** insulation) -{ - res_T res = RES_OK; - double e_insulation = data->ext_insulation; - double offset = 0; - struct scpr_polygon* pg_int = NULL; - struct scpr_polygon* pg_ext = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - struct scad_geometry* footprint_int = NULL; - struct scad_geometry* footprint_ext = NULL; - double d[3] = {0, 0, 0}; - char* insulationname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !insulation) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_ext_insulation")); - insulationname = str_get(&name); - } - - offset = e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_polygon_create_copy(NULL, pg, &pg_ext)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*insulation footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); - - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); - - ERR(scad_cut_geometries( - NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); - - d[2] = height; - ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); - -exit: - scad_geometry_delete(footprint); - scad_geometry_delete(footprint_int); - scad_geometry_delete(footprint_ext); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - if (pg_ext) scpr_polygon_ref_put(pg_ext); - return res; -error: - goto exit; -} - -static res_T -build_crawlspace - (const char* prefix, - const struct scpr_polygon* pg, - const struct data_model1* data, - struct scad_geometry** crawlspace) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_insulation = data->ext_insulation; - double e_crawl = data->crawl; - double e_floor = data->floor; - double e_floor_insulation = data->floor_insulation; - double offset = 0; - double z_crawl= 0; - struct scpr_polygon* pg_int = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - double d[3] = {0, 0, 0}; - char* crawlname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !crawlspace) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_crawlspace")); - crawlname = str_get(&name); - } - - offset = e_wall + e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - z_crawl = - e_floor - e_floor_insulation - e_crawl; - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, z_crawl, nverts, &footprint)); - - d[2] = e_crawl; - ERR(scad_geometry_extrude(footprint, crawlname, d, crawlspace)); - -exit: - scad_geometry_delete(footprint); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} - -static res_T -build_habitable - (const char* prefix, - const struct scpr_polygon* pg, - const double height, - const struct data_model1* data, - struct scad_geometry* floor, - struct scad_geometry** cavity) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_ext_insulation = data->ext_insulation; - double e_int_insulation = data->int_insulation; - double e_roof = data->roof; - double e_roof_insulation = data->roof_insulation; - double e_attic = data->attic; - double offset = 0; - struct scpr_polygon* pg_int = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - struct scad_geometry* geom = NULL; - double d[3] = {0, 0, 0}; - char* cavityname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !cavity) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_cavity")); - cavityname = str_get(&name); - } - - offset = e_wall + e_ext_insulation + e_int_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, 0, nverts, &footprint)); - - 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)); - } else { - ERR(scad_geometry_copy(geom, cavityname, cavity)); - } - -exit: - scad_geometry_delete(footprint); - scad_geometry_delete(geom); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} - -static res_T -build_attic - (const char* prefix, - const struct scpr_polygon* pg, - const double height, - const struct data_model1* data, - struct scad_geometry** attic) -{ - res_T res = RES_OK; - double e_wall = data->wall; - double e_insulation = data->ext_insulation; - double e_roof = data->roof; - double e_attic = data->attic; - double offset = 0; - double z_attic = 0; - struct scpr_polygon* pg_int = NULL; - size_t nverts = 0; - struct scad_geometry* footprint = NULL; - double d[3] = {0, 0, 0}; - char* atticname = NULL; - struct str name; - int is_init = 0; - - if (!pg || !data || !attic) { - res = RES_BAD_ARG; - goto error; - } - - if (prefix) { - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_attic")); - atticname = str_get(&name); - } - - offset = e_wall + e_insulation; - ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); - ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); - - /*footprint*/ - ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); - z_attic = height - e_roof - e_attic; - ERR(scad_add_polygon( - NULL, get_position_pg, pg_int, z_attic, nverts, &footprint)); - - d[2] = e_attic; - ERR(scad_geometry_extrude(footprint, atticname, d, attic)); - -exit: - scad_geometry_delete(footprint); - if (is_init) str_release(&name); - if (pg_int) scpr_polygon_ref_put(pg_int); - return res; -error: - goto exit; -} - -static res_T -build_windows - (const char* prefix, - const struct data_model1* data, - struct data_cad_model1* data_cad) -{ - res_T res = RES_OK; - size_t i = 0; - double N[3]; - double dir[3]; - double scale[3]; - struct scad_geometry* surface = NULL; - struct scad_geometry* hole = NULL; - struct scad_geometry** hole_list = NULL; - struct scad_geometry* geom = NULL; - struct scad_geometry* bcavity = NULL; - struct scad_geometry** list = NULL; - struct scad_geometry* glass = NULL; - struct scad_geometry** glass_list = NULL; - size_t list_n = 0; - char* name = NULL; - struct str gname; - int is_init = 0; - - if (!data || !data_cad) { - res = RES_BAD_ARG; - goto error; - } - - scale[0] = sqrt(data->glass_ratio); - scale[1] = scale[0]; - scale[2] = scale[0]; - - /* 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 = NULL; - size_t center_n = 0; - - ERR(scad_geometry_get_centerofmass(list[i], &center, &center_n)); - - ERR(scad_geometry_normal(list[i], center, N, NULL, &surface)); - - if (N[2] != 0) { - ERR(scad_geometry_delete(surface)); - surface = NULL; - continue; /* keep only vertical face */ - } - - ERR(scad_geometry_dilate(surface, center, scale)); - - dir[0] = 1.1*N[0] * (data->wall + data->int_insulation + data->ext_insulation); - dir[1] = 1.1*N[1] * (data->wall + data->int_insulation + data->ext_insulation); - dir[2] = 1.1*N[2] * (data->wall + data->int_insulation + data->ext_insulation); - ERR(scad_geometry_extrude(surface, NULL, dir, &hole)); - sa_push(hole_list, hole); - - dir[0] = N[0] * 0.024; - dir[1] = N[1] * 0.024; - dir[2] = N[2] * 0.024; - ERR(scad_geometry_extrude(surface, NULL, dir, &glass)); - sa_push(glass_list, glass); - - ERR(scad_geometry_delete(surface)); - surface = NULL; - } - - /* wall perforation */ - ERR(scad_geometry_get_name(data_cad->wall, &name)); - ERR(scad_cut_geometries( - NULL, &data_cad->wall, 1, hole_list, sa_size(hole_list), &geom)); - ERR(scad_geometry_delete(data_cad->wall)); - /*data_cad->wall = geom;*/ - ERR(scad_geometry_copy(geom, name, &data_cad->wall)); - ERR(scad_geometry_delete(geom)); - geom = NULL; - - /* internal insulation perforation */ - if (data_cad->internal_insulation) { - ERR(scad_geometry_get_name(data_cad->internal_insulation, &name)); - ERR(scad_cut_geometries( - NULL, &data_cad->internal_insulation, 1, - hole_list, sa_size(hole_list), &geom)); - ERR(scad_geometry_delete(data_cad->internal_insulation)); - ERR(scad_geometry_copy(geom, name, &data_cad->internal_insulation)); - ERR(scad_geometry_delete(geom)); - geom = NULL; - } - - /* external insulation perforation */ - if (data_cad->external_insulation) { - ERR(scad_geometry_get_name(data_cad->external_insulation, &name)); - ERR(scad_cut_geometries( - NULL, &data_cad->external_insulation, 1, - hole_list, sa_size(hole_list), &geom)); - ERR(scad_geometry_delete(data_cad->external_insulation)); - ERR(scad_geometry_copy(geom, name, &data_cad->external_insulation)); - ERR(scad_geometry_delete(geom)); - geom = NULL; - } - - /* build glass */ - if (prefix) { - str_init(NULL, &gname); - is_init = 1; - ERR(str_set(&gname, prefix)); - ERR(str_append(&gname, "_glass")); - } - - ERR(scad_fuse_geometries(str_cget(&gname), glass_list, 1, - glass_list+1, sa_size(glass_list) - 1, &data_cad->glass)); - -exit: - for (i=0 ; i<list_n; ++i) { - scad_geometry_delete(list[i]); - } - for (i=0 ; i<sa_size(hole_list); ++i) { - scad_geometry_delete(hole_list[i]); - } - for (i=0 ; i<sa_size(glass_list); ++i) { - scad_geometry_delete(glass_list[i]); - } - if (hole_list) sa_release(hole_list); - if (glass_list) sa_release(glass_list); - if (surface) scad_geometry_delete(surface); - if (geom) scad_geometry_delete(geom); - if (bcavity) scad_geometry_delete(bcavity); - /*scad_synchronize();*/ - if (name) free(name); - if (list) free(list); - if (is_init) str_release(&gname); - return res; -error: - goto exit; -} - -static res_T -build_boundary - (const char* prefix, - struct data_cad_model1* data_cad, - struct scad_geometry*** boundary) -{ - res_T res = RES_OK; - struct scad_geometry** list = NULL; - struct scad_geometry* bound = NULL; - char* boundaryname = NULL; - struct str name; - int is_init = 0; - - if (!prefix || !data_cad || !boundary) { - res = RES_BAD_ARG; - goto error; - } - - str_init(NULL, &name); - is_init = 1; - - sa_push(list, data_cad->wall); - sa_push(list, data_cad->roof); - sa_push(list, data_cad->floor); - sa_push(list, data_cad->habitable_cavity); - sa_push(list, data_cad->fake_ground); - if (data_cad->foundation) sa_push(list, data_cad->foundation); - if (data_cad->intermediate_floor) sa_push(list, data_cad->intermediate_floor); - if (data_cad->external_insulation) sa_push(list, data_cad->external_insulation); - if (data_cad->internal_insulation) sa_push(list, data_cad->internal_insulation); - if (data_cad->roof_insulation) sa_push(list, data_cad->roof_insulation); - if (data_cad->floor_insulation) sa_push(list, data_cad->floor_insulation); - if (data_cad->attic_cavity) sa_push(list, data_cad->attic_cavity); - if (data_cad->crawlspace_cavity) sa_push(list, data_cad->crawlspace_cavity); - if (data_cad->glass) sa_push(list, data_cad->glass); - - - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_boundary_wall")); - boundaryname = str_get(&name); - ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), - &data_cad->wall, 1, &bound)); - sa_push(*boundary, bound); - - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_boundary_roof")); - boundaryname = str_get(&name); - ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), - &data_cad->roof, 1, &bound)); - sa_push(*boundary, bound); - - if (data_cad->glass) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_boundary_glass")); - boundaryname = str_get(&name); - ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), - &data_cad->glass, 1, &bound)); - sa_push(*boundary, bound); - } - - if (data_cad->external_insulation) { - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_boundary_ext_insulation")); - boundaryname = str_get(&name); - ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), - &data_cad->external_insulation, 1, &bound)); - sa_push(*boundary, bound); - } - - if (data_cad->internal_insulation) { - size_t count = 0; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_boundary_int_insulation")); - boundaryname = str_get(&name); - ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), - &data_cad->internal_insulation, 1, &bound)); - ERR(scad_geometry_get_count(bound, &count)); - if (count>0) sa_push(*boundary, bound); - } - -exit: - if (is_init) str_release(&name); - if (list) sa_release(list); - return res; -error: - goto exit; -} - -static res_T -build_connection - (const char* prefix, - struct data_cad_model1* data_cad, - struct scad_geometry*** connection) -{ - res_T res = RES_OK; - struct scad_geometry* connect = NULL; - size_t count = 0; - char* cname = NULL; - struct str name; - int is_init = 0; - - if (!prefix || !data_cad || !connection) { - res = RES_BAD_ARG; - goto error; - } - - str_init(NULL, &name); - is_init = 1; - -#define CREATE_CONNECT(G1,G2,SUFFIX) ERR(str_set(&name, prefix));\ - ERR(str_append(&name, SUFFIX));\ - cname = str_get(&name);\ - ERR(scad_geometries_common_boundaries\ - (cname,\ - &data_cad->G1, 1,\ - &data_cad->G2, 1,\ - &connect));\ - ERR(scad_geometry_get_count(connect, &count)); \ - if (count>0) sa_push(*connection, connect); - - - /* -------------------------------------------------------------------------*/ - /* habitable cavity connections */ - /* -------------------------------------------------------------------------*/ - - /* with floor */ - CREATE_CONNECT(habitable_cavity,floor,"_C_cavity_floor"); - - /* with wall */ - CREATE_CONNECT(habitable_cavity,wall,"_C_cavity_wall"); - - /* with glass */ - if (data_cad->glass) { - CREATE_CONNECT(habitable_cavity,glass,"_C_cavity_glass"); - } - - /* with internal insulation */ - if (data_cad->internal_insulation) { - CREATE_CONNECT(habitable_cavity,internal_insulation,"_C_cavity_internal_insulation"); - } - - /* with roof insulation */ - if (data_cad->roof_insulation) { - CREATE_CONNECT(habitable_cavity,roof_insulation,"_C_roof_insulation"); - } else { - /* with roof */ - CREATE_CONNECT(habitable_cavity,roof,"_C_cavity_roof"); - } - - /* with intermediate floor */ - if (data_cad->intermediate_floor) { - CREATE_CONNECT(habitable_cavity,intermediate_floor,"_C_cavity_intermediate_floor"); - } - - /* -------------------------------------------------------------------------*/ - /* crawlspace cavity connections */ - /* -------------------------------------------------------------------------*/ - - if (data_cad->crawlspace_cavity) { - /* with floor insulation */ - if (data_cad->floor_insulation) { - CREATE_CONNECT(crawlspace_cavity, floor_insulation,"_C_crawlspace_insulation"); - } else { - /* with floor */ - CREATE_CONNECT(crawlspace_cavity, floor,"_C_crawlspace_floor"); - } - - /* with wall */ - CREATE_CONNECT(crawlspace_cavity, foundation,"_C_crawlspace_foundation"); - } - - /* -------------------------------------------------------------------------*/ - /* attic cavity connections */ - /* -------------------------------------------------------------------------*/ - - if (data_cad->attic_cavity) { - /* with roof */ - CREATE_CONNECT(attic_cavity, roof,"_C_attic_roof"); - - /* with roof insulation */ - CREATE_CONNECT(attic_cavity, roof_insulation,"_C_attic_insulation"); - - /* with wall */ - CREATE_CONNECT(attic_cavity, wall,"_C_attic_wall"); - } - -#undef CREATE_CONNECT - -exit: - if (is_init) str_release(&name); - return res; -error: - goto exit; -} - -static res_T -build_footprint - (struct scpr_polygon* pg, struct scad_geometry** footprint) -{ - res_T res = RES_OK; - size_t nverts = 0; - - if (!pg || !footprint) { - res = RES_BAD_ARG; - goto error; - } - - ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); - ERR(scad_add_polygon( - NULL, get_position_pg, pg, 0, nverts, footprint)); - -exit: - return res; -error: - goto exit; - -} - -static res_T -build_fake_ground - (struct data_cad_model1* cad, - struct scpr_polygon* pg, - const double depth, - struct scad_geometry** ground) -{ - res_T res = RES_OK; - double dir[3] = {0, 0, 0}; - struct scpr_polygon* pg_offset = NULL; - struct scad_geometry** list = NULL; - struct scad_geometry* footprint = NULL; - struct scad_geometry* geom = NULL; - - if (!cad || !pg || !ground ) { - res = RES_BAD_ARG; - goto error; - } - - if (cad->foundation) sa_push(list, cad->foundation); - if (cad->crawlspace_cavity) sa_push(list, cad->crawlspace_cavity); - if (cad->floor) sa_push(list, cad->floor); - if (cad->floor_insulation) sa_push(list, cad->floor_insulation); - - ERR(scpr_polygon_create_copy(NULL, pg, &pg_offset)); - ERR(scpr_offset_polygon(pg_offset, 0.1, SCPR_JOIN_MITER)); - - ERR(build_footprint(pg_offset, &footprint)); - - dir[2] = -depth*1.1; - ERR(scad_geometry_extrude(footprint, NULL, dir, &geom)); - - ERR(scad_cut_geometries(NULL, &geom, 1, list, sa_size(list), ground)); - -exit: - if (pg_offset) scpr_polygon_ref_put(pg_offset); - if (list) sa_release(list); - if (footprint) scad_geometry_delete(footprint); - if (geom) scad_geometry_delete(geom); - return res; -error: - goto exit; -} - - -static res_T -building_ground_connection - (const char* prefix, - struct data_cad_model1* cad, - struct scad_geometry** connection) -{ - res_T res = RES_OK; - char* cname = NULL; - struct str name; - int is_init = 0; - struct scad_geometry** list = NULL; - struct scad_geometry* list_boundary = NULL; - struct scad_geometry* footprint = NULL; - - if (!prefix || !cad || !connection) { - res = RES_BAD_ARG; - goto error; - } - - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, prefix)); - ERR(str_append(&name, "_C_building_ground")); - cname = str_get(&name); - - if (cad->foundation) sa_push(list, cad->foundation); - if (cad->attic_cavity) sa_push(list, cad->attic_cavity); - if (cad->floor) sa_push(list, cad->floor); - if (cad->floor_insulation) sa_push(list, cad->floor_insulation); - if (cad->external_insulation) sa_push(list, cad->external_insulation); - if (cad->wall) sa_push(list, cad->wall); - - ERR(scad_geometries_common_boundaries( - cname, list, sa_size(list), - &cad->fake_ground, 1, - connection)); - -exit: - if (list) sa_release(list); - if (is_init) str_release(&name); - if (list_boundary) scad_geometry_delete(list_boundary); - if (footprint) scad_geometry_delete(footprint); - return res; -error: - goto exit; -} - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - -res_T -init_model1 - (struct building* building, struct htable_building_params* htparams) -{ - res_T res = RES_OK; - struct data_model1 data; - struct building_params* params; - - params = htable_building_params_find(htparams, building->data_name); - if (params == NULL) { - res = RES_BAD_ARG; - goto error; - } - - if (params->model != building->model) { - res = RES_BAD_ARG; - goto error; - } - - data = *(struct data_model1*)params->data; - building->data = malloc(sizeof(struct data_model1)); - if (!building->data) { - res = RES_MEM_ERR; - goto error; - } - *(struct data_model1*)(building->data) = data; - building->build_cad = &build_cad_model1; - building->export_stl = &export_stl_model1; - building->release = &release_model1; - building->build_footprint = &build_footprint_model1; - -exit: - return res; -error: - goto exit; -} - -res_T -build_cad_model1(struct building* building) -{ - res_T res = RES_OK; - size_t id = building->id; - enum model_type model = building->model; - double height = building->height; - double depth = 0; - struct scpr_polygon* pg = building->pg; - struct data_model1* data = (struct data_model1 *)building->data; - struct data_cad_model1* data_cad; - struct str prefix; - int is_init = 0; - - if (!building) { - res = RES_BAD_ARG; - goto error; - } - - str_init(NULL, &prefix); - is_init = 1; - ERR(str_set(&prefix, "building_")); - ERR(str_append_printf(&prefix, "%lu_", (unsigned long)id)); - ERR(str_append(&prefix, model_str[model])); - - data_cad = malloc(sizeof(struct data_cad_model1)); - data_cad->wall = NULL; - data_cad->roof = NULL; - data_cad->floor = NULL; - data_cad->intermediate_floor = NULL; - data_cad->habitable_cavity = NULL; - data_cad->crawlspace_cavity = NULL; - data_cad->attic_cavity = NULL; - data_cad->internal_insulation = NULL; - data_cad->external_insulation = NULL; - data_cad->floor_insulation = NULL; - data_cad->roof_insulation = NULL; - data_cad->foundation = NULL; - data_cad->glass = NULL; - data_cad->ground_connection = NULL; - data_cad->boundary = NULL; - data_cad->connection = NULL; - building->data_cad = (struct data_cad_model1*)data_cad; - - /* build mandatories elements : - - floor - - wall - - roof - */ - - ERR(build_floor(str_cget(&prefix), pg, data, &data_cad->floor)); - - ERR(build_wall(str_cget(&prefix), "wall", pg, height, data, &data_cad->wall)); - - ERR(build_roof(str_cget(&prefix), pg, height, data, &data_cad->roof)); - - /* build optionnal elements : - - foundation - - intermediate floor - - external insulation - - internal insulation - - roof insulation - - floor insulation - */ - - if (data->foundation > 0) { - depth = -data->foundation; - ERR(build_wall( - str_cget(&prefix), "foundation", pg, depth, data, &data_cad->foundation)); - } else { - data_cad->foundation = NULL; - } - - if (data->inter_floor_n > 0) { - ERR(build_inter_floor( - str_cget(&prefix), pg, height, data, &data_cad->intermediate_floor)); - } else { - data_cad->intermediate_floor = NULL; - } - - if (data->ext_insulation > 0) { - ERR(build_ext_insulation( - str_cget(&prefix), pg, height, data, &data_cad->external_insulation)); - } else { - data_cad->external_insulation = NULL; - } - - if (data->int_insulation > 0) { - ERR(build_int_insulation( - str_cget(&prefix), pg, height, data, data_cad->intermediate_floor, - &data_cad->internal_insulation)); - } else { - data_cad->internal_insulation = NULL; - } - - if (data->roof_insulation > 0) { - ERR(build_roof_insulation( - str_cget(&prefix), pg, height, data, &data_cad->roof_insulation)); - } else { - data_cad->roof_insulation = NULL; - } - - if (data->floor_insulation > 0) { - ERR(build_floor_insulation( - str_cget(&prefix), pg, data, &data_cad->floor_insulation)); - } else { - data_cad->floor_insulation = NULL; - } - - /* build cavities : - - attic - - habitable - - crawlspace - */ - - if (data->attic > 0) { - ERR(build_attic( - str_cget(&prefix), pg, height, data, &data_cad->attic_cavity)); - } else { - data_cad->attic_cavity = NULL; - } - - ERR(build_habitable( - str_cget(&prefix), pg, height, data, data_cad->intermediate_floor, - &data_cad->habitable_cavity)); - - if (data->crawl > 0) { - ERR(build_crawlspace( - str_cget(&prefix), pg, data, &data_cad->crawlspace_cavity)); - } else { - data_cad->crawlspace_cavity = NULL; - } - - /* windows */ - if (data->glass_ratio > 0) { - ERR(build_windows(str_cget(&prefix), data, data_cad)); - } - - /* fake ground */ - depth = MMAX(data->foundation, data->floor + data->floor_insulation + data->crawl); - ERR(build_fake_ground(data_cad, pg, depth, &data_cad->fake_ground)); - - ERR(scad_scene_partition()); - - /* build ground/buildind connection */ - ERR(building_ground_connection(str_cget(&prefix), data_cad, - &data_cad->ground_connection)); - - /* build boundaries */ - data_cad->boundary = NULL; - ERR(build_boundary(str_cget(&prefix), data_cad, &data_cad->boundary)); - - /* build connections */ - data_cad->connection = NULL; - ERR(build_connection(str_cget(&prefix), data_cad, &data_cad->connection)); - -exit: - if (is_init) str_release(&prefix); - return res; -error: - goto exit; -} - -res_T -build_footprint_model1 - (struct building* building, - struct scad_geometry** footprint) -{ - res_T res = RES_OK; - struct scpr_polygon* pg = building->pg; - - if (!building || !footprint) { - res = RES_BAD_ARG; - goto error; - } - - ERR(build_footprint(pg, footprint)); - -exit: - return res; -error: - goto exit; -} - -res_T -export_stl_model1 - (const struct building* building, const int binary) -{ - res_T res = RES_OK; - struct data_cad_model1* data_cad = (struct data_cad_model1 *)building->data_cad; - size_t i = 0; - - /* floor export */ - ERR(scad_stl_export(data_cad->floor, NULL, binary)); - - /* wall export */ - ERR(scad_stl_export(data_cad->wall, NULL, binary)); - - /* roof export */ - ERR(scad_stl_export(data_cad->roof, NULL, binary)); - - /* foundation export */ - if (data_cad->foundation) { - ERR(scad_stl_export(data_cad->foundation, NULL, binary)); - } - - /* glass export */ - if (data_cad->glass) { - 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, binary)); - } - - /* internal insulation export*/ - if (data_cad->internal_insulation) { - 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, binary)); - } - - /* roof insulation export*/ - if (data_cad->roof_insulation) { - 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, binary)); - } - - /* attic cavity export*/ - if (data_cad->attic_cavity) { - ERR(scad_stl_export(data_cad->attic_cavity, NULL, binary)); - } - - /* habitable cavity export*/ - 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, binary)); - } - - /* boundary export*/ - for (i=0; i<sa_size(data_cad->boundary); ++i) { - ERR(scad_stl_export(data_cad->boundary[i], NULL, binary)); - } - - /* connections export*/ - for (i=0; i<sa_size(data_cad->connection); ++i) { - ERR(scad_stl_export(data_cad->connection[i], NULL, binary)); - } - - /* ground/building connection export*/ - ERR(scad_stl_export(data_cad->ground_connection, NULL, binary)); - -exit: - return res; -error: - goto exit; -} - -res_T -release_model1 - (struct building* building) -{ - res_T res = RES_OK; - struct data_model1* data = (struct data_model1 *)building->data; - struct data_cad_model1* data_cad = (struct data_cad_model1 *)building->data_cad; - - scpr_polygon_ref_put(building->pg); - - str_release(building->data_name); - - if (data_cad->boundary) sa_release(data_cad->boundary); - if (data_cad->connection) sa_release(data_cad->connection); - if (data) free(data); - if (data_cad) free(data_cad); - - return res; -} diff --git a/src/cg_building_model1.h b/src/cg_building_model1.h @@ -1,89 +0,0 @@ -/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA - * Copyright (C) 2022 CNRS - * Copyright (C) 2022 Sorbonne Université - * Copyright (C) 2022 Université Paul Sabatier - * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef BUILDING_MODEL1_H -#define BUILDING_MODEL1_H - -#include <rsys/rsys.h> - -struct scad_geometry; - -struct building; -struct htable_building_params; -struct building_params; - -/* specific data for model 0 */ -struct data_model1 { - size_t inter_floor_n; /* number of intermediate floor >= 0 */ - double wall; /* wall thickness > 0 */ - double floor; /* floor thickness > 0*/ - double inter_floor; /* intermediate floor thickness > 0 */ - double roof; /* roof thickness > 0*/ - double int_insulation; /* internal insulation thickness >= 0 */ - double ext_insulation; /* external insulation thickness >= 0 */ - double floor_insulation; /* floor insulation thickness >= 0 */ - double roof_insulation; /* roof insulation thickness >= 0*/ - double foundation; /* foundation depth >= 0 */ - double crawl; /* crawl space height >= 0 */ - double attic; /* attic height >= 0 (and only if roof insulation > 0)*/ - double glass_ratio; /* in [0, 1] */ -}; - -struct data_cad_model1 { - struct scad_geometry* wall; - struct scad_geometry* roof; - struct scad_geometry* floor; - struct scad_geometry* foundation; /* can be NULL */ - struct scad_geometry* intermediate_floor; /* can be NULL */ - struct scad_geometry* habitable_cavity; - struct scad_geometry* crawlspace_cavity; /* can be NULL */ - struct scad_geometry* attic_cavity; /* can be NULL */ - struct scad_geometry* internal_insulation; /* can be NULL */ - struct scad_geometry* external_insulation; /* can be NULL */ - struct scad_geometry* floor_insulation; /* can be NULL */ - struct scad_geometry* roof_insulation; /* can be NULL */ - struct scad_geometry* glass; - struct scad_geometry* fake_ground;/*not exported, used for ground connection*/ - struct scad_geometry* ground_connection; - struct scad_geometry** boundary; - struct scad_geometry** connection; - size_t n_connection; -}; - -res_T -init_model1 - (struct building* building, struct htable_building_params* htparams); - -res_T -build_cad_model1(struct building* building); - -res_T -build_footprint_model1 - (struct building* building, - struct scad_geometry** footprint); - -res_T -export_stl_model1 - (const struct building* building, const int binary); - -res_T -release_model1 - (struct building* building); - -#endif /* BUILDING_MODEL1_H */ diff --git a/src/cg_catalog.c b/src/cg_catalog.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "cg.h" +#include "cg_catalog.h" +#include "cg_catalog_parsing.h" +#include "cg_constructive_mode_0.h" +#include "cg_constructive_mode_1.h" +#include "cg_constructive_mode_0_parsing_schemas.h" +#include "cg_constructive_mode_1_parsing_schemas.h" + +#include <rsys/rsys.h> +#include <rsys/mem_allocator.h> +#include <rsys/logger.h> +#include <rsys/str.h> + +res_T +create_catalog + (struct mem_allocator* allocator, + struct logger* logger, + struct parsed_catalog* parsed_catalog, + struct catalog** out_catalog) +{ + res_T res = RES_OK; + size_t i, j, count; + const struct parsed_catalog_items* items; + struct catalog* catalog; + struct str name; + int name_initialized = 0; + + ASSERT(allocator && logger && parsed_catalog && out_catalog); + + catalog = MEM_ALLOC(allocator, sizeof(*catalog)); + if(!catalog) { + res = RES_MEM_ERR; + goto error; + } + + str_init(allocator, &name); + name_initialized = 0; + + catalog->allocator = allocator; + catalog->logger = logger; + htable_dataset_cmode_0_init(allocator, &catalog->catalog_0); + htable_dataset_cmode_1_init(allocator, &catalog->catalog_1); + count = darray_parsed_catalog_items_size_get(&parsed_catalog->catalog); + items = darray_parsed_catalog_items_cdata_get(&parsed_catalog->catalog); + + for(i = 0; i < count; i++) { + switch(items[i].constructive_mode) { + case mode_0: { + const struct parsed_catalog_cmode_0* parsed_0 = items[i].parsed_items; + for(j = 0; j < parsed_0->datasets_count; j++) { + const struct parsed_dataset_cmode_0* parsed_item + = parsed_0->datasets + j; + struct dataset_cmode_0 item; + ERR(str_set(&name, parsed_item->name)); + if(htable_dataset_cmode_0_find(&catalog->catalog_0, &name)) { + logger_print(logger, LOG_ERROR, + "Duplicate dataset name: '%s' (in file '%s').\n", + parsed_item->name, items[i].filename); + res = RES_BAD_ARG; + goto error; + } + item.wall_thickness = parsed_item->wall_thickness; + item.floor_thickness = parsed_item->floor_thickness; + ERR(htable_dataset_cmode_0_set(&catalog->catalog_0, &name, &item)); + } + break; + } + case mode_1: { + const struct parsed_catalog_cmode_1* parsed_1 = items[i].parsed_items; + for(j = 0; j < parsed_1->datasets_count; j++) { + const struct parsed_dataset_cmode_1* parsed_item + = parsed_1->datasets + j; + struct dataset_cmode_1 item; + ERR(str_set(&name, parsed_item->name)); + if(htable_dataset_cmode_1_find(&catalog->catalog_1, &name)) { + logger_print(logger, LOG_ERROR, + "Duplicate dataset name: '%s' (in file '%s').\n", + parsed_item->name, items[i].filename); + res = RES_BAD_ARG; + goto error; + } + 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; + item.roof_thickness = parsed_item->roof_thickness; + item.internal_insulation_thickness = parsed_item->internal_insulation_thickness; + item.external_insulation_thickness = parsed_item->external_insulation_thickness; + item.floor_insulation_thickness = parsed_item->floor_insulation_thickness; + item.roof_insulation_thickness = parsed_item->roof_insulation_thickness; + item.foundation_depth = parsed_item->foundation_depth; + item.crawl_height = parsed_item->crawl_height; + item.attic_height = parsed_item->attic_height; + item.glass_ratio = parsed_item->glass_ratio; + ERR(htable_dataset_cmode_1_set(&catalog->catalog_1, &name, &item)); + } + break; + } + default: FATAL("Invalid enum value."); + } + } +exit: + if(name_initialized) str_release(&name); + *out_catalog = catalog; + return res; +error: + release_catalog(catalog); + catalog = NULL; + goto exit; +} + +void +release_catalog + (struct catalog* catalog) +{ + if(!catalog) return; + + htable_dataset_cmode_0_release(&catalog->catalog_0); + htable_dataset_cmode_1_release(&catalog->catalog_1); + MEM_RM(catalog->allocator, catalog); +} + diff --git a/src/cg_catalog.h b/src/cg_catalog.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef FG_CATALOG__ +#define FG_CATALOG__ + +#include "cg_constructive_mode_0.h" +#include "cg_constructive_mode_1.h" +#include "cg_constructive_mode_0_parsing_schemas.h" +#include "cg_constructive_mode_1_parsing_schemas.h" + +struct mem_allocator; +struct logger; +struct parsed_catalog; +struct catalog; + +struct catalog { + struct mem_allocator* allocator; + struct logger* logger; + struct htable_dataset_cmode_0 catalog_0; + struct htable_dataset_cmode_1 catalog_1; +}; + +res_T +create_catalog + (struct mem_allocator* allocator, + struct logger* logger, + struct parsed_catalog* parsed_catalog, + struct catalog** out_catalog); + +void +release_catalog + (struct catalog* catalog); + +#endif diff --git a/src/cg_catalog_parsing.c b/src/cg_catalog_parsing.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "cg.h" +#include "cg_args.h" +#include "cg_catalog_parsing.h" +#include "cg_constructive_modes_parsing_schemas.h" +#include "cg_building.h" + +#include <rsys/logger.h> +#include <rsys/str.h> + +#include <cyaml/cyaml.h> + +static const struct cyaml_schema_value* +get_schema_from_parsed_cmode + (const enum parsed_cmode_type parsed_cmode) +{ + switch(parsed_cmode) { + case PARSED_CMODE_0: + return &constructive_mode_0_schema; + case PARSED_CMODE_1: + return &constructive_mode_1_schema; + default: FATAL("Invalid enum value.\n"); + } +} + +res_T +parse_catalog + (const struct darray_catalog_filenames* files_array, + struct mem_allocator* allocator, + struct logger* logger, + const struct cyaml_config* config, + struct parsed_catalog** out_parsed) +{ + res_T res = RES_OK; + cyaml_err_t err; + size_t i, files_count; + struct parsed_catalog_items* items; + struct parsed_catalog* parsed; + struct parsed_cmode* parsed_cmode = NULL; + char* filename = NULL; + (void)logger; + + ASSERT(files_array && allocator && logger && out_parsed); + + parsed = MEM_ALLOC(allocator, sizeof(*parsed)); + if(!parsed) { + res = RES_MEM_ERR; + goto error; + } + + parsed->allocator = allocator; + parsed->logger = logger; + + files_count = darray_catalog_filenames_size_get(files_array); + + darray_parsed_catalog_items_init(allocator, &parsed->catalog); + ERR(darray_parsed_catalog_items_resize(&parsed->catalog, files_count)); + items = darray_parsed_catalog_items_data_get(&parsed->catalog); + for(i = 0; i < files_count; i++) { + const struct cyaml_schema_value* schema; + + /* Parse constructive mode only */ + filename = darray_catalog_filenames_cdata_get(files_array)[i]; + err = cyaml_load_file(filename, config, &constructive_mode_schema, + (void**)&parsed_cmode, NULL); + ERR(cyaml_err_to_res_T(err)); + + /* Parse catalog items according to constructive mode */ + schema = get_schema_from_parsed_cmode(parsed_cmode->cmode_type); + err = cyaml_load_file(filename, config, schema, &items[i].parsed_items, NULL); + ERR(cyaml_err_to_res_T(err)); + + /* Set other fields*/ + items[i].filename = filename; + items[i].constructive_mode = parsed_cmode->cmode_type; + + /* Free tmp struct */ + err = cyaml_free(config, &constructive_mode_schema, parsed_cmode, 1); + CHK(RES_OK == cyaml_err_to_res_T(err)); + parsed_cmode = NULL; + filename = NULL; + } + +exit: + if(parsed_cmode) { + err = cyaml_free(config, &city_schema, parsed_cmode, 1); + CHK(RES_OK == cyaml_err_to_res_T(err)); + } + *out_parsed = parsed; + return res; +error: + if(filename) { + logger_print(logger, LOG_ERROR, + "Error parsing catalog file '%s'.\n", filename); + } + release_parsed_catalog(config, parsed); + parsed = NULL; + goto exit; +} + +void +release_parsed_catalog + (const struct cyaml_config* config, + struct parsed_catalog* parsed) +{ + struct parsed_catalog_items* items; + size_t i, count; + + if(!parsed) return; + + ASSERT(config); + + count = darray_parsed_catalog_items_size_get(&parsed->catalog); + items = darray_parsed_catalog_items_data_get(&parsed->catalog); + for(i = 0; i < count; i++) { + const struct cyaml_schema_value* schema + = get_schema_from_parsed_cmode(items[i].constructive_mode); + cyaml_err_t err = cyaml_free(config, schema, items[i].parsed_items, 1); + CHK(RES_OK == cyaml_err_to_res_T(err)); + } + darray_parsed_catalog_items_release(&parsed->catalog); + MEM_RM(parsed->allocator, parsed); +} diff --git a/src/cg_catalog_parsing.h b/src/cg_catalog_parsing.h @@ -0,0 +1,66 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef PARSING_H +#define PARSING_H + +#include "cg_building.h" +#include "cg_constructive_mode_0_parsing_schemas.h" +#include "cg_constructive_mode_1_parsing_schemas.h" +#include "cg_constructive_modes_parsing_schemas.h" + +#include <rsys/rsys.h> +#include <rsys/dynamic_array.h> + +struct logger; +struct mem_allocator; +struct cyaml_config; +struct cyaml_schema_value; +struct darray_catalog_filenames; + +struct parsed_catalog_items { + enum parsed_cmode_type constructive_mode; + const char* filename; + void* parsed_items; +}; + +#define DARRAY_NAME parsed_catalog_items +#define DARRAY_DATA struct parsed_catalog_items +#include <rsys/dynamic_array.h> + +struct parsed_catalog { + struct mem_allocator* allocator; + struct logger* logger; + struct darray_parsed_catalog_items catalog; +}; + +res_T +parse_catalog + (const struct darray_catalog_filenames* files, + struct mem_allocator* allocator, + struct logger* logger, + const struct cyaml_config* config, + struct parsed_catalog** catalog); + +void +release_parsed_catalog + (const struct cyaml_config* config, + struct parsed_catalog* parsed); + +#endif /*PARSING_H*/ diff --git a/src/cg_city.c b/src/cg_city.c @@ -17,139 +17,177 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <string.h> +#include "cg.h" +#include "cg_city.h" +#include "cg_constructive_mode_0.h" +#include "cg_ground.h" +#include "cg_catalog_parsing.h" +#include "cg_city_parsing.h" +#include "cg_building.h" +#include "cg_args.h" +#include "cg_city_parsing_schemas.h" #include <rsys/text_reader.h> #include <rsys/cstr.h> +#include <rsys/logger.h> +#include <rsys/mem_allocator.h> #include <rsys/stretchy_array.h> +#include <rsys/double4.h> -#include "cg.h" -#include "cg_city.h" -#include "cg_parsing.h" -#include "cg_building.h" -#include "cg_args.h" +#include <star/scpr.h> + +#include <string.h> res_T -city_init(struct logger* logger, struct city* city, struct args* args) +create_city + (struct mem_allocator* allocator, + struct logger* logger, + const struct args* args, + struct parsed_city* parsed_city, + struct catalog* catalog, + struct city** out_city) { res_T res = RES_OK; size_t i=0; - struct txtrdr* reader = NULL; - struct htable_building_params ht_params; + struct city* city = NULL; + (void)logger; - city->binary_export = args->binary_export; + ASSERT(logger && allocator && args && parsed_city && catalog && out_city); - ERR(txtrdr_file(NULL, args->city_model_file, '#', &reader)); - ERR(parse_city(logger, reader, city)); + city = MEM_CALLOC(allocator, 1, sizeof(*city)); + if(!city) { + res = RES_MEM_ERR; + goto error; + } + + city->buildings_count = parsed_city->city_building_list_count; + city->buildings = MEM_CALLOC(allocator, city->buildings_count, + sizeof(*city->buildings)); + if(!city->buildings) { + res = RES_MEM_ERR; + goto error; + } - ERR(parse_building_params(logger, &ht_params)); + city->allocator = allocator; + city->logger = logger; + city->verbosisty_level = args->verbosity_level; + city->binary_export = args->binary_export; - for (i=0; i<city->n ; ++i) { - city->building[i].release = NULL; - switch(city->building[i].model) { - case model0: - city->building[i].init = &init_model0; + city->ground_depth = parsed_city->ground.depth; + d4_set(city->ground_extent, parsed_city->ground.extent); + + /* create buildings depending on their constructive modes */ + for (i = 0; i < city->buildings_count ; ++i) { + struct parsed_city_building* parsed_data = parsed_city->city_building_list + i; + struct building* building = city->buildings + i; + switch(parsed_data->cmode_type) { + case PARSED_CMODE_0: + ERR(init_cmode_0(building, allocator, logger, parsed_data, catalog)); break; - case model1: - city->building[i].init = &init_model1; + case PARSED_CMODE_1: + ERR(init_cmode_1(building, allocator, logger, parsed_data, catalog)); break; default: res = RES_BAD_ARG; goto error; } - ERR(city->building[i].init(&city->building[i], &ht_params)); } exit: - txtrdr_ref_put(reader); - htable_building_params_release(&ht_params); + *out_city = city; return res; error: + release_city(city); + out_city = NULL; goto exit; } -res_T -city_release(struct city* city) +void +release_city(struct city* city) { - res_T res = RES_OK; - size_t i,n; + size_t i; + + if(!city) return; /* iterate on building */ - n = city->n; - for (i=0; i<n; ++i) { - if (city->building[i].release) { - ERR(city->building[i].release(&city->building[i])); - } + for (i=0; i<city->buildings_count; ++i) { + struct building* building = city->buildings + i; + SCPR(polygon_ref_put(building->pg)); + if(building->name_initialized) str_release(&building->name); } - ERR(ground_release(&city->ground)); - - if (city->building) sa_release(city->building); - -exit: - return res; -error: - goto exit; + MEM_RM(city->allocator, city->buildings); + MEM_RM(city->allocator, city); } res_T -city_cad_build(struct logger* logger, struct city* city) +city_cad_build(struct city* city) { res_T res = RES_OK; struct scad_options options = SCAD_DEFAULT_OPTIONS__; - size_t i,n; + int scad_initialized = 0; + size_t i; - ERR(scad_initialize(logger, NULL, 0)); + /* Initialize star-cad */ + ERR(scad_initialize(city->logger, city->allocator, city->verbosisty_level)); + scad_initialized = 1; options.Mesh.MeshSizeFromPoints = 0; ERR(scad_set_options(&options)); - /* iterate on building */ - n = city->n; - for (i=0; i<n; ++i) { + /* iterate on buildings */ + for(i=0; i<city->buildings_count; ++i) { + struct building* building = city->buildings + i; + struct data_cad_cmode_0* cad = NULL; /* create building */ - ERR(city->building[i].build_cad(&city->building[i])); + ERR(building->functors->build_cad(building, city->allocator, city->logger, + (void**)&cad)); ERR(scad_scene_mesh()); - ERR(city->building[i].export_stl(&city->building[i], city->binary_export)); + ERR(building->functors->export_stl(cad, city->allocator, city->logger, + city->binary_export)); + ERR(building->functors->release_cad(city->allocator, city->logger, cad)); ERR(scad_scene_clear()); } exit: - scad_finalize(); + if(scad_initialized) CHK(RES_OK == scad_finalize()); return res; error: goto exit; } res_T -city_ground_build(struct logger* logger, struct city* city) +city_ground_build(struct city* city) { res_T res = RES_OK; struct scad_options options = SCAD_DEFAULT_OPTIONS__; - size_t i,n; + int scad_initialized = 0; + struct ground ground = GROUND_NULL__; + size_t i; - ERR(scad_initialize(logger, NULL, 0)); + ERR(ground_allocate(city->allocator, city->buildings_count, &ground)); + + /* Initialize star-cad */ + ERR(scad_initialize(city->logger, city->allocator, city->verbosisty_level)); + scad_initialized = 1; options.Mesh.MeshSizeFromPoints = 0; ERR(scad_set_options(&options)); - - /* iterate on building */ - n = city->n; - city->ground.n = n; - city->ground.footprint = malloc(n * sizeof(struct scad_geometry*)); - for (i=0; i<n; ++i) { + /* iterate on buildings */ + for(i = 0; i < ground.footprints_count ; ++i) { + struct building* building = city->buildings + i; + struct scad_geometry** footprint = ground.footprints + i; /* create building footprint */ - ERR(city->building[i].build_footprint - (&city->building[i], - &city->ground.footprint[i])); + ERR(building->functors->build_footprint(building, city->allocator, + city->logger, footprint)); } - - ERR(ground_build_cad(&city->ground)); + ERR(ground_build_cad(city, &ground)); ERR(scad_scene_mesh()); - ERR(ground_export_stl(&city->ground, city->binary_export)); + ERR(ground_export_stl(&ground, city->binary_export)); exit: - scad_finalize(); + ground_release(city->allocator, &ground); + if(scad_initialized) CHK(RES_OK == scad_finalize()); return res; error: goto exit; diff --git a/src/cg_city.h b/src/cg_city.h @@ -20,61 +20,48 @@ #ifndef CITY_H #define CITY_H -#include <star/scad.h> - #include "cg_ground.h" +#include <star/scad.h> + struct logger; +struct mem_allocator; struct building; struct args; - -static INLINE void -log_prt_fn(const char* msg, void* ctx) -{ - ASSERT(msg); - (void)ctx; - - fprintf(stderr, "\x1b[32moutput:\x1b[0m %s", msg); -} - -static INLINE void -log_warn_fn(const char* msg, void* ctx) -{ - ASSERT(msg); - (void)ctx; - - fprintf(stderr, "\x1b[33mwarning:\x1b[0m %s", msg); -} - -static INLINE void -log_err_fn(const char* msg, void* ctx) -{ - ASSERT(msg); - (void)ctx; - - fprintf(stderr, "\x1b[31merror:\x1b[0m %s", msg); -} +struct parsed_city; +struct catalog; struct city { - struct building* building; /* list of buildings */ - size_t n; - struct ground ground; + double ground_extent[4]; /* [xmin, xmax, ymin, ymax */ + double ground_depth; + struct building* buildings; /* list of buildings */ + size_t buildings_count; int binary_export; -}; -#define CITY_NULL__ {NULL, 0, GROUND_NULL__, 0} -static const struct city CITY_NULL = CITY_NULL__; + struct mem_allocator* allocator; + struct logger* logger; + int verbosisty_level; +}; res_T -city_init(struct logger* logger, struct city* city, struct args* arg); +create_city + (struct mem_allocator* allocator, + struct logger* logger, + const struct args* args, + struct parsed_city* parsed_city, + struct catalog* catalog, + struct city** out_city); res_T -city_cad_build(struct logger* logger, struct city* city); +city_cad_build + (struct city* city); res_T -city_ground_build(struct logger* logger, struct city* city); +city_ground_build + (struct city* city); + +void +release_city(struct city* city); -res_T -city_release(struct city* city); #endif /*CITY_H*/ diff --git a/src/cg_city_parsing.c b/src/cg_city_parsing.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "cg.h" +#include "cg_city_parsing.h" +#include "cg_city_parsing_schemas.h" +#include "cg_ground.h" +#include "cg_city.h" + +#include <star/scpr.h> + +#include <rsys/logger.h> +#include <rsys/mem_allocator.h> + +#include <cyaml/cyaml.h> + +res_T +parse_city + (const char* name, + struct mem_allocator* allocator, + struct logger* logger, + const struct cyaml_config* config, + struct parsed_city** out_parsed) +{ + res_T res = RES_OK; + struct parsed_city *parsed = NULL; + cyaml_err_t err; + + ASSERT(allocator && logger && name && config && out_parsed); + + err = cyaml_load_file(name, config, &city_schema, (void**)&parsed, NULL); + ERR(cyaml_err_to_res_T(err)); + + parsed->allocator = allocator; + parsed->logger = logger; + +exit: + *out_parsed = parsed; + return res; +error: + logger_print(logger, LOG_ERROR, "Error parsing city map file '%s'.\n", name); + release_parsed_city(config, parsed); + parsed = NULL; + goto exit; +} + +void +release_parsed_city + (const struct cyaml_config* config, + struct parsed_city* parsed) +{ + cyaml_err_t err; + + if(!parsed) return; + + ASSERT(config); + + err = cyaml_free(config, &city_schema, parsed, 1); + CHK(RES_OK == cyaml_err_to_res_T(err)); +} diff --git a/src/cg_city_parsing.h b/src/cg_city_parsing.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef CITY_PARSING_H +#define CITY_PARSING_H + +#include <rsys/rsys.h> + +struct cyaml_config; +struct parsed_city; +struct mem_allocator; +struct logger; + +res_T +parse_city + (const char* name, + struct mem_allocator* allocator, + struct logger* logger, + const struct cyaml_config* config, + struct parsed_city** out_parsed); + +void +release_parsed_city + (const struct cyaml_config* config, + struct parsed_city* parsed); + +#endif /*CITY_PARSING_H*/ diff --git a/src/cg_city_parsing_schemas.h b/src/cg_city_parsing_schemas.h @@ -0,0 +1,145 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef FG_CITY_PARSING_SCHEMAS__ +#define FG_CITY_PARSING_SCHEMAS__ + +#include "cg_constructive_modes_parsing_schemas.h" + +#include <cyaml/cyaml.h> + +/********************************************************/ +/* Types used for parsing and to define parsing schemas */ +/********************************************************/ + +struct parsed_city_building { + char* name; + enum parsed_cmode_type cmode_type; + char* dataset_name; + double* vertice; /* flat array of vertice: { x0 y0 x1 y1 x2 y2... } */ + double height; + + unsigned vertice_count; +}; + +struct parsed_ground { + double extent[4]; + double depth; +}; + +struct parsed_city { + struct mem_allocator* allocator; + struct logger* logger; + struct parsed_city_building* city_building_list; + struct parsed_ground ground; + + unsigned city_building_list_count; +}; + +static const struct cyaml_schema_value coord_schema = { + CYAML_VALUE_FLOAT(CYAML_FLAG_DEFAULT, double), +}; + +static const cyaml_schema_field_t ground_fields_schema[] = { + CYAML_FIELD_FLOAT("depth", CYAML_FLAG_DEFAULT, struct parsed_ground, + depth), + CYAML_FIELD_SEQUENCE_FIXED("extent", CYAML_FLAG_FLOW, struct parsed_ground, + extent, &coord_schema, 4), + CYAML_FIELD_END +}; + +static const struct cyaml_schema_value p_ground_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct parsed_ground, + ground_fields_schema), +}; + +static const struct cyaml_schema_value entry_schema_double = { + CYAML_VALUE_FLOAT(CYAML_FLAG_DEFAULT, double), +}; + +static const struct cyaml_schema_value double2_schema = { + CYAML_VALUE_SEQUENCE_FIXED(CYAML_FLAG_DEFAULT, double, + &entry_schema_double, 2), +}; + +static const cyaml_schema_field_t city_building_fields_schema[] = { + CYAML_FIELD_STRING_PTR("id", /* TODO: rename "name" */ + CYAML_FLAG_POINTER, struct parsed_city_building, name, 0, CYAML_UNLIMITED), + CYAML_FIELD_ENUM("model", /* TODO: rename "constructive_mode" */ + CYAML_FLAG_CASE_INSENSITIVE, struct parsed_city_building, cmode_type, + city_building_types_strings, CYAML_ARRAY_LEN(city_building_types_strings)), + CYAML_FIELD_STRING_PTR("data", /* TODO: rename "parameter_set" */ + CYAML_FLAG_POINTER, struct parsed_city_building, dataset_name, 0, CYAML_UNLIMITED), + { + .key = "polygon", /*TODO: rename "external_polygon" */ + .value = { + .type = CYAML_SEQUENCE, + .flags = CYAML_FLAG_POINTER | CYAML_FLAG_FLOW, + .data_size = sizeof(double[2]), + .sequence = { + .entry = &double2_schema, + .min = 3, + .max = CYAML_UNLIMITED, + } + }, + /* TODO: add list of polygons "internal_polygons" */ + .data_offset = offsetof(struct parsed_city_building, vertice), + .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, + height), + CYAML_FIELD_END +}; + +static const struct cyaml_schema_value city_building_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_DEFAULT, struct parsed_city_building, + city_building_fields_schema), +}; + +static const cyaml_schema_field_t city_fields_schema[] = { + CYAML_FIELD_MAPPING("ground", CYAML_FLAG_DEFAULT, + struct parsed_city, ground, ground_fields_schema), + { + .key = "building", /* TODO: rename "buildings" */ + .value = { + .type = CYAML_SEQUENCE, + .flags = CYAML_FLAG_POINTER, + .data_size = sizeof(struct parsed_city_building), + .sequence = { + .entry = &city_building_schema, + .min = 1, + .max = CYAML_UNLIMITED, + } + }, + .data_offset = offsetof(struct parsed_city, city_building_list), + .count_size = sizeof(((struct parsed_city*)0)->city_building_list_count), + .count_offset = offsetof(struct parsed_city, city_building_list_count), + }, + CYAML_FIELD_END +}; + +/* Top-level schema. The top level value for the city is a mapping. + * Its fields are defined in plan_fields_schema. + */ +static const cyaml_schema_value_t city_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct parsed_city, city_fields_schema), +}; + +#endif diff --git a/src/cg_constructive_mode.h b/src/cg_constructive_mode.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef CONSTRUCTIVE_MODE_H__ +#define CONSTRUCTIVE_MODE_H__ + +#include <rsys/rsys.h> +#include "cg_city_parsing_schemas.h" + +#include <star/scpr.h> + +static void +get_nverts(const size_t icomp, size_t* nverts, void* context) +{ + struct parsed_city_building* parsed_data = context; + ASSERT(icomp == 0); (void)icomp; + *nverts = parsed_data->vertice_count; +} + +static void +get_pos(const size_t icomp, const size_t ivert, double pos[2], void* context) +{ + struct parsed_city_building* parsed_data = context; + ASSERT(icomp == 0); (void)icomp; + pos[0] = parsed_data->vertice[ivert*2 + 0]; + pos[1] = parsed_data->vertice[ivert*2 + 1]; +} + +static void get_position_pg + (const size_t ivert, double pos[2], void* ctx) +{ + struct scpr_polygon* pg = ctx; + ASSERT(pos && pg); + CHK(scpr_polygon_get_position(pg, 0, ivert, pos) == RES_OK); +} + +#endif + diff --git a/src/cg_constructive_mode_0.c b/src/cg_constructive_mode_0.c @@ -0,0 +1,634 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "cg.h" +#include "cg_building.h" +#include "cg_catalog.h" +#include "cg_city.h" +#include "cg_city_parsing_schemas.h" +#include "cg_constructive_mode_0.h" +#include "cg_constructive_mode.h" + +#include <rsys/rsys.h> +#include <rsys/str.h> +#include <rsys/logger.h> +#include <star/scad.h> + +static res_T +build_floor_footprint + (struct scpr_polygon* pg, + struct scad_geometry** footprint) +{ + res_T res = RES_OK; + size_t nverts; + + ASSERT(pg && footprint); + ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); + ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, footprint)); + +exit: + return res; +error: + goto exit; +} + +static res_T +build_floor + (const char* prefix, + struct scpr_polygon* pg, + struct building* b, + struct scad_geometry** floor) +{ + res_T res = RES_OK; + double e; + struct dataset_cmode_0* data; + struct scad_geometry* footprint = NULL; + double d[3] = {0, 0, 0}; + char* floorname = NULL; + struct str name; + int is_init = 0; + + ASSERT(pg && b && floor); + + data = (struct dataset_cmode_0*)b->data; + e = data->floor_thickness; + + str_init(NULL, &name); + is_init = 1; + if (prefix) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_floor")); + floorname = str_get(&name); + } + + ERR(build_floor_footprint(pg, &footprint)); + + d[2] = e; + ERR(scad_geometry_extrude(footprint, floorname, d, floor)); + +exit: + SCAD(geometry_delete(footprint)); + if (is_init) str_release(&name); + return res; +error: + goto exit; +} + +static res_T +build_roof + (const char* prefix, + const struct building* b, + const struct scad_geometry* floor, + struct scad_geometry** roof) +{ + res_T res = RES_OK; + double height; + double e; + double d[3] = {0, 0, 0}; + struct dataset_cmode_0* data; + char* roofname = NULL; + struct str name; + int is_init = 0; + + ASSERT(b && floor && roof); + + str_init(NULL, &name); + is_init = 1; + if (prefix) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_roof")); + roofname = str_get(&name); + } + + height = b->height; + data = (struct dataset_cmode_0*)b->data; + e = data->floor_thickness; + + ERR(scad_geometry_copy(floor, roofname, roof)); + d[2] = height - e ; + ERR(scad_geometry_translate(*roof, d)); + +exit: + if (is_init) str_release(&name); + return res; +error: + goto exit; +} + +static res_T +build_wall_footprint + (struct scpr_polygon* pg, + struct scpr_polygon* pg_int, + struct scad_geometry** footprint) +{ + res_T res = RES_OK; + struct scad_geometry* polygon = NULL; + struct scad_geometry* polygon_int = NULL; + size_t nverts, nverts_int; + + ASSERT(pg && pg_int && footprint); + + ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); + ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &polygon)); + + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts_int)); + ERR(scad_add_polygon(NULL, get_position_pg, pg_int, 0, nverts_int, &polygon_int)); + + ERR(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)); + return res; +error: + goto exit; +} + +static res_T +build_wall + (const char* prefix, + struct scpr_polygon* pg, + struct scpr_polygon* pg_int, + struct building* b, + struct scad_geometry** wall) +{ + res_T res = RES_OK; + double height; + struct scad_geometry* footprint = NULL; + double d[3] = {0, 0, 0}; + char* wallname = NULL; + struct str name; + int is_init = 0; + + ASSERT(pg && pg_int && b && wall); + + height = b->height; + + str_init(NULL, &name); + is_init = 1; + if (prefix) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_wall")); + wallname = str_get(&name); + } + + ERR(build_wall_footprint(pg, pg_int, &footprint)); + + d[2] = height; + ERR(scad_geometry_extrude(footprint, wallname, d, wall)); + +exit: + if(footprint) SCAD(geometry_delete(footprint)); + if (is_init) str_release(&name); + return res; +error: + goto exit; +} + +static res_T +build_cavity + (const char* prefix, + struct scpr_polygon* pg, + const struct building* b, + struct scad_geometry** cavity) +{ + res_T res = RES_OK; + double e, height; + struct dataset_cmode_0* data; + double d[3] = {0, 0, 0}; + struct scad_geometry* polygon = NULL; + char* cavityname = NULL; + struct str name; + int is_init = 0; + size_t nverts; + + ASSERT(pg && b && cavity); + + height = b->height; + data = (struct dataset_cmode_0*)b->data; + e = data->floor_thickness; + + str_init(NULL, &name); + is_init = 1; + if (prefix) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_cavity")); + cavityname = str_get(&name); + } + + ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); + ERR(scad_add_polygon(NULL, get_position_pg, pg, e, nverts, &polygon)); + + d[2] = height - e; + ERR(scad_geometry_extrude(polygon, cavityname, d, cavity)); + +exit: + if(polygon) SCAD(geometry_delete(polygon)); + if (is_init) str_release(&name); + return res; +error: + goto exit; +} + +static res_T +build_connection + (const char* prefix, + struct mem_allocator* allocator, + struct data_cad_cmode_0* cad) +{ + res_T res = RES_OK; + char* cname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && cad); + + cad->connection = MEM_CALLOC(allocator, 3, sizeof(struct scad_geometry*)); + if(!cad->connection) { + res = RES_MEM_ERR; + goto error; + } + cad->n_connection = 3; + + /* cavity/floor connection */ + str_init(NULL, &name); + is_init = 1; + if (prefix) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_C_cavity_floor")); + cname = str_get(&name); + } + + ERR(scad_geometries_common_boundaries(cname, &cad->cavity, 1, &cad->floor, 1, + &cad->connection[0])); + + /* cavity/wall connection */ + if (prefix) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_C_cavity_wall")); + cname = str_get(&name); + } + + ERR(scad_geometries_common_boundaries(cname, &cad->cavity, 1, &cad->wall, 1, + &cad->connection[1])); + + /* cavity/roof connection */ + if (prefix) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_C_cavity_roof")); + cname = str_get(&name); + } + + ERR(scad_geometries_common_boundaries(cname, &cad->cavity, 1, &cad->roof, 1, + &cad->connection[2])); + +exit: + if (is_init) str_release(&name); + return res; +error: + goto exit; +} + +static res_T +build_boundary + (const char* prefix, + struct mem_allocator* allocator, + struct data_cad_cmode_0* cad) +{ + res_T res = RES_OK; + struct scad_geometry** list = NULL; + struct scad_geometry* boundary = NULL; + char* cname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && cad); + + list = MEM_ALLOC(allocator, 4 * sizeof(struct scad_geometry*)); + if(!list) { + res = RES_MEM_ERR; + goto error; + } + list[0] = cad->floor; + list[1] = cad->wall; + list[2] = cad->roof; + list[3] = cad->cavity; + + str_init(NULL, &name); + is_init = 1; + if (prefix) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_boundary")); + cname = str_get(&name); + } + + ERR(scad_geometry_boundary(NULL, list, 4, &boundary)); + + ERR(scad_cut_geometries(cname, &boundary, 1, &cad->ground_connection, 1, + &cad->boundary)); + +exit: + if(boundary) SCAD(geometry_delete(boundary)); + MEM_RM(allocator, list); + if (is_init) str_release(&name); + return res; +error: + goto exit; +} + +static res_T +building_ground_connection + (const char* prefix, + struct scpr_polygon* pg, + const double e, + struct scad_geometry** connection) +{ + res_T res = RES_OK; + struct scpr_polygon* pg_int = NULL; + struct scad_geometry* geom[2] = { NULL, NULL }; + char* cname = NULL; + struct str name; + int is_init = 0; + + ASSERT(pg && e > 0 && connection); + + if (prefix) { + str_init(NULL, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_C_building_ground")); + cname = str_get(&name); + } + + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -e, SCPR_JOIN_MITER)); + + ERR(build_wall_footprint(pg, pg_int, &geom[0])); + ERR(build_floor_footprint(pg, &geom[1])); + + ERR(scad_fragment_geometries(cname, &geom[0], 1, &geom[1], 1, connection)); + +exit: + if(is_init) str_release(&name); + if(geom[0]) SCAD(geometry_delete(geom[0])); + if(geom[1]) SCAD(geometry_delete(geom[1])); + if(pg_int) SCPR(polygon_ref_put(pg_int)); + return res; +error: + goto exit; +} + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +res_T +init_cmode_0 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct parsed_city_building* parsed_data, + struct catalog* catalog) +{ + res_T res = RES_OK; + struct dataset_cmode_0* dataset; + struct str dataset_name; + int name_initialized = 0; + static struct constructive_mode_functors functors_0 + = { + &init_cmode_0, + &build_cad_cmode_0, + &build_footprint_cmode_0, + &export_stl_cmode_0, + &release_cad_cmode_0 + }; + (void)parsed_data; + + if(!building || !allocator || !parsed_data || !catalog) { + res = RES_BAD_ARG; + goto error; + } + + building->constructive_mode = mode_0; + building->functors = &functors_0; + building->height = parsed_data->height; + str_init(allocator, &building->name); + building->name_initialized = 1; + str_init(allocator, &dataset_name); + name_initialized = 1; + ERR(str_set(&building->name, parsed_data->name)); + ERR(str_set(&dataset_name, parsed_data->dataset_name)); + + ERR(scpr_polygon_create(allocator, &building->pg)); + ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos, + parsed_data)); + dataset = htable_dataset_cmode_0_find(&catalog->catalog_0, &dataset_name); + if (dataset == NULL) { + ERR(logger_print(logger, LOG_ERROR, + "Unknown dataset name: '%s' used by building '%s'.\n", + str_cget(&dataset_name), str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + + building->data = dataset; + +exit: + if(name_initialized) str_release(&dataset_name); + return res; +error: + goto exit; +} + +res_T +build_cad_cmode_0 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + 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; + + if (!building || !allocator || !cad) { + res = RES_BAD_ARG; + goto error; + } + + height = building->height; + pg = building->pg; + data = (struct dataset_cmode_0 *)building->data; + + if (height <= 0 || data->wall_thickness <= 0 || data->floor_thickness <= 0) { + res = RES_BAD_ARG; + goto error; + } + + data_cad = MEM_CALLOC(allocator, 1, sizeof(struct data_cad_cmode_0)); + if(!data_cad) { + res = RES_MEM_ERR; + goto error; + } + + e_wall = data->wall_thickness; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -e_wall, SCPR_JOIN_MITER)); + + /* build floor with pg_int */ + name = str_cget(&building->name); + ERR(build_floor(name, pg_int, building, &data_cad->floor)); + + /* roof is a translated copy of floor */ + 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)); + + /* build cavity */ + ERR(build_cavity(name, pg_int, building, &data_cad->cavity)); + + ERR(scad_scene_partition()); + + /* build ground/building connection */ + ERR(building_ground_connection(name, pg, e_wall, &data_cad->ground_connection)); + + /* build boundary */ + ERR(build_boundary(name, allocator, data_cad)); + + /* build cavity/floor connectiona*/ + ERR(build_connection(name, allocator, data_cad)); + +exit: + if(pg_int) SCPR(polygon_ref_put(pg_int)); + *(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)); + data_cad = NULL; + goto exit; +} + +res_T +build_footprint_cmode_0 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct scad_geometry** footprint) +{ + res_T res = RES_OK; + struct scpr_polygon* pg = building->pg; + struct dataset_cmode_0* data = (struct dataset_cmode_0 *)building->data; + double e_wall; + (void)allocator; (void)logger; + + if(!building || ! footprint) { + res = RES_BAD_ARG; + goto error; + } + + e_wall = data->wall_thickness; + + ERR(building_ground_connection(NULL, pg, e_wall, footprint)); + +exit: + return res; +error: + goto exit; +} + +res_T +export_stl_cmode_0 + (void* cad, + struct mem_allocator* allocator, + struct logger* logger, + 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; + + if(!cad) { + res = RES_BAD_ARG; + goto error; + } + + /* floor export */ + ERR(scad_stl_export(data_cad->floor, NULL, binary)); + + /* roof export */ + ERR(scad_stl_export(data_cad->roof, NULL, binary)); + + /* wall export */ + ERR(scad_stl_export(data_cad->wall, NULL, binary)); + + /* cavity export */ + 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, binary)); + } + + /* boundary export */ + ERR(scad_stl_export(data_cad->boundary, NULL, binary)); + + /* footprint export */ + ERR(scad_stl_export(data_cad->ground_connection, NULL, binary)); + +exit: + return res; +error: + goto exit; +} + +res_T +release_cad_cmode_0 + (struct mem_allocator* allocator, + struct logger* logger, + void* cad) +{ + res_T res = RES_OK; + struct data_cad_cmode_0* data_cad = (struct data_cad_cmode_0 *)cad; + size_t i; + (void)logger; + + if(!allocator || ! cad) { + res = RES_BAD_ARG; + goto error; + } + + if(data_cad->boundary) SCAD(geometry_delete(data_cad->boundary)); + for(i = 0; i < data_cad->n_connection; i++) { + SCAD(geometry_delete(data_cad->connection[i])); + } + MEM_RM(allocator, data_cad->connection); + MEM_RM(allocator, data_cad); + +exit: + return res; +error: + goto exit; +} diff --git a/src/cg_constructive_mode_0.h b/src/cg_constructive_mode_0.h @@ -0,0 +1,99 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef CONSTRUCTIVE_MODE_0_H +#define CONSTRUCTIVE_MODE_0_H + +#include <rsys/rsys.h> +#include <rsys/str.h> +#include <rsys/hash_table.h> + +struct scad_geometry; + +struct building; +struct mem_allocator; +struct logger; +struct parsed_city_building; +struct catalog; + +/* specific data for constructive mode 0 */ +struct dataset_cmode_0 { + double wall_thickness; + double floor_thickness; +}; + +#define HTABLE_NAME dataset_cmode_0 +#define HTABLE_DATA struct dataset_cmode_0 +#define HTABLE_KEY struct str +#define HTABLE_KEY_FUNCTOR_INIT str_init +#define HTABLE_KEY_FUNCTOR_RELEASE str_release +#define HTABLE_KEY_FUNCTOR_COPY str_copy +#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release +#define HTABLE_KEY_FUNCTOR_COPY_AND_CLEAR str_copy_and_clear +#define HTABLE_KEY_FUNCTOR_EQ str_eq +#define HTABLE_KEY_FUNCTOR_HASH str_hash +#include <rsys/hash_table.h> + +struct data_cad_cmode_0 { + struct scad_geometry* wall; + struct scad_geometry* roof; + struct scad_geometry* floor; + struct scad_geometry* cavity; + struct scad_geometry* boundary; + struct scad_geometry** connection; + struct scad_geometry* ground_connection; + size_t n_connection; +}; + +res_T +init_cmode_0 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct parsed_city_building* parsed_data, + struct catalog* catalog); + +res_T +build_cad_cmode_0 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + void** cad); + +res_T +build_footprint_cmode_0 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct scad_geometry** footprint); + +res_T +export_stl_cmode_0 + (void* cad, + struct mem_allocator* allocator, + struct logger* logger, + const int binary); + +res_T +release_cad_cmode_0 + (struct mem_allocator* allocator, + struct logger* logger, + void* cad); + +#endif /* CONSTRUCTIVE_MODE_0_H */ diff --git a/src/cg_constructive_mode_0_parsing_schemas.h b/src/cg_constructive_mode_0_parsing_schemas.h @@ -0,0 +1,97 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef FG_MODE0_PARSING_SCHEMAS__ +#define FG_MODE0_PARSING_SCHEMAS__ + +#include "cg_building.h" +#include "cg_city_parsing_schemas.h" + +#include <cyaml/cyaml.h> + +#include <rsys/rsys.h> +#include <rsys/str.h> + +struct scpr_polygon; +struct scad_geometry; +struct mem_allocator; + +struct parsed_dataset_cmode_0 { + char* name; + double wall_thickness; /* must be > 0 */ + double floor_thickness; /* must be > 0 */ +}; + +/********************************************************/ +/* Types used for parsing and to define parsing schemas */ +/********************************************************/ + +struct parsed_catalog_cmode_0 { + struct parsed_dataset_cmode_0* datasets; + size_t datasets_count; +}; + +static const cyaml_schema_field_t dataset_cmode_0_fields_schema[] = { + CYAML_FIELD_STRING_PTR("name", CYAML_FLAG_POINTER, + struct parsed_dataset_cmode_0, name, 0, CYAML_UNLIMITED), + CYAML_FIELD_FLOAT("wall_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_0, wall_thickness), + CYAML_FIELD_FLOAT("floor_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_0, floor_thickness), + CYAML_FIELD_END +}; + +static const struct cyaml_schema_value p_dataset_cmode_0_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct parsed_dataset_cmode_0, + dataset_cmode_0_fields_schema), +}; + +static const struct cyaml_schema_value dataset_cmode_0_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_DEFAULT, struct parsed_dataset_cmode_0, + dataset_cmode_0_fields_schema), +}; + +static const cyaml_schema_field_t cmode_0_fields_schemas[] = { + CYAML_FIELD_IGNORE("contructive_mode_type", CYAML_FLAG_DEFAULT), + { + .key = "sets", + .value = { + .type = CYAML_SEQUENCE, + .flags = CYAML_FLAG_POINTER, + .data_size = sizeof(struct parsed_dataset_cmode_0), + .sequence = { + .entry = &dataset_cmode_0_schema, + .min = 1, + .max = CYAML_UNLIMITED, + } + }, + .data_offset = offsetof(struct parsed_catalog_cmode_0, datasets), + .count_size = sizeof(((struct parsed_catalog_cmode_0*)0)->datasets_count), + .count_offset = offsetof(struct parsed_catalog_cmode_0, datasets_count), + }, + CYAML_FIELD_END +}; + +/* Top-level schema. The top level value for the constructive mode is a mapping */ +static const cyaml_schema_value_t constructive_mode_0_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct parsed_catalog_cmode_0, + cmode_0_fields_schemas), +}; + +#endif diff --git a/src/cg_constructive_mode_1.c b/src/cg_constructive_mode_1.c @@ -0,0 +1,1486 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "cg.h" +#include "cg_building.h" +#include "cg_catalog.h" +#include "cg_city_parsing_schemas.h" +#include "cg_constructive_mode.h" +#include "cg_constructive_mode_1.h" + +#include <rsys/str.h> +#include <rsys/logger.h> +#include <rsys/stretchy_array.h> +#include <star/scad.h> +#include <star/scpr.h> + +static res_T +build_floor + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const struct dataset_cmode_1* data, + struct scad_geometry** floor) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_insulation = data->external_insulation_thickness; + double e_floor = data->floor_thickness; + double offset = 0; + struct scpr_polygon* pg_int = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + double d[3] = {0, 0, 0}; + char* floorname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && floor); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_floor")); + floorname = str_get(&name); + } + + offset = e_wall + e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + ERR(scad_add_polygon(NULL, get_position_pg, pg_int, 0, nverts, &footprint)); + + d[2] = -e_floor; + ERR(scad_geometry_extrude(footprint, floorname, d, floor)); + +exit: + SCAD(geometry_delete(footprint)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + return res; +error: + goto exit; +} + +static res_T +build_wall + (const char* prefix, + const char* suffix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const double height, + const struct dataset_cmode_1* data, + struct scad_geometry** wall) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_insulation = data->external_insulation_thickness; + double offset = 0; + struct scpr_polygon* pg_int = NULL; + struct scpr_polygon* pg_ext = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + struct scad_geometry* footprint_int = NULL; + struct scad_geometry* footprint_ext = NULL; + double d[3] = {0, 0, 0}; + char* wallname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && wall); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + if (suffix) { + ERR(str_append(&name, "_")); + ERR(str_append(&name, suffix)); + } + wallname = str_get(&name); + } + + offset = e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_ext)); + ERR(scpr_offset_polygon(pg_ext, -offset, SCPR_JOIN_MITER)); + + offset = e_wall + e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*wall footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts)); + ERR(scad_add_polygon( + NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); + + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + ERR(scad_add_polygon( + NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); + + ERR(scad_cut_geometries( + NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); + + d[2] = height; + ERR(scad_geometry_extrude(footprint, wallname, d, wall)); + +exit: + SCAD(geometry_delete(footprint)); + SCAD(geometry_delete(footprint_int)); + SCAD(geometry_delete(footprint_ext)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + if (pg_ext) SCPR(polygon_ref_put(pg_ext)); + return res; +error: + goto exit; +} + +static res_T +build_int_insulation + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const double height, + const struct dataset_cmode_1* data, + struct scad_geometry* inter_floor, + struct scad_geometry** insulation) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_roof = data->roof_thickness; + double e_roof_insulation = data->roof_insulation_thickness; + double attic = data->attic_height; + double e_ext_insulation = data->external_insulation_thickness; + double e_int_insulation = data->internal_insulation_thickness; + double offset = 0; + struct scpr_polygon* pg_int = NULL; + struct scpr_polygon* pg_ext = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + struct scad_geometry* footprint_int = NULL; + struct scad_geometry* footprint_ext = NULL; + struct scad_geometry* geom = NULL; + double d[3] = {0, 0, 0}; + char* insulationname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && insulation); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_int_insulation")); + insulationname = str_get(&name); + } + + offset = e_ext_insulation + e_wall; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_ext)); + ERR(scpr_offset_polygon(pg_ext, -offset, SCPR_JOIN_MITER)); + + offset = e_ext_insulation + e_wall + e_int_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /* insulation footprint */ + ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts)); + ERR(scad_add_polygon( + NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); + + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + ERR(scad_add_polygon(NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); + + ERR(scad_cut_geometries(NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); + + d[2] = height - e_roof - attic - e_roof_insulation; + ERR(scad_geometry_extrude(footprint, NULL, d, &geom)); + + if (inter_floor) { + ERR(scad_cut_geometries(insulationname, &geom, 1, &inter_floor, 1, insulation)); + } else { + ERR(scad_geometry_copy(geom, insulationname, insulation)); + } + +exit: + SCAD(geometry_delete(footprint)); + SCAD(geometry_delete(footprint_int)); + SCAD(geometry_delete(footprint_ext)); + SCAD(geometry_delete(geom)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + if (pg_ext) SCPR(polygon_ref_put(pg_ext)); + return res; +error: + goto exit; +} + +static res_T +build_roof + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const double height, + const struct dataset_cmode_1* data, + struct scad_geometry** roof) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_insulation = data->external_insulation_thickness; + double e_roof = data->roof_thickness; + double offset = 0; + double z_roof = 0; + struct scpr_polygon* pg_int = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + double d[3] = {0, 0, 0}; + char* roofname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && roof); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_roof")); + roofname = str_get(&name); + } + + offset = e_wall + e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + z_roof = height - e_roof; + ERR(scad_add_polygon(NULL, get_position_pg, pg_int, z_roof, nverts, &footprint)); + + d[2] = e_roof; + ERR(scad_geometry_extrude(footprint, roofname, d, roof)); + +exit: + SCAD(geometry_delete(footprint)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + return res; +error: + goto exit; +} + +static res_T +build_roof_insulation + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const double height, + const struct dataset_cmode_1* data, + struct scad_geometry** insulation) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_insulation = data->external_insulation_thickness; + double e_roof = data->roof_thickness; + double attic = data->attic_height; + double e_roof_insulation = data->roof_insulation_thickness; + double offset = 0; + double z_insulation = 0; + struct scpr_polygon* pg_int = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + double d[3] = {0, 0, 0}; + char* insulationname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && insulation); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_roof_insulation")); + insulationname = str_get(&name); + } + + offset = e_wall + e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + z_insulation = height - e_roof - attic - e_roof_insulation; + ERR(scad_add_polygon( + NULL, get_position_pg, pg_int, z_insulation, nverts, &footprint)); + + d[2] = e_roof_insulation; + ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); + +exit: + SCAD(geometry_delete(footprint)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + return res; +error: + goto exit; +} + +static res_T +build_floor_insulation + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const struct dataset_cmode_1* data, + struct scad_geometry** insulation) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_insulation = data->external_insulation_thickness; + double e_floor = data->floor_thickness; + double e_floor_insulation = data->floor_insulation_thickness; + double offset = 0; + double z_insulation = 0; + struct scpr_polygon* pg_int = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + double d[3] = {0, 0, 0}; + char* insulationname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && insulation); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_floor_insulation")); + insulationname = str_get(&name); + } + + offset = e_wall + e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + z_insulation = - e_floor - e_floor_insulation; + ERR(scad_add_polygon( + NULL, get_position_pg, pg_int, z_insulation, nverts, &footprint)); + + d[2] = e_floor_insulation; + ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); + +exit: + SCAD(geometry_delete(footprint)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + return res; +error: + goto exit; +} + +static res_T +build_inter_floor + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const double height, + const struct dataset_cmode_1* data, + struct scad_geometry** inter_floor) +{ + res_T res = RES_OK; + size_t i = 0; + size_t floor_n = data->inter_floor_count; + double e_roof = data->roof_thickness; + double e_roof_ins = data->roof_insulation_thickness; + double attic = data->attic_height; + double e_floor = data->inter_floor_thickness; + double e_wall = data->wall_thickness; + double e_insulation = data->external_insulation_thickness; + double offset = 0; + double z_floor = 0; + double h_cavity = 0; + struct scpr_polygon* pg_int = NULL; + size_t nverts = 0; + struct scad_geometry** floor_list = NULL; + double d[3] = {0, 0, 0}; + char* floorname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && inter_floor); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_inter_floor")); + floorname = str_get(&name); + } + + offset = e_wall + e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + + h_cavity = height - e_roof - attic - e_roof_ins - (double)floor_n*e_floor; + z_floor = h_cavity/(double)(1 + floor_n); + d[2] = e_floor; + for (i=0; i< floor_n; ++i) { + 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_geometry_extrude(footprint, NULL, d, &floor)); + sa_push(floor_list, floor); + ERR(scad_geometry_delete(footprint)); + z_floor += h_cavity/(double)(1 + floor_n) + e_floor; + } + + ERR(scad_fuse_geometries( + floorname, + floor_list, sa_size(floor_list), + floor_list, sa_size(floor_list), + inter_floor)); + +exit: + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + if (floor_list) { + for (i=0; i< floor_n; ++i) { + SCAD(geometry_delete(floor_list[i])); + } + sa_release(floor_list); + } + return res; +error: + goto exit; +} + +static res_T +build_ext_insulation + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const double height, + const struct dataset_cmode_1* data, + struct scad_geometry** insulation) +{ + res_T res = RES_OK; + double e_insulation = data->external_insulation_thickness; + double offset = 0; + struct scpr_polygon* pg_int = NULL; + struct scpr_polygon* pg_ext = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + struct scad_geometry* footprint_int = NULL; + struct scad_geometry* footprint_ext = NULL; + double d[3] = {0, 0, 0}; + char* insulationname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && insulation); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_ext_insulation")); + insulationname = str_get(&name); + } + + offset = e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_polygon_create_copy(NULL, pg, &pg_ext)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*insulation footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_ext, 0, &nverts)); + ERR(scad_add_polygon( + NULL, get_position_pg, pg_ext, 0, nverts, &footprint_ext)); + + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + ERR(scad_add_polygon( + NULL, get_position_pg, pg_int, 0, nverts, &footprint_int)); + + ERR(scad_cut_geometries( + NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); + + d[2] = height; + ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); + +exit: + SCAD(geometry_delete(footprint)); + SCAD(geometry_delete(footprint_int)); + SCAD(geometry_delete(footprint_ext)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + if (pg_ext) SCPR(polygon_ref_put(pg_ext)); + return res; +error: + goto exit; +} + +static res_T +build_crawlspace + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const struct dataset_cmode_1* data, + struct scad_geometry** crawlspace) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_insulation = data->external_insulation_thickness; + double e_crawl = data->crawl_height; + double e_floor = data->floor_thickness; + double e_floor_insulation = data->floor_insulation_thickness; + double offset = 0; + double z_crawl= 0; + struct scpr_polygon* pg_int = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + double d[3] = {0, 0, 0}; + char* crawlname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && crawlspace); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_crawlspace")); + crawlname = str_get(&name); + } + + offset = e_wall + e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + z_crawl = - e_floor - e_floor_insulation - e_crawl; + ERR(scad_add_polygon( + NULL, get_position_pg, pg_int, z_crawl, nverts, &footprint)); + + d[2] = e_crawl; + ERR(scad_geometry_extrude(footprint, crawlname, d, crawlspace)); + +exit: + SCAD(geometry_delete(footprint)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + return res; +error: + goto exit; +} + +static res_T +build_habitable + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const double height, + const struct dataset_cmode_1* data, + struct scad_geometry* floor, + struct scad_geometry** cavity) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_ext_insulation = data->external_insulation_thickness; + double e_int_insulation = data->internal_insulation_thickness; + double e_roof = data->roof_thickness; + double e_roof_insulation = data->roof_insulation_thickness; + double e_attic = data->attic_height; + double offset = 0; + struct scpr_polygon* pg_int = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + struct scad_geometry* geom = NULL; + double d[3] = {0, 0, 0}; + char* cavityname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && cavity); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_cavity")); + cavityname = str_get(&name); + } + + offset = e_wall + e_ext_insulation + e_int_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + ERR(scad_add_polygon( + NULL, get_position_pg, pg_int, 0, nverts, &footprint)); + + 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)); + } else { + ERR(scad_geometry_copy(geom, cavityname, cavity)); + } + +exit: + SCAD(geometry_delete(footprint)); + SCAD(geometry_delete(geom)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + return res; +error: + goto exit; +} + +static res_T +build_attic + (const char* prefix, + struct mem_allocator* allocator, + const struct scpr_polygon* pg, + const double height, + const struct dataset_cmode_1* data, + struct scad_geometry** attic) +{ + res_T res = RES_OK; + double e_wall = data->wall_thickness; + double e_insulation = data->external_insulation_thickness; + double e_roof = data->roof_thickness; + double e_attic = data->attic_height; + double offset = 0; + double z_attic = 0; + struct scpr_polygon* pg_int = NULL; + size_t nverts = 0; + struct scad_geometry* footprint = NULL; + double d[3] = {0, 0, 0}; + char* atticname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && pg && data && attic); + + if (prefix) { + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_attic")); + atticname = str_get(&name); + } + + offset = e_wall + e_insulation; + ERR(scpr_polygon_create_copy(NULL, pg, &pg_int)); + ERR(scpr_offset_polygon(pg_int, -offset, SCPR_JOIN_MITER)); + + /*footprint*/ + ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); + z_attic = height - e_roof - e_attic; + ERR(scad_add_polygon( + NULL, get_position_pg, pg_int, z_attic, nverts, &footprint)); + + d[2] = e_attic; + ERR(scad_geometry_extrude(footprint, atticname, d, attic)); + +exit: + SCAD(geometry_delete(footprint)); + if (is_init) str_release(&name); + if (pg_int) SCPR(polygon_ref_put(pg_int)); + return res; +error: + goto exit; +} + +static res_T +build_windows + (const char* prefix, + struct mem_allocator* allocator, + const struct dataset_cmode_1* data, + struct data_cad_cmode_1* data_cad) +{ + res_T res = RES_OK; + size_t i = 0; + double N[3]; + double dir[3]; + double scale[3]; + struct scad_geometry* surface = NULL; + struct scad_geometry* hole = NULL; + struct scad_geometry** hole_list = NULL; + struct scad_geometry* geom = NULL; + struct scad_geometry* bcavity = NULL; + struct scad_geometry** list = NULL; + struct scad_geometry* glass = NULL; + struct scad_geometry** glass_list = NULL; + size_t list_n = 0; + struct str gname; + int is_init = 0; + + ASSERT(allocator && data && data_cad); + + scale[0] = sqrt(data->glass_ratio); + scale[1] = scale[0]; + scale[2] = scale[0]; + + /* 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 = NULL; + size_t center_n = 0; + + ERR(scad_geometry_get_centerofmass(list[i], &center, &center_n)); + + ERR(scad_geometry_normal(list[i], center, N, NULL, &surface)); + + if (N[2] != 0) { + ERR(scad_geometry_delete(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); + ERR(scad_geometry_extrude(surface, NULL, dir, &hole)); + sa_push(hole_list, hole); + + dir[0] = N[0] * 0.024; + dir[1] = N[1] * 0.024; + dir[2] = N[2] * 0.024; + ERR(scad_geometry_extrude(surface, NULL, dir, &glass)); + sa_push(glass_list, glass); + + ERR(scad_geometry_delete(surface)); + surface = NULL; + } + + /* wall perforation */ + ERR(scad_cut_geometries(NULL, &data_cad->wall, 1, + hole_list, sa_size(hole_list), &geom)); + ERR(scad_geometry_swap_names(data_cad->wall, geom)); + ERR(scad_geometry_delete(data_cad->wall)); + data_cad->wall = geom; + geom = NULL; + + /* internal insulation perforation */ + if (data_cad->internal_insulation) { + ERR(scad_cut_geometries(NULL, &data_cad->internal_insulation, 1, + hole_list, sa_size(hole_list), &geom)); + ERR(scad_geometry_swap_names(data_cad->internal_insulation, geom)); + ERR(scad_geometry_delete(data_cad->internal_insulation)); + data_cad->internal_insulation = geom; + geom = NULL; + } + + /* external insulation perforation */ + if (data_cad->external_insulation) { + ERR(scad_cut_geometries(NULL, &data_cad->external_insulation, 1, + hole_list, sa_size(hole_list), &geom)); + ERR(scad_geometry_swap_names(data_cad->external_insulation, geom)); + ERR(scad_geometry_delete(data_cad->external_insulation)); + data_cad->external_insulation = geom; + geom = NULL; + } + + /* build glass */ + if (prefix) { + str_init(allocator, &gname); + is_init = 1; + ERR(str_set(&gname, prefix)); + ERR(str_append(&gname, "_glass")); + } + + ERR(scad_fuse_geometries(str_cget(&gname), glass_list, 1, + glass_list+1, sa_size(glass_list) - 1, &data_cad->glass)); + +exit: + for (i=0 ; i<list_n; ++i) { + SCAD(geometry_delete(list[i])); + } + for (i=0 ; i<sa_size(hole_list); ++i) { + SCAD(geometry_delete(hole_list[i])); + } + for (i=0 ; i<sa_size(glass_list); ++i) { + SCAD(geometry_delete(glass_list[i])); + } + if (hole_list) sa_release(hole_list); + if (glass_list) sa_release(glass_list); + if (surface) SCAD(geometry_delete(surface)); + if (geom) SCAD(geometry_delete(geom)); + if (bcavity) SCAD(geometry_delete(bcavity)); + MEM_RM(allocator, list); + if (is_init) str_release(&gname); + return res; +error: + goto exit; +} + +static res_T +build_boundary + (const char* prefix, + struct mem_allocator* allocator, + struct data_cad_cmode_1* data_cad, + struct scad_geometry*** boundary) +{ + res_T res = RES_OK; + struct scad_geometry** list = NULL; + struct scad_geometry* bound = NULL; + char* boundaryname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && prefix && data_cad && boundary); + + str_init(allocator, &name); + is_init = 1; + + sa_push(list, data_cad->wall); + sa_push(list, data_cad->roof); + sa_push(list, data_cad->floor); + sa_push(list, data_cad->habitable_cavity); + sa_push(list, data_cad->fake_ground); + if (data_cad->foundation) sa_push(list, data_cad->foundation); + if (data_cad->intermediate_floor) sa_push(list, data_cad->intermediate_floor); + if (data_cad->external_insulation) sa_push(list, data_cad->external_insulation); + if (data_cad->internal_insulation) sa_push(list, data_cad->internal_insulation); + if (data_cad->roof_insulation) sa_push(list, data_cad->roof_insulation); + if (data_cad->floor_insulation) sa_push(list, data_cad->floor_insulation); + if (data_cad->attic_cavity) sa_push(list, data_cad->attic_cavity); + if (data_cad->crawlspace_cavity) sa_push(list, data_cad->crawlspace_cavity); + if (data_cad->glass) sa_push(list, data_cad->glass); + + + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_boundary_wall")); + boundaryname = str_get(&name); + ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), + &data_cad->wall, 1, &bound)); + sa_push(*boundary, bound); + + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_boundary_roof")); + boundaryname = str_get(&name); + ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), + &data_cad->roof, 1, &bound)); + sa_push(*boundary, bound); + + if (data_cad->glass) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_boundary_glass")); + boundaryname = str_get(&name); + ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), + &data_cad->glass, 1, &bound)); + sa_push(*boundary, bound); + } + + if (data_cad->external_insulation) { + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_boundary_ext_insulation")); + boundaryname = str_get(&name); + ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), + &data_cad->external_insulation, 1, &bound)); + sa_push(*boundary, bound); + } + + if (data_cad->internal_insulation) { + size_t count = 0; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_boundary_int_insulation")); + boundaryname = str_get(&name); + ERR(scad_geometries_common_boundaries(boundaryname, list, sa_size(list), + &data_cad->internal_insulation, 1, &bound)); + ERR(scad_geometry_get_count(bound, &count)); + if (count>0) sa_push(*boundary, bound); + } + +exit: + if (is_init) str_release(&name); + if (list) sa_release(list); + return res; +error: + goto exit; +} + +static res_T +build_connection + (const char* prefix, + struct mem_allocator* allocator, + struct data_cad_cmode_1* data_cad, + struct scad_geometry*** connection) +{ + res_T res = RES_OK; + struct scad_geometry* connect = NULL; + size_t count = 0; + char* cname = NULL; + struct str name; + int is_init = 0; + + ASSERT(allocator && prefix && data_cad && connection); + + str_init(allocator, &name); + is_init = 1; + +#define CREATE_CONNECT(G1,G2,SUFFIX) ERR(str_set(&name, prefix));\ + ERR(str_append(&name, SUFFIX));\ + cname = str_get(&name);\ + ERR(scad_geometries_common_boundaries\ + (cname,\ + &data_cad->G1, 1,\ + &data_cad->G2, 1,\ + &connect));\ + ERR(scad_geometry_get_count(connect, &count)); \ + if (count>0) sa_push(*connection, connect); + + + /* -------------------------------------------------------------------------*/ + /* habitable cavity connections */ + /* -------------------------------------------------------------------------*/ + + /* with floor */ + CREATE_CONNECT(habitable_cavity,floor,"_C_cavity_floor"); + + /* with wall */ + CREATE_CONNECT(habitable_cavity,wall,"_C_cavity_wall"); + + /* with glass */ + if (data_cad->glass) { + CREATE_CONNECT(habitable_cavity,glass,"_C_cavity_glass"); + } + + /* with internal insulation */ + if (data_cad->internal_insulation) { + CREATE_CONNECT(habitable_cavity,internal_insulation,"_C_cavity_internal_insulation"); + } + + /* with roof insulation */ + if (data_cad->roof_insulation) { + CREATE_CONNECT(habitable_cavity,roof_insulation,"_C_roof_insulation"); + } else { + /* with roof */ + CREATE_CONNECT(habitable_cavity,roof,"_C_cavity_roof"); + } + + /* with intermediate floor */ + if (data_cad->intermediate_floor) { + CREATE_CONNECT(habitable_cavity,intermediate_floor,"_C_cavity_intermediate_floor"); + } + + /* -------------------------------------------------------------------------*/ + /* crawlspace cavity connections */ + /* -------------------------------------------------------------------------*/ + + if (data_cad->crawlspace_cavity) { + /* with floor insulation */ + if (data_cad->floor_insulation) { + CREATE_CONNECT(crawlspace_cavity, floor_insulation,"_C_crawlspace_insulation"); + } else { + /* with floor */ + CREATE_CONNECT(crawlspace_cavity, floor,"_C_crawlspace_floor"); + } + + /* with wall */ + CREATE_CONNECT(crawlspace_cavity, foundation,"_C_crawlspace_foundation"); + } + + /* -------------------------------------------------------------------------*/ + /* attic cavity connections */ + /* -------------------------------------------------------------------------*/ + + if (data_cad->attic_cavity) { + /* with roof */ + CREATE_CONNECT(attic_cavity, roof,"_C_attic_roof"); + + /* with roof insulation */ + CREATE_CONNECT(attic_cavity, roof_insulation,"_C_attic_insulation"); + + /* with wall */ + CREATE_CONNECT(attic_cavity, wall,"_C_attic_wall"); + } + +#undef CREATE_CONNECT + +exit: + if (is_init) str_release(&name); + return res; +error: + goto exit; +} + +static res_T +build_footprint + (struct scpr_polygon* pg, + struct scad_geometry** footprint) +{ + res_T res = RES_OK; + size_t nverts = 0; + + ASSERT(pg && footprint); + + ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); + ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, footprint)); + +exit: + return res; +error: + goto exit; +} + +static res_T +build_fake_ground + (struct data_cad_cmode_1* cad, + struct scpr_polygon* pg, + const double depth, + struct scad_geometry** ground) +{ + res_T res = RES_OK; + double dir[3] = {0, 0, 0}; + struct scpr_polygon* pg_offset = NULL; + struct scad_geometry** list = NULL; + struct scad_geometry* footprint = NULL; + struct scad_geometry* geom = NULL; + + ASSERT(cad && pg && ground ); + + if (cad->foundation) sa_push(list, cad->foundation); + if (cad->crawlspace_cavity) sa_push(list, cad->crawlspace_cavity); + if (cad->floor) sa_push(list, cad->floor); + if (cad->floor_insulation) sa_push(list, cad->floor_insulation); + + ERR(scpr_polygon_create_copy(NULL, pg, &pg_offset)); + ERR(scpr_offset_polygon(pg_offset, 0.1, SCPR_JOIN_MITER)); + + ERR(build_footprint(pg_offset, &footprint)); + + dir[2] = -depth*1.1; + ERR(scad_geometry_extrude(footprint, NULL, dir, &geom)); + + ERR(scad_cut_geometries(NULL, &geom, 1, list, sa_size(list), ground)); + +exit: + if (pg_offset) SCPR(polygon_ref_put(pg_offset)); + if (list) sa_release(list); + if (footprint) SCAD(geometry_delete(footprint)); + if (geom) SCAD(geometry_delete(geom)); + return res; +error: + goto exit; +} + +static res_T +building_ground_connection + (const char* prefix, + struct mem_allocator* allocator, + struct data_cad_cmode_1* cad, + struct scad_geometry** connection) +{ + res_T res = RES_OK; + char* cname = NULL; + struct str name; + int is_init = 0; + struct scad_geometry** list = NULL; + struct scad_geometry* list_boundary = NULL; + struct scad_geometry* footprint = NULL; + + ASSERT(prefix && allocator && cad && connection); + + str_init(allocator, &name); + is_init = 1; + ERR(str_set(&name, prefix)); + ERR(str_append(&name, "_C_building_ground")); + cname = str_get(&name); + + if (cad->foundation) sa_push(list, cad->foundation); + if (cad->attic_cavity) sa_push(list, cad->attic_cavity); + if (cad->floor) sa_push(list, cad->floor); + if (cad->floor_insulation) sa_push(list, cad->floor_insulation); + if (cad->external_insulation) sa_push(list, cad->external_insulation); + if (cad->wall) sa_push(list, cad->wall); + + ERR(scad_geometries_common_boundaries( + cname, list, sa_size(list), + &cad->fake_ground, 1, + connection)); + +exit: + if (list) sa_release(list); + if (is_init) str_release(&name); + if (list_boundary) SCAD(geometry_delete(list_boundary)); + if (footprint) SCAD(geometry_delete(footprint)); + return res; +error: + goto exit; +} + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +res_T +init_cmode_1 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct parsed_city_building* parsed_data, + struct catalog* catalog) +{ + res_T res = RES_OK; + struct dataset_cmode_1* dataset; + struct str dataset_name; + int name_initialized = 0; + static struct constructive_mode_functors functors_1 + = { + &init_cmode_1, + &build_cad_cmode_1, + &build_footprint_cmode_1, + &export_stl_cmode_1, + &release_cad_cmode_1 + }; + (void) parsed_data; + + if(!building || !allocator || !parsed_data ||!catalog) { + res = RES_BAD_ARG; + goto error; + } + + building->constructive_mode = mode_1; + building->functors = &functors_1; + building->height = parsed_data->height; + str_init(allocator, &building->name); + building->name_initialized = 1; + str_init(allocator, &dataset_name); + name_initialized = 1; + ERR(str_set(&building->name, parsed_data->name)); + ERR(str_set(&dataset_name, parsed_data->dataset_name)); + + ERR(scpr_polygon_create(allocator, &building->pg)); + ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos, + parsed_data)); + dataset = htable_dataset_cmode_1_find(&catalog->catalog_1, &dataset_name); + if (dataset == NULL) { + ERR(logger_print(logger, LOG_ERROR, + "Unknown dataset name: '%s' used by building '%s'.\n", + str_cget(&dataset_name), str_cget(&building->name))); + res = RES_BAD_ARG; + goto error; + } + + building->data = dataset; + +exit: + if(name_initialized) str_release(&dataset_name); + return res; +error: + goto exit; +} + +res_T +build_cad_cmode_1 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + void** cad) +{ + res_T res = RES_OK; + double height = building->height; + double depth = 0; + struct scpr_polygon* pg = building->pg; + struct dataset_cmode_1* data = (struct dataset_cmode_1 *)building->data; + struct data_cad_cmode_1* data_cad = NULL; + const char* name; + + if (!building || !allocator || !cad) { + res = RES_BAD_ARG; + goto error; + } + + data_cad = MEM_CALLOC(allocator, 1, sizeof(struct data_cad_cmode_1)); + if(!data_cad) { + res = RES_MEM_ERR; + goto error; + } + + /* build mandatories elements : + - floor + - wall + - roof + */ + + name = str_cget(&building->name); + ERR(build_floor(name, allocator, pg, data, &data_cad->floor)); + + ERR(build_wall(name, "wall", allocator, pg, height, data, &data_cad->wall)); + + ERR(build_roof(name, allocator, pg, height, data, &data_cad->roof)); + + /* build optionnal elements : + - foundation + - intermediate floor + - external insulation + - internal insulation + - roof insulation + - floor insulation + */ + + if (data->foundation_depth > 0) { + depth = -data->foundation_depth; + ERR(build_wall(name, "foundation", allocator, pg, depth, data, + &data_cad->foundation)); + } + + if (data->inter_floor_count > 0) { + ERR(build_inter_floor(name, allocator, pg, height, data, + &data_cad->intermediate_floor)); + } + + if (data->external_insulation_thickness> 0) { + ERR(build_ext_insulation(name, allocator, pg, height, data, + &data_cad->external_insulation)); + } + + if (data->internal_insulation_thickness> 0) { + ERR(build_int_insulation(name, allocator, pg, height, data, + data_cad->intermediate_floor, &data_cad->internal_insulation)); + } + + if (data->roof_insulation_thickness > 0) { + ERR(build_roof_insulation(name, allocator, pg, height, data, + &data_cad->roof_insulation)); + } + + if (data->floor_insulation_thickness > 0) { + ERR(build_floor_insulation(name, allocator, pg, data, + &data_cad->floor_insulation)); + } + + /* build cavities : + - attic + - habitable + - crawlspace + */ + + if (data->attic_height > 0) { + ERR(build_attic(name, allocator, pg, height, data, &data_cad->attic_cavity)); + } + + ERR(build_habitable(name, allocator, pg, height, data, + data_cad->intermediate_floor, &data_cad->habitable_cavity)); + + if (data->crawl_height > 0) { + ERR(build_crawlspace(name, allocator, pg, data, &data_cad->crawlspace_cavity)); + } + + /* windows */ + if (data->glass_ratio > 0) { + ERR(build_windows(name, allocator, data, data_cad)); + } + + /* fake ground */ + depth = MMAX(data->foundation_depth, data->floor_thickness + + data->floor_insulation_thickness + data->crawl_height); + ERR(build_fake_ground(data_cad, pg, depth, &data_cad->fake_ground)); + + ERR(scad_scene_partition()); + + /* build ground/buildind connection */ + ERR(building_ground_connection(name, allocator, data_cad, + &data_cad->ground_connection)); + + /* build boundaries */ + ERR(build_boundary(name, allocator, data_cad, &data_cad->boundary)); + + /* build connections */ + ERR(build_connection(name, allocator, data_cad, &data_cad->connection)); + +exit: + *(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)); + data_cad = NULL; + goto exit; +} + +res_T +build_footprint_cmode_1 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct scad_geometry** footprint) +{ + res_T res = RES_OK; + struct scpr_polygon* pg = building->pg; + (void)allocator; (void)logger; + + if (!building || !footprint) { + res = RES_BAD_ARG; + goto error; + } + + ERR(build_footprint(pg, footprint)); + +exit: + return res; +error: + goto exit; +} + +res_T +export_stl_cmode_1 + (void* cad, + struct mem_allocator* allocator, + struct logger* logger, + 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; + goto error; + } + + /* floor export */ + ERR(scad_stl_export(data_cad->floor, NULL, binary)); + + /* wall export */ + ERR(scad_stl_export(data_cad->wall, NULL, binary)); + + /* roof export */ + ERR(scad_stl_export(data_cad->roof, NULL, binary)); + + /* foundation export */ + if (data_cad->foundation) { + ERR(scad_stl_export(data_cad->foundation, NULL, binary)); + } + + /* glass export */ + if (data_cad->glass) { + 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, binary)); + } + + /* internal insulation export*/ + if (data_cad->internal_insulation) { + 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, binary)); + } + + /* roof insulation export*/ + if (data_cad->roof_insulation) { + 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, binary)); + } + + /* attic cavity export*/ + if (data_cad->attic_cavity) { + ERR(scad_stl_export(data_cad->attic_cavity, NULL, binary)); + } + + /* habitable cavity export*/ + 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, binary)); + } + + /* boundary export*/ + for (i=0; i<sa_size(data_cad->boundary); ++i) { + ERR(scad_stl_export(data_cad->boundary[i], NULL, binary)); + } + + /* connections export*/ + for (i=0; i<sa_size(data_cad->connection); ++i) { + ERR(scad_stl_export(data_cad->connection[i], NULL, binary)); + } + + /* ground/building connection export*/ + ERR(scad_stl_export(data_cad->ground_connection, NULL, binary)); + +exit: + return res; +error: + goto exit; +} + +res_T +release_cad_cmode_1 + (struct mem_allocator* allocator, + struct logger* logger, + 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; + + if (!allocator || !cad) { + res = RES_BAD_ARG; + goto error; + } + + for(i = 0; i < sa_size(data_cad->boundary); i++) { + ERR(scad_geometry_delete(data_cad->boundary[i])); + } + for(i = 0; i < sa_size(data_cad->connection); i++) { + ERR(scad_geometry_delete(data_cad->connection[i])); + } + sa_release(data_cad->boundary); + sa_release(data_cad->connection); + MEM_RM(allocator, data_cad); + +exit: + return res; +error: + goto exit; +} diff --git a/src/cg_constructive_mode_1.h b/src/cg_constructive_mode_1.h @@ -0,0 +1,120 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef CONSTRUCTIVE_MODE_1_H +#define CONSTRUCTIVE_MODE_1_H + +#include <rsys/rsys.h> +#include <rsys/str.h> +#include <rsys/hash_table.h> + +struct scad_geometry; + +struct building; +struct mem_allocator; +struct logger; +struct parsed_city_building; +struct catalog; + +/* specific data for constructive mode 1 */ +struct dataset_cmode_1 { + 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 */ + double roof_thickness; /* must be > 0 */ + double internal_insulation_thickness; /* can be 0 */ + double external_insulation_thickness; /* can be 0 */ + double floor_insulation_thickness; /* can be 0 */ + double roof_insulation_thickness; /* can be 0 */ + double foundation_depth; /* can be 0 */ + double crawl_height; /* can be 0 */ + double attic_height; /* can be 0 */ + double glass_ratio; /* in [0, 1] */ +}; + +#define HTABLE_NAME dataset_cmode_1 +#define HTABLE_DATA struct dataset_cmode_1 +#define HTABLE_KEY struct str +#define HTABLE_KEY_FUNCTOR_INIT str_init +#define HTABLE_KEY_FUNCTOR_RELEASE str_release +#define HTABLE_KEY_FUNCTOR_COPY str_copy +#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release +#define HTABLE_KEY_FUNCTOR_COPY_AND_CLEAR str_copy_and_clear +#define HTABLE_KEY_FUNCTOR_EQ str_eq +#define HTABLE_KEY_FUNCTOR_HASH str_hash +#include <rsys/hash_table.h> + +struct data_cad_cmode_1 { + struct scad_geometry* wall; + struct scad_geometry* roof; + struct scad_geometry* floor; + struct scad_geometry* foundation; /* can be NULL */ + struct scad_geometry* intermediate_floor; /* can be NULL */ + struct scad_geometry* habitable_cavity; + struct scad_geometry* crawlspace_cavity; /* can be NULL */ + struct scad_geometry* attic_cavity; /* can be NULL */ + struct scad_geometry* internal_insulation; /* can be NULL */ + struct scad_geometry* external_insulation; /* can be NULL */ + struct scad_geometry* floor_insulation; /* can be NULL */ + struct scad_geometry* roof_insulation; /* can be NULL */ + struct scad_geometry* glass; + struct scad_geometry* fake_ground;/*not exported, used for ground connection*/ + struct scad_geometry* ground_connection; + struct scad_geometry** boundary; + struct scad_geometry** connection; + size_t n_connection; +}; + +res_T +init_cmode_1 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct parsed_city_building* parsed_data, + struct catalog* catalog); + +res_T +build_cad_cmode_1 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + void** cad); + +res_T +build_footprint_cmode_1 + (struct building* building, + struct mem_allocator* allocator, + struct logger* logger, + struct scad_geometry** footprint); + +res_T +export_stl_cmode_1 + (void* cad, + struct mem_allocator* allocator, + struct logger* logger, + const int binary); + +res_T +release_cad_cmode_1 + (struct mem_allocator* allocator, + struct logger* logger, + void* cad); + +#endif /* CONSTRUCTIVE_MODE_1_H */ diff --git a/src/cg_constructive_mode_1_parsing_schemas.h b/src/cg_constructive_mode_1_parsing_schemas.h @@ -0,0 +1,132 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef FG_MODE1_PARSING_SCHEMAS__ +#define FG_MODE1_PARSING_SCHEMAS__ + +#include "cg_building.h" +#include "cg_city_parsing_schemas.h" + +#include <cyaml/cyaml.h> + +#include <rsys/rsys.h> +#include <rsys/str.h> + +struct scpr_polygon; +struct scad_geometry; +struct mem_allocator; + +struct parsed_dataset_cmode_1 { + 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 */ + double roof_thickness; /* must be > 0 */ + double internal_insulation_thickness; /* can be 0 */ + double external_insulation_thickness; /* can be 0 */ + double floor_insulation_thickness; /* can be 0 */ + double roof_insulation_thickness; /* can be 0 */ + double foundation_depth; /* can be 0 */ + double crawl_height; /* can be 0 */ + double attic_height; /* can be 0 */ + double glass_ratio; /* in [0, 1] */ +}; + +/********************************************************/ +/* Types used for parsing and to define parsing schemas */ +/********************************************************/ + +struct parsed_catalog_cmode_1 { + struct parsed_dataset_cmode_1* datasets; + size_t datasets_count; +}; + +static const cyaml_schema_field_t dataset_cmode_1_fields_schema[] = { + CYAML_FIELD_STRING_PTR("name", CYAML_FLAG_POINTER, + struct parsed_dataset_cmode_1, name, 0, CYAML_UNLIMITED), + CYAML_FIELD_INT("inter_floor_count", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, inter_floor_count), + CYAML_FIELD_FLOAT("wall_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, wall_thickness), + CYAML_FIELD_FLOAT("floor_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, floor_thickness), + CYAML_FIELD_FLOAT("inter_floor_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, inter_floor_thickness), + CYAML_FIELD_FLOAT("roof_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, roof_thickness), + CYAML_FIELD_FLOAT("internal_insulation_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, internal_insulation_thickness), + CYAML_FIELD_FLOAT("external_insulation_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, external_insulation_thickness), + CYAML_FIELD_FLOAT("floor_insulation_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, floor_insulation_thickness), + CYAML_FIELD_FLOAT("roof_insulation_thickness", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, roof_insulation_thickness), + CYAML_FIELD_FLOAT("foundation_depth", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, foundation_depth), + CYAML_FIELD_FLOAT("crawl_height", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, crawl_height), + CYAML_FIELD_FLOAT("attic_height", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, attic_height), + CYAML_FIELD_FLOAT("glass_ratio", CYAML_FLAG_DEFAULT, + struct parsed_dataset_cmode_1, glass_ratio), + CYAML_FIELD_END +}; + +static const struct cyaml_schema_value p_dataset_cmode_1_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct parsed_dataset_cmode_1, + dataset_cmode_1_fields_schema), +}; + +static const struct cyaml_schema_value dataset_cmode_1_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_DEFAULT, struct parsed_dataset_cmode_1, + dataset_cmode_1_fields_schema), +}; + +static const cyaml_schema_field_t cmode_1_fields_schemas[] = { + CYAML_FIELD_IGNORE("contructive_mode_type", CYAML_FLAG_DEFAULT), + { + .key = "sets", + .value = { + .type = CYAML_SEQUENCE, + .flags = CYAML_FLAG_POINTER, + .data_size = sizeof(struct parsed_dataset_cmode_1), + .sequence = { + .entry = &dataset_cmode_1_schema, + .min = 1, + .max = CYAML_UNLIMITED, + } + }, + .data_offset = offsetof(struct parsed_catalog_cmode_1, datasets), + .count_size = sizeof(((struct parsed_catalog_cmode_1*)0)->datasets_count), + .count_offset = offsetof(struct parsed_catalog_cmode_1, datasets_count), + }, + CYAML_FIELD_END +}; + +/* Top-level schema. The top level value for the constructive mode is a mapping. + * Its fields are defined in cmode_1_fields_schemas. + */ +static const cyaml_schema_value_t constructive_mode_1_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct parsed_catalog_cmode_1, + cmode_1_fields_schemas), +}; + +#endif diff --git a/src/cg_constructive_modes_parsing_schemas.h b/src/cg_constructive_modes_parsing_schemas.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA + * Copyright (C) 2022 CNRS + * Copyright (C) 2022 Sorbonne Université + * Copyright (C) 2022 Université Paul Sabatier + * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef FG_CMODES_PARSING_SCHEMAS__ +#define FG_CMODES_PARSING_SCHEMAS__ + +#include <cyaml/cyaml.h> + +/********************************************************/ +/* Types used for parsing and to define parsing schemas */ +/********************************************************/ + +/* constructive mode type */ +enum parsed_cmode_type { + PARSED_CMODE_0, + PARSED_CMODE_1, + PARSED_CMODE_TYPE_UNDEFINED +}; + +/* Mapping from "constructive mode type" strings to enum parsed_cmode_type values for + * schema. */ +static const cyaml_strval_t city_building_types_strings[] = { + { "Constructive_Mode_0", PARSED_CMODE_0 }, + { "Constructive_Mode_1", PARSED_CMODE_1 } +}; + +struct parsed_cmode { + enum parsed_cmode_type cmode_type; +}; + +static const cyaml_schema_field_t constructive_mode_fields_schemas[] = { + CYAML_FIELD_ENUM("contructive_mode_type", + CYAML_FLAG_CASE_INSENSITIVE, struct parsed_cmode, cmode_type, + city_building_types_strings, CYAML_ARRAY_LEN(city_building_types_strings)), + CYAML_FIELD_IGNORE("sets", CYAML_FLAG_DEFAULT), + CYAML_FIELD_END +}; + +/* Top-level schema. The top level value for the constructive mode is a mapping */ +static const cyaml_schema_value_t constructive_mode_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, struct parsed_cmode, + constructive_mode_fields_schemas), +}; + +#endif diff --git a/src/cg_ground.c b/src/cg_ground.c @@ -18,6 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "cg_ground.h" +#include "cg_city.h" #include "cg.h" #include <rsys/str.h> @@ -25,52 +26,41 @@ res_T ground_build_cad - (struct ground* ground) + (struct city* city, + struct ground* ground) { res_T res = RES_OK; double origin[3]; double extent[3]; struct scad_geometry* ground_box = NULL; struct scad_geometry* bound = NULL; - struct str name; - int is_init = 0; - if (!ground) { + if (!city || !ground) { res = RES_BAD_ARG; goto error; } - origin[0] = ground->extent[0]; - origin[1] = ground->extent[2]; - origin[2] = -ground->depth; + origin[0] = city->ground_extent[0]; + origin[1] = city->ground_extent[2]; + origin[2] = -city->ground_depth; - extent[0] = ground->extent[1] - ground->extent[0]; - extent[1] = ground->extent[3] - ground->extent[2]; - extent[2] = ground->depth; + extent[0] = city->ground_extent[1] - city->ground_extent[0]; + extent[1] = city->ground_extent[3] - city->ground_extent[2]; + extent[2] = city->ground_depth; if (origin[2] > 0 || extent[0] < 0 || extent[1] < 0 || extent[2] < 0 ) { res = RES_BAD_ARG; goto error; } - str_init(NULL, &name); - is_init = 1; - ERR(str_set(&name, "ground")); - - ERR(scad_add_box - (NULL /*str_cget(&name)*/, - origin, - extent, - &ground_box)); - + ERR(scad_add_box(NULL, origin, extent, &ground_box)); ERR(scad_geometry_boundary(NULL, &ground_box, 1, &bound)); ERR(scad_cut_geometries(NULL, &bound, 1, - ground->footprint, ground->n, &ground->boundary)); + ground->footprints, ground->footprints_count, &ground->boundary)); exit: - if (is_init) str_release(&name); - if (bound) scad_geometry_delete(bound); + if (bound) SCAD(geometry_delete(bound)); return res; error: goto exit; @@ -90,11 +80,32 @@ error: } res_T -ground_release(struct ground* ground) +ground_allocate + (struct mem_allocator* allocator, + const size_t count, + struct ground* ground) { res_T res = RES_OK; - if (ground->footprint) free(ground->footprint); + ground->footprints_count = count; + ground->footprints + = MEM_ALLOC(allocator, ground->footprints_count * sizeof(*ground->footprints)); + if(!ground->footprints) { + res = RES_MEM_ERR; + goto error; + } +exit: return res; +error: + goto exit; +} + +void +ground_release + (struct mem_allocator* allocator, + struct ground* ground) +{ + SCAD(geometry_delete(ground->boundary)); + MEM_RM(allocator, ground->footprints); } diff --git a/src/cg_ground.h b/src/cg_ground.h @@ -22,32 +22,39 @@ #include <rsys/rsys.h> +struct city; + struct scad_scene; struct scad_geometry; +struct mem_allocator; struct ground { - /* generic building data */ - double extent[4]; /* [xmin, xmax, ymin, ymax */ - double depth; - /* cad representation */ - struct scad_scene* scene; - struct scad_geometry* geometry; struct scad_geometry* boundary; - struct scad_geometry** footprint; /* list of building footprint */ - size_t n; /* number of footprint */ + struct scad_geometry** footprints; /* list of building footprint */ + size_t footprints_count; /* number of footprint */ }; -#define GROUND_NULL__ {{0,0,0,0}, 0, NULL, NULL, NULL, NULL, 0} +#define GROUND_NULL__ {NULL, NULL, 0} static const struct ground GROUND_NULL = GROUND_NULL__; res_T -ground_build_cad(struct ground* ground); +ground_build_cad + (struct city* city, + struct ground* ground); res_T ground_export_stl(const struct ground* ground, const int binary); res_T -ground_release(struct ground* ground); +ground_allocate + (struct mem_allocator* allocator, + const size_t count, + struct ground* ground); + +void +ground_release + (struct mem_allocator* allocator, + struct ground* ground); #endif /* GROUND */ diff --git a/src/cg_main.c b/src/cg_main.c @@ -19,24 +19,65 @@ #include "cg.h" #include "cg_args.h" +#include "cg_building.h" #include "cg_city.h" +#include "cg_city_parsing.h" +#include "cg_catalog.h" +#include "cg_catalog_parsing.h" +#include "cg_constructive_mode_0_parsing_schemas.h" +#include "cg_constructive_mode_1_parsing_schemas.h" + +#include <cyaml/cyaml.h> #include <rsys/rsys.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> +#include <star/scad.h> -char const* model_str [2] = { - "model0", - "model1" -}; - -static void +static int check_memory_allocator(struct mem_allocator* allocator) { if(MEM_ALLOCATED_SIZE(allocator)) { char dump[4096]; MEM_DUMP(allocator, dump, sizeof(dump)/sizeof(char)); fprintf(stderr, "%s\n", dump); - FATAL("Memory leaks.\n"); + fprintf(stderr, "Memory leaks.\n"); + return 1; + } + return 0; +} + +static void cg_log + (enum cyaml_log_e level, + void *_ctx, + const char *fmt, + va_list args) +{ + struct logger* logger = (struct logger*)_ctx; + enum log_type type; + ASSERT(logger && fmt); + + switch(level) { + case CYAML_LOG_ERROR: type = LOG_ERROR; break; + case CYAML_LOG_WARNING: type = LOG_WARNING; break; + case CYAML_LOG_NOTICE: type = LOG_OUTPUT; break; + default: return; /* Do not log this level of messages */ + } + logger_vprint(logger, type, fmt, args); +} + +static void* cg_mem + (void *ctx, + void *ptr, + size_t size) +{ + struct mem_allocator* allocator = (struct mem_allocator*)ctx; + ASSERT(allocator); + if(size == 0) { + /* free() request */ + MEM_RM(allocator, ptr); + return NULL; + } else { + return MEM_REALLOC(allocator, ptr, size); } } @@ -45,11 +86,22 @@ int main { int err = EXIT_SUCCESS; res_T res = RES_OK; - struct args args; - struct city city = CITY_NULL; + struct args* args = NULL; + struct city* city = NULL; struct logger logger; struct mem_allocator allocator; + struct parsed_city* parsed_city = NULL; + struct parsed_catalog* parsed_catalog = NULL; + struct catalog* catalog = NULL; int logger_initialized = 0, allocator_initialized = 0; + const struct cyaml_config config = { + .log_fn = cg_log, + .log_ctx = &logger, + .mem_fn = cg_mem, + .mem_ctx = &allocator, + .log_level = CYAML_LOG_WARNING, /* Logging errors and warnings only. */ + .flags = CYAML_CFG_DEFAULT, + }; /* init allocator and logger */ ERR(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); @@ -63,39 +115,67 @@ int main logger_set_stream(&logger, LOG_ERROR, log_err_fn, NULL); /* parse command line */ - ERR(parse_args(&logger, argc, argv, &args)); - if(args.print_help) { + ERR(parse_args(&allocator, &logger, argc, argv, &args)); + if(args->print_help) { short_help(); goto exit; } - else if(args.print_version) { + else if(args->print_version) { print_version(); goto exit; } /* Deactivate some loggin according to the -V arg */ - if(args.verbose < 1) + if(args->verbosity_level < 1) logger_set_stream(&logger, LOG_ERROR, NULL, NULL); - if(args.verbose < 2) + if(args->verbosity_level < 2) logger_set_stream(&logger, LOG_WARNING, NULL, NULL); - if(args.verbose < 3) + if(args->verbosity_level < 3) logger_set_stream(&logger, LOG_OUTPUT, NULL, NULL); - ERR(city_init(&logger, &city, &args)); - ERR(city_cad_build(&logger, &city)); - ERR(city_ground_build(&logger, &city)); + /* Parse catalog. + * No semantic validation is done at this stage */ + ERR(parse_catalog(&args->catalog_filenames, &allocator, &logger, &config, + &parsed_catalog)); + + /* Create catalog from parsed data. + * Semantic validation is done along the process as well as the emission of + * informative logs */ + ERR(create_catalog(&allocator, &logger, parsed_catalog, &catalog)); + release_parsed_catalog(&config, parsed_catalog); + parsed_catalog = NULL; + + /* Parse city description. + * No semantic validation is done at this stage */ + ERR(parse_city(args->city_filename, &allocator, &logger, &config, &parsed_city)); + + /* Create city with parsed data. + * Semantic validation is done along the process as well as the emission of + * informative logs */ + ERR(create_city(&allocator, &logger, args, parsed_city, catalog, &city)); + release_parsed_city(&config, parsed_city); + parsed_city = NULL; + release_args(args); + args = NULL; + + ERR(city_ground_build(city)); + ERR(city_cad_build(city)); exit: - city_release(&city); + release_args(args); + release_city(city); + release_catalog(catalog); + release_parsed_catalog(&config, parsed_catalog); + release_parsed_city(&config, parsed_city); if(logger_initialized) logger_release(&logger); if(allocator_initialized) { - check_memory_allocator(&allocator); + if(check_memory_allocator(&allocator)) err = EXIT_FAILURE; mem_shutdown_proxy_allocator(&allocator); CHK(mem_allocated_size() == 0); } return err; error: err = EXIT_FAILURE; - printf("ERROR\n"); + printf("City generator failed.\n"); goto exit; } diff --git a/src/cg_parsing.c b/src/cg_parsing.c @@ -1,465 +0,0 @@ -/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA - * Copyright (C) 2022 CNRS - * Copyright (C) 2022 Sorbonne Université - * Copyright (C) 2022 Université Paul Sabatier - * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "cg.h" -#include "cg_parsing.h" -#include "cg_ground.h" -#include "cg_building.h" -#include "cg_city.h" - -#include <star/scpr.h> - -#include <rsys/cstr.h> -#include <rsys/logger.h> -#include <rsys/str.h> -#include <rsys/text_reader.h> -#include <rsys/stretchy_array.h> - - /*Funtion removing spaces from string*/ -static char* -remove_spaces(char *string) -{ - /*non_space_count to keep the frequency of non space characters*/ - int i; - int non_space_count = 0; - - /*Traverse a string and if it is non space character then, place it at - * index non_space_count*/ - for (i = 0; string[i] != '\0'; i++) { - if (string[i] != ' ') { - string[non_space_count] = string[i]; - non_space_count++; /* non_space_count incremented */ - } - } - - /*Finally placing final character at the string end*/ - string[non_space_count] = '\0'; - return string; -} - -static res_T -strtolower(const char * src, char* dst ) -{ - res_T res = RES_OK; - - if (!src || !dst) { - res = RES_BAD_ARG; - goto error; - } - - while((*dst++ = (char)tolower(*src++ ))); - -exit: - return res; -error: - goto exit; -} - -static enum model_type get_enum_value(char * val) -{ - int i=0; - for (i=0; i<MODEL_COUNT_; ++i) - if (!strcmp(model_str[i], val)) - return (enum model_type)i; - return MODEL_COUNT_; -} - -static res_T -parse_ground - (struct logger* logger, - struct txtrdr* reader, - struct ground* ground) -{ - res_T res = RES_OK; - char* line = NULL; - - ERR(txtrdr_read_line(reader)); - while (txtrdr_get_line(reader)){ - double depth = 0; - char* value = NULL; - - line = remove_spaces(txtrdr_get_line(reader)); - ERR(strtolower(line, line)); - - if (sscanf(line, "depth=%lf", &depth) == 1 ) { - ground->depth = depth; - } - - value = malloc((1 + strlen(line )) * sizeof(char)); - if (sscanf(line, "extent=%s", value) == 1 ) { - size_t sz = 0; - if (cstr_to_list_double(value, ',', ground->extent, &sz, 4) - != RES_OK || sz != 4) - { - logger_print(logger, LOG_ERROR, - "[ground] extent value not valid: 4 values required.\n"); - res = RES_BAD_ARG; - if (value) free(value); - goto error; - } - } - if (value) free(value); - - /*if new section break*/ - if (sscanf(line, "[%[^]]", value) == 1 ) { - break; - } - ERR(txtrdr_read_line(reader)); - } - - /*check depth*/ - if (ground->depth <= 0) { - logger_print(logger, LOG_ERROR, - "[ground] depth value not valid: must be > 0.\n"); - res = RES_BAD_ARG; - goto error; - } - - /*check extent*/ - if (ground->extent[0] >= ground->extent[1] - || ground->extent[2] >= ground->extent[3]) { - logger_print(logger, LOG_ERROR, - "[ground] extent value not valid: xmax must be > xmin and ymax must be > ymin.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - return res; -error: - goto exit; -} - -struct polygon_context{ - double* pos; - size_t* nvert; - size_t ncomps; -}; - -static void -get_nverts(const size_t icomp, size_t* nverts, void* context) -{ - const struct polygon_context* pg_ctx = context; - *nverts = pg_ctx->nvert[icomp]; -} - -static void -get_pos(const size_t icomp, const size_t ivert, double pos[2], void* context) -{ - const struct polygon_context* pg_ctx = context; - size_t i, begin = 0; - - for (i=0; i<icomp; ++i) { - begin += pg_ctx->nvert[i]*2; - } - pos[0] = pg_ctx->pos[begin + ivert*2 + 0]; - pos[1] = pg_ctx->pos[begin + ivert*2 + 1]; -} - -static res_T -parse_polygon(const char* str, void* data) -{ - res_T res = RES_OK; - struct polygon_context* pg_ctx = data; - double value; - - ERR(cstr_to_double(str, &value)); - - pg_ctx->nvert[pg_ctx->ncomps] += 1; - sa_push(pg_ctx->pos, value); - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_polygon_list(const char* str, void* data) -{ - res_T res = RES_OK; - struct polygon_context* pg_ctx = data; - double* pos = NULL; - - sa_push(pg_ctx->nvert, 0); - ERR(cstr_parse_list(str, ',', parse_polygon, pg_ctx)); - if (pg_ctx->nvert[pg_ctx->ncomps]%2 != 0) { - res = RES_BAD_ARG; - goto error; - } else { - pg_ctx->nvert[pg_ctx->ncomps] /= 2; - } - pg_ctx->ncomps += 1; - -exit: - if (pos) sa_release(pos); - return res; -error: - goto exit; -} - -static res_T -parse_building - (struct logger* logger, - struct txtrdr* reader, - struct building* building) -{ - res_T res = RES_OK; - char* line = NULL; - int m; - (void)logger; - - ERR(txtrdr_read_line(reader)); - while (txtrdr_get_line(reader)){ - size_t id = 0; - double height = 0; - char* value = NULL; - char* tmp; - - tmp = txtrdr_get_line(reader); - line = remove_spaces(tmp); - ERR(strtolower(line, line)); - value = malloc(( strlen(line )) * sizeof(char)); - - if (sscanf(line, "id=%lu", &id) == 1 ) { - building->id = id; - } - - else if (sscanf(line, "height=%lf", &height) == 1 ) { - building->height = height; - } - - else if (sscanf(line, "polygon=%s", value) == 1 ) { - struct polygon_context pg_ctx = {NULL, NULL, 0}; - - ERR(scpr_polygon_create(NULL, &building->pg)); - if (cstr_parse_list(value, ';', parse_polygon_list, &pg_ctx) != RES_OK ) { - size_t line_num; - line_num = txtrdr_get_line_num(reader); - logger_print(logger, LOG_ERROR, - "[polygon] description not valid on line: %lu\n", - (unsigned long)line_num); - goto error; - } - - ERR(scpr_polygon_setup_indexed_vertices( - building->pg, pg_ctx.ncomps, - get_nverts, - get_pos, - &pg_ctx)); - - sa_release(pg_ctx.pos); - sa_release(pg_ctx.nvert); - } - - else if (sscanf(line, "model=model%d", &m) == 1 ) { - switch(m) { - case 0: - building->model = model0; - break; - case 1: - building->model = model1; - break; - default: - res = RES_BAD_ARG; - goto error; - } - } - - else if (sscanf(line, "data=%s", value) == 1 ) { - building->data_name = malloc(sizeof(struct str)); - str_init(NULL, building->data_name); - str_set(building->data_name, value); - } - - /*if new section break*/ - else if (sscanf(line, "[%[^]]", value) == 1 ) { - break; - } - - else { - printf("===> %s \n", line); - res = RES_BAD_ARG; - goto error; - } - - free(value); - ERR(txtrdr_read_line(reader)); - } - - /*check height*/ - if (building->height <= 0) { - logger_print(logger, LOG_ERROR, - "[building] height value not valid: must be > 0.\n"); - res = RES_BAD_ARG; - goto error; - } - - /*check model*/ - if (building->model == MODEL_COUNT_) { - logger_print(logger, LOG_ERROR, - "[model] not recognized.\n"); - res = RES_BAD_ARG; - goto error; - } - - /*TODO : check polygon and unique id*/ - -exit: - return res; -error: - goto exit; -} - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - -res_T -parse_city - (struct logger* logger, - struct txtrdr* reader, - struct city* city) -{ - res_T res = RES_OK; - char* line = NULL; - struct building b; - - ERR(txtrdr_read_line(reader)); - - while (txtrdr_get_line(reader)){ - line = txtrdr_get_line(reader); - ERR(strtolower(line, line)); - if (strcmp(line, "[building]") == 0) { - ERR(parse_building(logger, reader, &b)); - sa_push(city->building, b); - continue; - } - if (strcmp(line, "[ground]") == 0) { - ERR(parse_ground(logger, reader, &city->ground)); - continue; - } - ERR(txtrdr_read_line(reader)); - } - - city->n = sa_size(city->building); - -exit: - return res; -error: - goto exit; -} - -res_T -parse_building_params - (struct logger* logger, - struct htable_building_params* ht_params) -{ - res_T res = RES_OK; - struct data_model0* data0; - struct data_model1* data1; - struct building_params* params0; - (void)logger; - - htable_building_params_init(NULL, ht_params); - - params0 = malloc(2*sizeof(struct building_params)); - if (!params0) { - res = RES_MEM_ERR; - goto error; - } - - data0 = malloc(sizeof(struct data_model0)); - if (!data0) { - res = RES_MEM_ERR; - goto error; - } - params0[0].model = model0; - str_init(NULL, &params0[0].name); - str_set(&params0[0].name, "b0"); - data0->wall = 0.2; - data0->floor = 0.3; - params0[0].data = malloc(sizeof(struct data_model0)); - params0[0].data = (void*)data0; - ERR(htable_building_params_set(ht_params, &params0[0].name, &params0[0])); - - data1 = malloc(sizeof(struct data_model1)); - if (!data1) { - res = RES_MEM_ERR; - goto error; - } - params0[1].model = model1; - str_init(NULL, &params0[1].name); - str_set(&params0[1].name, "b1"); - data1->wall = 0.25; - data1->floor = 0.35; - data1->inter_floor = 0.2; - data1->inter_floor_n = 0; - data1->roof = 0.3; - data1->int_insulation = 0.1; - data1->ext_insulation = 0.2; - data1->floor_insulation = 0; - data1->roof_insulation = 0; - data1->foundation = 2; - data1->crawl = 0; - data1->attic = 0; - data1->glass_ratio = 0.5; - params0[1].data = malloc(sizeof(struct data_model1)); - params0[1].data = (void*)data1; - ERR(htable_building_params_set(ht_params, &params0[1].name, &params0[1])); - - /* check coherence */ - if (data1->roof_insulation <= 0) data1->attic = 0; - if (data1->inter_floor <= 0) data1->inter_floor_n = 0; - if (data1->inter_floor_n <= 0) data1->inter_floor = 0; - - -exit: - free(params0); - return res; -error: - htable_building_params_release(ht_params); - goto exit; -} - -res_T -release_params_building(struct building_params* params) -{ - res_T res = RES_OK; - size_t i; - - if (!params) { - res = RES_BAD_ARG; - goto error; - } - - printf("size params %lu \n", sa_size(params)); - - for (i=0; i<sa_size(params); ++i) { - free(params[i].data); - } - - sa_release(params); - -exit: - return res; -error: - goto exit; -} - diff --git a/src/cg_parsing.h b/src/cg_parsing.h @@ -1,48 +0,0 @@ -/* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA - * Copyright (C) 2022 CNRS - * Copyright (C) 2022 Sorbonne Université - * Copyright (C) 2022 Université Paul Sabatier - * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef PARSING_H -#define PARSING_H - -#include <ctype.h> - -#include <rsys/rsys.h> - -struct txtrdr; -struct logger; -struct htable_building_params; - -struct city; -struct building_params; - -res_T -parse_city - (struct logger* logger, - struct txtrdr* reader, - struct city* city); - -res_T -parse_building_params - (struct logger* logger, - struct htable_building_params* ht_params); - -res_T -release_params_building(struct building_params* params); - -#endif /*PARSING_H*/