star-uvm

Spatial structuring of unstructured volumetric meshes
git clone git://git.meso-star.fr/star-uvm.git
Log | Files | Refs | README | LICENSE

commit ae4d27842dfb20c710380de8e840d41959083491
parent cc97338e42269d232fa95417faf30a02bf13d3f9
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  4 Jan 2023 12:11:00 +0100

Merge branch 'release_0.1'

Diffstat:
MREADME.md | 2+-
Mcmake/CMakeLists.txt | 22+++++++++++-----------
Msrc/suvm.h | 24+++++++++++++++++++++++-
Msrc/suvm_c.h | 2+-
Msrc/suvm_device.c | 2+-
Msrc/suvm_device.h | 2+-
Msrc/suvm_primitive.c | 2+-
Msrc/suvm_volume.c | 148++++++++++++++++++++++++++++++++++---------------------------------------------
Msrc/suvm_volume.h | 2+-
Msrc/suvm_volume_at.c | 18++++++++++++++----
Msrc/suvm_volume_intersect_aabb.c | 2+-
Asrc/suvm_voxelize.c | 438+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/suvm_voxelize_sth.c | 431-------------------------------------------------------------------------------
Msrc/test_suvm_ball.h | 6+++---
Msrc/test_suvm_box.h | 7+++----
Msrc/test_suvm_device.c | 2+-
Msrc/test_suvm_primitive_intersection.c | 2+-
Msrc/test_suvm_utils.h | 2+-
Msrc/test_suvm_volume.c | 57++++++++++++++++++++++++++++++++++++++++++++++++++-------
19 files changed, 615 insertions(+), 556 deletions(-)

