star-sp

Random number generators and distributions
git clone git://git.meso-star.fr/star-sp.git
Log | Files | Refs | README | LICENSE

commit 6ff800d59f21902c621b04a86d2ab7ad0b7bc4bc
parent 958cefa602645282b4ac22fcd1fc2f689a6c7f37
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Tue, 24 Sep 2019 16:59:06 +0200

Add uniform sampling in a tetrahedron

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/ssp.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ssp_ran.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_ssp_ran_tetrahedron.c | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/test_ssp_ran_tetrahedron.h | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 348 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -180,6 +180,7 @@ if(NOT NO_TEST) new_test(test_ssp_ran_sphere ${MATH_LIB}) new_test(test_ssp_ran_sphere_cap ${MATH_LIB}) new_test(test_ssp_ran_triangle ${MATH_LIB}) + new_test(test_ssp_ran_tetrahedron ${MATH_LIB}) new_test(test_ssp_ran_uniform_disk) rcmake_copy_runtime_libraries(test_ssp_rng) endif() diff --git a/src/ssp.h b/src/ssp.h @@ -465,6 +465,63 @@ ssp_ran_triangle_uniform_float_pdf } /******************************************************************************* + * Tetrahedron distribution + ******************************************************************************/ + /* Uniform sampling of a tetrahedron */ +SSP_API double* +ssp_ran_tetrahedron_uniform + (struct ssp_rng* rng, + const double v0[3], /* Position of the 1st vertex */ + const double v1[3], /* Position of the 2nd vertex */ + const double v2[3], /* Position of the 3rd vertex */ + const double v3[3], /* Position of the 4th vertex */ + double sample[3], /* Sampled position */ + double* pdf); /* Can be NULL => pdf not computed */ + +SSP_API float* +ssp_ran_tetrahedron_uniform_float + (struct ssp_rng* rng, + const float v0[3], /* Position of the 1st vertex */ + const float v1[3], /* Position of the 2nd vertex */ + const float v2[3], /* Position of the 3rd vertex */ + const float v3[3], /* Position of the 4th vertex */ + float sample[3], /* Sampled position */ + float* pdf); /* Can be NULL => pdf not computed */ + +/* Return the probability distribution for a uniform point sampling in a tetrahedron */ +static INLINE double +ssp_ran_tetrahedron_uniform_pdf + (const double v0[3], + const double v1[3], + const double v2[3], + const double v3[3]) +{ + double vec0[3], vec1[3], vec2[3], tmp[3]; + ASSERT(v0 && v1 && v2 && v3); + + d3_sub(vec0, v1, v2); + d3_sub(vec1, v3, v2); + d3_sub(vec2, v0, v2); + return 6 / fabs(d3_dot(d3_cross(tmp, vec0, vec1), vec2)); +} + +static INLINE float +ssp_ran_tetrahedron_uniform_float_pdf + (const float v0[3], + const float v1[3], + const float v2[3], + const float v3[3]) +{ + float vec0[3], vec1[3], vec2[3], tmp[3]; + ASSERT(v0 && v1 && v2 && v3); + + f3_sub(vec0, v1, v2); + f3_sub(vec1, v3, v2); + f3_sub(vec2, v0, v2); + return 6 / fabsf(f3_dot(f3_cross(tmp, vec0, vec1), vec2)); +} + +/******************************************************************************* * Hemisphere distribution ******************************************************************************/ /* Uniform sampling of an unit hemisphere whose up direction is implicitly the diff --git a/src/ssp_ran.c b/src/ssp_ran.c @@ -291,6 +291,94 @@ ssp_ran_triangle_uniform_float } double* +ssp_ran_tetrahedron_uniform + (struct ssp_rng* rng, + const double v0[3], + const double v1[3], + const double v2[3], + const double v3[3], + double sample[3], + double* pdf) +{ + double a, s, t, u; /* Barycentric coordinates of the sampled point. */ + double tmp0[3], tmp1[3], tmp2[3], tmp3[3], tmp4[3], tmp5[3]; + ASSERT(rng && v0 && v1 && v2 && v3 && sample); + + s = ssp_rng_canonical(rng); + t = ssp_rng_canonical(rng); + u = ssp_rng_canonical(rng); + + if (s + t > 1) { /* Cut and fold the cube into a prism */ + s = 1 - s; + t = 1 - t; + } + if (t + u > 1) { /* Cut and fold the prism into a tetrahedron */ + double swp = u; + u = 1 - s - t; + t = 1 - swp; + } + else if (s + t + u > 1) { + double swp = u; + u = s + t + u - 1; + s = 1 - t - swp; + } + a = 1 - s - t - u; + + d3_add(sample, + d3_add(tmp4, d3_muld(tmp0, v0, a), d3_muld(tmp1, v1, s)), + d3_add(tmp5, d3_muld(tmp2, v2, t), d3_muld(tmp3, v3, u))); + + if (pdf) + *pdf = ssp_ran_tetrahedron_uniform_pdf(v0, v1, v2, v3); + + return sample; +} + +float* +ssp_ran_tetrahedron_uniform_float + (struct ssp_rng* rng, + const float v0[3], + const float v1[3], + const float v2[3], + const float v3[3], + float sample[3], + float* pdf) +{ + float a, s, t, u; /* Barycentric coordinates of the sampled point. */ + float tmp0[3], tmp1[3], tmp2[3], tmp3[3], tmp4[3], tmp5[3]; + ASSERT(rng && v0 && v1 && v2 && v3 && sample); + + s = ssp_rng_canonical_float(rng); + t = ssp_rng_canonical_float(rng); + u = ssp_rng_canonical_float(rng); + + if (s + t > 1) { /* Cut and fold the cube into a prism */ + s = 1 - s; + t = 1 - t; + } + if (t + u > 1) { /* Cut and fold the prism into a tetrahedron */ + float swp = u; + u = 1 - s - t; + t = 1 - swp; + } + else if (s + t + u > 1) { + float swp = u; + u = s + t + u - 1; + s = 1 - t - swp; + } + a = 1 - s - t - u; + + f3_add(sample, + f3_add(tmp4, f3_mulf(tmp0, v0, a), f3_mulf(tmp1, v1, s)), + f3_add(tmp5, f3_mulf(tmp2, v2, t), f3_mulf(tmp3, v3, u))); + + if (pdf) + *pdf = ssp_ran_tetrahedron_uniform_float_pdf(v0, v1, v2, v3); + + return sample; +} + +double* ssp_ran_hemisphere_uniform_local (struct ssp_rng* rng, double sample[3], diff --git a/src/test_ssp_ran_tetrahedron.c b/src/test_ssp_ran_tetrahedron.c @@ -0,0 +1,42 @@ +/* Copyright (C) |Meso|Star> 2015-2018 (contact@meso-star.com) + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#define TYPE_FLOAT 1 +#include "test_ssp_ran_tetrahedron.h" + +#define TYPE_FLOAT 0 +#include "test_ssp_ran_tetrahedron.h" + +int +main(int argc, char** argv) +{ + (void)argc, (void)argv; + test_float(); + test_double(); + return 0; +} diff --git a/src/test_ssp_ran_tetrahedron.h b/src/test_ssp_ran_tetrahedron.h @@ -0,0 +1,160 @@ +/* Copyright (C) |Meso|Star> 2015-2018 (contact@meso-star.com) + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#ifndef TEST_SSP_RAN_TETRA_H +#define TEST_SSP_RAN_TETRA_H + +#include "ssp.h" +#include "test_ssp_utils.h" + +#include <rsys/float4.h> + +#define NSAMPS 128 + +#endif /* TEST_SSP_RAN_TETRA_H */ + +#if TYPE_FLOAT==0 + #define REAL double + #define TEST test_double + #define RNG_UNIFORM_R ssp_rng_uniform_double + #define RAN_TETRA_UNIFORM ssp_ran_tetrahedron_uniform + #define RAN_TETRA_UNIFORM_PDF ssp_ran_tetrahedron_uniform_pdf + #define EQ_EPS_R eq_eps + #define FABS_R fabs + #define R3 d3 + #define R3_DOT d3_dot + #define R3_SUB d3_sub + #define R3_MINUS d3_minus + #define R3_CROSS d3_cross + #define R3_LEN d3_len + +#elif TYPE_FLOAT==1 + #define REAL float + #define TEST test_float + #define RNG_UNIFORM_R ssp_rng_uniform_float + #define RAN_TETRA_UNIFORM ssp_ran_tetrahedron_uniform_float + #define RAN_TETRA_UNIFORM_PDF ssp_ran_tetrahedron_uniform_float_pdf + #define EQ_EPS_R eq_epsf + #define FABS_R fabsf + #define R3 f3 + #define R3_DOT f3_dot + #define R3_SUB f3_sub + #define R3_MINUS f3_minus + #define R3_CROSS f3_cross + #define R3_LEN f3_len + +#else + #error "TYPE_FLOAT must be defined either 0 or 1" +#endif + +static void +TEST() +{ + struct ssp_rng* rng; + struct mem_allocator allocator; + REAL samps[NSAMPS][3]; + REAL A[3], B[3], C[3], D[3]; + REAL v0[3], v1[3], v2[3], v3[3], v4[3]; + REAL in0[3], in1[3], in2[3], in3[3]; + REAL pdf[NSAMPS]; + size_t i, j; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + + FOR_EACH(j, 0, 100) { + FOR_EACH(i, 0, 3) { + A[i] = RNG_UNIFORM_R(rng, 0, 1); + B[i] = RNG_UNIFORM_R(rng, 0, 1); + C[i] = RNG_UNIFORM_R(rng, 0, 1); + D[i] = RNG_UNIFORM_R(rng, 0, 1); + } + + R3_SUB(v0, B, A); + R3_SUB(v1, C, A); + R3_SUB(v2, C, B); + R3_SUB(v3, D, A); + R3_SUB(v4, D, C); + /* Inward vectors perpandicular to faces */ + R3_CROSS(in0, v0, v1); + if (R3_DOT(in0, v3) < 0) R3_MINUS(in0, in0); + R3_CROSS(in1, v1, v3); + if (R3_DOT(in1, v0) < 0) R3_MINUS(in1, in1); + R3_CROSS(in2, v3, v0); + if (R3_DOT(in2, v1) < 0) R3_MINUS(in2, in2); + R3_CROSS(in3, v2, v4); + if (R3_DOT(in3, v3) > 0) R3_MINUS(in3, in3); + + FOR_EACH(i, 0, NSAMPS) { + REAL X[3], tmp[3]; + REAL dot = 0; + REAL vol = 0; + + CHK(RAN_TETRA_UNIFORM(rng, A, B, C, D, samps[i], &pdf[i]) == samps[i]); + + /* Check sample is in the tetrahedron */ + R3_SUB(X, samps[i], A); + dot = R3_DOT(X, in0); + CHK(sign(dot) == 1); + dot = R3_DOT(X, in1); + CHK(sign(dot) == 1); + dot = R3_DOT(X, in2); + CHK(sign(dot) == 1); + dot = R3_DOT(X, in3); + CHK(sign(dot) == -1); + + /* Check pdf */ + vol = FABS_R(R3_DOT(R3_CROSS(tmp, v0, v1), v3)) / 6; + CHK(EQ_EPS_R(pdf[i], RAN_TETRA_UNIFORM_PDF(A, B, C, D), (REAL)1.e-8) == 1); + /* Pdf is 1/vol + * But numerical value depends on the vector used to compute it */ + CHK(EQ_EPS_R(vol * pdf[i], 1, (REAL)1.e-5) == 1); + } + } + + ssp_rng_ref_put(rng); + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); +} + +#undef REAL +#undef TEST +#undef RNG_UNIFORM_R +#undef RAN_TETRA_UNIFORM +#undef RAN_TETRA_UNIFORM_PDF +#undef EQ_EPS_R +#undef FABS_R +#undef R3 +#undef R3_DOT +#undef R3_SUB +#undef R3_MINUS +#undef R3_CROSS +#undef R3_LEN +#undef TYPE_FLOAT