cg_construction_mode.c (4380B)
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_default.h" 22 #include "cg_building.h" 23 #include "cg_city.h" 24 #include "cg_city_parsing_schemas.h" 25 #include "cg_construction_mode.h" 26 27 #include <rsys/rsys.h> 28 #include <rsys/str.h> 29 #include <rsys/logger.h> 30 #include <rsys/double2.h> 31 32 #include <star/scad.h> 33 #include <star/scpr.h> 34 35 void 36 get_nverts(const size_t icomp, size_t* nverts, void* context) 37 { 38 struct parsed_city_building* parsed_data = context; 39 ASSERT(icomp == 0); (void)icomp; 40 *nverts = parsed_data->vertice_count; 41 } 42 43 void 44 get_pos(const size_t icomp, const size_t ivert, double pos[2], void* context) 45 { 46 struct parsed_city_building* parsed_data = context; 47 ASSERT(icomp == 0); (void)icomp; 48 pos[0] = parsed_data->vertice[ivert*2 + 0]; 49 pos[1] = parsed_data->vertice[ivert*2 + 1]; 50 } 51 52 res_T 53 init_building_base 54 (struct building* building, 55 struct city* city, 56 struct parsed_city_building* parsed_data) 57 { 58 int inside, cw; 59 size_t count; 60 double l[2], u[2], t[2]; 61 res_T res = RES_OK; 62 63 ASSERT(city && building && parsed_data); 64 65 building->city = city; 66 str_init(city->allocator, &building->name); 67 str_init(city->allocator, &building->dataset_name); 68 str_init(city->allocator, &building->external_layer_name); 69 htable_building_init(city->allocator, &building->close_buildings); 70 darray_double_init(city->allocator, &building->levels_height); 71 building->structs_initialized = 1; 72 73 ERR(str_set(&building->name, parsed_data->name)); 74 ERR(str_set(&building->dataset_name, parsed_data->dataset_name)); 75 ERR(scpr_polygon_create(city->scpr, &building->pg)); 76 ERR(scpr_polygon_setup_indexed_vertices(building->pg, 1, get_nverts, get_pos, 77 parsed_data)); 78 ERR(scpr_polygon_get_vertices_count(building->pg, 0, &count)); 79 if(parsed_data->vertice_count != count) { 80 logger_print(city->logger, LOG_WARNING, 81 "Building '%s' had quasi-identical or aligned vertices that have been removed.\n", 82 str_cget(&building->name)); 83 } 84 /* First try with a slightly decreased bbox as buildings are not allowed to 85 * reach the bbox limit */ 86 d2(t, CG2_MIN_DISTANCE_TO_MAP_LIMITS, CG2_MIN_DISTANCE_TO_MAP_LIMITS); 87 d2_add(l, city->lower, t); 88 d2_sub(u, city->upper, t); 89 ERR(scpr_polygon_in_bbox(building->pg, l, u, &inside)); 90 if(!inside) { 91 ERR(scpr_polygon_in_bbox(building->pg, city->lower, city->upper, &inside)); 92 logger_print(city->logger, 93 (city->keep_running_on_errors ? LOG_WARNING : LOG_ERROR), 94 (inside 95 ? "Building '%s' is too close to the map limits.\n" 96 : "Building '%s' is out of the ground extent.\n"), 97 str_cget(&building->name)); 98 building->event_flags 99 |= (inside ? BUILDING_TOO_CLOSE_TO_BORDER : BUILDING_OUT_OF_GROUND_EXTENT); 100 res = RES_BAD_ARG; 101 goto error; 102 } 103 /* Force orientation so that pg's normal is upward */ 104 ERR(scpr_polygon_is_component_cw(building->pg, 0, &cw)); 105 if(!cw) { 106 ERR(scpr_polygon_reverse_component(building->pg, 0)); 107 } 108 109 exit: 110 return res; 111 error: 112 goto exit; 113 } 114 115 res_T 116 release_building_base 117 (struct building* building) 118 { 119 res_T res = RES_OK; 120 121 ASSERT(building); 122 123 if(building->structs_initialized) { 124 str_release(&building->name); 125 str_release(&building->dataset_name); 126 str_release(&building->external_layer_name); 127 htable_building_release(&building->close_buildings); 128 darray_double_release(&building->levels_height); 129 } 130 if(building->pg) { 131 ERR(scpr_polygon_ref_put(building->pg)); 132 } 133 134 exit: 135 return res; 136 error: 137 goto exit; 138 }