senc2d_scene.c (9981B)
1 /* Copyright (C) 2018-2021, 2023, 2024 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "senc2d.h" 17 #include "senc2d_device_c.h" 18 #include "senc2d_scene_c.h" 19 #include "senc2d_scene_analyze_c.h" 20 21 #include <rsys/rsys.h> 22 #include <rsys/double2.h> 23 #include <rsys/mem_allocator.h> 24 25 #include <limits.h> 26 27 /****************************************************************************** 28 * Helper function 29 *****************************************************************************/ 30 static void 31 scene_release(ref_T * ref) 32 { 33 struct senc2d_device* dev = NULL; 34 struct senc2d_scene* scn = NULL; 35 ASSERT(ref); 36 scn = CONTAINER_OF(ref, struct senc2d_scene, ref); 37 dev = scn->dev; 38 darray_segment_in_release(&scn->segments_in); 39 darray_position_release(&scn->vertices); 40 darray_side_range_release(&scn->media_use); 41 42 darray_segment_enc_release(&scn->analyze.segments_enc); 43 darray_enclosure_release(&scn->analyze.enclosures); 44 darray_enc_ids_array_release(&scn->analyze.enc_ids_array_by_medium); 45 darray_frontier_vertex_release(&scn->analyze.frontiers); 46 darray_seg_id_release(&scn->analyze.overlapping_ids); 47 48 MEM_RM(dev->allocator, scn); 49 SENC2D(device_ref_put(dev)); 50 } 51 52 static INLINE int 53 compatible_medium 54 (const medium_id_t m1, 55 const medium_id_t m2) 56 { 57 if(m1 == SENC2D_UNSPECIFIED_MEDIUM || m2 == SENC2D_UNSPECIFIED_MEDIUM) 58 return 1; 59 return (m1 == m2); 60 } 61 62 /****************************************************************************** 63 * Exported functions 64 *****************************************************************************/ 65 res_T 66 senc2d_scene_create 67 (struct senc2d_device* dev, 68 const int conv, 69 const seg_id_t nsegs, 70 void(*indices)(const seg_id_t, vrtx_id_t*, void*), 71 void(*media)(const seg_id_t, medium_id_t*, void*), 72 const vrtx_id_t nverts, 73 void(*position)(const vrtx_id_t, double*, void* ctx), 74 void* ctx, 75 struct senc2d_scene** out_scn) 76 { 77 struct senc2d_scene* scn = NULL; 78 /* Tables to detect duplicates */ 79 struct htable_vrtx unique_vertices; 80 struct htable_seg unique_segments; 81 vrtx_id_t nv; 82 seg_id_t ns; 83 res_T res = RES_OK; 84 85 if(!dev || !out_scn || !indices || !position || !nverts || !nsegs 86 /* Convention must be set both regarding FRONT/BACK and INSIDE/OUTSIDE */ 87 || !(conv & (SENC2D_CONVENTION_NORMAL_FRONT | SENC2D_CONVENTION_NORMAL_BACK)) 88 || !(conv & (SENC2D_CONVENTION_NORMAL_INSIDE | SENC2D_CONVENTION_NORMAL_OUTSIDE))) 89 return RES_BAD_ARG; 90 91 htable_vrtx_init(dev->allocator, &unique_vertices); 92 htable_seg_init(dev->allocator, &unique_segments); 93 94 scn = MEM_CALLOC(dev->allocator, 1, sizeof(struct senc2d_scene)); 95 if(!scn) { 96 log_err(dev, LIB_NAME":%s: could not allocate the star-enclosures-2d scene.\n", 97 FUNC_NAME); 98 res = RES_MEM_ERR; 99 goto error; 100 } 101 ref_init(&scn->ref); 102 SENC2D(device_ref_get(dev)); 103 scn->dev = dev; 104 scn->convention = conv; 105 scn->nsegs = nsegs; 106 scn->next_medium_idx = 0; 107 scn->nverts = nverts; 108 darray_segment_in_init(dev->allocator, &scn->segments_in); 109 darray_position_init(dev->allocator, &scn->vertices); 110 darray_side_range_init(dev->allocator, &scn->media_use); 111 112 darray_segment_enc_init(scn->dev->allocator, &scn->analyze.segments_enc); 113 darray_enclosure_init(scn->dev->allocator, &scn->analyze.enclosures); 114 darray_enc_ids_array_init(scn->dev->allocator, 115 &scn->analyze.enc_ids_array_by_medium); 116 darray_frontier_vertex_init(scn->dev->allocator, &scn->analyze.frontiers); 117 /* Enclosure 0 is always defined for infinite */ 118 OK(darray_enclosure_resize(&scn->analyze.enclosures, 1)); 119 scn->analyze.enclosures_count = 1; 120 darray_seg_id_init(scn->dev->allocator, &scn->analyze.overlapping_ids); 121 122 OK(darray_position_reserve(&scn->vertices, scn->nverts)); 123 OK(darray_segment_in_reserve(&scn->segments_in, scn->nsegs)); 124 OK(htable_vrtx_reserve(&unique_vertices, scn->nverts)); 125 OK(htable_seg_reserve(&unique_segments, scn->nsegs)); 126 127 /* Get vertices */ 128 FOR_EACH(nv, 0, nverts) { 129 vrtx_id_t* p_vrtx; 130 union double2 tmp; 131 position(nv, tmp.vec, ctx); 132 p_vrtx = htable_vrtx_find(&unique_vertices, &tmp); 133 if(p_vrtx) { 134 /* Duplicate vertex */ 135 log_err(scn->dev, LIB_NAME":%s: vertex "PRTF_VRTX" is a duplicate.\n", 136 FUNC_NAME, nv); 137 res = RES_BAD_ARG; 138 goto error; 139 } 140 /* New vertex */ 141 ASSERT(nv == htable_vrtx_size_get(&unique_vertices)); 142 OK(darray_position_push_back(&scn->vertices, &tmp)); 143 OK(htable_vrtx_set(&unique_vertices, &tmp, &nv)); 144 } 145 /* Get segments */ 146 FOR_EACH(ns, 0, nsegs) { 147 int j; 148 seg_id_t s; 149 medium_id_t med[2] 150 = { SENC2D_UNSPECIFIED_MEDIUM, SENC2D_UNSPECIFIED_MEDIUM }; 151 vrtx_id_t ind[2]; 152 union vrtx_id2 seg_key; 153 struct segment_in tmp; 154 seg_id_t* p_seg; 155 indices(ns, ind, ctx); 156 FOR_EACH(j, 0, 2) { 157 if(ind[j] >= nverts) { 158 log_err(scn->dev, 159 LIB_NAME":%s: segment "PRTF_SEG" uses invalid vertex id "PRTF_VRTX".\n", 160 FUNC_NAME, ns, ind[j]); 161 res = RES_BAD_ARG; 162 goto error; 163 } 164 ASSERT(ind[j] <= VRTX_MAX__); 165 tmp.vertice_id[j] = ind[j]; 166 } 167 if(tmp.vertice_id[0] == tmp.vertice_id[1]) { 168 log_err(scn->dev, LIB_NAME":%s: segment "PRTF_SEG" is degenerated.\n", 169 FUNC_NAME, ns); 170 res = RES_BAD_ARG; 171 goto error; 172 } 173 /* Get media */ 174 if(media) { 175 media(ns, med, ctx); 176 for(s = SENC2D_FRONT; s <= SENC2D_BACK; s += SENC2D_BACK - SENC2D_FRONT) { 177 if(med[s] == SENC2D_UNSPECIFIED_MEDIUM || med[s] <= MEDIUM_MAX__) 178 continue; 179 res = RES_BAD_ARG; 180 goto error; 181 } 182 } 183 seg_make_key(&seg_key, tmp.vertice_id); 184 p_seg = htable_seg_find(&unique_segments, &seg_key); 185 if(p_seg) { 186 /* Duplicate segment */ 187 log_err(scn->dev, LIB_NAME":%s: segment "PRTF_SEG" is a duplicate.\n", 188 FUNC_NAME, ns); 189 res = RES_BAD_ARG; 190 goto error; 191 } 192 /* New segment */ 193 ASSERT(ns == htable_seg_size_get(&unique_segments)); 194 OK(htable_seg_set(&unique_segments, &seg_key, &ns)); 195 for(s = SENC2D_FRONT; s <= SENC2D_BACK; s += SENC2D_BACK - SENC2D_FRONT) { 196 struct side_range* media_use; 197 size_t m_idx = medium_id_2_medium_idx(med[s]); 198 tmp.medium[s] = med[s]; 199 if(m_idx >= scn->next_medium_idx) { 200 medium_id_t medium; 201 medium = (medium_id_t)m_idx; 202 scn->next_medium_idx = medium; 203 OK(darray_side_range_resize(&scn->media_use, 1 + m_idx)); 204 } 205 /* media_use 0 is for SENC2D_UNSPECIFIED_MEDIUM */ 206 media_use = darray_side_range_data_get(&scn->media_use) + m_idx; 207 media_use->first = 208 MMIN(media_use->first, SEGIDxSIDE_2_SEGSIDE(ns, s)); 209 ASSERT(media_use->first < 2 * (scn->nsegs + 1)); 210 media_use->last = 211 MMAX(media_use->last, SEGIDxSIDE_2_SEGSIDE(ns, s)); 212 ASSERT(media_use->last < 2 * (scn->nsegs + 1)); 213 ASSERT(media_use->first <= media_use->last); 214 } 215 OK(darray_segment_in_push_back(&scn->segments_in, &tmp)); 216 } 217 218 OK(darray_enc_ids_array_resize(&scn->analyze.enc_ids_array_by_medium, 219 1 + scn->next_medium_idx)); /* +1 is for undef */ 220 /* Proceed to the analyze */ 221 OK(scene_analyze(scn)); 222 223 exit: 224 htable_vrtx_release(&unique_vertices); 225 htable_seg_release(&unique_segments); 226 if(scn) *out_scn = scn; 227 return res; 228 229 error: 230 if(scn) { 231 SENC2D(scene_ref_put(scn)); 232 scn = NULL; 233 } 234 goto exit; 235 } 236 237 res_T 238 senc2d_scene_get_convention 239 (const struct senc2d_scene* scn, 240 int* convention) 241 { 242 if(!scn || !convention) return RES_BAD_ARG; 243 *convention = scn->convention; 244 return RES_OK; 245 } 246 247 res_T 248 senc2d_scene_get_segments_count 249 (const struct senc2d_scene* scn, 250 seg_id_t* count) 251 { 252 if(!scn || !count) return RES_BAD_ARG; 253 *count = scn->nsegs; 254 return RES_OK; 255 } 256 257 res_T 258 senc2d_scene_get_segment 259 (const struct senc2d_scene* scn, 260 const seg_id_t iseg, 261 vrtx_id_t indices[2]) 262 { 263 const struct segment_in* seg; 264 int i; 265 if(!scn || !indices 266 || iseg >= darray_segment_in_size_get(&scn->segments_in)) 267 return RES_BAD_ARG; 268 seg = darray_segment_in_cdata_get(&scn->segments_in) + iseg; 269 FOR_EACH(i, 0, 2) indices[i] = seg->vertice_id[i]; 270 return RES_OK; 271 } 272 273 res_T 274 senc2d_scene_get_segment_media 275 (const struct senc2d_scene* scn, 276 const seg_id_t iseg, 277 medium_id_t media[2]) 278 { 279 const struct segment_in* seg; 280 int i; 281 if(!scn || !media 282 || iseg >= darray_segment_in_size_get(&scn->segments_in)) 283 return RES_BAD_ARG; 284 seg = darray_segment_in_cdata_get(&scn->segments_in) + iseg; 285 FOR_EACH(i, 0, 2) media[i] = seg->medium[i]; 286 return RES_OK; 287 } 288 289 res_T 290 senc2d_scene_get_vertices_count 291 (const struct senc2d_scene* scn, 292 vrtx_id_t* count) 293 { 294 if(!scn || !count) return RES_BAD_ARG; 295 *count = scn->nverts; 296 return RES_OK; 297 } 298 299 res_T 300 senc2d_scene_get_vertex 301 (const struct senc2d_scene* scn, 302 const vrtx_id_t ivert, 303 double coord[2]) 304 { 305 const union double2* v; 306 if(!scn || !coord 307 || ivert >= darray_position_size_get(&scn->vertices)) 308 return RES_BAD_ARG; 309 v = darray_position_cdata_get(&scn->vertices) + ivert; 310 d2_set(coord, v->vec); 311 return RES_OK; 312 } 313 314 res_T 315 senc2d_scene_ref_get(struct senc2d_scene* scn) 316 { 317 if(!scn) return RES_BAD_ARG; 318 ref_get(&scn->ref); 319 return RES_OK; 320 } 321 322 res_T 323 senc2d_scene_ref_put(struct senc2d_scene* scn) 324 { 325 if(!scn) return RES_BAD_ARG; 326 ref_put(&scn->ref, scene_release); 327 return RES_OK; 328 }