sphin_surface.c (12386B)
1 /* Copyright (C) 2024-2026 Centre National de la Recherche Scientifique 2 * Copyright (C) 2024-2026 Clermont Auvergne INP 3 * Copyright (C) 2024-2026 INSA Lyon 4 * Copyright (C) 2024-2026 Institut Mines Télécom Albi-Carmaux 5 * Copyright (C) 2024-2026 Institut National Polytechnique de Toulouse 6 * Copyright (C) 2024-2026 |Méso|Star> (contact@meso-star.com) 7 * Copyright (C) 2024-2026 PhotonLyX (info@photonlyx.com) 8 * Copyright (C) 2024-2026 Université de Lorraine 9 * Copyright (C) 2024-2026 Université Paul Sabatier 10 * Copyright (C) 2024-2026 Université Toulouse - Jean Jaurès 11 * 12 * This program is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation, either version 3 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 24 #define _POSIX_C_SOURCE 200112L /* for strtok_r support */ 25 26 #include "sphin.h" 27 #include "sphin_brdf.h" 28 #include "sphin_btdf.h" 29 #include "sphin_c.h" 30 #include "sphin_config.h" 31 #include "sphin_geometry.h" 32 #include "sphin_sensor_surface.h" 33 #include "sphin_source_surface.h" 34 #include "sphin_surface.h" 35 36 #include <rsys/mem_allocator.h> 37 #include <rsys/ref_count.h> 38 #include <rsys/rsys.h> 39 #include <rsys/str.h> 40 #include <rsys/text_reader.h> 41 42 struct sphin_brdf; 43 struct sphin_btdf; 44 struct sphin_sensor_surface; 45 struct sphin_source_surface; 46 47 struct sphin_surface { 48 struct str name; 49 struct sphin* sphin; 50 struct sphin_brdf* brdf; 51 struct sphin_btdf* btdf; 52 struct darray_sphin_geometry_ptr geometries; /* dynamic array of struct 53 geometry. see rsys/dynamic_array.h */ 54 struct sphin_sensor_surface* sensor_surface; 55 struct sphin_source_surface* source_surface; 56 ref_T ref; 57 }; 58 59 /******************************************************************************* 60 * Helper functions 61 ******************************************************************************/ 62 static res_T 63 surface_create 64 (struct sphin* sphin, 65 const char* name, 66 struct sphin_surface** out_surface) 67 { 68 struct sphin_surface* surface = NULL; 69 res_T res = RES_OK; 70 71 ASSERT(NULL != sphin); 72 ASSERT(NULL != out_surface); 73 ASSERT(NULL != name); 74 ASSERT('\0' != name[0]); /* Name can't be empty */ 75 76 surface = MEM_CALLOC(sphin->allocator, 1, sizeof(struct sphin_surface)); 77 if (NULL == surface) { res = RES_MEM_ERR; goto error; } 78 79 /* Init volume ref counter and init member variables */ 80 ref_init(&surface->ref); 81 SPHIN(ref_get(sphin)); 82 surface->sphin = sphin; 83 surface->brdf = NULL; 84 surface->btdf = NULL; 85 surface->sensor_surface= NULL; 86 surface->source_surface = NULL; 87 88 str_init(sphin->allocator, &surface->name); 89 darray_sphin_geometry_ptr_init(sphin->allocator, &surface->geometries); 90 res = str_set(&surface->name, name); 91 if (RES_OK != res) { goto error; } 92 93 exit: 94 *out_surface = surface; 95 return res; 96 error: 97 if (NULL != surface) { 98 SPHIN(surface_ref_put(surface)); 99 surface = NULL; 100 } 101 goto exit; 102 } 103 104 static void 105 release_surface 106 (ref_T* address) 107 { 108 size_t i, ngeometries; 109 struct sphin* sphin = NULL; 110 struct sphin_brdf* brdf = NULL; 111 struct sphin_btdf* btdf = NULL; 112 struct sphin_geometry** geometries = NULL; 113 struct sphin_sensor_surface* sensor_surface = NULL; 114 struct sphin_source_surface* source_surface = NULL; 115 struct sphin_surface* surface = NULL; 116 ASSERT(NULL != address); 117 118 surface = CONTAINER_OF(address, struct sphin_surface, ref); 119 str_release(&surface->name); 120 121 /* Retrieve the number of geometries associated with the volume and decrease 122 * the reference counter of each one of them */ 123 ngeometries = darray_sphin_geometry_ptr_size_get(&surface->geometries); 124 geometries = darray_sphin_geometry_ptr_data_get(&surface->geometries); 125 126 /* Put references for each one of the geometries */ 127 FOR_EACH(i, 0, ngeometries) { 128 SPHIN(geometry_ref_put(geometries[i])); 129 }; 130 131 if (NULL != geometries) { 132 darray_sphin_geometry_ptr_release(&surface->geometries); 133 } 134 135 sphin = surface->sphin; 136 brdf = surface->brdf; 137 btdf = surface->btdf; 138 sensor_surface = surface->sensor_surface; 139 source_surface = surface->source_surface; 140 MEM_RM(sphin->allocator, surface); 141 if (NULL != source_surface) { 142 SPHIN(source_surface_ref_put(source_surface)); 143 } 144 if (NULL != sensor_surface) { 145 SPHIN(sensor_surface_ref_put(sensor_surface)); 146 } 147 if (NULL != brdf) { 148 SPHIN(brdf_ref_put(brdf)); 149 } 150 if (NULL != btdf) { 151 SPHIN(btdf_ref_put(btdf)); 152 } 153 SPHIN(ref_put(sphin)); 154 } 155 156 static res_T 157 parse_geometry 158 (struct sphin_surface* surface, 159 struct txtrdr* txtrdr, 160 char* value) 161 { 162 struct sphin_geometry* geom = NULL; 163 res_T res = RES_OK; 164 165 ASSERT(NULL != surface); 166 ASSERT(NULL != txtrdr); 167 168 if (NULL == value) {res = RES_BAD_ARG; goto error; } 169 170 res = geometry_parse(surface->sphin, value, &geom); 171 if (RES_OK != res) { goto error; } 172 173 /* Append a new element to the end of the volume->geometries dynamic array */ 174 res = darray_sphin_geometry_ptr_push_back(&surface->geometries, &geom); 175 if (RES_OK != res) { goto error; } 176 177 res = txtrdr_read_line(txtrdr); 178 if (RES_OK != res) { goto error; } 179 180 exit: 181 return res; 182 error: 183 goto exit; 184 } 185 186 /******************************************************************************* 187 * Local functions 188 ******************************************************************************/ 189 res_T 190 parse_surface 191 (struct sphin_config* config, 192 struct txtrdr* txtrdr, 193 const char* name) 194 { 195 struct sphin_surface* surface = NULL; 196 struct str line; 197 char* keyword = NULL; 198 char* token = NULL; 199 char* token_ptr = NULL; 200 res_T res = RES_OK; 201 202 ASSERT(NULL != config); 203 ASSERT(NULL != txtrdr); 204 ASSERT(NULL != name); 205 ASSERT('\0' != name[0]); /* Name can't be empty */ 206 207 str_init(config->sphin->allocator, &line); 208 209 res = surface_create(config->sphin, name, &surface); 210 if (RES_OK != res) { goto error; } 211 212 res = txtrdr_read_line(txtrdr); 213 if (RES_OK != res) { goto error; } 214 215 while (NULL != txtrdr_get_line(txtrdr)) { 216 res = str_set(&line, txtrdr_get_cline(txtrdr)); 217 if (RES_OK != res) { goto error; } 218 219 /* parse keyword */ 220 token = strtok_r(str_get(&line), ":", &token_ptr); 221 if (NULL == token){ res = RES_BAD_ARG; goto error; } 222 keyword = trim_keyword(token); 223 if (NULL == keyword){ res = RES_BAD_ARG; goto error; } 224 /* parse value */ 225 token = token_ptr; 226 if (0 == strcmp(keyword, "geometry")){ 227 res = parse_geometry(surface, txtrdr, token); 228 } 229 else if (0 == strcmp(keyword, "brdf")){ 230 res = parse_brdf(surface->sphin, txtrdr, token, &surface->brdf); 231 } 232 else if (0 == strcmp(keyword, "btdf")){ 233 res = parse_btdf(surface->sphin, txtrdr, token, &surface->btdf); 234 } 235 else if (0 == strcmp(keyword, "source")) { 236 /* source should not have a name. 237 * strings are not allowed in the input file after the : 238 * check if there is only tabs and spaces after : */ 239 token = strtok_r(NULL, " \t", &token_ptr); 240 if (NULL != token) { res = RES_BAD_ARG; goto error; } 241 res = parse_source_surface(surface->sphin, 242 txtrdr, name, &surface->source_surface); 243 } 244 else if (0 == strcmp(keyword, "sensor")) { 245 /* sensor_surface should not have a name. 246 * strings are not allowed in the input file after the : 247 * check if there is only tabs and spaces after : */ 248 token = strtok_r(NULL, " \t", &token_ptr); 249 if (NULL != token) { res = RES_BAD_ARG; goto error; } 250 res = parse_sensor_surface 251 (surface->sphin, txtrdr, name, &surface->sensor_surface); 252 } 253 else { 254 break; 255 } 256 if (RES_OK != res) { goto error; } 257 } 258 259 /* Append a new element to the end of the sphin_config->surfaces array */ 260 res = darray_sphin_surface_ptr_push_back(&config->surfaces, &surface); 261 if (RES_OK != res) { goto error; } 262 263 exit: 264 str_release(&line); 265 return res; 266 error: 267 if (NULL != surface) { 268 SPHIN(surface_ref_put(surface)); 269 surface = NULL; 270 } 271 goto exit; 272 } 273 274 /******************************************************************************* 275 * Exported functions 276 ******************************************************************************/ 277 res_T 278 sphin_surface_ref_get 279 (struct sphin_surface* surface) 280 { 281 if (NULL == surface) { 282 return RES_BAD_ARG; 283 } 284 ref_get(&surface->ref); 285 return RES_OK; 286 } 287 288 res_T 289 sphin_surface_ref_put 290 (struct sphin_surface* surface) 291 { 292 if (NULL == surface) { 293 return RES_BAD_ARG; 294 } 295 ref_put(&surface->ref, release_surface); 296 return RES_OK; 297 } 298 299 res_T 300 sphin_surface_get_name 301 (struct sphin_surface* surface, 302 char** name) 303 { 304 if (NULL == surface || NULL == name) { 305 return RES_BAD_ARG; 306 } 307 *name = (char*)str_get((struct str*)&surface->name); 308 return RES_OK; 309 } 310 311 res_T 312 sphin_surface_get_sensor 313 (struct sphin_surface* surface, 314 struct sphin_sensor_surface** sensor_surface) 315 { 316 if (NULL == surface 317 || NULL == sensor_surface) { 318 return RES_BAD_ARG; 319 } 320 *sensor_surface = surface->sensor_surface; 321 return RES_OK; 322 } 323 324 res_T 325 sphin_surface_get_brdf 326 (const struct sphin_surface* surface, 327 struct sphin_brdf** brdf) 328 { 329 if (NULL == surface || NULL == brdf) { 330 return RES_BAD_ARG; 331 } 332 *brdf = surface->brdf; 333 return RES_OK; 334 } 335 336 res_T 337 sphin_surface_get_btdf 338 (const struct sphin_surface* surface, 339 struct sphin_btdf** btdf) 340 { 341 if (NULL == surface || NULL == btdf) { 342 return RES_BAD_ARG; 343 } 344 *btdf = surface->btdf; 345 return RES_OK; 346 } 347 348 res_T 349 sphin_surface_get_source 350 (const struct sphin_surface* surface, 351 struct sphin_source_surface** source_surface) 352 { 353 if (NULL == surface || NULL == source_surface) { 354 return RES_BAD_ARG; 355 } 356 357 *source_surface = surface->source_surface; /* NULL if surface has no source */ 358 return RES_OK; 359 } 360 361 res_T 362 sphin_surface_get_geometry_count 363 (struct sphin_surface* surface, 364 size_t* ngeometries) 365 { 366 if (NULL == surface) { 367 return RES_BAD_ARG; 368 } 369 370 *ngeometries = darray_sphin_geometry_ptr_size_get(&surface->geometries); 371 372 return RES_OK; 373 } 374 375 res_T 376 sphin_surface_get_geometry 377 (struct sphin_surface* surface, 378 size_t igeometry, 379 struct sphin_geometry** geometry) 380 { 381 size_t ngeometries; 382 if (NULL == surface) { 383 return RES_BAD_ARG; 384 } 385 386 ngeometries = darray_sphin_geometry_ptr_size_get(&surface->geometries); 387 if (igeometry > ngeometries) { 388 return RES_BAD_ARG; 389 } 390 391 *geometry = darray_sphin_geometry_ptr_data_get 392 (&surface->geometries)[igeometry]; 393 394 return RES_OK; 395 } 396 397 res_T 398 sphin_surface_compute_total_area 399 (struct sphin_surface* surface, 400 double* area) 401 { 402 double total_geometry_area = 0; 403 size_t geometry_count = 0; 404 size_t i = 0; 405 struct sphin_geometry* geometry = NULL; 406 res_T res = RES_OK; 407 408 geometry_count = darray_sphin_geometry_ptr_size_get(&surface->geometries); 409 410 FOR_EACH(i, 0, geometry_count) { 411 geometry = darray_sphin_geometry_ptr_data_get(&surface->geometries)[i]; 412 total_geometry_area += geometry_compute_area(geometry); 413 } 414 415 *area = total_geometry_area; 416 return res; 417 } 418 419 res_T 420 sphin_surface_source_get_power 421 (struct sphin_surface* surface, 422 double* power) 423 { 424 double sum_powers = 0; 425 double total_geometry_area = 0; 426 size_t geometry_count = 0; 427 size_t i = 0; 428 struct sphin_geometry* geometry = NULL; 429 struct sphin_source_surface* source_surface = NULL; 430 struct sphin_source_surface_flux_density density = 431 SPHIN_SOURCE_SURFACE_FLUX_DENSITY_NULL; 432 res_T res = RES_OK; 433 434 source_surface = surface->source_surface; 435 436 if (NULL == source_surface) { 437 res = RES_BAD_ARG; 438 goto error; 439 } 440 441 res = sphin_source_surface_get_flux_density(source_surface, &density); 442 if (RES_OK != res) { goto error; } 443 444 geometry_count = darray_sphin_geometry_ptr_size_get(&surface->geometries); 445 446 FOR_EACH(i, 0, geometry_count) { 447 geometry = darray_sphin_geometry_ptr_data_get(&surface->geometries)[i]; 448 total_geometry_area += geometry_compute_area(geometry); 449 } 450 451 sum_powers = total_geometry_area * density.flux_density; 452 453 exit: 454 *power = sum_powers; 455 return res; 456 error: 457 goto exit; 458 }