diff --git a/README.md b/README.md @@ -29,7 +29,7 @@ informations on CMake. ## License -Copyright (C) 2020, 2021 [|Meso|Star>](https://www.meso-star.com) +Copyright (C) 2020-2023 [|Méso|Star>](https://www.meso-star.com) (<contact@meso-star.com>). Star-UnstructuredVolumetricMesh is free software released under the GPL v3+ license: GNU GPL version 3 or later. You are welcome to redistribute it under certain conditions; refer to the COPYING file for diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +# Copyright (C) 2020-2023 |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 @@ -25,9 +25,9 @@ option(NO_TEST "Do not build tests" OFF) ################################################################################ find_package(Embree 3.6 REQUIRED) find_package(RCMake 0.4 REQUIRED) -find_package(RSys 0.12 REQUIRED) +find_package(RSys 0.13 REQUIRED) if(NOT NO_TEST) - find_package(StarTetraHedra) + find_package(StarMesh) endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) @@ -44,8 +44,8 @@ endif() # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 0) -set(VERSION_PATCH 1) +set(VERSION_MINOR 1) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SUVM_FILES_SRC @@ -91,7 +91,7 @@ if(NOT NO_TEST) ${SUVM_SOURCE_DIR}/test_suvm_utils.h) target_link_libraries(${_name} suvm RSys ${ARGN}) endfunction() - + function(new_test _name) build_test(${_name} ${ARGN}) add_test(${_name} ${_name}) @@ -101,12 +101,12 @@ if(NOT NO_TEST) new_test(test_suvm_volume) new_test(test_suvm_primitive_intersection) - if(StarTetraHedra_FOUND) - add_executable(suvm_voxelize ${SUVM_SOURCE_DIR}/suvm_voxelize_sth.c) - target_link_libraries(suvm_voxelize RSys StarTetraHedra suvm) + if(StarMesh_FOUND) + add_executable(suvm_voxelize ${SUVM_SOURCE_DIR}/suvm_voxelize.c) + target_link_libraries(suvm_voxelize RSys StarMesh suvm) else() - message(STATUS "Star-TetraHedra was not found. " - "The suvm_voxelize_sth program will not be build.") + message(STATUS "Star-Mesh was not found. " + "The program suvm_voxelize will not be built") endif() endif() diff --git a/src/suvm.h b/src/suvm.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 @@ -97,6 +97,18 @@ struct suvm_polyhedron { float upper[3/*#coords*/]; }; +/* Internal copy of the unstructured mesh */ +struct suvm_mesh_desc { + const float* positions; + const uint32_t* indices; + size_t nvertices; + size_t nprimitives; + unsigned dvertex; /* Dimension of a vertex */ + unsigned dprimitive; /* Dimension of a primitive */ +}; +#define SUVM_MESH_DESC_NULL__ {NULL, NULL, 0, 0, 0, 0} +static const struct suvm_mesh_desc SUVM_MESH_DESC_NULL = SUVM_MESH_DESC_NULL__; + struct suvm_tetrahedral_mesh_args { size_t ntetrahedra; /* #tetrahedra */ size_t nvertices; /* #vertices */ @@ -229,6 +241,16 @@ suvm_volume_compute_hash const int cpnt_mask, /* Combination of suvm_volume_cpnt_flag */ hash256_T hash); +SUVM_API res_T +suvm_volume_get_mesh_desc + (const struct suvm_volume* volume, + struct suvm_mesh_desc* desc); + +SUVM_API res_T +suvm_mesh_desc_compute_hash + (const struct suvm_mesh_desc* desc, + hash256_T hash); + /******************************************************************************* * Primitive API ******************************************************************************/ diff --git a/src/suvm_c.h b/src/suvm_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/suvm_device.c b/src/suvm_device.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/suvm_device.h b/src/suvm_device.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/suvm_primitive.c b/src/suvm_primitive.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/suvm_volume.c b/src/suvm_volume.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 @@ -23,18 +23,6 @@ #include <rsys/dynamic_array_size_t.h> #include <rsys/ref_count.h> -struct hash_context { - struct cpnt { - const void* mem; - size_t size; /* Size in bytes */ - size_t chunk_min; /* Inclusive */ - size_t chunk_max; /* Exclusive */ - } cpnts[4]; - int ncpnts; - int icpnt; -}; -static const struct hash_context HASH_CONTEXT_NULL; - /* Generate the dynamic array of RTCBuildPrimitive */ #define DARRAY_NAME rtc_prim #define DARRAY_DATA struct RTCBuildPrimitive @@ -521,40 +509,6 @@ error: } static void -get_chunk(char dst[64], const size_t ichunk, void* context) -{ - struct hash_context* ctx = context; - const struct cpnt* cpnt = NULL; - const char* chunk = NULL; - size_t cpnt_offset = 0; - size_t chunk_sz = 0; - ASSERT(dst && ctx && ctx->icpnt < 4); - - /* Fetch the component to handle */ - cpnt = ctx->cpnts + ctx->icpnt; - ASSERT(cpnt->chunk_min <= ichunk); - ASSERT(cpnt->chunk_max > ichunk); - - /* Compute the offset into the component up to the data to copy */ - cpnt_offset = (ichunk - cpnt->chunk_min) * 64; - - /* Fetch the address toward the data to copy and compute the data size */ - chunk = (const char*)cpnt->mem + cpnt_offset; - chunk_sz = MMIN(cpnt->size - cpnt_offset, 64); - - /* Copy the component data toward the chunk */ - memcpy(dst, chunk, chunk_sz); - - /* Clean up the chunk from the last written byte to the end of the chunk */ - if(chunk_sz < 64) memset(dst + chunk_sz, 0, 64 - chunk_sz); - - /* Progress into the component */ - while(ichunk == ctx->cpnts[ctx->icpnt].chunk_max - 1 && ctx->icpnt < 4) { - ++ctx->icpnt; - } -} - -static void volume_release(ref_T* ref) { struct suvm_volume* vol = NULL; @@ -701,10 +655,7 @@ suvm_volume_compute_hash const int cpnt_mask, hash256_T hash) { - struct chunked_data_desc chunked_data = CHUNKED_DATA_DESC_NULL; - struct hash_context ctx = HASH_CONTEXT_NULL; - size_t sz = 0; - int i = 0; + struct sha256_ctx ctx; res_T res = RES_OK; if(!vol || !hash) { @@ -712,53 +663,80 @@ suvm_volume_compute_hash goto error; } - /* Setup the components to hash */ + sha256_ctx_init(&ctx); + if(cpnt_mask & SUVM_POSITIONS) { - ctx.cpnts[i].mem = darray_float_cdata_get(&vol->positions); - ctx.cpnts[i].size = darray_float_size_get(&vol->positions) * sizeof(float); - ++i; + const float* pos = darray_float_cdata_get(&vol->positions); + const size_t n = darray_float_size_get(&vol->positions); + sha256_ctx_update(&ctx, (const char*)pos, sizeof(*pos)*n); } if(cpnt_mask & SUVM_INDICES) { - ctx.cpnts[i].mem = darray_u32_cdata_get(&vol->indices); - ctx.cpnts[i].size = darray_u32_size_get(&vol->indices) * sizeof(uint32_t); - ++i; + const uint32_t* ids = darray_u32_cdata_get(&vol->indices); + const size_t n = darray_u32_size_get(&vol->indices); + sha256_ctx_update(&ctx, (const char*)ids, sizeof(*ids)*n); } if(cpnt_mask & SUVM_PRIMITIVE_DATA) { - ctx.cpnts[i].mem = vol->prim_data.mem; - ctx.cpnts[i].size = vol->prim_data.size * vol->prim_data.elmt_stride; - ++i; + const size_t sz = vol->prim_data.size * vol->prim_data.elmt_stride; + sha256_ctx_update(&ctx, vol->prim_data.mem, sz); } if(cpnt_mask & SUVM_VERTEX_DATA) { - ctx.cpnts[i].mem = vol->vert_data.mem; - ctx.cpnts[i].size = vol->vert_data.size * vol->vert_data.elmt_stride; - ++i; - } - ctx.ncpnts = i; - - /* Precompute the range of chunks overlapped by each component */ - FOR_EACH(i, 0, ctx.ncpnts) { - const size_t nchunks = (ctx.cpnts[i].size + 63/*ceil*/) / 64; - sz += nchunks * 64; - if(i == 0) { - ctx.cpnts[i].chunk_min = 0; - ctx.cpnts[i].chunk_max = nchunks; - } else { - ctx.cpnts[i].chunk_min = ctx.cpnts[i-1].chunk_max; - ctx.cpnts[i].chunk_max = ctx.cpnts[i-1].chunk_max + nchunks; - } + const size_t sz = vol->vert_data.size * vol->vert_data.elmt_stride; + sha256_ctx_update(&ctx, vol->vert_data.mem, sz); } - /* Setup the index of the 1st component to hash */ - ctx.icpnt = 0; + sha256_ctx_finalize(&ctx, hash); + +exit: + return res; +error: + goto exit; +} + +res_T +suvm_volume_get_mesh_desc + (const struct suvm_volume* vol, + struct suvm_mesh_desc* desc) +{ + res_T res = RES_OK; + + if(!vol || !desc) { + res = RES_BAD_ARG; + goto error; + } - /* Hash the volume data */ - chunked_data.get_chunk512 = get_chunk; - chunked_data.size = sz; - chunked_data.context = &ctx; - hash_sha256_chunked_data(&chunked_data, hash); + desc->positions = darray_float_cdata_get(&vol->positions); + desc->indices = darray_u32_cdata_get(&vol->indices); + desc->dvertex = 3; + desc->dprimitive = 4; + desc->nvertices = darray_float_size_get(&vol->positions) / desc->dvertex; + desc->nprimitives = darray_u32_size_get(&vol->indices) / desc->dprimitive; exit: return res; error: goto exit; } + +res_T +suvm_mesh_desc_compute_hash(const struct suvm_mesh_desc* desc, hash256_T hash) +{ + struct sha256_ctx ctx; + + if(!desc || !hash) return RES_BAD_ARG; + + #define HASH(Var, Nb) \ + sha256_ctx_update(&ctx, (const char*)(Var), sizeof(*Var)*(Nb)); + + sha256_ctx_init(&ctx); + HASH(desc->positions, desc->nvertices*desc->dvertex); + HASH(desc->indices, desc->nprimitives*desc->dprimitive); + HASH(&desc->nvertices, 1); + HASH(&desc->nprimitives, 1); + HASH(&desc->dvertex, 1); + HASH(&desc->dprimitive, 1); + sha256_ctx_finalize(&ctx, hash); + + #undef HASH + + return RES_OK; +} diff --git a/src/suvm_volume.h b/src/suvm_volume.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/suvm_volume_at.c b/src/suvm_volume_at.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 @@ -44,7 +44,7 @@ intersect_leaf float n0[3], n1[3], n2[3], n3[3]; float p[3]; float d0, d1, d2, d3; - float h0, h1, h2, h3; + float h1, h2, h3; size_t itetra; ASSERT(vol && leaf && pos && bcoords); ASSERT(leaf->prim_id < volume_get_primitives_count(vol)); @@ -80,7 +80,6 @@ intersect_leaf v2 = darray_float_cdata_get(&vol->positions) + tetra[2]*3; /* Distance of tetrahedron corners to their opposite face */ - h0 = f3_dot(n0, f3_sub(p, v3, v0)); h1 = f3_dot(n1, f3_sub(p, v2, v1)); h2 = f3_dot(n2, f3_sub(p, v0, v2)); h3 = f3_dot(n3, f3_sub(p, v1, v3)); @@ -89,7 +88,18 @@ intersect_leaf bcoords[0] = d2 / h2; bcoords[1] = d3 / h3; bcoords[2] = d1 / h1; - bcoords[3] = d0 / h0; + +#if 1 + /* Do not use d0 and h0 to calculate the last barycentric coordinate but + * calculate it from the 3 others. This gets around the numerical imprecision + * and ensures that the sum of the bcoords is indeed 1 */ + bcoords[3] = 1.f - bcoords[0] - bcoords[1] - bcoords[2]; +#else + { + const float h0 = f3_dot(n0, f3_sub(p, v3, v0)); + bcoords[3] = d0 / h0; + } +#endif return 1; } diff --git a/src/suvm_volume_intersect_aabb.c b/src/suvm_volume_intersect_aabb.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/suvm_voxelize.c b/src/suvm_voxelize.c @@ -0,0 +1,438 @@ +/* Copyright (C) 2020-2023 |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 General Public License for more details. + * + * 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 /* getopt/close support */ + +#include "suvm.h" +#include <star/smsh.h> +#include <rsys/clock_time.h> +#include <rsys/cstr.h> +#include <rsys/mem_allocator.h> + +#include <string.h> +#include <unistd.h> /* getopt & close functions */ + +struct args { + const char* input_filename; + const char* output_filename; + unsigned def[3]; + int precompute_normals; + int quit; + int verbose; +}; + +static const struct args ARGS_DEFAULT = { + NULL, /* Input file */ + NULL, /* Output file */ + {64, 64, 64}, /* Definition */ + 0, /* Precompute normals */ + 0, /* Quit */ + 0 /* Verbose */ +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +print_help(const char* cmd) +{ + ASSERT(cmd); + printf( +"Usage: %s [options] [file]\n" +"Voxelize a smsh(5) file and save result following VTK file format.\n" +"With no file option, mesh is read from standard input\n", + cmd); + printf("\n"); + printf( +" -d X:Y:Z voxelisation definition along the 3 axes.\n" +" Default definition is %u:%u:%u.\n", + ARGS_DEFAULT.def[0], + ARGS_DEFAULT.def[1], + ARGS_DEFAULT.def[2]); + printf( +" -h display this help and exit.\n"); + printf( +" -n precompute the tetrahedra normals.\n"); + printf( +" -o <output> filename of the output VTK file. If not defined, write\n" +" results to standard ouput\n"); + printf( +" -v make the program verobse.\n"); + printf("\n"); + printf( +"Copyright (C) 2020-2023 |Méso|Star> <contact@meso-star.com>.\n" +"This is free software released under the GNU GPL license, version 3 or\n" +"later. You are free to change or redistribute it under certain\n" +"conditions <http://gnu.org.licenses/gpl.html>\n"); +} + +static void +args_release(struct args* args) +{ + ASSERT(args); + *args = ARGS_DEFAULT; +} + +static res_T +args_init(struct args* args, const int argc, char** argv) +{ + size_t n; + int opt; + res_T res = RES_OK; + ASSERT(args); + + *args = ARGS_DEFAULT; + + while((opt = getopt(argc, argv, "d:hno:v")) != -1) { + switch(opt) { + case 'd': + res = cstr_to_list_uint(optarg, ':', args->def, &n, 3); + if(res == RES_OK && n != 3) res = RES_BAD_ARG; + if(!args->def[0] || !args->def[1] || !args->def[2]) res = RES_BAD_ARG; + break; + case 'h': + print_help(argv[0]); + args_release(args); + args->quit = 1; + break; + case 'n': + args->precompute_normals = 1; + break; + case 'o': + args->output_filename = optarg; + break; + case 'v': args->verbose = 1; break; + default: res = RES_BAD_ARG; break; + } + if(res != RES_OK) { + if(optarg) { + fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n", + argv[0], optarg, opt); + } + goto error; + } + } + + if(optind < argc) { + args->input_filename = argv[optind]; + } + +exit: + optind = 1; + return res; +error: + args_release(args); + goto exit; +} + +static void +get_indices(const size_t itetra, size_t ids[4], void* ctx) +{ + const uint64_t* ui64; + struct smsh_desc* desc = ctx; + ASSERT(desc && desc->dcell == 4); + ui64 = smsh_desc_get_cell(desc, itetra); + ids[0] = (size_t)ui64[0]; + ids[1] = (size_t)ui64[1]; + ids[2] = (size_t)ui64[2]; + ids[3] = (size_t)ui64[3]; +} + +static void +get_position(const size_t ivert, double pos[3], void* ctx) +{ + const double* dbl; + struct smsh_desc* desc = ctx; + ASSERT(desc && desc->dnode == 3); + dbl = smsh_desc_get_node(desc, ivert); + pos[0] = dbl[0]; + pos[1] = dbl[1]; + pos[2] = dbl[2]; +} + +static void +write_voxels + (FILE* stream, + const int* vxls, + const unsigned def[3], + const double vxl_sz[3], + const double org[3]) +{ + size_t ix, iy, iz; + size_t ivxl; + size_t i; + ASSERT(stream && vxls && def && def[0] && def[1] && def[2]); + + fprintf(stream, "# vtk DataFile Version 2.0\n"); + fprintf(stream, "Volumetric grid\n"); + fprintf(stream, "ASCII\n"); + + fprintf(stream, "DATASET RECTILINEAR_GRID\n"); + fprintf(stream, "DIMENSIONS %u %u %u\n", def[0]+1, def[1]+1, def[2]+1); + fprintf(stream, "X_COORDINATES %u float\n", def[0]+1); + FOR_EACH(i, 0, def[0]+1) fprintf(stream, "%g ", (double)i*vxl_sz[0] + org[0]); + fprintf(stream, "\n"); + fprintf(stream, "Y_COORDINATES %u float\n", def[1]+1); + FOR_EACH(i, 0, def[1]+1) fprintf(stream, "%g ", (double)i*vxl_sz[1] + org[1]); + fprintf(stream, "\n"); + fprintf(stream, "Z_COORDINATES %u float\n", def[2]+1); + FOR_EACH(i, 0, def[2]+1) fprintf(stream, "%g ", (double)i*vxl_sz[2] + org[2]); + fprintf(stream, "\n"); + + fprintf(stream, "CELL_DATA %u\n", def[0]*def[1]*def[2]); + fprintf(stream, "SCALARS intersect_type int 1\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + + ivxl = 0; + FOR_EACH(iz, 0, def[2]) { + FOR_EACH(iy, 0, def[1]) { + FOR_EACH(ix, 0, def[0]) { + fprintf(stream, "%i\n", vxls[ivxl]); + ++ivxl; + } + } + } +} + +static res_T +voxelize_suvm_volume + (const struct suvm_volume* vol, + const unsigned def[3], + int* vxls) +{ + double low[3], upp[3]; + double vxl_sz[3]; + size_t iprim; + size_t nprims; + int progress = 0; + res_T res = RES_OK; + ASSERT(vol && def && def[0] && def[1] && def[2] && vxls); + + /* Compute the voxel size */ + res = suvm_volume_get_aabb(vol, low, upp); + if(res != RES_OK) goto error; + vxl_sz[0] = (upp[0] - low[0]) / (double)def[0]; + vxl_sz[1] = (upp[1] - low[1]) / (double)def[1]; + vxl_sz[2] = (upp[2] - low[2]) / (double)def[2]; + + res = suvm_volume_get_primitives_count(vol, &nprims); + if(res != RES_OK) goto error; + + FOR_EACH(iprim, 0, nprims) { + struct suvm_primitive prim = SUVM_PRIMITIVE_NULL; + struct suvm_polyhedron poly; + size_t ivxl_low[3]; + size_t ivxl_upp[3]; + size_t ivxl[3]; + size_t i = 0; + int pcent; + + CHK(suvm_volume_get_primitive(vol, iprim, &prim) == RES_OK); + CHK(suvm_primitive_setup_polyhedron(&prim, &poly) == RES_OK); + + /* Transform the polyhedron AABB in voxel space */ + ivxl_low[0] = (size_t)((poly.lower[0] - low[0]) / vxl_sz[0]); + ivxl_low[1] = (size_t)((poly.lower[1] - low[1]) / vxl_sz[1]); + ivxl_low[2] = (size_t)((poly.lower[2] - low[2]) / vxl_sz[2]); + ivxl_upp[0] = (size_t)ceil((poly.upper[0] - low[0]) / vxl_sz[0]); + ivxl_upp[1] = (size_t)ceil((poly.upper[1] - low[1]) / vxl_sz[1]); + ivxl_upp[2] = (size_t)ceil((poly.upper[2] - low[2]) / vxl_sz[2]); + CHK(ivxl_low[0] < def[0] && ivxl_upp[0] <= def[0]); + CHK(ivxl_low[1] < def[1] && ivxl_upp[1] <= def[1]); + CHK(ivxl_low[2] < def[2] && ivxl_upp[2] <= def[2]); + + FOR_EACH(ivxl[2], ivxl_low[2], ivxl_upp[2]) { + float vxl_low[3]; + float vxl_upp[3]; + vxl_low[0] = (float)low[0]; + vxl_low[1] = (float)low[1]; + vxl_low[2] = (float)((double)ivxl[2] * vxl_sz[2] + low[2]); + vxl_upp[0] = (float)upp[0]; + vxl_upp[1] = (float)upp[1]; + vxl_upp[2] = vxl_low[2] + (float)vxl_sz[2]; + + FOR_EACH(ivxl[1], ivxl_low[1], ivxl_upp[1]) { + vxl_low[1] = (float)((double)ivxl[1] * vxl_sz[1] + low[1]); + vxl_upp[1] = vxl_low[1] + (float)vxl_sz[1]; + FOR_EACH(ivxl[0], ivxl_low[0], ivxl_upp[0]) { + vxl_low[0] = (float)((double)ivxl[0] * vxl_sz[0] + low[0]); + vxl_upp[0] = vxl_low[0] + (float)vxl_sz[0]; + + i = ivxl[0] + ivxl[1]*def[0] + ivxl[2]*def[0]*def[1]; + vxls[i] += (int)suvm_polyhedron_intersect_aabb(&poly, vxl_low, vxl_upp); + } + } + } + pcent = (int)((double)iprim * 100 / (double)nprims + 0.5/*round*/); + if(pcent > progress) { + progress = pcent; + fprintf(stderr, "Voxelizing: %3d%%\r", progress); + fflush(stderr); + } + } + + fprintf(stderr, "Voxelizing: %3d%%\n", progress); + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * Main functions + ******************************************************************************/ +int +main(int argc, char** argv) +{ + char dump[128]; + struct args args = ARGS_DEFAULT; + FILE* stream_out = stdout; + FILE* stream_in = stdin; + const char* stream_out_name = "stdout"; + const char* stream_in_name = "stdin"; + struct smsh* smsh = NULL; + struct smsh_create_args smsh_args = SMSH_CREATE_ARGS_DEFAULT; + struct smsh_desc desc = SMSH_DESC_NULL; + struct suvm_device* suvm = NULL; + struct suvm_volume* vol = NULL; + struct suvm_tetrahedral_mesh_args msh_args = SUVM_TETRAHEDRAL_MESH_ARGS_NULL; + struct time t0, t1; + int* vxls = NULL; + double low[3]; + double upp[3]; + double vxl_sz[3]; + res_T res = RES_OK; + int err = 0; + + res = args_init(&args, argc, argv); + if(res != RES_OK) goto error; + if(args.quit) goto exit; + + /* Setup input stream */ + if(args.input_filename) { + stream_in = fopen(args.input_filename, "r"); + if(!stream_in) { + fprintf(stderr, "Could not open the input file '%s' -- %s.\n", + args.input_filename, strerror(errno)); + goto error; + } + stream_in_name = args.input_filename; + } + + /* Setup output stream */ + if(args.output_filename) { + stream_out = fopen(args.output_filename, "w"); + if(!stream_out) { + fprintf(stderr, "Could not open the output file '%s' -- %s.\n", + args.output_filename, strerror(errno)); + goto error; + } + stream_out_name = args.output_filename; + (void)stream_out_name; + } + + + /* Load the submitted file */ + smsh_args.verbose = args.verbose; + res = smsh_create(&smsh_args, &smsh); + if(res != RES_OK) goto error; + res = smsh_load_stream(smsh, stream_in, stream_in_name); + if(res != RES_OK) goto error; + res = smsh_get_desc(smsh, &desc); + if(res != RES_OK) goto error; + if(desc.dnode != 3 || desc.dcell != 4) { + fprintf(stderr, "Only tetrahedrical mesh are supported\n"); + res = RES_BAD_ARG; + goto error; + } + if(args.verbose) { + fprintf(stderr, "#nodes: %u; #tetrahedra: %u\n", desc.dnode, desc.dcell); + } + + res = suvm_device_create(NULL, NULL, args.verbose, &suvm); + if(res != RES_OK) goto error; + + msh_args.nvertices = desc.nnodes; + msh_args.ntetrahedra = desc.ncells; + msh_args.get_indices = get_indices; + msh_args.get_position = get_position; + msh_args.context = &desc; + msh_args.precompute_normals = args.precompute_normals; + + /* Setup the volume from the loaded data */ + if(args.verbose) { + fprintf(stderr, "Partitionning the tetrahedral mesh '%s'\n", stream_in_name); + } + time_current(&t0); + res = suvm_tetrahedral_mesh_create(suvm, &msh_args, &vol); + if(res != RES_OK) goto error; + time_sub(&t0, time_current(&t1), &t0); + time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump)); + if(args.verbose) { + fprintf(stderr, "Build acceleration structure in %s\n", dump); + } + + /* Allocate the list of voxels */ + vxls = mem_calloc(args.def[0]*args.def[1]*args.def[2], sizeof(*vxls)); + if(!vxls) { + fprintf(stderr, "Could not allocate the list of voxels.\n"); + res = RES_MEM_ERR; + goto error; + } + + /* Voxelize the volume */ + time_current(&t0); + res = voxelize_suvm_volume(vol, args.def, vxls); + if(res != RES_OK) goto error; + time_sub(&t0, time_current(&t1), &t0); + time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump)); + if(args.verbose) { + fprintf(stderr, "Volume voxelized in %s\n", dump); + } + + /* Write the voxels */ + if(args.verbose) { + fprintf(stderr, "Writing voxels in '%s'\n", stream_out_name); + } + SUVM(volume_get_aabb(vol, low, upp)); + vxl_sz[0] = (upp[0] - low[0]) / (double)args.def[0]; + vxl_sz[1] = (upp[1] - low[1]) / (double)args.def[1]; + vxl_sz[2] = (upp[2] - low[2]) / (double)args.def[2]; + time_current(&t0); + write_voxels(stream_out, vxls, args.def, vxl_sz, low); + time_sub(&t0, time_current(&t1), &t0); + time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump)); + if(args.verbose) { + fprintf(stderr, "Voxels written in %s\n", dump); + } + +exit: + if(stream_out && stream_out != stdout) fclose(stream_out); + if(stream_in && stream_in != stdin) fclose(stream_in); + if(suvm) SUVM(device_ref_put(suvm)); + if(vol) SUVM(volume_ref_put(vol)); + if(smsh) SMSH(ref_put(smsh)); + if(vxls) mem_rm(vxls); + args_release(&args); + if(mem_allocated_size() != 0) { + fprintf(stderr, "Memory leaks: %lu Bytes.\n", + (unsigned long)mem_allocated_size()); + } + return err; +error: + err = -1; + goto exit; +} diff --git a/src/suvm_voxelize_sth.c b/src/suvm_voxelize_sth.c @@ -1,431 +0,0 @@ -/* Copyright (C) 2020, 2021 |Meso|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 General Public License for more details. - * - * 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 /* getopt/close support */ - -#include "suvm.h" -#include <star/sth.h> -#include <rsys/clock_time.h> -#include <rsys/cstr.h> -#include <rsys/mem_allocator.h> - -#include <string.h> -#include <unistd.h> /* getopt & close functions */ - -struct args { - const char* input_filename; - const char* output_filename; - unsigned def[3]; - int precompute_normals; - int quit; - int verbose; -}; - -static const struct args ARGS_DEFAULT = { - NULL, /* Input file */ - NULL, /* Output file */ - {64, 64, 64}, /* Definition */ - 0, /* Precompute normals */ - 0, /* Quit */ - 0 /* Verbose */ -}; - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static void -print_help(const char* cmd) -{ - ASSERT(cmd); - printf( -"Usage: %s [options] [file]\n" -"Voxelize the submitted Star-TetraHedra geometry and save the result\n" -"into a VTK file.\n", - cmd); - printf("\n"); - printf( -" -d X:Y:Z voxelisation definition along the 3 axes.\n" -" The default definition is %u:%u:%u.\n", - ARGS_DEFAULT.def[0], - ARGS_DEFAULT.def[1], - ARGS_DEFAULT.def[2]); - printf( -" -h display this help and exit.\n"); - printf( -" -n precompute the tetrahedra normals.\n"); - printf( -" -o <output> filename of the output VTK file. If not defined, write\n" -" results to standard ouput\n"); - printf( -" -v make the program verobse.\n"); - printf("\n"); - printf( -"Copyright (C) 2020, 2021 |Meso|Star> <contact@meso-star.com>.\n" -"This is free software released under the GNU GPL license, version 3 or\n" -"later. You are free to change or redistribute it under certain\n" -"conditions <http://gnu.org.licenses/gpl.html>\n"); -} - -static void -args_release(struct args* args) -{ - ASSERT(args); - *args = ARGS_DEFAULT; -} - -static res_T -args_init(struct args* args, const int argc, char** argv) -{ - size_t n; - int opt; - res_T res = RES_OK; - ASSERT(args); - - *args = ARGS_DEFAULT; - - while((opt = getopt(argc, argv, "d:hno:v")) != -1) { - switch(opt) { - case 'd': - res = cstr_to_list_uint(optarg, ':', args->def, &n, 3); - if(res == RES_OK && n != 3) res = RES_BAD_ARG; - if(!args->def[0] || !args->def[1] || !args->def[2]) res = RES_BAD_ARG; - break; - case 'h': - print_help(argv[0]); - args_release(args); - args->quit = 1; - break; - case 'n': - args->precompute_normals = 1; - break; - case 'o': - args->output_filename = optarg; - break; - case 'v': args->verbose = 1; break; - default: res = RES_BAD_ARG; break; - } - if(res != RES_OK) { - if(optarg) { - fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n", - argv[0], optarg, opt); - } - goto error; - } - } - - if(optind < argc) { - args->input_filename = argv[optind]; - } - -exit: - optind = 1; - return res; -error: - args_release(args); - goto exit; -} - -static void -get_indices(const size_t itetra, size_t ids[4], void* ctx) -{ - const uint64_t* ui64; - struct sth_desc* desc = ctx; - ASSERT(desc); - ui64 = sth_desc_get_tetrahedron_indices(desc, itetra); - ids[0] = (size_t)ui64[0]; - ids[1] = (size_t)ui64[1]; - ids[2] = (size_t)ui64[2]; - ids[3] = (size_t)ui64[3]; -} - -static void -get_position(const size_t ivert, double pos[3], void* ctx) -{ - const double* dbl; - struct sth_desc* desc = ctx; - ASSERT(desc); - dbl = sth_desc_get_vertex_position(desc, ivert); - pos[0] = dbl[0]; - pos[1] = dbl[1]; - pos[2] = dbl[2]; -} - -static void -write_voxels - (FILE* stream, - const int* vxls, - const unsigned def[3], - const double vxl_sz[3], - const double org[3]) -{ - size_t ix, iy, iz; - size_t ivxl; - size_t i; - ASSERT(stream && vxls && def && def[0] && def[1] && def[2]); - - fprintf(stream, "# vtk DataFile Version 2.0\n"); - fprintf(stream, "Volumetric grid\n"); - fprintf(stream, "ASCII\n"); - - fprintf(stream, "DATASET RECTILINEAR_GRID\n"); - fprintf(stream, "DIMENSIONS %u %u %u\n", def[0]+1, def[1]+1, def[2]+1); - fprintf(stream, "X_COORDINATES %u float\n", def[0]+1); - FOR_EACH(i, 0, def[0]+1) fprintf(stream, "%g ", (double)i*vxl_sz[0] + org[0]); - fprintf(stream, "\n"); - fprintf(stream, "Y_COORDINATES %u float\n", def[1]+1); - FOR_EACH(i, 0, def[1]+1) fprintf(stream, "%g ", (double)i*vxl_sz[1] + org[1]); - fprintf(stream, "\n"); - fprintf(stream, "Z_COORDINATES %u float\n", def[2]+1); - FOR_EACH(i, 0, def[2]+1) fprintf(stream, "%g ", (double)i*vxl_sz[2] + org[2]); - fprintf(stream, "\n"); - - fprintf(stream, "CELL_DATA %u\n", def[0]*def[1]*def[2]); - fprintf(stream, "SCALARS intersect_type int 1\n"); - fprintf(stream, "LOOKUP_TABLE default\n"); - - ivxl = 0; - FOR_EACH(iz, 0, def[2]) { - FOR_EACH(iy, 0, def[1]) { - FOR_EACH(ix, 0, def[0]) { - fprintf(stream, "%i\n", vxls[ivxl]); - ++ivxl; - } - } - } -} - -static res_T -voxelize_suvm_volume - (const struct suvm_volume* vol, - const unsigned def[3], - int* vxls) -{ - double low[3], upp[3]; - double vxl_sz[3]; - size_t iprim; - size_t nprims; - int progress = 0; - res_T res = RES_OK; - ASSERT(vol && def && def[0] && def[1] && def[2] && vxls); - - /* Compute the voxel size */ - res = suvm_volume_get_aabb(vol, low, upp); - if(res != RES_OK) goto error; - vxl_sz[0] = (upp[0] - low[0]) / (double)def[0]; - vxl_sz[1] = (upp[1] - low[1]) / (double)def[1]; - vxl_sz[2] = (upp[2] - low[2]) / (double)def[2]; - - res = suvm_volume_get_primitives_count(vol, &nprims); - if(res != RES_OK) goto error; - - FOR_EACH(iprim, 0, nprims) { - struct suvm_primitive prim = SUVM_PRIMITIVE_NULL; - struct suvm_polyhedron poly; - size_t ivxl_low[3]; - size_t ivxl_upp[3]; - size_t ivxl[3]; - size_t i = 0; - int pcent; - - CHK(suvm_volume_get_primitive(vol, iprim, &prim) == RES_OK); - CHK(suvm_primitive_setup_polyhedron(&prim, &poly) == RES_OK); - - /* Transform the polyhedron AABB in voxel space */ - ivxl_low[0] = (size_t)((poly.lower[0] - low[0]) / vxl_sz[0]); - ivxl_low[1] = (size_t)((poly.lower[1] - low[1]) / vxl_sz[1]); - ivxl_low[2] = (size_t)((poly.lower[2] - low[2]) / vxl_sz[2]); - ivxl_upp[0] = (size_t)ceil((poly.upper[0] - low[0]) / vxl_sz[0]); - ivxl_upp[1] = (size_t)ceil((poly.upper[1] - low[1]) / vxl_sz[1]); - ivxl_upp[2] = (size_t)ceil((poly.upper[2] - low[2]) / vxl_sz[2]); - CHK(ivxl_low[0] < def[0] && ivxl_upp[0] <= def[0]); - CHK(ivxl_low[1] < def[1] && ivxl_upp[1] <= def[1]); - CHK(ivxl_low[2] < def[2] && ivxl_upp[2] <= def[2]); - - FOR_EACH(ivxl[2], ivxl_low[2], ivxl_upp[2]) { - float vxl_low[3]; - float vxl_upp[3]; - vxl_low[0] = (float)low[0]; - vxl_low[1] = (float)low[1]; - vxl_low[2] = (float)((double)ivxl[2] * vxl_sz[2] + low[2]); - vxl_upp[0] = (float)upp[0]; - vxl_upp[1] = (float)upp[1]; - vxl_upp[2] = vxl_low[2] + (float)vxl_sz[2]; - - FOR_EACH(ivxl[1], ivxl_low[1], ivxl_upp[1]) { - vxl_low[1] = (float)((double)ivxl[1] * vxl_sz[1] + low[1]); - vxl_upp[1] = vxl_low[1] + (float)vxl_sz[1]; - FOR_EACH(ivxl[0], ivxl_low[0], ivxl_upp[0]) { - vxl_low[0] = (float)((double)ivxl[0] * vxl_sz[0] + low[0]); - vxl_upp[0] = vxl_low[0] + (float)vxl_sz[0]; - - i = ivxl[0] + ivxl[1]*def[0] + ivxl[2]*def[0]*def[1]; - vxls[i] += (int)suvm_polyhedron_intersect_aabb(&poly, vxl_low, vxl_upp); - } - } - } - pcent = (int)((double)iprim * 100 / (double)nprims + 0.5/*round*/); - if(pcent > progress) { - progress = pcent; - fprintf(stdout, "Voxelizing: %3d%%\r", progress); - fflush(stdout); - } - } - - printf("Voxelizing: %3d%%\n", progress); - -exit: - return res; -error: - goto exit; -} - -/******************************************************************************* - * Main functions - ******************************************************************************/ -int -main(int argc, char** argv) -{ - char dump[128]; - struct args args = ARGS_DEFAULT; - FILE* stream_out = stdout; - FILE* stream_in = stdin; - const char* stream_out_name = "stdout"; - const char* stream_in_name = "stdin"; - struct sth* sth = NULL; - struct sth_desc desc = STH_DESC_NULL; - struct suvm_device* suvm = NULL; - struct suvm_volume* vol = NULL; - struct suvm_tetrahedral_mesh_args msh_args = SUVM_TETRAHEDRAL_MESH_ARGS_NULL; - struct time t0, t1; - int* vxls = NULL; - double low[3]; - double upp[3]; - double vxl_sz[3]; - res_T res = RES_OK; - int err = 0; - - res = args_init(&args, argc, argv); - if(res != RES_OK) goto error; - if(args.quit) goto exit; - - /* Setup input stream */ - if(args.input_filename) { - stream_in = fopen(args.input_filename, "r"); - if(!stream_in) { - fprintf(stderr, "Could not open the input file '%s' -- %s.\n", - args.input_filename, strerror(errno)); - goto error; - } - stream_in_name = args.input_filename; - } - - /* Setup output stream */ - if(args.output_filename) { - stream_out = fopen(args.output_filename, "w"); - if(!stream_out) { - fprintf(stderr, "Could not open the output file '%s' -- %s.\n", - args.output_filename, strerror(errno)); - goto error; - } - stream_out_name = args.output_filename; - (void)stream_out_name; - } - - - /* Load the submitted file */ - res = sth_create(NULL, NULL, args.verbose, &sth); - if(res != RES_OK) goto error; - res = sth_load_stream(sth, stream_in, stream_in_name); - if(res != RES_OK) goto error; - res = sth_get_desc(sth, &desc); - if(res != RES_OK) goto error; - if(args.verbose) { - printf("#nodes: %lu; #tetrahedra: %lu\n", desc.nvertices, desc.ntetrahedra); - } - - res = suvm_device_create(NULL, NULL, args.verbose, &suvm); - if(res != RES_OK) goto error; - - msh_args.nvertices = desc.nvertices; - msh_args.ntetrahedra = desc.ntetrahedra; - msh_args.get_indices = get_indices; - msh_args.get_position = get_position; - msh_args.context = &desc; - msh_args.precompute_normals = args.precompute_normals; - - /* Setup the volume from the loaded data */ - if(args.verbose) { - printf("Partitionning the tetrahedral mesh '%s'\n", stream_in_name); - } - time_current(&t0); - res = suvm_tetrahedral_mesh_create(suvm, &msh_args, &vol); - if(res != RES_OK) goto error; - time_sub(&t0, time_current(&t1), &t0); - time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump)); - if(args.verbose) { - printf("Build acceleration structure in %s\n", dump); - } - - /* Allocate the list of voxels */ - vxls = mem_calloc(args.def[0]*args.def[1]*args.def[2], sizeof(*vxls)); - if(!vxls) { - fprintf(stderr, "Could not allocate the list of voxels.\n"); - res = RES_MEM_ERR; - goto error; - } - - /* Voxelize the volume */ - time_current(&t0); - res = voxelize_suvm_volume(vol, args.def, vxls); - if(res != RES_OK) goto error; - time_sub(&t0, time_current(&t1), &t0); - time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump)); - if(args.verbose) { - printf("Volume voxelized in %s\n", dump); - } - - /* Write the voxels */ - if(args.verbose) { - printf("Writing voxels in '%s'\n", stream_out_name); - } - SUVM(volume_get_aabb(vol, low, upp)); - vxl_sz[0] = (upp[0] - low[0]) / (double)args.def[0]; - vxl_sz[1] = (upp[1] - low[1]) / (double)args.def[1]; - vxl_sz[2] = (upp[2] - low[2]) / (double)args.def[2]; - time_current(&t0); - write_voxels(stream_out, vxls, args.def, vxl_sz, low); - time_sub(&t0, time_current(&t1), &t0); - time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump)); - if(args.verbose) { - printf("Voxels written in %s\n", dump); - } - -exit: - if(stream_out && stream_out != stdout) fclose(stream_out); - if(stream_in && stream_in != stdin) fclose(stream_in); - if(suvm) SUVM(device_ref_put(suvm)); - if(vol) SUVM(volume_ref_put(vol)); - if(sth) STH(ref_put(sth)); - if(vxls) mem_rm(vxls); - args_release(&args); - if(mem_allocated_size() != 0) { - fprintf(stderr, "Memory leaks: %lu Bytes.\n", - (unsigned long)mem_allocated_size()); - } - return err; -error: - err = -1; - goto exit; -} diff --git a/src/test_suvm_ball.h b/src/test_suvm_ball.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 @@ -5329,7 +5329,7 @@ const double ball_vertices[] = { -1.3397540e-01, -8.3003223e-02, -8.1768147e-02, 1.0188783e-01, -8.7012677e-02, -1.2649865e-01 }; -const size_t ball_nvertices = sizeof(ball_vertices) / sizeof(double[3]); +const size_t ball_nvertices = sizeof(ball_vertices) / (sizeof(double)*3); const size_t ball_tetrahedra[] = { 4099, 4031, 278, 4086, @@ -25032,6 +25032,6 @@ const size_t ball_tetrahedra[] = { 5157, 3404, 3494, 3391, 1380, 1381, 4890, 1429 }; -const size_t ball_ntetrahedra = sizeof(ball_tetrahedra)/sizeof(size_t[4]); +const size_t ball_ntetrahedra = sizeof(ball_tetrahedra)/(sizeof(size_t)*4); #endif /* TEST_SUVM_BALL_H */ diff --git a/src/test_suvm_box.h b/src/test_suvm_box.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 @@ -27,7 +27,7 @@ static const double box_vertices[9/*#vertices*/*3/*#coords per vertex*/] = { 1.0, 1.0, 1.0, 0.5, 0.5, 0.5 }; -static const size_t box_nverts = sizeof(box_vertices) / sizeof(double[3]); +static const size_t box_nverts = sizeof(box_vertices) / (sizeof(double)*3); /* The following array lists the indices toward the 3D vertices of each * boundary triangle. The index 8 references the vertex at the center of the @@ -46,7 +46,6 @@ static const size_t box_indices[12/*#tetras*/*4/*#indices per tetra*/] = { 2, 7, 6, 8, 7, 2, 3, 8, /* +Y */ 0, 5, 1, 8, 5, 0, 4, 8 /* -Y */ }; -static const size_t box_ntetras = sizeof(box_indices) / sizeof(size_t[4]); - +static const size_t box_ntetras = sizeof(box_indices) / (sizeof(size_t)*4); #endif /* TEST_SUVM_BOX_H */ diff --git a/src/test_suvm_device.c b/src/test_suvm_device.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/test_suvm_primitive_intersection.c b/src/test_suvm_primitive_intersection.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/test_suvm_utils.h b/src/test_suvm_utils.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 diff --git a/src/test_suvm_volume.c b/src/test_suvm_volume.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2020-2023 |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 @@ -169,12 +169,38 @@ check_volume_polyhedra(const struct suvm_volume* vol, struct mesh* msh) } static void +check_volume_mesh(const struct suvm_volume* vol, struct mesh* msh) +{ + struct suvm_mesh_desc desc = SUVM_MESH_DESC_NULL; + size_t i; + + CHK(suvm_volume_get_mesh_desc(vol, &desc) == RES_OK); + CHK(desc.nvertices == msh->nvertices); + CHK(desc.nprimitives == msh->ntetrahedra); + CHK(desc.dvertex == 3); + CHK(desc.dprimitive == 4); + + FOR_EACH(i, 0, desc.nvertices) { + CHK(desc.positions[i*3+0] == (float)msh->vertices[i*3+0]); + CHK(desc.positions[i*3+1] == (float)msh->vertices[i*3+1]); + CHK(desc.positions[i*3+2] == (float)msh->vertices[i*3+2]); + } + FOR_EACH(i, 0, desc.nprimitives) { + CHK(desc.indices[i*4+0] == (uint32_t)msh->tetrahedra[i*4+0]); + CHK(desc.indices[i*4+1] == (uint32_t)msh->tetrahedra[i*4+1]); + CHK(desc.indices[i*4+2] == (uint32_t)msh->tetrahedra[i*4+2]); + CHK(desc.indices[i*4+3] == (uint32_t)msh->tetrahedra[i*4+3]); + } +} + +static void test_tetrahedral_mesh_creation(struct suvm_device* dev) { struct mesh msh = MESH_NULL; struct suvm_tetrahedral_mesh_args args = SUVM_TETRAHEDRAL_MESH_ARGS_NULL; struct suvm_volume* vol = NULL; struct suvm_primitive prim = SUVM_PRIMITIVE_NULL; + struct suvm_mesh_desc desc = SUVM_MESH_DESC_NULL; struct suvm_polyhedron poly; size_t nprims; @@ -272,6 +298,12 @@ test_tetrahedral_mesh_creation(struct suvm_device* dev) check_volume_polyhedra(vol, &msh); + CHK(suvm_volume_get_mesh_desc(NULL, &desc) == RES_BAD_ARG); + CHK(suvm_volume_get_mesh_desc(vol, NULL) == RES_BAD_ARG); + CHK(suvm_volume_get_mesh_desc(vol, &desc) == RES_OK); + + check_volume_mesh(vol, &msh); + CHK(suvm_volume_ref_put(vol) == RES_OK); } @@ -485,6 +517,7 @@ check_hash const int has_prim_data, const int has_vert_data) { + struct suvm_mesh_desc msh_desc; void* mem = NULL; float* pos = NULL; uint32_t* ids = NULL; @@ -504,15 +537,23 @@ check_hash hash_sha256(NULL, 0, hash1); CHK(hash256_eq(hash0, hash1)); - /* Compute data size to hash. Note that SUVM align the data to hash on 64 - * bytes by padding data with null bytes if necessary */ - sz_pos = ALIGN_SIZE(msh->nvertices*sizeof(float[3]), 64u); - sz_ids = ALIGN_SIZE(msh->ntetrahedra*sizeof(uint32_t[4]), 64u); + msh_desc = SUVM_MESH_DESC_NULL; + CHK(suvm_mesh_desc_compute_hash(NULL, hash0) == RES_BAD_ARG); + CHK(suvm_mesh_desc_compute_hash(&msh_desc, NULL) == RES_BAD_ARG); + CHK(suvm_mesh_desc_compute_hash(&msh_desc, hash0) == RES_OK); + + CHK(suvm_volume_get_mesh_desc(vol, &msh_desc) == RES_OK); + CHK(suvm_mesh_desc_compute_hash(&msh_desc, hash1) == RES_OK); + CHK(!hash256_eq(hash0, hash1)); + + /* Compute data size to hash */ + sz_pos = msh->nvertices*sizeof(float[3]); + sz_ids = msh->ntetrahedra*sizeof(uint32_t[4]); if(has_prim_data) { - sz_prims = ALIGN_SIZE(msh->ntetrahedra*sizeof(size_t[4]), 64u); + sz_prims = msh->ntetrahedra*sizeof(size_t[4]); } if(has_vert_data) { - sz_verts = ALIGN_SIZE(msh->nvertices*sizeof(double[3]), 64u); + sz_verts = msh->nvertices*sizeof(double[3]); } mem = mem_calloc(1, sz_pos + sz_ids + sz_prims + sz_verts); CHK(mem != NULL); @@ -671,6 +712,7 @@ test_volume_at_cube(struct suvm_device* dev) msh.vertex_data_alignment = args.vertex_data.alignment; CHK(suvm_tetrahedral_mesh_create(dev, &args, &vol) == RES_OK); + check_volume_mesh(vol, &msh); pos[0] = 0.25; pos[1] = 0.4; @@ -821,6 +863,7 @@ test_volume_at_ball(struct suvm_device* dev) aabb_sz = d3_len(d3_sub(vec, aabb_upp, aabb_low)); CHK(suvm_tetrahedral_mesh_create(dev, &args, &vol) == RES_OK); + check_volume_mesh(vol, &msh); check_volume_polyhedra(vol, &msh);