cg_construction_mode_1.c (70866B)
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_types.h" 22 #include "cg_default.h" 23 #include "cg_building.h" 24 #include "cg_catalog.h" 25 #include "cg_city.h" 26 #include "cg_city_parsing_schemas.h" 27 #include "cg_construction_mode.h" 28 #include "cg_construction_mode_1.h" 29 #include "cg_vertex_denoiser.h" 30 #include "cg_stardis_model.h" 31 32 #include <rsys/rsys.h> 33 #include <rsys/str.h> 34 #include <rsys/logger.h> 35 #include <rsys/hash_table.h> 36 #include <rsys/double3.h> 37 #include <rsys/clock_time.h> 38 39 #include <star/scad.h> 40 #include <star/scpr.h> 41 42 static res_T 43 build_footprint 44 (struct scpr_polygon* pg, 45 const double z, 46 struct scad_geometry** footprint) 47 { 48 res_T res = RES_OK; 49 size_t nverts = 0; 50 51 ASSERT(pg && footprint); 52 53 ERR(scpr_polygon_get_vertices_count(pg, 0, &nverts)); 54 ERR(scad_add_polygon(NULL, get_position_pg, pg, z, nverts, footprint)); 55 56 exit: 57 return res; 58 error: 59 goto exit; 60 } 61 62 /* Return a polygon with the given offset. 63 * Get a reference: do put a reference on the result! */ 64 static res_T 65 do_offset 66 (struct building* building, 67 struct htable_polygons* polygons, 68 struct scpr_intersector* overlapping_intersector, 69 int *error_msg_printed, 70 const double offset, 71 struct scpr_polygon** p_out) 72 { 73 res_T res = RES_OK; 74 struct scpr_polygon** ptr_p; 75 76 ASSERT(building && polygons && overlapping_intersector 77 && error_msg_printed && p_out); 78 79 ptr_p = htable_polygons_find(polygons, &offset); 80 if(ptr_p) { 81 *p_out = *ptr_p; 82 ERR(scpr_polygon_ref_get(*p_out)); 83 } else { 84 size_t c; 85 ERR(scpr_polygon_create_copy(building->city->scpr, building->pg, p_out)); 86 ERR(scpr_offset_polygon(*p_out, offset, SCPR_JOIN_MITER)); 87 ERR(scpr_polygon_get_components_count(*p_out, &c)); 88 if(c != 1) { 89 ASSERT(offset < 0); 90 logger_print(building->city->logger, 91 (building->city->keep_running_on_errors ? LOG_WARNING : LOG_ERROR), 92 "Building '%s' shape is not compatible with wall thickness.\n", 93 str_cget(&building->name)); 94 building->event_flags |= BUILDING_REMOVED; 95 *error_msg_printed = 1; 96 res = RES_BAD_ARG; 97 goto error; 98 } 99 ERR(scpr_intersector_register_polygon(overlapping_intersector, *p_out)); 100 ERR(htable_polygons_set(polygons, &offset, p_out)); 101 } 102 103 exit: 104 return res; 105 error: 106 if(!ptr_p) SCPR(polygon_ref_put(*p_out)); /* Created here */ 107 *p_out = NULL; 108 goto exit; 109 } 110 111 static res_T 112 build_floor 113 (struct building* building, 114 int *error_msg_printed, 115 const struct dataset_cmode_1* data, 116 struct scpr_intersector* overlapping_intersector, 117 struct htable_polygons* polygons, 118 struct darray_geometries* current_cad, 119 struct scad_geometry** floor) 120 { 121 res_T res = RES_OK; 122 double e_wall = data->wall_thickness; 123 double e_insulation = data->external_insulation_thickness; 124 double e_floor = data->floor_thickness; 125 double offset = 0; 126 struct scpr_polygon* pg_int = NULL; 127 struct scad_geometry* footprint = NULL; 128 double d[3] = {0, 0, 0}; 129 char* floorname = NULL; 130 struct str name; 131 const char* prefix; 132 133 ASSERT(building && error_msg_printed && data && floor); 134 135 prefix = str_cget(&building->name); 136 str_init(building->city->allocator, &name); 137 ERR(str_set(&name, prefix)); 138 ERR(str_append(&name, "_S_floor")); 139 floorname = str_get(&name); 140 141 offset = -(e_wall + e_insulation); 142 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 143 offset, &pg_int)); 144 145 /*footprint*/ 146 ERR(build_footprint(pg_int, 0, &footprint)); 147 148 d[2] = -e_floor; 149 ERR(scad_geometry_extrude(footprint, floorname, d, floor)); 150 ERR(darray_geometries_push_back(current_cad, floor)); 151 152 exit: 153 if(footprint) SCAD(geometry_ref_put(footprint)); 154 str_release(&name); 155 if(pg_int) SCPR(polygon_ref_put(pg_int)); 156 return res; 157 error: 158 goto exit; 159 } 160 161 static res_T 162 build_wall 163 (struct building* building, 164 int *error_msg_printed, 165 const int is_foundation, 166 const char* suffix, 167 const double height, 168 const struct dataset_cmode_1* data, 169 struct scpr_intersector* overlapping_intersector, 170 struct htable_polygons* polygons, 171 struct darray_geometries* current_cad, 172 struct scad_geometry** wall) 173 { 174 res_T res = RES_OK; 175 double e_wall = data->wall_thickness; 176 double e_insulation = data->external_insulation_thickness; 177 double offset = 0; 178 struct scpr_polygon* pg_int = NULL; 179 struct scpr_polygon* pg_ext = NULL; 180 struct scad_geometry* footprint = NULL; 181 struct scad_geometry* footprint_int = NULL; 182 struct scad_geometry* footprint_ext = NULL; 183 double d[3] = {0, 0, 0}; 184 char* wallname = NULL; 185 struct str name; 186 const char* prefix; 187 188 ASSERT(building && error_msg_printed && data && wall); 189 190 prefix = str_cget(&building->name); 191 str_init(building->city->allocator, &name); 192 ERR(str_set(&name, prefix)); 193 if(suffix) { 194 ERR(str_append(&name, "_")); 195 ERR(str_append(&name, suffix)); 196 } 197 wallname = str_get(&name); 198 199 if(is_foundation) { 200 offset = -(e_insulation + 0.1*e_wall); 201 } else { 202 offset = -e_insulation; 203 } 204 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 205 offset, &pg_ext)); 206 207 offset = -(e_wall + e_insulation); 208 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 209 offset, &pg_int)); 210 211 /* wall footprint*/ 212 ERR(build_footprint(pg_int, 0, &footprint_int)); 213 ERR(build_footprint(pg_ext, 0, &footprint_ext)); 214 ERR(scad_cut_geometries(NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); 215 216 d[2] = height; 217 ERR(scad_geometry_extrude(footprint, wallname, d, wall)); 218 ERR(darray_geometries_push_back(current_cad, wall)); 219 220 exit: 221 if(footprint) SCAD(geometry_ref_put(footprint)); 222 if(footprint_int) SCAD(geometry_ref_put(footprint_int)); 223 if(footprint_ext) SCAD(geometry_ref_put(footprint_ext)); 224 str_release(&name); 225 if(pg_ext) SCPR(polygon_ref_put(pg_ext)); 226 if(pg_int) SCPR(polygon_ref_put(pg_int)); 227 return res; 228 error: 229 goto exit; 230 } 231 232 static res_T 233 build_int_insulation 234 (struct building* building, 235 int *error_msg_printed, 236 const double height, 237 const struct dataset_cmode_1* data, 238 struct scad_geometry* inter_floor, 239 struct scpr_intersector* overlapping_intersector, 240 struct htable_polygons* polygons, 241 struct darray_geometries* current_cad, 242 struct scad_geometry** insulation) 243 { 244 res_T res = RES_OK; 245 double e_wall = data->wall_thickness; 246 double e_roof = data->roof_thickness; 247 double e_roof_insulation = data->roof_insulation_thickness; 248 double e_attic = data->attic_height; 249 double e_ext_insulation = data->external_insulation_thickness; 250 double e_int_insulation = data->internal_insulation_thickness; 251 double offset = 0; 252 struct scpr_polygon* pg_int = NULL; 253 struct scpr_polygon* pg_ext = NULL; 254 struct scad_geometry* footprint = NULL; 255 struct scad_geometry* footprint_int = NULL; 256 struct scad_geometry* footprint_ext = NULL; 257 struct scad_geometry* geom = NULL; 258 double d[3] = {0, 0, 0}; 259 char* insulationname = NULL; 260 struct str name; 261 const char* prefix; 262 263 ASSERT(building && error_msg_printed && data && insulation); 264 265 prefix = str_cget(&building->name); 266 str_init(building->city->allocator, &name); 267 ERR(str_set(&name, prefix)); 268 ERR(str_append(&name, "_S_internal_insulation")); 269 insulationname = str_get(&name); 270 271 offset = -(e_ext_insulation + e_wall); 272 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 273 offset, &pg_ext)); 274 275 offset = -(e_ext_insulation + e_wall + e_int_insulation); 276 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 277 offset, &pg_int)); 278 279 /* insulation footprint */ 280 ERR(build_footprint(pg_int, 0, &footprint_int)); 281 ERR(build_footprint(pg_ext, 0, &footprint_ext)); 282 ERR(scad_cut_geometries(NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); 283 284 d[2] = height - e_roof - e_attic - e_roof_insulation; 285 ERR(scad_geometry_extrude(footprint, NULL, d, &geom)); 286 287 if(inter_floor) { 288 ERR(scad_cut_geometries(insulationname, &geom, 1, &inter_floor, 1, insulation)); 289 } else { 290 ERR(scad_geometry_copy(geom, insulationname, insulation)); 291 } 292 ERR(darray_geometries_push_back(current_cad, insulation)); 293 294 exit: 295 if(footprint) SCAD(geometry_ref_put(footprint)); 296 if(footprint_int) SCAD(geometry_ref_put(footprint_int)); 297 if(footprint_ext) SCAD(geometry_ref_put(footprint_ext)); 298 if(geom) SCAD(geometry_ref_put(geom)); 299 str_release(&name); 300 if(pg_ext) SCPR(polygon_ref_put(pg_ext)); 301 if(pg_int) SCPR(polygon_ref_put(pg_int)); 302 return res; 303 error: 304 goto exit; 305 } 306 307 static res_T 308 build_roof 309 (struct building* building, 310 int *error_msg_printed, 311 const double height, 312 const struct dataset_cmode_1* data, 313 struct scpr_intersector* overlapping_intersector, 314 struct htable_polygons* polygons, 315 struct darray_geometries* current_cad, 316 struct scad_geometry** roof) 317 { 318 res_T res = RES_OK; 319 double e_wall = data->wall_thickness; 320 double e_insulation = data->external_insulation_thickness; 321 double e_roof = data->roof_thickness; 322 double offset = 0; 323 double z_roof = 0; 324 struct scpr_polygon* pg_int = NULL; 325 struct scad_geometry* footprint = NULL; 326 double d[3] = {0, 0, 0}; 327 char* roofname = NULL; 328 struct str name; 329 const char* prefix; 330 331 ASSERT(building && error_msg_printed && data && roof); 332 333 prefix = str_cget(&building->name); 334 str_init(building->city->allocator, &name); 335 ERR(str_set(&name, prefix)); 336 ERR(str_append(&name, "_S_roof")); 337 roofname = str_get(&name); 338 339 offset = -(e_wall + e_insulation); 340 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 341 offset, &pg_int)); 342 343 /*footprint*/ 344 z_roof = height - e_roof; 345 ERR(build_footprint(pg_int, z_roof, &footprint)); 346 347 d[2] = e_roof; 348 ERR(scad_geometry_extrude(footprint, roofname, d, roof)); 349 ERR(darray_geometries_push_back(current_cad, roof)); 350 351 exit: 352 if(footprint) SCAD(geometry_ref_put(footprint)); 353 str_release(&name); 354 if(pg_int) SCPR(polygon_ref_put(pg_int)); 355 return res; 356 error: 357 goto exit; 358 } 359 360 static res_T 361 build_roof_insulation 362 (struct building* building, 363 int *error_msg_printed, 364 const double height, 365 const struct dataset_cmode_1* data, 366 struct scpr_intersector* overlapping_intersector, 367 struct htable_polygons* polygons, 368 struct darray_geometries* current_cad, 369 struct scad_geometry** insulation) 370 { 371 res_T res = RES_OK; 372 double e_wall = data->wall_thickness; 373 double e_insulation = data->external_insulation_thickness; 374 double e_roof = data->roof_thickness; 375 double e_attic = data->attic_height; 376 double e_roof_insulation = data->roof_insulation_thickness; 377 double offset = 0; 378 double z_insulation = 0; 379 struct scpr_polygon* pg_int = NULL; 380 struct scad_geometry* footprint = NULL; 381 double d[3] = {0, 0, 0}; 382 char* insulationname = NULL; 383 struct str name; 384 const char* prefix; 385 386 ASSERT(building && error_msg_printed && data && insulation); 387 388 prefix = str_cget(&building->name); 389 str_init(building->city->allocator, &name); 390 ERR(str_set(&name, prefix)); 391 ERR(str_append(&name, "_S_roof_insulation")); 392 insulationname = str_get(&name); 393 394 offset = -(e_wall + e_insulation); 395 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 396 offset, &pg_int)); 397 398 /*footprint*/ 399 z_insulation = height - e_roof - e_attic - e_roof_insulation; 400 ERR(build_footprint(pg_int, z_insulation, &footprint)); 401 402 d[2] = e_roof_insulation; 403 ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); 404 ERR(darray_geometries_push_back(current_cad, insulation)); 405 406 exit: 407 if(footprint) SCAD(geometry_ref_put(footprint)); 408 str_release(&name); 409 if(pg_int) SCPR(polygon_ref_put(pg_int)); 410 return res; 411 error: 412 goto exit; 413 } 414 415 static res_T 416 build_floor_insulation 417 (struct building* building, 418 int *error_msg_printed, 419 const struct dataset_cmode_1* data, 420 struct scpr_intersector* overlapping_intersector, 421 struct htable_polygons* polygons, 422 struct darray_geometries* current_cad, 423 struct scad_geometry** insulation) 424 { 425 res_T res = RES_OK; 426 double e_wall = data->wall_thickness; 427 double e_insulation = data->external_insulation_thickness; 428 double e_floor = data->floor_thickness; 429 double e_floor_insulation = data->floor_insulation_thickness; 430 double offset = 0; 431 double z_insulation = 0; 432 struct scpr_polygon* pg_int = NULL; 433 struct scad_geometry* footprint = NULL; 434 double d[3] = {0, 0, 0}; 435 char* insulationname = NULL; 436 struct str name; 437 const char* prefix; 438 439 ASSERT(building && error_msg_printed && data && insulation); 440 441 prefix = str_cget(&building->name); 442 str_init(building->city->allocator, &name); 443 ERR(str_set(&name, prefix)); 444 ERR(str_append(&name, "_S_floor_insulation")); 445 insulationname = str_get(&name); 446 447 offset = -(e_wall + e_insulation); 448 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 449 offset, &pg_int)); 450 451 /*footprint*/ 452 z_insulation = - e_floor - e_floor_insulation; 453 ERR(build_footprint(pg_int, z_insulation, &footprint)); 454 455 d[2] = e_floor_insulation; 456 ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); 457 ERR(darray_geometries_push_back(current_cad, insulation)); 458 459 exit: 460 if(footprint) SCAD(geometry_ref_put(footprint)); 461 str_release(&name); 462 if(pg_int) SCPR(polygon_ref_put(pg_int)); 463 return res; 464 error: 465 goto exit; 466 } 467 468 static res_T 469 build_inter_floor 470 (struct building* building, 471 int *error_msg_printed, 472 const double height, 473 const struct dataset_cmode_1* data, 474 struct scpr_intersector* overlapping_intersector, 475 struct htable_polygons* polygons, 476 struct darray_geometries* current_cad, 477 struct scad_geometry** inter_floor) 478 { 479 res_T res = RES_OK; 480 size_t i = 0; 481 size_t floor_n = data->inter_floor_count; 482 double e_roof = data->roof_thickness; 483 double e_roof_ins = data->roof_insulation_thickness; 484 double e_attic = data->attic_height; 485 double e_floor = data->inter_floor_thickness; 486 double e_wall = data->wall_thickness; 487 double e_insulation = data->external_insulation_thickness; 488 double offset = 0; 489 double z_floor = 0; 490 double h_cavity = 0; 491 struct scpr_polygon* pg_int = NULL; 492 size_t nverts = 0; 493 struct scad_geometry** floor_list = NULL; 494 struct darray_geometries floor_array; 495 struct scad_geometry *footprint = NULL, *floor = NULL; 496 double d[3] = {0, 0, 0}; 497 char* floorname = NULL; 498 struct str name; 499 const char* prefix; 500 501 ASSERT(building && error_msg_printed && data && inter_floor); 502 503 darray_geometries_init(building->city->allocator, &floor_array); 504 505 prefix = str_cget(&building->name); 506 str_init(building->city->allocator, &name); 507 ERR(str_set(&name, prefix)); 508 ERR(str_append(&name, "_S_intermediate_floors")); 509 floorname = str_get(&name); 510 511 offset = -(e_wall + e_insulation); 512 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 513 offset, &pg_int)); 514 ERR(scpr_polygon_get_vertices_count(pg_int, 0, &nverts)); 515 516 h_cavity = height - e_roof - e_attic - e_roof_ins - (double)floor_n*e_floor; 517 z_floor = h_cavity/(double)(1 + floor_n); 518 d[2] = e_floor; 519 for(i = 0; i < floor_n; i++) { 520 ERR(scad_add_polygon(NULL, get_position_pg, pg_int, z_floor, nverts, 521 &footprint)); 522 ERR(scad_geometry_extrude(footprint, NULL, d, &floor)); 523 ERR(scad_geometry_ref_put(footprint)); 524 footprint = NULL; /* Avoid double free */ 525 ERR(darray_geometries_push_back(&floor_array, &floor)); 526 ERR(scad_geometry_ref_put(floor)); 527 floor = NULL; /* Avoid double free */ 528 z_floor += h_cavity/(double)(1 + floor_n) + e_floor; 529 } 530 ASSERT(darray_geometries_size_get(&floor_array) == floor_n); 531 532 floor_list = darray_geometries_data_get(&floor_array); 533 ERR(scad_fuse_geometries(floorname, floor_list, floor_n, floor_list, floor_n, 534 inter_floor)); 535 ERR(darray_geometries_push_back(current_cad, inter_floor)); 536 537 exit: 538 str_release(&name); 539 if(footprint) SCAD(geometry_ref_put(footprint)); 540 if(floor) SCAD(geometry_ref_put(floor)); 541 if(floor_list) darray_geometries_release(&floor_array); 542 if(pg_int) SCPR(polygon_ref_put(pg_int)); 543 return res; 544 error: 545 goto exit; 546 } 547 548 static res_T 549 build_ext_insulation 550 (struct building* building, 551 int *error_msg_printed, 552 const double height, 553 const struct dataset_cmode_1* data, 554 struct scpr_intersector* overlapping_intersector, 555 struct htable_polygons* polygons, 556 struct darray_geometries* current_cad, 557 struct scad_geometry** insulation) 558 { 559 res_T res = RES_OK; 560 double e_insulation = data->external_insulation_thickness; 561 double offset = 0; 562 struct scpr_polygon* pg_int = NULL; 563 struct scpr_polygon* pg_ext = NULL; 564 struct scpr_polygon** ptr_p; 565 struct scad_geometry* footprint = NULL; 566 struct scad_geometry* footprint_int = NULL; 567 struct scad_geometry* footprint_ext = NULL; 568 double d[3] = {0, 0, 0}; 569 char* insulationname = NULL; 570 struct str name; 571 const char* prefix; 572 573 ASSERT(building && data && polygons && insulation); 574 575 prefix = str_cget(&building->name); 576 str_init(building->city->allocator, &name); 577 ERR(str_set(&name, prefix)); 578 ERR(str_append(&name, "_S_external_insulation")); 579 insulationname = str_get(&name); 580 581 offset = -e_insulation; 582 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 583 offset, &pg_int)); 584 585 offset = 0; 586 ptr_p = htable_polygons_find(polygons, &offset); 587 ASSERT(ptr_p); /* Offset 0 is the first to be inserted in polygons */ 588 pg_ext = *ptr_p; 589 590 /*insulation footprint*/ 591 ERR(build_footprint(pg_int, 0, &footprint_int)); 592 ERR(build_footprint(pg_ext, 0, &footprint_ext)); 593 ERR(scad_cut_geometries(NULL, &footprint_ext, 1, &footprint_int, 1, &footprint)); 594 595 d[2] = height; 596 ERR(scad_geometry_extrude(footprint, insulationname, d, insulation)); 597 ERR(darray_geometries_push_back(current_cad, insulation)); 598 599 exit: 600 if(footprint) SCAD(geometry_ref_put(footprint)); 601 if(footprint_int) SCAD(geometry_ref_put(footprint_int)); 602 if(footprint_ext) SCAD(geometry_ref_put(footprint_ext)); 603 str_release(&name); 604 if(pg_int) SCPR(polygon_ref_put(pg_int)); 605 return res; 606 error: 607 goto exit; 608 } 609 610 static res_T 611 build_crawlspace 612 (struct building* building, 613 int *error_msg_printed, 614 const struct dataset_cmode_1* data, 615 struct scpr_intersector* overlapping_intersector, 616 struct htable_polygons* polygons, 617 struct darray_geometries* current_cad, 618 struct scad_geometry** crawlspace) 619 { 620 res_T res = RES_OK; 621 double e_wall = data->wall_thickness; 622 double e_insulation = data->external_insulation_thickness; 623 double e_crawl = data->crawl_height; 624 double e_floor = data->floor_thickness; 625 double e_floor_insulation = data->floor_insulation_thickness; 626 double offset = 0; 627 double z_crawl= 0; 628 struct scpr_polygon* pg_int = NULL; 629 struct scad_geometry* footprint = NULL; 630 double d[3] = {0, 0, 0}; 631 char* crawlname = NULL; 632 struct str name; 633 const char* prefix; 634 635 ASSERT(building && error_msg_printed && data && crawlspace); 636 637 prefix = str_cget(&building->name); 638 str_init(building->city->allocator, &name); 639 ERR(str_set(&name, prefix)); 640 ERR(str_append(&name, "_F_crawlspace")); 641 crawlname = str_get(&name); 642 643 offset = -(e_wall + e_insulation); 644 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 645 offset, &pg_int)); 646 647 /*footprint*/ 648 z_crawl = - e_floor - e_floor_insulation - e_crawl; 649 ERR(build_footprint(pg_int, z_crawl, &footprint)); 650 651 d[2] = e_crawl; 652 ERR(scad_geometry_extrude(footprint, crawlname, d, crawlspace)); 653 ERR(darray_geometries_push_back(current_cad, crawlspace)); 654 655 exit: 656 if(footprint) SCAD(geometry_ref_put(footprint)); 657 str_release(&name); 658 if(pg_int) SCPR(polygon_ref_put(pg_int)); 659 return res; 660 error: 661 goto exit; 662 } 663 664 static res_T 665 build_habitable 666 (struct building* building, 667 int *error_msg_printed, 668 const double height, 669 const struct dataset_cmode_1* data, 670 struct scad_geometry* floor, 671 struct scpr_intersector* overlapping_intersector, 672 struct htable_polygons* polygons, 673 struct darray_geometries* current_cad, 674 struct scad_geometry** cavity) 675 { 676 res_T res = RES_OK; 677 double e_wall = data->wall_thickness; 678 double e_ext_insulation = data->external_insulation_thickness; 679 double e_int_insulation = data->internal_insulation_thickness; 680 double e_roof = data->roof_thickness; 681 double e_roof_insulation = data->roof_insulation_thickness; 682 double e_attic = data->attic_height; 683 double offset = 0; 684 struct scpr_polygon* pg_int = NULL; 685 struct scad_geometry* footprint = NULL; 686 struct scad_geometry* geom = NULL; 687 double d[3] = {0, 0, 0}; 688 char* cavityname = NULL; 689 struct str name; 690 const char* prefix; 691 692 ASSERT(building && error_msg_printed && data && cavity); 693 694 prefix = str_cget(&building->name); 695 str_init(building->city->allocator, &name); 696 ERR(str_set(&name, prefix)); 697 ERR(str_append(&name, "_F_levels")); 698 cavityname = str_get(&name); 699 700 offset = -(e_wall + e_ext_insulation + e_int_insulation); 701 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 702 offset, &pg_int)); 703 ERR(build_footprint(pg_int, 0, &footprint)); 704 705 d[2] = height - e_roof - e_attic - e_roof_insulation; 706 ERR(scad_geometry_extrude(footprint, NULL, d, &geom)); 707 if(floor) { 708 ERR(scad_cut_geometries( 709 cavityname, &geom, 1, &floor, 1, cavity)); 710 } else { 711 ERR(scad_geometry_copy(geom, cavityname, cavity)); 712 } 713 ERR(darray_geometries_push_back(current_cad, cavity)); 714 715 exit: 716 if(footprint) SCAD(geometry_ref_put(footprint)); 717 if(geom) SCAD(geometry_ref_put(geom)); 718 str_release(&name); 719 if(pg_int) SCPR(polygon_ref_put(pg_int)); 720 return res; 721 error: 722 goto exit; 723 } 724 725 static res_T 726 build_attic 727 (struct building* building, 728 int *error_msg_printed, 729 const double height, 730 const struct dataset_cmode_1* data, 731 struct scpr_intersector* overlapping_intersector, 732 struct htable_polygons* polygons, 733 struct darray_geometries* current_cad, 734 struct scad_geometry** attic) 735 { 736 res_T res = RES_OK; 737 double e_wall = data->wall_thickness; 738 double e_insulation = data->external_insulation_thickness; 739 double e_roof = data->roof_thickness; 740 double e_attic = data->attic_height; 741 double offset = 0; 742 double z_attic = 0; 743 struct scpr_polygon* pg_int = NULL; 744 struct scad_geometry* footprint = NULL; 745 double d[3] = {0, 0, 0}; 746 char* atticname = NULL; 747 struct str name; 748 const char* prefix; 749 750 ASSERT(building && error_msg_printed && data && attic); 751 752 prefix = str_cget(&building->name); 753 str_init(building->city->allocator, &name); 754 ERR(str_set(&name, prefix)); 755 ERR(str_append(&name, "_F_attic")); 756 atticname = str_get(&name); 757 758 offset = -(e_wall + e_insulation); 759 ERR(do_offset(building, polygons, overlapping_intersector, error_msg_printed, 760 offset, &pg_int)); 761 762 /*footprint*/ 763 z_attic = height - e_roof - e_attic; 764 ERR(build_footprint(pg_int, z_attic, &footprint)); 765 766 d[2] = e_attic; 767 ERR(scad_geometry_extrude(footprint, atticname, d, attic)); 768 ERR(darray_geometries_push_back(current_cad, attic)); 769 770 exit: 771 if(footprint) SCAD(geometry_ref_put(footprint)); 772 str_release(&name); 773 if(pg_int) SCPR(polygon_ref_put(pg_int)); 774 return res; 775 error: 776 goto exit; 777 } 778 779 static res_T 780 build_windows 781 (const struct dataset_cmode_1* data, 782 struct data_cad_cmode_1* data_cad, 783 struct darray_geometries* current_cad, 784 struct darray_adjoining_data* adjoining_data) 785 { 786 res_T res = RES_OK; 787 size_t i, j, adjoining_n, removed_count, removed_hor = 0; 788 size_t removed_windows_sz = 0, removed_windows_adj = 0, removed_windows_self = 0; 789 size_t list_n = 0, array_n; 790 const char* prefix; 791 double N[3]; 792 double dir[3]; 793 double scale[3], scale_[3]; 794 struct scad_geometry* surface = NULL; 795 struct scad_geometry* win_surface = NULL; 796 struct scad_geometry* surface_ = NULL; 797 struct scad_geometry* hole = NULL; 798 struct scad_geometry* detect = NULL; 799 struct scad_geometry** hole_list = NULL; 800 struct darray_geometries hole_array; 801 struct scad_geometry* geom = NULL; 802 struct scad_geometry* hole_adjoining_intersect = NULL; 803 struct scad_geometry* bcavity = NULL; 804 struct scad_geometry** list = NULL; 805 struct scad_geometry** adj_list = NULL; 806 struct scad_geometry* glass = NULL; 807 struct scad_geometry** glass_list = NULL; 808 struct darray_geometries glass_array; 809 struct scad_geometry* env = NULL; 810 struct scad_geometry* benv = NULL; 811 struct scad_geometry* problem = NULL; 812 size_t floor_n; 813 double e_roof, e_roof_ins, e_attic, h_wall, e_floor; 814 struct str name; 815 struct adjoining_data* adj; 816 struct city* city; 817 struct mem_allocator* allocator; 818 double effective_ratio, total_wall_surface = 0, total_windows_surface = 0; 819 int meet_effective_ratio; 820 (void)removed_hor; 821 822 ASSERT(data && data_cad && adjoining_data); 823 824 city = data_cad->building->city; 825 allocator = city->allocator; 826 adjoining_n = darray_adjoining_data_size_get(adjoining_data); 827 adj = darray_adjoining_data_data_get(adjoining_data); 828 darray_geometries_init(allocator, &hole_array); 829 darray_geometries_init(allocator, &glass_array); 830 str_init(allocator, &name); 831 832 /* Compute wall height to help compute the minimum for windows area */ 833 floor_n = data->inter_floor_count; 834 e_roof = data->roof_thickness; 835 e_roof_ins = data->roof_insulation_thickness; 836 e_attic = data->attic_height; 837 e_floor = data->inter_floor_thickness; 838 h_wall = (data_cad->building->total_height- e_roof - e_attic - e_roof_ins 839 - (double)floor_n*e_floor) / (double)(floor_n + 1); 840 841 d3_splat(scale, sqrt(data->glass_ratio)); 842 d3_splat(scale_, MMIN(1, 1.05 * sqrt(data->glass_ratio))); 843 844 /* windows are build from the vertical faces of habitable cavities */ 845 ERR(scad_geometry_boundary("cavity_boundary", &data_cad->habitable_cavity, 1, 846 &bcavity)); 847 ERR(scad_geometry_explode(bcavity, "cavity_elt", &list, &list_n)); 848 ERR(scad_geometry_ref_put(bcavity)); 849 bcavity = NULL; 850 851 /* The boundary of the envelop of the building. 852 * To be used for windows validation */ 853 ERR(build_envelop(data_cad->building, &env)); 854 ERR(scad_geometry_boundary("envelop_boundary", &env, 1, &benv)); 855 ERR(scad_geometry_ref_put(env)); 856 env = NULL; 857 858 ERR(darray_geometries_reserve(&hole_array, list_n)); 859 ERR(darray_geometries_reserve(&glass_array, list_n)); 860 for(i = 0; i < list_n; i++) { 861 double hsz, wall_surface, center[3]; 862 size_t center_n; 863 size_t count; 864 int removed = 0; 865 866 ERR(scad_geometry_get_count(list[i], ¢er_n)); 867 ASSERT(center_n == 1); 868 ERR(scad_geometry_get_centerofmass(list[i], center)); 869 ERR(str_printf(&name, "surface_%lu", (long unsigned)i)); 870 ERR(scad_geometry_normal(list[i], center, N, str_cget(&name), &surface)); 871 872 if(N[2] != 0) { 873 ERR(scad_geometry_ref_put(surface)); 874 surface = NULL; 875 removed_hor++; 876 continue; /* keep only vertical face */ 877 } 878 879 ERR(scad_geometry_get_mass(list[i], &wall_surface)); 880 total_wall_surface += wall_surface; 881 if(wall_surface < CG2_MIN_WINDOWS_WIDTH * h_wall) { 882 /* this window would be too small */ 883 ERR(scad_geometry_ref_put(surface)); 884 surface = NULL; 885 removed = 1; 886 removed_windows_sz++; 887 } 888 889 if(!removed) { 890 /* Used to check for validity with a slitghly bigger size */ 891 ERR(str_printf(&name, "surface+_%lu", (long unsigned)i)); 892 ERR(scad_geometry_dilate(surface, center, scale_, str_cget(&name), 893 &surface_)); 894 } 895 896 if(!removed && adjoining_n) { 897 /* Use the same distance used in early stages for close neighbor detection */ 898 hsz = CG2_CLOSE_NEIGHBOR_DISTANCE + data->wall_thickness + 899 data->internal_insulation_thickness + data->external_insulation_thickness; 900 d3_muld(dir, N, hsz); 901 ERR(str_printf(&name, "detect_adj_%lu", (long unsigned)i)); 902 ERR(scad_geometry_extrude(surface_, str_cget(&name), dir, &detect)); 903 904 /* Check if detect intersects adjoining envelops */ 905 /* Push only if don't intersect */ 906 adj_list = MEM_REALLOC(allocator, adj_list, 907 adjoining_n * sizeof(struct scad_geometry*)); 908 for(j = 0; j < adjoining_n; j++) adj_list[j] = adj[j].envelop; 909 910 ERR(str_printf(&name, "adj_intersect_%lu", (long unsigned)i)); 911 ERR(scad_intersect_geometries(str_cget(&name), &detect, 1, adj_list, 912 adjoining_n, &hole_adjoining_intersect)); 913 ERR(scad_geometry_get_count(hole_adjoining_intersect, &count)); 914 if(count) { 915 removed = 1; 916 removed_windows_adj++; 917 } 918 ERR(scad_geometry_ref_put(hole_adjoining_intersect)); 919 hole_adjoining_intersect = NULL; 920 ERR(scad_geometry_ref_put(detect)); 921 detect = NULL; 922 } 923 924 /* Check if the window intersects an unexpected wall of the building: 925 * - the window is too large wrt of external size of the wall (the window's 926 * size is a % of the internal size of the wall that can be larger than 927 * the external size due to corners). 928 * - another wall facing the current one at a too close distance (can be the 929 * prev/next with sharp angle, or not), 930 * - a tiny unwanted wall created by noise at the polygon level (mainly due 931 * to the offseting algorithm). */ 932 if(!removed) { 933 /* Use smaller distance than the one used for neighbor detection */ 934 hsz = 0.1 + data->wall_thickness + data->internal_insulation_thickness 935 + data->external_insulation_thickness; 936 d3_muld(dir, N, hsz); 937 ERR(str_printf(&name, "detect_self_%lu", (long unsigned)i)); 938 ERR(scad_geometry_extrude(surface_, str_cget(&name), dir, &detect)); 939 /* Compute intersection between detect and envelop: the number of 940 * components is expected to be 1, or the window is better removed */ 941 ERR(str_printf(&name, "self_intersect_%lu", (long unsigned)i)); 942 ERR(scad_intersect_geometries(str_cget(&name), &benv, 1, &detect, 1, 943 &problem)); 944 ERR(scad_geometry_get_count(problem, &count)); 945 if(count != 1) { 946 removed = 1; 947 removed_windows_self++; 948 } 949 ERR(scad_geometry_ref_put(detect)); 950 detect = NULL; 951 ERR(scad_geometry_ref_put(problem)); 952 problem = NULL; 953 } 954 955 if(!removed) { 956 ERR(scad_geometry_dilate(surface, center, scale, NULL, &win_surface)); 957 ERR(str_printf(&name, "hole_%lu", (long unsigned)i)); 958 ERR(scad_geometry_extrude(win_surface, str_cget(&name), dir, &hole)); 959 ERR(darray_geometries_push_back(&hole_array, &hole)); 960 ERR(scad_geometry_ref_put(hole)); 961 hole = NULL; 962 d3_muld(dir, N, CG2_GLAZING_THICKNESS); 963 ERR(str_printf(&name, "glass_%lu", (long unsigned)i)); 964 ERR(scad_geometry_extrude(win_surface, str_cget(&name), dir, &glass)); 965 ERR(darray_geometries_push_back(&glass_array, &glass)); 966 ERR(darray_geometries_push_back(current_cad, &glass)); 967 ERR(scad_geometry_ref_put(glass)); 968 glass = NULL; 969 total_windows_surface += wall_surface * data->glass_ratio; 970 } 971 ASSERT(hole == NULL); 972 ASSERT(detect == NULL); 973 if(win_surface) { 974 ERR(scad_geometry_ref_put(win_surface)); 975 win_surface = NULL; 976 } 977 if(surface) { 978 ERR(scad_geometry_ref_put(surface)); 979 surface = NULL; 980 } 981 if(surface_) { 982 ERR(scad_geometry_ref_put(surface_)); 983 surface_ = NULL; 984 } 985 } 986 removed_count = removed_windows_sz + removed_windows_adj + removed_windows_self; 987 array_n = darray_geometries_size_get(&hole_array); 988 ASSERT(array_n == darray_geometries_size_get(&glass_array)); 989 ASSERT(array_n + removed_hor + removed_count == list_n); 990 991 prefix = str_cget(&data_cad->building->name); 992 if(removed_count != 0) { 993 logger_print(city->logger, LOG_WARNING, 994 "Building '%s' has %zu/%zu windows removed:\n", 995 prefix, removed_count, removed_count + array_n); 996 if(removed_windows_sz != 0) { 997 logger_print(city->logger, LOG_WARNING, 998 "- %zu windows removed due to too small size.\n", removed_windows_sz); 999 } 1000 if(removed_windows_adj != 0) { 1001 logger_print(city->logger, LOG_WARNING, 1002 "- %zu windows removed due to close neighbors.\n", removed_windows_adj); 1003 } 1004 if(removed_windows_self != 0) { 1005 logger_print(city->logger, LOG_WARNING, 1006 "- %zu windows removed due to self conflicts.\n", removed_windows_self); 1007 } 1008 } else { 1009 logger_print(city->logger, LOG_OUTPUT, 1010 "Building '%s' has no window removed (out of %zu).\n", prefix, array_n); 1011 } 1012 effective_ratio = total_windows_surface / total_wall_surface; 1013 meet_effective_ratio = data->glass_ratio == 0 1014 || fabs(effective_ratio - data->glass_ratio) / data->glass_ratio < 0.01; 1015 logger_print(city->logger, (meet_effective_ratio ? LOG_OUTPUT : LOG_WARNING), 1016 "Building '%s' overall glass ratio is %.1f %% (expected is %.1f %%).\n", 1017 prefix, 100 * effective_ratio, 100 * data->glass_ratio); 1018 1019 if(array_n > 0) { 1020 hole_list = darray_geometries_data_get(&hole_array); 1021 glass_list = darray_geometries_data_get(&glass_array); 1022 1023 /* wall perforation */ 1024 ERR(scad_cut_geometries(NULL, &data_cad->wall, 1, hole_list, array_n, &geom)); 1025 ERR(scad_geometries_swap(&data_cad->wall, &geom, 1, Scad_swap_geometry)); 1026 ERR(scad_geometry_ref_put(geom)); 1027 geom = NULL; 1028 1029 /* internal insulation perforation */ 1030 if(data_cad->internal_insulation) { 1031 ERR(scad_cut_geometries(NULL, &data_cad->internal_insulation, 1, 1032 hole_list, array_n, &geom)); 1033 ERR(scad_geometries_swap(&data_cad->internal_insulation, &geom, 1, 1034 Scad_swap_geometry)); 1035 ERR(scad_geometry_ref_put(geom)); 1036 geom = NULL; 1037 } 1038 1039 /* external insulation perforation */ 1040 if(data_cad->external_insulation) { 1041 ERR(scad_cut_geometries(NULL, &data_cad->external_insulation, 1, 1042 hole_list, array_n, &geom)); 1043 ERR(scad_geometries_swap(&data_cad->external_insulation, &geom, 1, 1044 Scad_swap_geometry)); 1045 ERR(scad_geometry_ref_put(geom)); 1046 geom = NULL; 1047 } 1048 1049 /* build glass */ 1050 ERR(str_set(&name, prefix)); 1051 ERR(str_append(&name, "_S_glazing")); 1052 ERR(scad_fuse_geometries(str_cget(&name), glass_list, array_n, 1053 glass_list, array_n, &data_cad->glazing)); 1054 } 1055 1056 exit: 1057 for(i = 0 ; i < list_n; i++) SCAD(geometry_ref_put(list[i])); 1058 darray_geometries_release(&hole_array); 1059 darray_geometries_release(&glass_array); 1060 if(env) SCAD(geometry_ref_put(env)); 1061 if(benv) SCAD(geometry_ref_put(benv)); 1062 if(surface) SCAD(geometry_ref_put(surface)); 1063 if(win_surface) SCAD(geometry_ref_put(win_surface)); 1064 if(problem) SCAD(geometry_ref_put(problem)); 1065 if(hole) SCAD(geometry_ref_put(hole)); 1066 if(detect) SCAD(geometry_ref_put(detect)); 1067 if(glass) SCAD(geometry_ref_put(glass)); 1068 if(geom) SCAD(geometry_ref_put(geom)); 1069 if(bcavity) SCAD(geometry_ref_put(bcavity)); 1070 if(hole_adjoining_intersect) SCAD(geometry_ref_put(hole_adjoining_intersect)); 1071 MEM_RM(allocator, list); 1072 MEM_RM(allocator, adj_list); 1073 str_release(&name); 1074 return res; 1075 error: 1076 goto exit; 1077 } 1078 1079 static res_T 1080 build_boundary 1081 (struct data_cad_cmode_1* data_cad, 1082 struct darray_adjoining_data* adjoining_data, 1083 struct darray_geometries* boundary) 1084 { 1085 res_T res = RES_OK; 1086 struct darray_geometries array; 1087 struct scad_geometry** list = NULL; 1088 struct scad_geometry* bound = NULL; 1089 char* boundaryname = NULL; 1090 struct str name; 1091 struct adjoining_data* adj; 1092 size_t adjoining_n, i = 0, count = 0; 1093 const char* prefix; 1094 1095 ASSERT(data_cad && adjoining_data && boundary); 1096 1097 prefix = str_cget(&data_cad->building->name); 1098 adjoining_n = darray_adjoining_data_size_get(adjoining_data); 1099 adj = darray_adjoining_data_data_get(adjoining_data); 1100 darray_geometries_init(data_cad->building->city->allocator, &array); 1101 str_init(data_cad->building->city->allocator, &name); 1102 1103 /* Ensure enough room for all geometries without error nor mem move */ 1104 ERR(darray_geometries_reserve(&array, 14 + adjoining_n)); 1105 /* Using wall here to compute boundary_wall is OK even if it doesn't take care 1106 * of conformity wrt the adjoining building. The reason is that the common 1107 * part that could end to be not conformal is not part of the boundary. As a 1108 * consequence it cannot be part of the result. */ 1109 ERR(darray_geometries_push_back(&array, &data_cad->wall)); 1110 ERR(darray_geometries_push_back(&array, &data_cad->roof)); 1111 ERR(darray_geometries_push_back(&array, &data_cad->floor)); 1112 ERR(darray_geometries_push_back(&array, &data_cad->habitable_cavity)); 1113 ERR(darray_geometries_push_back(&array, &data_cad->fake_ground)); 1114 if(data_cad->foundation) { 1115 ERR(darray_geometries_push_back(&array, &data_cad->foundation)); 1116 } 1117 if(data_cad->intermediate_floor) { 1118 ERR(darray_geometries_push_back(&array, &data_cad->intermediate_floor)); 1119 } 1120 if(data_cad->external_insulation) { 1121 ERR(darray_geometries_push_back(&array, &data_cad->external_insulation)); 1122 } 1123 if(data_cad->internal_insulation) { 1124 ERR(darray_geometries_push_back(&array, &data_cad->internal_insulation)); 1125 } 1126 if(data_cad->roof_insulation) { 1127 ERR(darray_geometries_push_back(&array, &data_cad->roof_insulation)); 1128 } 1129 if(data_cad->floor_insulation) { 1130 ERR(darray_geometries_push_back(&array, &data_cad->floor_insulation)); 1131 } 1132 if(data_cad->attic_cavity) { 1133 ERR(darray_geometries_push_back(&array, &data_cad->attic_cavity)); 1134 } 1135 if(data_cad->crawlspace_cavity) { 1136 ERR(darray_geometries_push_back(&array, &data_cad->crawlspace_cavity)); 1137 } 1138 if(data_cad->glazing) { 1139 ERR(darray_geometries_push_back(&array, &data_cad->glazing)); 1140 } 1141 for(i = 0; i < adjoining_n; i++) { 1142 /* Here we consider truly adjoining buildings, except removed ones (early 1143 * removed ones are not part of adjoining) */ 1144 if(adj[i].really_adjoining 1145 && !(adj[i].adjoining_building->event_flags & BUILDING_REMOVED)) 1146 { 1147 ERR(darray_geometries_push_back(&array, &adj[i].envelop)); 1148 } 1149 } 1150 1151 count = darray_geometries_size_get(&array); 1152 list = darray_geometries_data_get(&array); 1153 1154 /* Ensure enough room for all geometries without error nor mem move */ 1155 ERR(darray_geometries_reserve(boundary, 5+darray_geometries_size_get(boundary))); 1156 1157 ERR(str_set(&name, prefix)); 1158 ERR(str_append(&name, "_B_walls")); 1159 boundaryname = str_get(&name); 1160 ERR(scad_geometries_common_boundaries(boundaryname, list, count, 1161 &data_cad->wall, 1, &bound)); 1162 ERR(darray_geometries_push_back(boundary, &bound)); 1163 ERR(scad_geometry_ref_put(bound)); 1164 bound = NULL; 1165 1166 ERR(str_set(&name, prefix)); 1167 ERR(str_append(&name, "_B_roof")); 1168 boundaryname = str_get(&name); 1169 ERR(scad_geometries_common_boundaries(boundaryname, list, count, 1170 &data_cad->roof, 1, &bound)); 1171 ERR(darray_geometries_push_back(boundary, &bound)); 1172 ERR(scad_geometry_ref_put(bound)); 1173 bound = NULL; 1174 1175 if(data_cad->glazing) { 1176 ERR(str_set(&name, prefix)); 1177 ERR(str_append(&name, "_B_glazing")); 1178 boundaryname = str_get(&name); 1179 ERR(scad_geometries_common_boundaries(boundaryname, list, count, 1180 &data_cad->glazing, 1, &bound)); 1181 ERR(darray_geometries_push_back(boundary, &bound)); 1182 ERR(scad_geometry_ref_put(bound)); 1183 bound = NULL; 1184 } 1185 1186 if(data_cad->external_insulation) { 1187 ERR(str_set(&name, prefix)); 1188 ERR(str_append(&name, "_B_external_insulation")); 1189 boundaryname = str_get(&name); 1190 ERR(scad_geometries_common_boundaries(boundaryname, list, count, 1191 &data_cad->external_insulation, 1, &bound)); 1192 ERR(darray_geometries_push_back(boundary, &bound)); 1193 ERR(scad_geometry_ref_put(bound)); 1194 bound = NULL; 1195 } 1196 1197 if(data_cad->internal_insulation) { 1198 size_t bcount = 0; 1199 ERR(str_set(&name, prefix)); 1200 ERR(str_append(&name, "_B_internal_insulation")); 1201 boundaryname = str_get(&name); 1202 ERR(scad_geometries_common_boundaries(boundaryname, list, count, 1203 &data_cad->internal_insulation, 1, &bound)); 1204 ERR(scad_geometry_get_count(bound, &bcount)); 1205 if(bcount > 0) { 1206 ERR(darray_geometries_push_back(boundary, &bound)); 1207 } 1208 ERR(scad_geometry_ref_put(bound)); 1209 bound = NULL; 1210 } 1211 1212 exit: 1213 if(bound) SCAD(geometry_ref_put(bound)); 1214 str_release(&name); 1215 darray_geometries_release(&array); 1216 return res; 1217 error: 1218 goto exit; 1219 } 1220 1221 static res_T 1222 build_connection 1223 (struct data_cad_cmode_1* data_cad, 1224 struct darray_geometries* connection) 1225 { 1226 res_T res = RES_OK; 1227 struct scad_geometry* connect = NULL; 1228 size_t count = 0; 1229 char* cname = NULL; 1230 struct str name; 1231 const char* prefix; 1232 1233 ASSERT(data_cad && connection); 1234 1235 prefix = str_cget(&data_cad->building->name); 1236 str_init(data_cad->building->city->allocator, &name); 1237 1238 #define CREATE_CONNECT(G1,G2,SUFFIX) \ 1239 ERR(str_set(&name, prefix));\ 1240 ERR(str_append(&name, SUFFIX));\ 1241 cname = str_get(&name);\ 1242 ERR(scad_geometries_common_boundaries(cname, &data_cad->G1, 1,\ 1243 &data_cad->G2, 1, &connect));\ 1244 ERR(scad_geometry_get_count(connect, &count)); \ 1245 if(count > 0) { \ 1246 ERR(darray_geometries_push_back(connection, &connect)); \ 1247 } \ 1248 ERR(scad_geometry_ref_put(connect)); \ 1249 connect = NULL; 1250 1251 /* -------------------------------------------------------------------------*/ 1252 /* habitable cavity connections */ 1253 /* -------------------------------------------------------------------------*/ 1254 1255 /* with floor */ 1256 CREATE_CONNECT(habitable_cavity,floor,"_C_levels_floor"); 1257 1258 /* with wall */ 1259 CREATE_CONNECT(habitable_cavity,wall,"_C_levels_walls"); 1260 1261 /* with glass */ 1262 if(data_cad->glazing) { 1263 CREATE_CONNECT(habitable_cavity,glazing,"_C_levels_glazing"); 1264 } 1265 1266 /* with internal insulation */ 1267 if(data_cad->internal_insulation) { 1268 CREATE_CONNECT(habitable_cavity,internal_insulation,"_C_levels_internal_insulation"); 1269 } 1270 1271 /* with roof insulation */ 1272 if(data_cad->roof_insulation) { 1273 CREATE_CONNECT(habitable_cavity,roof_insulation,"_C_levels_roof_insulation"); 1274 } else { 1275 /* with roof */ 1276 CREATE_CONNECT(habitable_cavity,roof,"_C_levels_roof"); 1277 } 1278 1279 /* with intermediate floor */ 1280 if(data_cad->intermediate_floor) { 1281 CREATE_CONNECT(habitable_cavity,intermediate_floor,"_C_levels_intermediate_floors"); 1282 } 1283 1284 /* -------------------------------------------------------------------------*/ 1285 /* crawlspace cavity connections */ 1286 /* -------------------------------------------------------------------------*/ 1287 1288 if(data_cad->crawlspace_cavity) { 1289 /* with floor insulation */ 1290 if(data_cad->floor_insulation) { 1291 CREATE_CONNECT(crawlspace_cavity, floor_insulation,"_C_crawlspace_insulation"); 1292 } else { 1293 /* with floor */ 1294 CREATE_CONNECT(crawlspace_cavity, floor,"_C_crawlspace_floor"); 1295 } 1296 1297 /* with wall */ 1298 CREATE_CONNECT(crawlspace_cavity, foundation,"_C_crawlspace_foundation"); 1299 1300 /* with ground */ 1301 CREATE_CONNECT(crawlspace_cavity, fake_ground,"_C_crawlspace_ground"); 1302 } 1303 1304 /* -------------------------------------------------------------------------*/ 1305 /* attic cavity connections */ 1306 /* -------------------------------------------------------------------------*/ 1307 1308 if(data_cad->attic_cavity) { 1309 /* with roof */ 1310 CREATE_CONNECT(attic_cavity, roof,"_C_attic_roof"); 1311 1312 /* with roof insulation */ 1313 if(data_cad->roof_insulation) { 1314 CREATE_CONNECT(attic_cavity, roof_insulation,"_C_attic_insulation"); 1315 } 1316 1317 /* with wall */ 1318 CREATE_CONNECT(attic_cavity, wall,"_C_attic_walls"); 1319 } 1320 1321 #undef CREATE_CONNECT 1322 1323 exit: 1324 str_release(&name); 1325 return res; 1326 error: 1327 goto exit; 1328 } 1329 1330 static res_T 1331 build_fake_ground 1332 (struct data_cad_cmode_1* cad, 1333 const double depth, 1334 struct darray_geometries* current_cad, 1335 struct scad_geometry** ground) 1336 { 1337 res_T res = RES_OK; 1338 double dir[3] = {0, 0, 0}; 1339 struct scpr_polygon* pg_offset = NULL; 1340 size_t count; 1341 struct darray_geometries array; 1342 struct scad_geometry** list = NULL; 1343 struct scad_geometry* footprint = NULL; 1344 struct scad_geometry* geom = NULL; 1345 1346 ASSERT(cad && ground); 1347 1348 darray_geometries_init(cad->building->city->allocator, &array); 1349 1350 /* Ensure enough room for all geometries without error nor mem move */ 1351 ERR(darray_geometries_reserve(&array, 4)); 1352 if(cad->foundation) { 1353 ERR(darray_geometries_push_back(&array, &cad->foundation)); 1354 } 1355 if(cad->crawlspace_cavity) { 1356 ERR(darray_geometries_push_back(&array, &cad->crawlspace_cavity)); 1357 } 1358 if(cad->floor) { 1359 ERR(darray_geometries_push_back(&array, &cad->floor)); 1360 } 1361 if(cad->floor_insulation) { 1362 ERR(darray_geometries_push_back(&array, &cad->floor_insulation)); 1363 } 1364 1365 count = darray_geometries_size_get(&array); 1366 list = darray_geometries_data_get(&array); 1367 1368 ERR(scpr_polygon_create_copy(cad->building->city->scpr, cad->building->pg, &pg_offset)); 1369 ERR(scpr_offset_polygon(pg_offset, 0.1, SCPR_JOIN_MITER)); 1370 1371 ERR(build_footprint(pg_offset, 0, &footprint)); 1372 1373 dir[2] = -depth*1.1; 1374 ERR(scad_geometry_extrude(footprint, NULL, dir, &geom)); 1375 1376 ERR(scad_cut_geometries("fake_ground", &geom, 1, list, count, ground)); 1377 ERR(darray_geometries_push_back(current_cad, ground)); 1378 1379 exit: 1380 if(pg_offset) SCPR(polygon_ref_put(pg_offset)); 1381 darray_geometries_release(&array); 1382 if(footprint) SCAD(geometry_ref_put(footprint)); 1383 if(geom) SCAD(geometry_ref_put(geom)); 1384 return res; 1385 error: 1386 goto exit; 1387 } 1388 1389 static res_T 1390 building_ground_connection 1391 (struct data_cad_cmode_1* cad, 1392 struct scad_geometry** connection) 1393 { 1394 res_T res = RES_OK; 1395 char* cname = NULL; 1396 struct str name; 1397 size_t count; 1398 struct darray_geometries array; 1399 struct scad_geometry** list = NULL; 1400 struct scad_geometry* list_boundary = NULL; 1401 struct scad_geometry* footprint = NULL; 1402 const char* prefix; 1403 1404 ASSERT(cad && connection); 1405 1406 prefix = str_cget(&cad->building->name); 1407 darray_geometries_init(cad->building->city->allocator, &array); 1408 str_init(cad->building->city->allocator, &name); 1409 ERR(str_set(&name, prefix)); 1410 ERR(str_append(&name, "_C_ground")); 1411 cname = str_get(&name); 1412 1413 /* Ensure enough room for all geometries without error nor mem move */ 1414 ERR(darray_geometries_reserve(&array, 6)); 1415 if(cad->foundation) { 1416 ERR(darray_geometries_push_back(&array, &cad->foundation)); 1417 } 1418 if(cad->crawlspace_cavity) { 1419 ERR(darray_geometries_push_back(&array, &cad->crawlspace_cavity)); 1420 } 1421 if(cad->floor) { 1422 ERR(darray_geometries_push_back(&array, &cad->floor)); 1423 } 1424 if(cad->floor_insulation) { 1425 ERR(darray_geometries_push_back(&array, &cad->floor_insulation)); 1426 } 1427 if(cad->external_insulation) { 1428 ERR(darray_geometries_push_back(&array, &cad->external_insulation)); 1429 } 1430 if(cad->wall) { 1431 ERR(darray_geometries_push_back(&array, &cad->wall)); 1432 } 1433 1434 count = darray_geometries_size_get(&array); 1435 list = darray_geometries_data_get(&array); 1436 1437 ERR(scad_geometries_common_boundaries(cname, list, count, &cad->fake_ground, 1, 1438 connection)); 1439 1440 exit: 1441 darray_geometries_release(&array); 1442 str_release(&name); 1443 if(list_boundary) SCAD(geometry_ref_put(list_boundary)); 1444 if(footprint) SCAD(geometry_ref_put(footprint)); 1445 return res; 1446 error: 1447 goto exit; 1448 } 1449 1450 /*----------------------------------------------------------------------------*/ 1451 /*----------------------------------------------------------------------------*/ 1452 /*----------------------------------------------------------------------------*/ 1453 1454 res_T 1455 init_cmode_1 1456 (struct building* building, 1457 struct city* city, 1458 struct parsed_city_building* parsed_data, 1459 struct catalog* catalog, 1460 const double lower[2], 1461 const double upper[2]) 1462 { 1463 res_T res = RES_OK; 1464 struct str dataset_name; 1465 int name_initialized = 0; 1466 struct dataset_cmode_1* data; 1467 static struct construction_mode_functors functors_1 = { 1468 &init_cmode_1, 1469 &release_cmode_1, 1470 &build_cad_cmode_1, 1471 &build_footprint_cmode_1, 1472 &save_ground_connection_triangles_1, 1473 &export_stl_cmode_1, 1474 &release_cad_cmode_1 1475 }; 1476 struct mem_allocator* allocator; 1477 struct logger* logger; 1478 int has_external_insulation; 1479 (void) parsed_data; 1480 1481 if(!building || !city || !parsed_data || !catalog || !lower || !upper) { 1482 res = RES_BAD_ARG; 1483 goto error; 1484 } 1485 1486 allocator = city->allocator; 1487 logger = city->logger; 1488 building->construction_mode = mode_1; 1489 building->functors = &functors_1; 1490 1491 ERR(init_building_base(building, city, parsed_data)); 1492 1493 if(parsed_data->levels_height_count != 0) { 1494 ERR(logger_print(city->logger, LOG_ERROR, 1495 "Building '%s' defines 'levels_height' " 1496 "(feature not available in construction mode 1).\n", 1497 str_cget(&building->name))); 1498 res = RES_BAD_ARG; 1499 goto error; 1500 } 1501 1502 if(parsed_data->height <= 0) { 1503 ERR(logger_print(city->logger, LOG_ERROR, 1504 "Building '%s' height definition is invalid " 1505 "(construction mode 1 should define a positive height through the 'height' field).\n", 1506 str_cget(&building->name))); 1507 res = RES_BAD_ARG; 1508 goto error; 1509 } 1510 building->total_height = parsed_data->height; 1511 1512 str_init(allocator, &dataset_name); 1513 name_initialized = 1; 1514 ERR(str_set(&dataset_name, parsed_data->dataset_name)); 1515 building->data = htable_dataset_cmode_1_find(&catalog->catalog_1, &dataset_name); 1516 if(building->data == NULL) { 1517 ERR(logger_print(logger, LOG_ERROR, 1518 "Unknown dataset name: '%s' used by building '%s'.\n", 1519 str_cget(&dataset_name), str_cget(&building->name))); 1520 res = RES_BAD_ARG; 1521 goto error; 1522 } 1523 data = (struct dataset_cmode_1 *)building->data; 1524 has_external_insulation = (data->external_insulation_thickness != 0); 1525 ERR(str_set(&building->external_layer_name, 1526 (has_external_insulation ? "external_insulation" : "walls"))); 1527 1528 exit: 1529 if(name_initialized) str_release(&dataset_name); 1530 return res; 1531 error: 1532 goto exit; 1533 } 1534 1535 res_T 1536 release_cmode_1 1537 (struct building* building) 1538 { 1539 if(!building) return RES_BAD_ARG; 1540 return release_building_base(building); 1541 } 1542 1543 res_T 1544 build_cad_cmode_1 1545 (struct building* building, 1546 int dump_footprints_level, 1547 int keep_running_on_errors, 1548 struct darray_adjoining_data* adjoining_data, 1549 struct darray_geometries* current_cad, 1550 void** cad) 1551 { 1552 res_T res = RES_OK; 1553 double height = building->total_height; 1554 double depth = 0; 1555 struct dataset_cmode_1* data = (struct dataset_cmode_1 *)building->data; 1556 struct data_cad_cmode_1* data_cad = NULL; 1557 const char* name; 1558 struct scpr_intersector* overlapping_intersector = NULL; 1559 struct scpr_intersector_check_callbacks callbacks 1560 = SCPR_INTERSECTOR_CHECK_CALLBACKS_NULL__; 1561 size_t adjoining_n = 0; 1562 struct callback_ctx ctx = CB_CTX_NULL__; 1563 int error_occured = 0, error_msg_printed = 0;; 1564 struct htable_polygons polygons; 1565 int polygons_initialized = 0; 1566 double zero = 0; 1567 struct mem_allocator* allocator; 1568 struct logger* logger = NULL; 1569 size_t i, cad_count = 0; 1570 struct scad_geometry** cur_cad = NULL; 1571 struct scad_geometry** partitioned = NULL; 1572 struct time t0, dt, tw, dtw; 1573 char buf[128]; 1574 1575 if(!building || !cad || !adjoining_data) { 1576 res = RES_BAD_ARG; 1577 goto error; 1578 } 1579 1580 time_current(&t0); 1581 name = str_cget(&building->name); 1582 allocator = building->city->allocator; 1583 logger = building->city->logger; 1584 1585 logger_print(logger, LOG_OUTPUT, 1586 "Building '%s' construction mode 1, dataset '%s', %g m tall.\n", 1587 name, str_cget(&building->dataset_name), building->total_height); 1588 1589 data_cad = MEM_CALLOC(allocator, 1, sizeof(struct data_cad_cmode_1)); 1590 if(!data_cad) { 1591 res = RES_MEM_ERR; 1592 goto error; 1593 } 1594 building->data_cad = data_cad; 1595 data_cad->building = building; 1596 darray_common_trg_init(allocator, &data_cad->common_trg); 1597 darray_geometries_init(allocator, &data_cad->adj_walls); 1598 darray_geometries_init(allocator, &data_cad->boundary); 1599 darray_geometries_init(allocator, &data_cad->connection); 1600 1601 htable_polygons_init(allocator, &polygons); 1602 polygons_initialized = 1; 1603 1604 ERR(scpr_intersector_create(building->city->scpr, &overlapping_intersector)); 1605 ERR(scpr_intersector_register_polygon(overlapping_intersector, building->pg)); 1606 /* An htable to associate offset polygons to offsets. Not really for 1607 * performance, but to avoid considering the same polygon more than once when 1608 * checking for polygon intersections (that would be an error). */ 1609 ERR(htable_polygons_set(&polygons, &zero, &building->pg)); 1610 1611 /* build mandatories elements : 1612 - floor 1613 - wall 1614 - roof 1615 */ 1616 1617 ERR(build_floor(building, &error_msg_printed, data, overlapping_intersector, 1618 &polygons, current_cad, &data_cad->floor)); 1619 1620 ERR(build_wall(building, &error_msg_printed, 0, "S_walls", height, data, 1621 overlapping_intersector, &polygons, current_cad, &data_cad->wall)); 1622 1623 ERR(build_roof(building, &error_msg_printed, 1624 height, data, 1625 overlapping_intersector, &polygons, current_cad, &data_cad->roof)); 1626 1627 /* build optionnal elements : 1628 - foundation 1629 - intermediate floor 1630 - external insulation 1631 - internal insulation 1632 - roof insulation 1633 - floor insulation 1634 */ 1635 1636 if(data->foundation_depth > 0) { 1637 depth = -data->foundation_depth; 1638 ERR(build_wall(building, &error_msg_printed, 1, "S_foundation", depth, 1639 data, overlapping_intersector, &polygons, current_cad, &data_cad->foundation)); 1640 } 1641 1642 if(data->inter_floor_count > 0) { 1643 ERR(build_inter_floor(building, &error_msg_printed, height, data, 1644 overlapping_intersector, &polygons, current_cad, &data_cad->intermediate_floor)); 1645 } 1646 1647 if(data->external_insulation_thickness> 0) { 1648 ERR(build_ext_insulation(building, &error_msg_printed, height, data, 1649 overlapping_intersector, &polygons, current_cad, &data_cad->external_insulation)); 1650 } 1651 1652 if(data->internal_insulation_thickness> 0) { 1653 ERR(build_int_insulation(building, &error_msg_printed, height, data, 1654 data_cad->intermediate_floor, overlapping_intersector, &polygons, 1655 current_cad, &data_cad->internal_insulation)); 1656 } 1657 1658 if(data->roof_insulation_thickness > 0) { 1659 ERR(build_roof_insulation(building, &error_msg_printed, height, data, 1660 overlapping_intersector, &polygons, current_cad, &data_cad->roof_insulation)); 1661 } 1662 1663 if(data->floor_insulation_thickness > 0) { 1664 ERR(build_floor_insulation(building, &error_msg_printed, data, 1665 overlapping_intersector, &polygons, current_cad, &data_cad->floor_insulation)); 1666 } 1667 1668 /* build cavities : 1669 - attic 1670 - habitable 1671 - crawlspace 1672 */ 1673 1674 if(data->attic_height > 0) { 1675 ERR(build_attic(building, &error_msg_printed, height, data, 1676 overlapping_intersector, &polygons, current_cad, &data_cad->attic_cavity)); 1677 } 1678 1679 ERR(build_habitable(building, &error_msg_printed, height, data, 1680 data_cad->intermediate_floor, overlapping_intersector, &polygons, 1681 current_cad, &data_cad->habitable_cavity)); 1682 1683 if(data->crawl_height > 0) { 1684 ERR(build_crawlspace(building, &error_msg_printed, data, 1685 overlapping_intersector, &polygons, current_cad, &data_cad->crawlspace_cavity)); 1686 } 1687 1688 /* Check for registered polygons overlapping */ 1689 ctx.city = building->city; 1690 ctx.buildings = building; 1691 ctx.buildings_count = 1; 1692 ctx.intersection_found = &error_occured; 1693 ctx.search_type = TESTING_1_BUILDING_INTERNALS; 1694 ctx.dump_footprints_level = dump_footprints_level; 1695 ctx.keep_running_on_errors = keep_running_on_errors; 1696 callbacks.simple_intersection = simple_intersection; 1697 ERR(scpr_intersector_check(overlapping_intersector, &callbacks, &ctx)); 1698 if(error_occured) { 1699 logger_print(logger, LOG_ERROR, 1700 "Internal error generating CAD for building '%s'.\n", 1701 name); 1702 building->event_flags |= BUILDING_REMOVED; 1703 error_msg_printed = 1; 1704 res = RES_BAD_ARG; 1705 goto error; 1706 } 1707 1708 /* build adjoining envelop */ 1709 adjoining_n = htable_building_size_get(&building->close_buildings); 1710 if(adjoining_n > 0) { 1711 ERR(build_adjoining(building, 0, current_cad, adjoining_data)); 1712 } 1713 1714 /* windows */ 1715 if(data->glass_ratio > 0) { 1716 time_current(&tw); 1717 ERR(build_windows(data, data_cad, current_cad, adjoining_data)); 1718 time_sub(&dtw, time_current(&dtw), &tw); 1719 } 1720 1721 /* fake ground */ 1722 depth = MMAX(data->foundation_depth, 1723 data->floor_thickness + data->floor_insulation_thickness + data->crawl_height); 1724 ERR(build_fake_ground(data_cad, depth, current_cad, &data_cad->fake_ground)); 1725 1726 /* print partial computation time */ 1727 time_sub(&dt, time_current(&dt), &t0); 1728 time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); 1729 if(data->glass_ratio > 0) { 1730 char bufw[128]; 1731 time_dump(&dtw, TIME_SEC | TIME_MSEC, NULL, bufw, sizeof(bufw)); 1732 logger_print(logger, LOG_OUTPUT, 1733 "Building '%s' CAO stage done in %s (windows creation in %s).\n", 1734 name, buf, bufw); 1735 } else { 1736 logger_print(logger, LOG_OUTPUT, 1737 "Building '%s' CAO stage done in %s.\n", name, buf); 1738 } 1739 time_current(&t0); 1740 1741 /* Partition CAD */ 1742 cad_count = darray_geometries_size_get(current_cad); 1743 partitioned = MEM_CALLOC(allocator, cad_count, sizeof(*partitioned)); 1744 if(!partitioned) { 1745 res = RES_MEM_ERR; 1746 goto error; 1747 } 1748 cur_cad = darray_geometries_data_get(current_cad); 1749 ERR(scad_geometries_partition(cur_cad, cad_count, Scad_dump_on_overlapping_error, 1750 partitioned)); 1751 /* Swap original geometry and partitioned geometry in data_cad (was 1752 * accumulated into current_cad) */ 1753 ERR(scad_geometries_swap(cur_cad, partitioned, cad_count, Scad_swap_geometry)); 1754 for(i = 0; i < cad_count; i++) { 1755 if(partitioned[i]) { 1756 ERR(scad_geometry_ref_put(partitioned[i])); 1757 } 1758 } 1759 MEM_RM(allocator, partitioned); 1760 partitioned = NULL; 1761 1762 /* print partial computation time */ 1763 time_sub(&dt, time_current(&dt), &t0); 1764 time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); 1765 logger_print(logger, LOG_OUTPUT, 1766 "Building '%s' partitioning stage done in %s.\n", name, buf); 1767 time_current(&t0); 1768 1769 /* After partitioning, manage common parts with other buildings */ 1770 adjoining_n = darray_adjoining_data_size_get(adjoining_data); 1771 if(adjoining_n > 0) { 1772 size_t a, c; 1773 struct b_pair pair; 1774 struct darray_double* common; 1775 struct adjoining_data* adjoining 1776 = darray_adjoining_data_data_get(adjoining_data); 1777 struct scad_geometry* extern_most = data_cad->external_insulation 1778 ? data_cad->external_insulation : data_cad->wall; 1779 for(a = 0; a < adjoining_n; a++) { 1780 struct adjoining_data* adj = adjoining + a; 1781 ERR(scad_geometries_common_boundaries(NULL, &extern_most, 1, 1782 &adj->envelop, 1, &adj->common_geometry)); 1783 ERR(scad_geometry_get_count(adj->common_geometry, &c)); 1784 adj->really_adjoining = (c != 0); 1785 if(!adj->really_adjoining) { 1786 logger_print(logger, LOG_OUTPUT, 1787 "Building '%s': neighbor '%s' not really adjoining.\n", 1788 name, 1789 str_cget(&adj->adjoining_building->name)); 1790 continue; 1791 } 1792 make_b_pair(&pair, building, adj->adjoining_building); 1793 /* Keep track of the geometry to replace and the mesh to output instead */ 1794 ERR(darray_geometries_push_back(&data_cad->adj_walls, &adj->common_geometry)); 1795 ERR(darray_common_trg_push_back(&data_cad->common_trg, &pair)); 1796 common = htable_common_find(&building->city->common, &pair); 1797 if(!common) { 1798 /* The mesh doesn't exist yet and won't be created until a further step. 1799 * We need to store the geometry id so that the mesh can be stored when 1800 * created. */ 1801 adj->save = 1; 1802 } 1803 } 1804 } 1805 1806 /* build ground/building connection */ 1807 ERR(building_ground_connection(data_cad, &data_cad->ground_connection)); 1808 1809 /* build boundaries */ 1810 ERR(build_boundary(data_cad, adjoining_data, &data_cad->boundary)); 1811 1812 /* build connections */ 1813 ERR(build_connection(data_cad, &data_cad->connection)); 1814 1815 /* print partial computation time */ 1816 time_sub(&dt, time_current(&dt), &t0); 1817 time_dump(&dt, TIME_SEC | TIME_MSEC, NULL, buf, sizeof(buf)); 1818 logger_print(logger, LOG_OUTPUT, 1819 "Building '%s' connections stage done in %s.\n", name, buf); 1820 time_current(&t0); 1821 1822 exit: 1823 if(partitioned) { 1824 for(i = 0; i < cad_count; i++) { 1825 if(partitioned[i]) SCAD(geometry_ref_put(partitioned[i])); 1826 } 1827 MEM_RM(allocator, partitioned); 1828 } 1829 if(polygons_initialized) htable_polygons_release(&polygons); 1830 if(overlapping_intersector) SCPR(intersector_ref_put(overlapping_intersector)); 1831 if(cad) *(struct data_cad_cmode_1**)cad = data_cad; 1832 return res; 1833 error: 1834 if(logger && building && !error_msg_printed) { 1835 logger_print(logger, LOG_ERROR, 1836 "Unknown error generating CAD for building '%s'.\n", 1837 str_cget(&building->name)); 1838 } 1839 if(data_cad) CHK(RES_OK == release_cad_cmode_1(data_cad)); 1840 data_cad = NULL; 1841 goto exit; 1842 } 1843 1844 res_T 1845 build_footprint_cmode_1 1846 (struct building* building, 1847 struct scad_geometry** footprint) 1848 { 1849 res_T res = RES_OK; 1850 1851 if(!building || !footprint) { 1852 res = RES_BAD_ARG; 1853 goto error; 1854 } 1855 1856 ERR(build_footprint(building->pg, 0, footprint)); 1857 1858 exit: 1859 return res; 1860 error: 1861 goto exit; 1862 } 1863 1864 res_T save_ground_connection_triangles_1 1865 (void* cad, 1866 struct darray_double* triangles) 1867 { 1868 res_T res = RES_OK; 1869 struct data_cad_cmode_1* data_cad = cad; 1870 1871 if(!cad || !triangles) { 1872 res = RES_BAD_ARG; 1873 goto error; 1874 } 1875 1876 ERR(scad_stl_get_data(data_cad->ground_connection, triangles)); 1877 1878 exit: 1879 return res; 1880 error: 1881 goto exit; 1882 } 1883 1884 res_T 1885 export_stl_cmode_1 1886 (void* cad, 1887 const int binary) 1888 { 1889 res_T res = RES_OK; 1890 struct data_cad_cmode_1* data_cad = (struct data_cad_cmode_1 *)cad; 1891 size_t i = 0, j, common_n = 0, coord_count = 0; 1892 struct darray_double trg; 1893 struct str name; 1894 int initialized = 0; 1895 struct scad_geometry** list = NULL; 1896 struct mem_allocator* allocator = NULL; 1897 struct city* city; 1898 struct building* building; 1899 struct vertex_denoiser* denoiser; 1900 FILE* model = NULL; 1901 FILE* vars = NULL; 1902 fpos_t model_pos, vars_pos; 1903 long model_count = 0; 1904 const char* n; 1905 static int fst = 1; 1906 1907 if(!cad) { 1908 res = RES_BAD_ARG; 1909 goto error; 1910 } 1911 1912 building = data_cad->building; 1913 city = building->city; 1914 allocator = city->allocator; 1915 denoiser = city->denoiser; 1916 model = city->stardis_model; 1917 vars = city->set_vars; 1918 1919 if(!fst) fprintf(model, "\n"); 1920 fst = 0; 1921 fprintf(model, 1922 "# Building '%s' construction mode 1, dataset '%s', %g m tall\n", 1923 str_cget(&building->name), str_cget(&building->dataset_name), 1924 building->total_height); 1925 fgetpos(model, &model_pos); 1926 fprintf(vars, 1927 "\n# Building '%s' construction mode 1, dataset '%s', %g m tall\n", 1928 str_cget(&building->name), str_cget(&building->dataset_name), 1929 building->total_height); 1930 fgetpos(vars, &vars_pos); 1931 1932 if(darray_geometries_size_get(&data_cad->adj_walls) == 0) { 1933 /* wall export */ 1934 ERR(stl_export_denoised_geometry(denoiser, data_cad->wall, 1935 Scad_force_normals_outward, binary)); 1936 1937 /* external insulation export */ 1938 if(data_cad->external_insulation) { 1939 ERR(stl_export_denoised_geometry(denoiser, data_cad->external_insulation, 1940 Scad_force_normals_outward, binary)); 1941 } 1942 } else { 1943 /* There is some adjoining building(s) to manage */ 1944 struct scad_geometry* extern_most = data_cad->external_insulation 1945 ? data_cad->external_insulation : data_cad->wall; 1946 size_t common_count = darray_common_trg_size_get(&data_cad->common_trg); 1947 const char* tmp; 1948 1949 if(data_cad->external_insulation) { 1950 /* wall export is not impacted as walls are not the external layer */ 1951 ERR(stl_export_denoised_geometry(denoiser, data_cad->wall, 1952 Scad_force_normals_outward, binary)); 1953 } 1954 1955 /* The external layer must use the common triangles */ 1956 darray_double_init(allocator, &trg); 1957 str_init(allocator, &name); 1958 initialized = 1; 1959 /* Get the triangles that are not common with adjoining buildings */ 1960 ERR(scad_stl_get_data_partial(extern_most, 1961 darray_geometries_data_get(&data_cad->adj_walls), 1962 darray_geometries_size_get(&data_cad->adj_walls), &trg)); 1963 coord_count = darray_double_size_get(&trg); 1964 /* Add the triangles from adjoining buildings */ 1965 for(i = 0; i < common_count; i++) { 1966 size_t sz; 1967 struct b_pair* pair = darray_common_trg_data_get(&data_cad->common_trg)+ i; 1968 const double *t9; 1969 double* tgt; 1970 struct darray_double* common = NULL; 1971 /* Get triangles */ 1972 common = htable_common_find(&city->common, pair); 1973 if(!common) { 1974 res = RES_BAD_ARG; 1975 goto error; 1976 } 1977 t9 = darray_double_cdata_get(common); 1978 /* Add common triangles */ 1979 sz = darray_double_size_get(common); 1980 ASSERT(sz % 9 == 0); 1981 ASSERT(coord_count == darray_double_size_get(&trg)); 1982 ERR(darray_double_resize(&trg, coord_count + sz)); 1983 tgt = darray_double_data_get(&trg); 1984 for(j = 0; j < sz; j++) { 1985 tgt[coord_count + j] = t9[j]; 1986 } 1987 coord_count += sz; 1988 ASSERT(coord_count % 9 == 0); 1989 } 1990 ERR(scad_geometry_get_name(extern_most, &tmp)); 1991 ERR(str_set(&name, tmp)); 1992 ERR(str_append(&name, ".stl")); 1993 ERR(denoise_array(denoiser, &trg)); 1994 ERR(scad_stl_data_write(&trg, str_cget(&name), Scad_force_normals_outward, 1995 binary)); 1996 } 1997 1998 STARDIS_SOLID(wall); 1999 2000 if(data_cad->external_insulation) { 2001 STARDIS_SOLID(external_insulation); 2002 } 2003 2004 /* floor export */ 2005 ERR(stl_export_denoised_geometry(denoiser, data_cad->floor, 2006 Scad_force_normals_outward, binary)); 2007 2008 STARDIS_SOLID(floor); 2009 2010 /* roof export */ 2011 ERR(stl_export_denoised_geometry(denoiser, data_cad->roof, 2012 Scad_force_normals_outward, binary)); 2013 2014 STARDIS_SOLID(roof); 2015 2016 /* foundation export */ 2017 if(data_cad->foundation) { 2018 ERR(stl_export_denoised_geometry(denoiser, data_cad->foundation, 2019 Scad_force_normals_outward, binary)); 2020 2021 STARDIS_SOLID(foundation); 2022 } 2023 2024 /* glass export */ 2025 if(data_cad->glazing) { 2026 ERR(stl_export_denoised_geometry(denoiser, data_cad->glazing, 2027 Scad_force_normals_outward, binary)); 2028 2029 STARDIS_SOLID(glazing); 2030 } 2031 2032 /* intermediate floor export*/ 2033 if(data_cad->intermediate_floor) { 2034 ERR(stl_export_denoised_geometry(denoiser, data_cad->intermediate_floor, 2035 Scad_force_normals_outward, binary)); 2036 2037 STARDIS_SOLID(intermediate_floor); 2038 } 2039 2040 /* internal insulation export*/ 2041 if(data_cad->internal_insulation) { 2042 ERR(stl_export_denoised_geometry(denoiser, data_cad->internal_insulation, 2043 Scad_force_normals_outward, binary)); 2044 2045 STARDIS_SOLID(internal_insulation); 2046 } 2047 2048 /* roof insulation export*/ 2049 if(data_cad->roof_insulation) { 2050 ERR(stl_export_denoised_geometry(denoiser, data_cad->roof_insulation, 2051 Scad_force_normals_outward, binary)); 2052 2053 STARDIS_SOLID(roof_insulation); 2054 } 2055 2056 /* floor insulation export*/ 2057 if(data_cad->floor_insulation) { 2058 ERR(stl_export_denoised_geometry(denoiser, data_cad->floor_insulation, 2059 Scad_force_normals_outward, binary)); 2060 2061 STARDIS_SOLID(floor_insulation); 2062 } 2063 2064 /* attic cavity export*/ 2065 if(data_cad->attic_cavity) { 2066 ERR(stl_export_denoised_geometry(denoiser, data_cad->attic_cavity, 2067 Scad_force_normals_outward, binary)); 2068 2069 STARDIS_FLUID(attic_cavity); 2070 } 2071 2072 /* habitable cavity export*/ 2073 ERR(stl_export_denoised_geometry(denoiser, data_cad->habitable_cavity, 2074 Scad_force_normals_outward, binary)); 2075 2076 STARDIS_FLUID(habitable_cavity); 2077 2078 /* crawlspace cavity export*/ 2079 if(data_cad->crawlspace_cavity) { 2080 ERR(stl_export_denoised_geometry(denoiser, data_cad->crawlspace_cavity, 2081 Scad_force_normals_outward, binary)); 2082 2083 STARDIS_FLUID(crawlspace_cavity); 2084 } 2085 2086 /* boundary export*/ 2087 for(i = 0; i < darray_geometries_size_get(&data_cad->boundary); i++) { 2088 struct scad_geometry* b = darray_geometries_data_get(&data_cad->boundary)[i]; 2089 ERR(stl_export_denoised_geometry(denoiser, b, Scad_keep_normals_unchanged, 2090 binary)); 2091 2092 ERR(scad_geometry_get_name(b, &n)); 2093 STARDIS_H_BOUND_2(SFC, n); 2094 } 2095 2096 /* connections export*/ 2097 for(i = 0; i < darray_geometries_size_get(&data_cad->connection); i++) { 2098 struct scad_geometry* c = darray_geometries_data_get(&data_cad->connection)[i]; 2099 ERR(stl_export_denoised_geometry(denoiser, c, Scad_keep_normals_unchanged, 2100 binary)); 2101 2102 ERR(scad_geometry_get_name(c, &n)); 2103 STARDIS_SFC_2(SFC, n); 2104 } 2105 2106 /* ground/building connection export*/ 2107 ERR(stl_export_denoised_geometry(denoiser, data_cad->ground_connection, 2108 Scad_keep_normals_unchanged, binary)); 2109 2110 /* No need to describe solid-solid connections until there is a contact 2111 * resistance */ 2112 2113 exit: 2114 for(j = 0; j < common_n; j++) { 2115 if(list[j]) SCAD(geometry_ref_put(list[j])); 2116 } 2117 MEM_RM(allocator, list); 2118 if(initialized) { 2119 darray_double_release(&trg); 2120 str_release(&name); 2121 } 2122 return res; 2123 error: 2124 if(data_cad) { 2125 logger_print(data_cad->building->city->logger, LOG_ERROR, 2126 "Internal error '"__FILE__"': creating STL for building '%s'.\n", 2127 str_cget(&data_cad->building->name)); 2128 } 2129 /* Reset stardis model file */ 2130 if(model) { 2131 long l; 2132 fsetpos(model, &model_pos); 2133 for(l = 0; l < model_count; l += 40) 2134 fprintf(model, " \n"); 2135 fprintf(model, "# Building '%s' construction cancelled\n", 2136 str_cget(&building->name)); 2137 } 2138 if(vars) { 2139 fprintf(vars, "# Building '%s' construction cancelled\n", 2140 str_cget(&building->name)); 2141 } 2142 goto exit; 2143 } 2144 2145 res_T 2146 release_cad_cmode_1 2147 (void* cad) 2148 { 2149 res_T res = RES_OK; 2150 struct data_cad_cmode_1* data_cad = (struct data_cad_cmode_1 *)cad; 2151 struct mem_allocator* allocator; 2152 2153 if(!cad) { 2154 res = RES_BAD_ARG; 2155 goto error; 2156 } 2157 2158 allocator = data_cad->building->city->allocator; 2159 darray_geometries_release(&data_cad->boundary); 2160 darray_geometries_release(&data_cad->connection); 2161 darray_common_trg_release(&data_cad->common_trg); 2162 darray_geometries_release(&data_cad->adj_walls); 2163 2164 #define GDEL(Field) \ 2165 if(data_cad->Field) SCAD(geometry_ref_put(data_cad->Field)); \ 2166 /* To ease debugging, write NULL after deletion */ \ 2167 data_cad->Field = NULL 2168 GDEL(attic_cavity); 2169 GDEL(crawlspace_cavity); 2170 GDEL(external_insulation); 2171 GDEL(fake_ground); 2172 GDEL(floor); 2173 GDEL(floor_insulation); 2174 GDEL(foundation); 2175 GDEL(glazing); 2176 GDEL(ground_connection); 2177 GDEL(habitable_cavity); 2178 GDEL(intermediate_floor); 2179 GDEL(internal_insulation); 2180 GDEL(roof); 2181 GDEL(roof_insulation); 2182 GDEL(wall); 2183 #undef GDEL 2184 MEM_RM(allocator, data_cad); 2185 2186 exit: 2187 return res; 2188 error: 2189 goto exit; 2190 }