cg_building.c (5168B)
1 /* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA 2 * Copyright (C) 2022 CNRS 3 * Copyright (C) 2022 Sorbonne Université 4 * Copyright (C) 2022 Université Paul Sabatier 5 * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "cg.h" 21 #include "cg_city.h" 22 #include "cg_building.h" 23 24 #include <rsys/str.h> 25 #include <rsys/mem_allocator.h> 26 #include <rsys/logger.h> 27 28 #include <star/scad.h> 29 30 void 31 adjoining_data_release(struct adjoining_data* data) 32 { 33 ASSERT(data); 34 if(data->envelop) { 35 SCAD(geometry_ref_put(data->envelop)); 36 data->envelop = NULL; 37 } 38 if(data->common_geometry) { 39 SCAD(geometry_ref_put(data->common_geometry)); 40 data->common_geometry = NULL; 41 } 42 } 43 44 res_T 45 adjoining_data_copy 46 (struct adjoining_data* dst, const struct adjoining_data* src) 47 { 48 ASSERT(dst && src); 49 dst->adjoining_building = src->adjoining_building; 50 dst->main_building = src->main_building; 51 dst->common_geometry = src->common_geometry; 52 if(dst->common_geometry) SCAD(geometry_ref_get(dst->common_geometry)); 53 dst->envelop = src->envelop; 54 if(dst->envelop) SCAD(geometry_ref_get(dst->envelop)); 55 dst->save = src->save; 56 return RES_OK; 57 } 58 59 res_T 60 adjoining_data_copy_and_release 61 (struct adjoining_data* dst, const struct adjoining_data* src) 62 { 63 ASSERT(dst && src); 64 dst->adjoining_building = src->adjoining_building; 65 dst->main_building = src->main_building; 66 dst->common_geometry = src->common_geometry; 67 dst->envelop = src->envelop; 68 dst->save = src->save; 69 return RES_OK; 70 } 71 72 void get_position_pg 73 (const size_t ivert, double pos[2], void* ctx) 74 { 75 struct scpr_polygon* pg = ctx; 76 ASSERT(pos && pg); 77 CHK(scpr_polygon_get_position(pg, 0, ivert, pos) == RES_OK); 78 } 79 80 res_T 81 build_envelop 82 (struct building* building, 83 struct scad_geometry** envelop) 84 { 85 res_T res = RES_OK; 86 size_t nverts = 0; 87 double height = building->total_height; 88 double d[3] = {0, 0, 0}; 89 struct scpr_polygon* pg = building->pg; 90 struct scad_geometry* footprint = NULL; 91 struct str name; 92 93 str_init(building->city->allocator, &name); 94 95 ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); 96 ERR(scad_add_polygon(NULL, get_position_pg, pg, 0, nverts, &footprint)); 97 98 /* wall envelop */ 99 d[2] = height; 100 ERR(str_printf(&name, "%s_envelop", str_cget(&building->name))); 101 ERR(scad_geometry_extrude(footprint, str_cget(&name), d, envelop)); 102 103 exit: 104 str_release(&name); 105 if (footprint) SCAD(geometry_ref_put(footprint)); 106 return res; 107 error: 108 goto exit; 109 } 110 111 res_T 112 build_adjoining 113 (struct building* building, 114 const int silent, 115 struct darray_geometries* current_cad, 116 struct darray_adjoining_data* adjoining) 117 { 118 res_T res = RES_OK; 119 size_t count, prev, i = 0; 120 struct htable_building_iterator it, end; 121 struct htable_building* close_buildings; 122 struct str msg; 123 struct mem_allocator* allocator; 124 struct logger* logger; 125 126 ASSERT(building && current_cad && adjoining); 127 128 allocator = building->city->allocator; 129 logger = building->city->logger; 130 close_buildings = &building->close_buildings; 131 count = htable_building_size_get(close_buildings); 132 133 if(!silent) { 134 str_init(allocator, &msg); 135 ERR(str_printf(&msg, 136 "Building '%s' considering close neighbor(s) when creating CAD:", 137 str_cget(&building->name))); 138 } 139 140 /* iterate over adjoining building */ 141 htable_building_begin(close_buildings, &it); 142 htable_building_end(close_buildings, &end); 143 prev = darray_adjoining_data_size_get(adjoining); 144 ERR(darray_adjoining_data_reserve(adjoining, prev + count)); 145 while(!htable_building_iterator_eq(&it, &end)) { 146 struct building* close_building = *htable_building_iterator_key_get(&it); 147 struct adjoining_data adj; 148 htable_building_iterator_next(&it); 149 if(close_building->event_flags & BUILDING_REMOVED_EARLY) 150 continue; 151 adjoining_data_init(allocator, &adj); 152 ERR(build_envelop(close_building, &adj.envelop)); 153 ERR(darray_geometries_push_back(current_cad, &adj.envelop)); 154 ERR(scad_geometry_ref_put(adj.envelop)); /* Ownership transfer */ 155 adj.main_building = building; 156 adj.adjoining_building = close_building; 157 if(!silent) { 158 ERR(str_append_printf(&msg, (i ? ", '%s'" : " '%s'"), 159 str_cget(&close_building->name))); 160 } 161 ERR(darray_adjoining_data_push_back(adjoining, &adj)); 162 i++; 163 } 164 165 if(!silent) { 166 logger_print(logger, LOG_OUTPUT, "%s.\n", str_cget(&msg)); 167 } 168 169 exit: 170 if(!silent) str_release(&msg); 171 return res; 172 error: 173 darray_adjoining_data_clear(adjoining); 174 goto exit; 175 }