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], ¢er_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