quakeforge/libs/util/test/test-bary.c
Bill Currie 0cd6d93030 Add a function to get the barycentric coords of a point.
It "works" for lines, triangles and tetrahedrons. For lines and triangles,
it gives the barycentric coordinates of the perpendicular projection of the
point onto to features. Only tetrahedrons are guaranteed to reproduce the
original point.
2013-03-12 14:16:42 +09:00

116 lines
2.9 KiB
C

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "QF/mathlib.h"
#include "QF/mersenne.h"
#include "QF/sys.h"
vec3_t points[] = {
{-1, -1, 1},
{ 1, 1, 1},
{-1, 1, -1},
{ 1, -1, -1},
{-1, -1, -1},
{ 1, 1, -1},
{-1, 1, 1},
{ 1, -1, 1},
{ 0, 0, 0},
};
const vec_t *line[] = {points[0], points[1]};
const vec_t *tri[] = {points[0], points[1], points[2]};
const vec_t *tetra[] = {points[0], points[1], points[2], points[3]};
struct {
const vec_t **points;
int num_points;
vec_t *x;
vec_t expect[4];
} tests[] = {
{line, 2, points[0], {1, 0}},
{line, 2, points[1], {0, 1}},
{line, 2, points[2], {0.5, 0.5}},
{line, 2, points[3], {0.5, 0.5}},
{line, 2, points[8], {0.5, 0.5}},
{tri, 3, points[0], {1, 0, 0}},
{tri, 3, points[1], {0, 1, 0}},
{tri, 3, points[2], {0, 0, 1}},
{tri, 3, points[3], {0.333333284, 0.333333333, 0.333333333}},//rounding :P
{tri, 3, points[8], {0.333333284, 0.333333333, 0.333333333}},//rounding :P
{tetra, 4, points[0], {1, 0, 0, 0}},
{tetra, 4, points[1], {0, 1, 0, 0}},
{tetra, 4, points[2], {0, 0, 1, 0}},
{tetra, 4, points[3], {0, 0, 0, 1}},
{tetra, 4, points[4], { 0.5, -0.5, 0.5, 0.5}},
{tetra, 4, points[5], {-0.5, 0.5, 0.5, 0.5}},
{tetra, 4, points[6], { 0.5, 0.5, 0.5, -0.5}},
{tetra, 4, points[7], { 0.5, 0.5, -0.5, 0.5}},
{tetra, 4, points[8], {0.25, 0.25, 0.25, 0.25}},
};
#define num_tests (sizeof (tests) / sizeof (tests[0]))
static inline float
rnd (mtstate_t *mt)
{
union {
uint32_t u;
float f;
} uf;
do {
uf.u = mtwist_rand (mt) & 0x3fffffff;
} while (!uf.u);
return uf.f - 1.0;
}
int
main (int argc, const char **argv)
{
int res = 0;
size_t i;
int j;
vec_t lambda[4];
mtstate_t mt;
double start, end;
for (i = 0; i < num_tests; i ++) {
BarycentricCoords (tests[i].points, tests[i].num_points, tests[i].x,
lambda);
for (j = 0; j < tests[i].num_points; j++) {
if (tests[i].expect[j] != lambda[j])
break;
}
if (j != tests[i].num_points) {
res = 1;
printf ("test %d failed\n", (int) i);
printf ("expect:");
for (j = 0; j < tests[i].num_points; j++)
printf (" %.9g", tests[i].expect[j]);
printf ("\ngot :");
for (j = 0; j < tests[i].num_points; j++)
printf (" %.9g", lambda[j]);
printf ("\n");
}
}
mtwist_seed (&mt, 0);
start = Sys_DoubleTime ();
for (i = 0; i < 1000000; i++) {
vec3_t p, x;
VectorSet (rnd (&mt), rnd (&mt), rnd (&mt), p);
BarycentricCoords (tetra, 4, p, lambda);
VectorZero (x);
for (j = 0; j < 4; j++)
VectorMultAdd (x, lambda[j], tetra[j], x);
if (VectorDistance_fast (x, p) > 1e-4) {
res = 1;
printf ("[%.9g %.9g %.9g] != [%.9g %.9g %.9g]: [%g %g %g %g]\n",
VectorExpand (x), VectorExpand (p), QuatExpand (lambda));
break;
}
}
end = Sys_DoubleTime ();
printf ("%d itterations in %gs: %g itters/second\n", (int) i, end - start,
i / (end - start));
return res;
}