mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-13 08:27:39 +00:00
0cd6d93030
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.
116 lines
2.9 KiB
C
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;
|
|
}
|