star-stl

Load STereo Lithography (StL) file format
git clone git://git.meso-star.fr/star-stl.git
Log | Files | Refs | README | LICENSE

commit f975c37d1a26b4c05e98d6243d20b2d48bf7e5a7
parent 658f2a58a7123d7f4c8143e94182468d4b8878a6
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu,  3 Jul 2025 14:24:29 +0200

Merge branch 'release_0.7'

Diffstat:
MMakefile | 2++
MREADME.md | 5+++++
Mconfig.mk | 2+-
Msrc/sstl.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sstl_desc.c | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 207 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile @@ -146,6 +146,7 @@ lint: ################################################################################ TEST_SRC =\ src/test_sstl.c\ + src/test_sstl_desc.c\ src/test_sstl_load_ascii.c\ src/test_sstl_load_binary.c\ src/test_sstl_writer.c @@ -179,6 +180,7 @@ $(TEST_OBJ): config.mk sstl-local.pc $(CC) $(CFLAGS_TEST) -c $(@:.o=.c) -o $@ test_sstl \ +test_sstl_desc \ test_sstl_load_ascii \ test_sstl_load_binary \ test_sstl_writer \ diff --git a/README.md b/README.md @@ -18,6 +18,11 @@ Edit config.mk as needed, then run: ## Release notes +### Version 0.7 + +- Add the Descriptors API to facilitate access to mesh data from its raw + data structure. + ### Version 0.6 - Improve code readability and simplicity by rewriting the internal diff --git a/config.mk b/config.mk @@ -1,4 +1,4 @@ -VERSION = 0.6 +VERSION = 0.7 PREFIX = /usr/local LIB_TYPE = SHARED diff --git a/src/sstl.h b/src/sstl.h @@ -162,6 +162,56 @@ sstl_get_desc struct sstl_desc* desc); /******************************************************************************* + * Descriptor API. This is a set of help functions for retrieving mesh data from + * their raw representation. + ******************************************************************************/ +static INLINE res_T +sstl_desc_get_triangle_ids + (const struct sstl_desc* desc, + const size_t itri, + unsigned ids[3]) +{ + if(!desc || !ids || itri >= desc->triangles_count) return RES_BAD_ARG; + ids[0] = desc->indices[itri*3/*#ids per triangle*/ + 0]; + ids[1] = desc->indices[itri*3/*#ids per triangle*/ + 1]; + ids[2] = desc->indices[itri*3/*#ids per triangle*/ + 2]; + return RES_OK; +} + +static INLINE res_T +sstl_desc_get_vertex_coords + (const struct sstl_desc* desc, + const size_t ivtx, + float coords[3]) +{ + if(!desc || !coords || ivtx >= desc->vertices_count) return RES_BAD_ARG; + coords[0] = desc->vertices[ivtx*3/*#coords per vertex*/ + 0]; + coords[1] = desc->vertices[ivtx*3/*#coords per vertex*/ + 1]; + coords[2] = desc->vertices[ivtx*3/*#coords per vertex*/ + 2]; + return RES_OK; +} + +static INLINE res_T +sstl_desc_get_facet + (const struct sstl_desc* desc, + const size_t itri, + struct sstl_facet* facet) +{ + unsigned ids[3] = {0,0,0}; + + if(!desc || !facet || itri >= desc->triangles_count) return RES_BAD_ARG; + + #define CALL(Func) {res_T res; if((res = Func) != RES_OK) return res;} (void)0 + CALL(sstl_desc_get_triangle_ids(desc, itri, ids)); + CALL(sstl_desc_get_vertex_coords(desc, ids[0], facet->vertices[0])); + CALL(sstl_desc_get_vertex_coords(desc, ids[1], facet->vertices[1])); + CALL(sstl_desc_get_vertex_coords(desc, ids[2], facet->vertices[2])); + #undef CALL + + return RES_OK; +} + +/******************************************************************************* * Writer API ******************************************************************************/ SSTL_API res_T diff --git a/src/test_sstl_desc.c b/src/test_sstl_desc.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2015, 2016, 2019, 2021, 2023, 2025 |Méso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "sstl.h" + +#include <rsys/float3.h> +#include <rsys/mem_allocator.h> + +static const float vertices[4/*#vertices*/*3/*#coords*/] = { + 0.0f, 0.0f, 0.0f, + 0.1f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.1f, + 0.0f, 0.1f, 0.0f, +}; +static const size_t nvertices = sizeof(vertices)/(sizeof(float)*3); + +static const unsigned indices[4/*#triangles*/*3/*#ids*/] = { + 0, 1, 2, + 0, 3, 1, + 0, 2, 3, + 1, 3, 2 +}; +static const size_t ntriangles = sizeof(indices)/(sizeof(unsigned)*3); + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static FILE* +write_tetrahedron(struct sstl* sstl, const enum sstl_type type) +{ + struct sstl_facet facet = SSTL_FACET_NULL; + struct sstl_writer_create_args args = SSTL_WRITER_CREATE_ARGS_DEFAULT; + struct sstl_writer* writer = NULL; + FILE* fp = NULL; + size_t i = 0; + + CHK(sstl != NULL); + + CHK((fp = tmpfile()) != NULL); + args.filename = "Tetrahedron.stl"; + args.stream = fp; + args.type = type; + args.solid_name = "cube corner"; + args.verbose = 3; + CHK(sstl_writer_create(&args, &writer) == RES_OK); + + FOR_EACH(i, 0, ntriangles) { + f3_set(facet.vertices[0], vertices+(indices[i*3/*#ids*/+0])*3/*#coords*/); + f3_set(facet.vertices[1], vertices+(indices[i*3/*#ids*/+1])*3/*#coords*/); + f3_set(facet.vertices[2], vertices+(indices[i*3/*#ids*/+2])*3/*#coords*/); + CHK(sstl_write_facet(writer, &facet) == RES_OK); + } + + CHK(sstl_writer_ref_put(writer) == RES_OK); + rewind(fp); + return fp; +} + +static void +check_tetrahedron(struct sstl* sstl, FILE* fp) +{ + struct sstl_desc desc = SSTL_DESC_NULL; + struct sstl_facet facet = SSTL_FACET_NULL; + float coords[3] = {0,0,0}; + unsigned ids[3] = {0,0,0}; + size_t i = 0; + + CHK(sstl != NULL); + CHK(fp != NULL); + + CHK(sstl_load_stream(sstl, fp, "Tetrahedron") == RES_OK); + + CHK(sstl_get_desc(NULL, &desc) == RES_BAD_ARG); + CHK(sstl_get_desc(sstl, NULL) == RES_BAD_ARG); + CHK(sstl_get_desc(sstl, &desc) == RES_OK); + + CHK(desc.vertices_count == nvertices); + CHK(desc.triangles_count == ntriangles); + + CHK(sstl_desc_get_vertex_coords(NULL, 0, coords) == RES_BAD_ARG); + CHK(sstl_desc_get_vertex_coords(&desc, nvertices, coords) == RES_BAD_ARG); + CHK(sstl_desc_get_vertex_coords(&desc, 0, NULL) == RES_BAD_ARG); + FOR_EACH(i, 0, desc.vertices_count) { + CHK(sstl_desc_get_vertex_coords(&desc, i, coords) == RES_OK); + CHK(f3_eq(coords, vertices + i*3)); + } + + CHK(sstl_desc_get_triangle_ids(NULL, 0, ids) == RES_BAD_ARG); + CHK(sstl_desc_get_triangle_ids(&desc, ntriangles, ids) == RES_BAD_ARG); + CHK(sstl_desc_get_triangle_ids(&desc, 0, NULL) == RES_BAD_ARG); + FOR_EACH(i, 0, desc.triangles_count) { + CHK(sstl_desc_get_triangle_ids(&desc, i, ids) == RES_OK); + CHK(ids[0] == indices[i*3+0]); + CHK(ids[1] == indices[i*3+1]); + CHK(ids[2] == indices[i*3+2]); + } + + CHK(sstl_desc_get_facet(NULL, 0, &facet) == RES_BAD_ARG); + CHK(sstl_desc_get_facet(&desc, ntriangles, &facet) == RES_BAD_ARG); + CHK(sstl_desc_get_facet(&desc, 0, NULL) == RES_BAD_ARG); + FOR_EACH(i, 0, desc.triangles_count) { + CHK(sstl_desc_get_facet(&desc, i, &facet) == RES_OK); + CHK(sstl_desc_get_triangle_ids(&desc, i, ids) == RES_OK); + + CHK(sstl_desc_get_vertex_coords(&desc, ids[0], coords) == RES_OK); + CHK(f3_eq(coords, facet.vertices[0])); + CHK(sstl_desc_get_vertex_coords(&desc, ids[1], coords) == RES_OK); + CHK(f3_eq(coords, facet.vertices[1])); + CHK(sstl_desc_get_vertex_coords(&desc, ids[2], coords) == RES_OK); + CHK(f3_eq(coords, facet.vertices[2])); + } +} + +/******************************************************************************* + * The test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct sstl* sstl = NULL; + FILE* fp = NULL; + (void)argc, (void)argv; + + CHK(sstl_create(NULL, NULL, 3, &sstl) == RES_OK); + + CHK((fp = write_tetrahedron(sstl, SSTL_ASCII)) != NULL); + check_tetrahedron(sstl, fp); + CHK(fclose(fp) == 0); + + CHK((fp = write_tetrahedron(sstl, SSTL_BINARY)) != NULL); + check_tetrahedron(sstl, fp); + CHK(fclose(fp) == 0); + + CHK(sstl_ref_put(sstl) == RES_OK); + CHK(mem_allocated_size() == 0); + return 0; +}