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_ground.c (7091B)


      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_ground.h"
     22 #include "cg_building.h"
     23 #include "cg_city.h"
     24 #include "cg_vertex_denoiser.h"
     25 #include "cg_stardis_model.h"
     26 
     27 #include <rsys/rsys.h>
     28 #include <rsys/dynamic_array_double.h>
     29 #include <rsys/str.h>
     30 
     31 #include <star/scad.h>
     32 
     33 #define GDEL(Tgt) \
     34   if(Tgt) SCAD(geometry_ref_put(Tgt)); \
     35   /* To avoid double delete, set to NULL after deletion */ \
     36   Tgt = NULL
     37 
     38 #define GPUSH(G) \
     39   ASSERT(G); \
     40   ERR(darray_geometries_push_back(&ground->boundaries, &(G))); \
     41   ERR(scad_geometry_ref_put(G)); /* Ownership is transfered to array */ \
     42   surface = NULL; \
     43   (G) = NULL;
     44 
     45 res_T
     46 ground_build_cad
     47   (struct mem_allocator* allocator,
     48    struct city* city)
     49 {
     50   res_T res = RES_OK;
     51   double origin[3];
     52   double extent[3];
     53   struct scad_geometry* bound = NULL;
     54   struct scad_geometry** list;
     55   struct scad_geometry* surface = NULL;
     56   struct scad_geometry* tmp = NULL;
     57   size_t i, count = 0;
     58   struct ground* ground;
     59 
     60   ASSERT(city);
     61 
     62   ground = &city->ground;
     63   origin[0] = city->lower[0];
     64   origin[1] = city->lower[1];
     65   origin[2] = -city->ground_depth;
     66 
     67   extent[0] = city->upper[0] - city->lower[0];
     68   extent[1] = city->upper[1] - city->lower[1];
     69   extent[2] = city->ground_depth;
     70 
     71   if(origin[2] > 0 || extent[0] < 0 || extent[1] < 0 || extent[2] < 0 ) {
     72     res = RES_BAD_ARG;
     73     goto error;
     74   }
     75 
     76   ERR(scad_add_box(NULL, origin, extent, &ground->box));
     77   ERR(scad_geometry_boundary(NULL, &ground->box, 1, &bound));
     78 
     79   ERR(scad_geometry_explode(bound, NULL, &list, &count));
     80   ERR(darray_geometries_reserve(&ground->boundaries, count));
     81 
     82   for(i = 0; i < count; i++) {
     83     double center[3];
     84     size_t center_n;
     85     double N[3];
     86 
     87     ERR(scad_geometry_get_count(list[i], &center_n));
     88     ASSERT(center_n == 1);
     89     ERR(scad_geometry_get_centerofmass(list[i], center));
     90     ERR(scad_geometry_normal(list[i], center, N, NULL, &surface));
     91 
     92     if (N[0] == 0 && N[1] == 0 && N[2] == -1) {
     93       ERR(scad_geometry_rename(surface, "ground_B_bottom"));
     94       ground->bottom = surface;
     95       GPUSH(surface);
     96     }
     97     else if (N[0] == 0 && N[1] == 0 && N[2] == 1) {
     98       struct scad_geometry** footprints =
     99         darray_geometries_data_get(&ground->footprints);
    100       size_t fpcount = darray_geometries_size_get(&ground->footprints);
    101       if(fpcount) {
    102         ERR(scad_cut_geometries("ground_B_top", &surface, 1, footprints, fpcount,
    103               &tmp));
    104         GDEL(surface);
    105         ground->top = tmp;
    106         GPUSH(tmp);
    107       } else {
    108         ERR(scad_geometry_rename(surface, "ground_B_top"));
    109         ground->top = surface;
    110         GPUSH(surface);
    111       }
    112     }
    113     else if (N[0] == -1 && N[1] == 0 && N[2] == 0) {
    114       ERR(scad_geometry_rename(surface, "ground_B_lateral_0"));
    115       GPUSH(surface);
    116     }
    117     else if (N[0] == 1 && N[1] == 0 && N[2] == 0) {
    118       ERR(scad_geometry_rename(surface, "ground_B_lateral_1"));
    119       GPUSH(surface);
    120     }
    121     else if (N[0] == 0 && N[1] == -1 && N[2] == 0) {
    122       ERR(scad_geometry_rename(surface, "ground_B_lateral_2"));
    123       GPUSH(surface);
    124     }
    125     else if (N[0] == 0 && N[1] == 1 && N[2] == 0) {
    126       ERR(scad_geometry_rename(surface, "ground_B_lateral_3"));
    127       GPUSH(surface);
    128     }
    129     else FATAL("Wrong ground box boundary.");
    130   }
    131 
    132 exit:
    133   for (i = 0; i < count; i++) {
    134     GDEL(list[i]);
    135   }
    136   MEM_RM(allocator, list);
    137   GDEL(surface);
    138   GDEL(tmp);
    139   GDEL(bound);
    140   return res;
    141 error:
    142   goto exit;
    143 }
    144 #undef GPUSH
    145 
    146 res_T
    147 ground_export_stl
    148   (struct city* city)
    149 {
    150   res_T res = RES_OK;
    151   struct ground* ground;
    152   struct vertex_denoiser* denoiser;
    153   struct mem_allocator* allocator;
    154   struct darray_double trg;
    155   const char* name;
    156   struct str filename;
    157   int binary;
    158   FILE* model = NULL;
    159   FILE* vars = NULL;
    160   const char* n;
    161   size_t i = 0;
    162   long model_count = 0;
    163 
    164   ASSERT(city);
    165   (void)model_count; /* To allow STARDIS_SOLID_ use */
    166   ground = &city->ground;
    167   binary = city->binary_export;
    168   denoiser = city->denoiser;
    169   allocator = city->allocator;
    170   darray_double_init(allocator, &trg);
    171   str_init(allocator, &filename);
    172   model = city->stardis_model;
    173   vars = city->set_vars;
    174 
    175   fprintf(model, "\n# GROUND\n");
    176   fprintf(vars, "\n# GROUND\n");
    177 
    178   for(i = 0; i < darray_geometries_size_get(&ground->boundaries); i++) {
    179     struct scad_geometry* b = darray_geometries_data_get(&ground->boundaries)[i];
    180     ERR(scad_geometry_get_name(b, &n));
    181     /* Boundary files */
    182     darray_double_clear(&trg);
    183     ERR(scad_stl_get_data(b, &trg));
    184     if(b == ground->top) {
    185       /* Add patches */
    186       ERR(darray_double_merge(&trg, &ground->ground_patches));
    187     }
    188     ERR(scad_geometry_get_name(b, &name));
    189     ERR(str_set(&filename, name));
    190     ERR(str_append(&filename, ".stl"));
    191     ERR(denoise_array(denoiser, &trg));
    192     ERR(scad_stl_data_write(&trg, str_cget(&filename),
    193         Scad_keep_normals_unchanged, binary));
    194     if(b == ground->bottom) {
    195       STARDIS_T_BOUND_2_model(ground_B_bottom, n);
    196     } else {
    197       if(b == ground->top) {
    198         STARDIS_H_BOUND_2_model(ground_B_top, n);
    199       }else {
    200         STARDIS_F_BOUND_2(ground_B_lateral, n);
    201       }
    202     }
    203     /* Also collect boundaries triangles into ground body */
    204     ERR(darray_double_merge(&ground->ground_building_connections, &trg));
    205   }
    206   ERR(denoise_array(denoiser, &ground->ground_building_connections));
    207   ERR(scad_stl_data_write(&ground->ground_building_connections, "ground_body.stl",
    208         Scad_force_normals_outward, binary));
    209 
    210   STARDIS_SOLID_2_model(ground_body, "ground_body");
    211 
    212 exit:
    213   darray_double_release(&trg);
    214   str_release(&filename);
    215   return res;
    216 error:
    217   goto exit;
    218 }
    219 
    220 void
    221 ground_init
    222   (struct mem_allocator* allocator,
    223    struct ground* ground)
    224 {
    225   ground->box = NULL;
    226   darray_double_init(allocator, &ground->ground_building_connections);
    227   darray_double_init(allocator, &ground->ground_patches);
    228   darray_geometries_init(allocator, &ground->footprints);
    229   darray_geometries_init(allocator, &ground->boundaries);
    230 }
    231 
    232 void
    233 ground_clear
    234   (struct ground* ground)
    235 {
    236   GDEL(ground->box);
    237   darray_geometries_purge(&ground->footprints);
    238   darray_geometries_purge(&ground->boundaries);
    239   darray_double_purge(&ground->ground_building_connections);
    240   darray_double_purge(&ground->ground_patches);
    241 }
    242 
    243 #undef GDEL