mrumtl

Describe materials that vary spectrally
git clone git://git.meso-star.fr/mrumtl.git
Log | Files | Refs | README | LICENSE

commit 3b91a936e1b113f3c3eb2c6246fc199bd2f136b6
parent 500541ee420d6c9be4bb385708e22a2de712a310
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 28 Feb 2020 15:54:04 +0100

Write the mrumtl_load function

Write the while parsing process

Diffstat:
MREADME.md | 6+++---
Msrc/mrumtl.c | 575+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/mrumtl.h | 6++++++
3 files changed, 584 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md @@ -21,6 +21,6 @@ for further informations on CMake. ## Licenses Copyright (C) 2020 [|Meso|Star>](http://www.meso-star.com) -<contact@meso-star.com>. They are released under the GPL v3+ license: GNU GPL -version 3 or later. You are welcome to redistribute them under certain -conditions; refer to the COPYING file for details. +<contact@meso-star.com>. MRUMTL is free software released under the GPL v3+ +license: GNU GPL version 3 or later. You are welcome to redistribute them under +certain conditions; refer to the COPYING file for details. diff --git a/src/mrumtl.c b/src/mrumtl.c @@ -13,13 +13,67 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#define _POSIX_C_SOURCE 200112L /* strtok_r support */ + #include "mrumtl.h" +#include <rsys/cstr.h> +#include <rsys/dynamic_array.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> +#include <rsys/text_reader.h> + +#include <string.h> + +enum brdf_list_type { + BRDF_LIST_BAND, + BRDF_LIST_WLEN, + BRDF_LIST_NONE__ +}; + +struct brdf_lambertian { + double reflectivity; +}; + +struct brdf_specular { + double reflectivity; +}; + +struct mrumtl_brdf { + enum mrumtl_brdf_type type; + union { + struct brdf_lambertian lambertian; + struct brdf_specular specular; + } data; +}; + +struct brdf_wlen { + double wlen; /* In nanometers */ + struct mrumtl_brdf brdf; +}; + +struct brdf_band { + double wlen_min; /* In nanometers */ + double wlen_max; /* In nanometers */ + struct mrumtl_brdf brdf; +}; + +/* Define the dynamic array of per wavelength BRDF */ +#define DARRAY_NAME brdf_wlen +#define DARRAY_DATA struct brdf_wlen +#include <rsys/dynamic_array.h> + +/* Define the dynamic array of per band BRDF */ +#define DARRAY_NAME brdf_band +#define DARRAY_DATA struct brdf_band +#include <rsys/dynamic_array.h> struct mrumtl { + enum brdf_list_type brdf_list_type; + struct darray_brdf_wlen brdf_wlens; + struct darray_brdf_band brdf_bands; + int verbose; struct logger* logger; struct logger logger__; @@ -83,6 +137,492 @@ log_msg } } +static INLINE void +log_err(const struct mrumtl* mrumtl, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(mrumtl && msg); + + va_start(vargs_list, msg); + log_msg(mrumtl, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +static INLINE void +log_warn(const struct mrumtl* mrumtl, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(mrumtl && msg); + + va_start(vargs_list, msg); + log_msg(mrumtl, LOG_WARNING, msg, vargs_list); + + va_end(vargs_list); +} + +static res_T +parse_brdf_lambertian + (struct mrumtl* mrumtl, + struct txtrdr* txtrdr, + char** tk_ctx, + struct brdf_lambertian* brdf) +{ + char* tk = NULL; + res_T res = RES_OK; + ASSERT(mrumtl && txtrdr && tk_ctx && brdf); + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + log_err(mrumtl, "%s:%lu: missing lambertian reflectivity.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_double(tk, &brdf->reflectivity); + if(res != RES_OK) { + log_err(mrumtl, "%s:%lu: invalid lambertian reflectivity `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + + if(brdf->reflectivity < 0 || brdf->reflectivity > 1) { + log_err(mrumtl, "%s:%lu: the lambertian reflectivity must lie in [0, 1] " + "while the submitted value is %g.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + brdf->reflectivity); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_brdf_specular + (struct mrumtl* mrumtl, + struct txtrdr* txtrdr, + char** tk_ctx, + struct brdf_specular* brdf) +{ + char* tk = NULL; + res_T res = RES_OK; + ASSERT(mrumtl && txtrdr && tk_ctx && brdf); + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + log_err(mrumtl, "%s:%lu: missing specular reflectivity.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_double(tk, &brdf->reflectivity); + if(res != RES_OK) { + log_err(mrumtl, "%s:%lu: invalid specular reflectivity `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), &tk); + res = RES_BAD_ARG; + goto error; + } + + if(brdf->reflectivity < 0 || brdf->reflectivity > 1) { + log_err(mrumtl, "%s:%lu: the specular reflectivity must lie in [0, 1] " + "while the submitted value is %g.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + brdf->reflectivity); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_brdf + (struct mrumtl* mrumtl, + struct txtrdr* txtrdr, + char** tk_ctx, + struct mrumtl_brdf* brdf) +{ + char* tk = NULL; + res_T res = RES_OK; + ASSERT(mrumtl && txtrdr && tk_ctx && brdf); + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + log_err(mrumtl, "%s:%lu: no BRDF type is defined.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp(tk, "lambertian")) { + res = parse_brdf_lambertian(mrumtl, txtrdr, tk_ctx, &brdf->data.lambertian); + if(res != RES_OK) goto error; + brdf->type = MRUMTL_BRDF_LAMBERTIAN; + } else if(!strcmp(tk, "specular")) { + res = parse_brdf_specular(mrumtl, txtrdr, tk_ctx, &brdf->data.specular); + if(res != RES_OK) goto error; + brdf->type = MRUMTL_BRDF_SPECULAR; + } else { + log_err(mrumtl, "%s:%lu: invalid BRDF type `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_wlen_brdf + (struct mrumtl* mrumtl, + struct txtrdr* txtrdr, + struct brdf_wlen* brdf) +{ + char* tk = NULL; + char* tk_ctx = NULL; + res_T res = RES_OK; + ASSERT(mrumtl && txtrdr && brdf); + + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + + if(!txtrdr_get_cline(txtrdr)) { + log_err(mrumtl, + "%s:%lu: missing a wavelength BRDF. " + "Expecting %lu BRDFs while only %lu was parsed.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + (unsigned long)darray_brdf_wlen_size_get(&mrumtl->brdf_wlens), + (unsigned long)(brdf - darray_brdf_wlen_cdata_get(&mrumtl->brdf_wlens))); + res = RES_BAD_ARG; + goto error; + } + + tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + ASSERT(tk); + + res = cstr_to_double(tk, &brdf->wlen); + if(res != RES_OK) { + log_err(mrumtl, "%s:%lu: invalid wavelength `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + goto error; + } + + res = parse_brdf(mrumtl, txtrdr, &tk_ctx, &brdf->brdf); + if(res != RES_OK) goto error; + + tk = strtok_r(NULL, "", &tk_ctx); + if(tk) { + log_err(mrumtl, "%s:%lu: unexpected directive `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_band_brdf + (struct mrumtl* mrumtl, + struct txtrdr* txtrdr, + struct brdf_band* brdf) +{ + char* tk = NULL; + char* tk_ctx = NULL; + res_T res = RES_OK; + ASSERT(mrumtl && txtrdr && brdf); + + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + + if(!txtrdr_get_cline(txtrdr)) { + log_err(mrumtl, + "%s:%lu: missing a band BRDF. " + "Expecting %lu BRDFs while only %lu was parsed.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + (unsigned long)darray_brdf_band_size_get(&mrumtl->brdf_bands), + (unsigned long)(brdf - darray_brdf_band_cdata_get(&mrumtl->brdf_bands))); + res = RES_BAD_ARG; + goto error; + } + + tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + ASSERT(tk); + + res = cstr_to_double(tk, &brdf->wlen_min); + if(res != RES_OK) { + log_err(mrumtl, "%s:%lu: invalid band min boundary `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + goto error; + } + + tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + if(!tk) { + log_err(mrumtl, "%s:%lu: missing band max boundary.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_double(tk, &brdf->wlen_max); + if(res != RES_OK) { + log_err(mrumtl, "%s:%lu: invalid band max boundary `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + goto error; + } + + if(brdf->wlen_min > brdf->wlen_max) { + log_err(mrumtl, "%s:%lu: the band boundaries are degenerated -- [%g, %g].\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + brdf->wlen_min, brdf->wlen_max); + res = RES_BAD_ARG; + goto error; + } + + res = parse_brdf(mrumtl, txtrdr, &tk_ctx, &brdf->brdf); + if(res != RES_OK) goto error; + + tk = strtok_r(NULL, "", &tk_ctx); + if(tk) { + log_err(mrumtl, "%s:%lu: unexpected directive `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_wlens_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) +{ + char* tk = NULL; + unsigned long count = 0; + unsigned long i; + res_T res = RES_OK; + ASSERT(mrumtl && txtrdr && tk_ctx); + + mrumtl->brdf_list_type = BRDF_LIST_WLEN; + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + log_err(mrumtl, "%s:%lu: the number of wavelengths is missing.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_ulong(tk, &count); + if(res != RES_OK) { + log_err(mrumtl, "%s:%lu: invalid wavelengths count `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + + tk = strtok_r(NULL, "", tk_ctx); + if(tk) { + log_err(mrumtl, "%s:%lu: unexpected text `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + + res = darray_brdf_wlen_resize(&mrumtl->brdf_wlens, count); + if(res != RES_OK) { + log_err(mrumtl, + "%s:%lu: could not allocate the list of per wavelength BRDF -- %s.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + + FOR_EACH(i, 0, count) { + struct brdf_wlen* brdf = NULL; + + brdf = darray_brdf_wlen_data_get(&mrumtl->brdf_wlens) + i; + + res = parse_wlen_brdf(mrumtl, txtrdr, brdf); + if(res != RES_OK) goto error; + + if(i > 0 && brdf[0].wlen <= brdf[-1].wlen) { + log_err(mrumtl, + "%s:%lu: the BRDF must be sorted un ascending order " + "wrt their wavelength.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + } + +exit: + return res; +error: + darray_brdf_wlen_clear(&mrumtl->brdf_wlens); + goto exit; +} + +static res_T +parse_bands_list(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) +{ + char* tk = NULL; + unsigned long count = 0; + unsigned long i = 0; + res_T res = RES_OK; + ASSERT(mrumtl && txtrdr && tk_ctx); + + mrumtl->brdf_list_type = BRDF_LIST_BAND; + + tk = strtok_r(NULL, " \t", tk_ctx); + if(!tk) { + log_err(mrumtl, "%s:%lu: the number of bands is missing.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_ulong(tk, &count); + if(res != RES_OK) { + log_err(mrumtl, "%s:%lu: invalid bands count `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + + tk = strtok_r(NULL, "", tk_ctx); + if(tk) { + log_err(mrumtl, "%s:%lu: unexpected text `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + + res = darray_brdf_band_resize(&mrumtl->brdf_bands, count); + if(res != RES_OK) { + log_err(mrumtl, + "%s:%lu: could not allocate the list of per band BRDF -- %s.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + + FOR_EACH(i, 0, count) { + struct brdf_band* brdf = NULL; + + brdf = darray_brdf_band_data_get(&mrumtl->brdf_bands) + i; + + res = parse_band_brdf(mrumtl, txtrdr, brdf); + if(res != RES_OK) goto error; + + if(i > 0 && brdf[0].wlen_min < brdf[-1].wlen_max) { + log_err(mrumtl, + "%s:%lu: the BRDF must be sorted un ascending order " + "wrt their band and the bands must not overlapped.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); + res = RES_BAD_ARG; + goto error; + } + } + +exit: + return res; +error: + darray_brdf_band_clear(&mrumtl->brdf_bands); + goto exit; +} + +static res_T +parse_data(struct mrumtl* mrumtl, struct txtrdr* txtrdr) +{ + char* tk = NULL; + char* tk_ctx = NULL; + res_T res = RES_OK; + ASSERT(mrumtl && txtrdr); + + tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); + ASSERT(tk); + + if(!strcmp(tk, "wavelengths")) { + res = parse_wlens_list(mrumtl, txtrdr, &tk_ctx); + if(res != RES_BAD_ARG) goto error; + } else if(!strcmp(tk, "bands")) { + res = parse_bands_list(mrumtl, txtrdr, &tk_ctx); + if(res != RES_BAD_ARG) goto error; + } else { + log_err(mrumtl, "%s:%lu: unexpected directive `%s'.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +load_stream(struct mrumtl* mrumtl, FILE* stream, const char* stream_name) +{ + struct txtrdr* txtrdr = NULL; + res_T res = RES_OK; + ASSERT(mrumtl && stream && stream_name); + + res = txtrdr_stream(mrumtl->allocator, stream, stream_name, '#', &txtrdr); + if(res != RES_OK) { + log_err(mrumtl, "Could not create the text reader to parse `%s' -- %s.\n", + stream_name, res_to_cstr(res)); + goto error; + } + + for(;;) { + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + + if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ + + res = parse_data(mrumtl, txtrdr); + if(res != RES_OK) goto error; + } + +exit: + if(txtrdr) txtrdr_ref_put(txtrdr); + return res; +error: + goto exit; +} + static void release_mrumtl(ref_T* ref) { @@ -90,6 +630,9 @@ release_mrumtl(ref_T* ref) ASSERT(ref); mrumtl = CONTAINER_OF(ref, struct mrumtl, ref); + darray_brdf_band_release(&mrumtl->brdf_bands); + darray_brdf_wlen_release(&mrumtl->brdf_wlens); + /* First release the programs that uses the libs array */ if(mrumtl->logger == &mrumtl->logger__) logger_release(&mrumtl->logger__); MEM_RM(mrumtl->allocator, mrumtl); @@ -132,6 +675,9 @@ mrumtl_create ref_init(&mrumtl->ref); mrumtl->allocator = allocator; mrumtl->verbose = verbose; + darray_brdf_band_init(mrumtl->allocator, &mrumtl->brdf_bands); + darray_brdf_wlen_init(mrumtl->allocator, &mrumtl->brdf_wlens); + mrumtl->brdf_list_type = BRDF_LIST_NONE__; if(logger) { mrumtl->logger = logger; @@ -174,3 +720,32 @@ mrumtl_ref_put(struct mrumtl* mrumtl) return RES_OK; } +res_T +mrumtl_load(struct mrumtl* mrumtl, const char* filename) +{ + FILE* fp = NULL; + res_T res = RES_OK; + + if(!mrumtl || filename) { + res = RES_BAD_ARG; + goto error; + } + + fp = fopen(filename, "r"); + if(!fp) { + log_err(mrumtl, "%s: error opening file `%s' -- %s.\n", + FUNC_NAME, strerror(errno)); + res = RES_IO_ERR; + goto error; + } + + res = load_stream(mrumtl, fp, filename); + if(res != RES_OK) goto error; + +exit: + if(fp) fclose(fp); + return res; +error: + goto exit; +} + diff --git a/src/mrumtl.h b/src/mrumtl.h @@ -36,6 +36,12 @@ #define MRUMTL(Func) mrumtl_ ## Func #endif +enum mrumtl_brdf_type { + MRUMTL_BRDF_LAMBERTIAN, + MRUMTL_BRDF_SPECULAR, + MRUMTL_BRDF_NONE__ +}; + /* Forward declaration of external data types */ struct logger; struct mem_allocator;