commit 4d57423397b6ac7aa0a6cd184ca160d9c180ef88
parent 7d41b6c42c46e3bd1a4bd59ee66cf841501b0679
Author: Eduardo Fontana Lazzari <edufonlaz@gmail.com>
Date: Mon, 24 Mar 2025 13:46:49 +0100
Allow unit specification for geometries in the input file
Geometries are now scaled according to the specified unit.
Added corresponding tests and documentation.
Diffstat:
3 files changed, 50 insertions(+), 6 deletions(-)
diff --git a/doc/star-phor-input.scd b/doc/star-phor-input.scd
@@ -56,9 +56,10 @@ The file format describing a photoreactive system is as follows:++
[<sensor>]++
[<surface-source>]++
++
-<geometry> ::= *geometry:* <geometry-side> <geometry-filename>++
+<geometry> ::= *geometry:* <geometry-side> <geometry-filename> [<geometry-unit>]++
<geometry-side> ::= *FRONT* | *BACK*++
<geometry-filename> ::= path % STL files only; spaces not allowed ++
+<geometry-unit> ::= *m* | *cm* | *mm* | *km* % if no unit is specified, meter is assumed++
++
<sensor> ::= *sensor:* [<comment>]++
*response_function:* real++
diff --git a/src/sphin_geometry.c b/src/sphin_geometry.c
@@ -104,10 +104,12 @@ geometry_parse
char* side = NULL;
char* filename = NULL;
char* token_ptr = NULL;
+ char* unit = NULL;
struct sphin_geometry* geom = NULL;
struct sstl* sstl = NULL;
struct sstl_desc sstl_desc;
double* coords = NULL;
+ double scaling_factor;
size_t* indices = NULL;
res_T res = RES_OK;
@@ -133,6 +135,15 @@ geometry_parse
filename = strtok_r(NULL, " \t", &token_ptr);
if (NULL == filename){ res = RES_BAD_ARG; goto error; }
+ /* Parse unit and evaluate scaling factor*/
+ unit = strtok_r(NULL, " \t", &token_ptr);
+ if (NULL == unit
+ || 0 == strcmp(unit, "m")){scaling_factor = 1e+00;}
+ else if (0 == strcmp(unit, "cm")){scaling_factor = 1e-02;}
+ else if (0 == strcmp(unit, "mm")){scaling_factor = 1e-03;}
+ else if (0 == strcmp(unit, "km")){scaling_factor = 1e+03;}
+ else { res = RES_BAD_ARG; goto error; }
+
/* Create geometry */
res = geometry_create(sphin, filename, &geom);
if (RES_OK != res) { goto error; }
@@ -154,7 +165,7 @@ geometry_parse
indices = darray_size_t_data_get(&geom->indices);
FOR_EACH(i, 0, sstl_desc.vertices_count*3) {
- coords[i] = (double)sstl_desc.vertices[i];
+ coords[i] = (double)sstl_desc.vertices[i]*scaling_factor;
}
FOR_EACH(i, 0, sstl_desc.triangles_count*3) {
indices[i] = (size_t)sstl_desc.indices[i];
diff --git a/src/test_sphin_load_geometry.c b/src/test_sphin_load_geometry.c
@@ -25,6 +25,7 @@
#include "sphin.h"
#include "test_sphin_utils.h"
+#include <rsys/math.h>
#include <rsys/mem_allocator.h>
#include <string.h>
@@ -48,8 +49,8 @@ write_stl_test_files
" facet normal 0.0 0.0 -1.0\n"
" outer loop\n"
" vertex 0.0 0.0 0.0\n"
- " vertex 1.0 0.0 0.0\n"
- " vertex 0.0 1.0 0.0\n"
+ " vertex 1.935 0.0 0.0\n"
+ " vertex 0.0 0.0 3.142\n"
" endloop\n"
" endfacet\n"
"endsolid";
@@ -168,8 +169,11 @@ test_geometry_api
CHK(fp = fopen(path, "w+"));
fprintf(fp, "\t\t surface : \"surface name\"\n");
fprintf(fp, "\tgeometry: FRONT test_0.stl\t\n");
- fprintf(fp, "\tgeometry: BACK test_1.stl \t\n");
+ fprintf(fp, "\tgeometry: BACK test_1.stl\t\n");
fprintf(fp, "\tgeometry: BACK test_2.stl\n");
+ fprintf(fp, "\tgeometry: BACK test_1.stl cm\t\n");
+ fprintf(fp, "\tgeometry: BACK test_1.stl mm\t\n");
+ fprintf(fp, "\tgeometry: BACK test_1.stl km\t\n");
fclose(fp);
CHK(sphin_load(sphin, path, &config) == RES_OK);
@@ -178,7 +182,7 @@ test_geometry_api
CHK(sphin_config_get_surface(config, 0, &surface) == RES_OK);
CHK(sphin_surface_get_geometry_count(NULL, &ngeometries) == RES_BAD_ARG);
CHK(sphin_surface_get_geometry_count(surface, &ngeometries) == RES_OK);
- CHK(ngeometries == 3);
+ CHK(ngeometries == 6);
igeometry = 0;
CHK(sphin_surface_get_geometry(surface, igeometry, &geom) == RES_OK);
@@ -204,6 +208,34 @@ test_geometry_api
CHK(desc.mesh.vertex_count == 8);
CHK(strcmp(desc.filename, "test_2.stl") == 0);
+ /* Test geometry units */
+
+ /* In the following assertions, we use an epsilon (tolerable error) of 1e-6
+ * instead of the 1e-15 used elsewhere in sphin. This is because, although
+ * sphin performs all computations using doubles, the third-party library
+ * star-stl, which is used to parse STL files, handles mesh coordinates
+ * using floats (even though those are exposed as doubles by sphin).
+ * As a result, the precision of geometrical coordinates is
+ * limited to approximately six digits. */
+
+ igeometry++;
+ CHK(sphin_surface_get_geometry(surface, igeometry, &geom) == RES_OK);
+ CHK(sphin_geometry_get_desc(geom, &desc) == RES_OK);
+ CHK(eq_eps(desc.mesh.coords[3], 0.01935, 1e-9));
+ CHK(eq_eps(desc.mesh.coords[8], 0.03142, 1e-9));
+
+ igeometry++;
+ CHK(sphin_surface_get_geometry(surface, igeometry, &geom) == RES_OK);
+ CHK(sphin_geometry_get_desc(geom, &desc) == RES_OK);
+ CHK(eq_eps(desc.mesh.coords[3], 0.001935, 1e-8));
+ CHK(eq_eps(desc.mesh.coords[8], 0.003142, 1e-8));
+
+ igeometry++;
+ CHK(sphin_surface_get_geometry(surface, igeometry, &geom) == RES_OK);
+ CHK(sphin_geometry_get_desc(geom, &desc) == RES_OK);
+ CHK(eq_eps(desc.mesh.coords[3], 1935, 1e-3));
+ CHK(eq_eps(desc.mesh.coords[8], 3142, 1e-3));
+
CHK(sphin_geometry_ref_get(NULL) == RES_BAD_ARG);
CHK(sphin_geometry_ref_put(NULL) == RES_BAD_ARG);
CHK(sphin_geometry_ref_get(geom) == RES_OK);