city_generator2

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

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], &center_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 }