/*
* goc.c
* Copyright (C) 2008, 2009 Tomasz Koziara (t.koziara AT gmail.com)
* -------------------------------------------------------------------
* geometric object contact detection
*/
/* This file is part of Solfec.
* Solfec is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Solfec 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 Solfec. If not, see . */
#include
#include
#include "alg.h"
#include "box.h"
#include "msh.h"
#include "cvx.h"
#include "sph.h"
#include "cvi.h"
#include "gjk.h"
#include "goc.h"
#include "err.h"
#define MAGNIFY 10.0 /* contact is lost if gap >= GEOMETRIC_EPSILON * MAGNIFY */
/* line-plane intersection => intersection = point + direction * coef if 1 is returned */
inline static int lineplane (double *plane, double *point, double *direction, double *coef)
{
double d;
d = DOT (plane, direction);
if (fabs (d) < GEOMETRIC_EPSILON * MAGNIFY) return 0; /* the penalty solver is sensitice to ill-computed gaps, hece our caution */
*coef = - PLANE (plane, point) / d;
return 1;
}
/* compute semi-negative penetration gap from surface triangles */
inline static double convex_convex_gap (TRI *tri, int m, double *point, double *normal)
{
double plane [4],
min = DBL_MAX,
max = -min,
coef;
for (; m > 0; tri ++, m --)
{
COPY (tri->out, plane);
plane [3] = - DOT (plane, tri->ver [0]);
if (lineplane (plane, point, normal, &coef))
{
if (coef < min) min = coef;
if (coef > max) max = coef;
}
}
return (min < 0 && max > 0 ? min - max : 0);
}
/* compute semi-negative convex-sphere gap */
inline static double convex_sphere_gap (double *pla, int npla, double *center, double radius, double *normal)
{
double plane [4],
max = -DBL_MAX,
coef;
for (; npla > 0; pla += 6, npla --)
{
COPY (pla, plane);
plane [3] = - DOT (plane, pla+3);
if (lineplane (plane, center, normal, &coef))
{
if (coef > max) max = coef;
}
}
max = fabs (max);
return (radius > max ? max - radius : 0);
}
/* compute semi-negative sphere-sphere gap */
inline static double sphere_sphere_gap (double *ca, double ra, double *cb, double rb, double *normal)
{
double x [3], d, e;
SUB (cb, ca, x);
d = DOT (x, normal);
e = ra + rb;
return (e > d ? d - e : 0);
}
/* return a surface code with the input point closest to an input plane */
inline static int nearest_surface (double *pnt, double *pla, int *sur, int n)
{
double v [3], d, min = DBL_MAX;
int ret = sur [0];
for (; n > 0; n --, pla += 6, sur ++)
{
SUB (pnt, pla+3, v);
d = DOT (pla, v);
if (fabs (d) < min)
{
min = d;
ret = *sur;
}
}
return ret;
}
/* compute average point and resultant normal; return normal variance */
inline static double point_and_normal (int negative, TRI *tri, int m,
int *surf, int nsurf, double *point, double *normal, double *area, int *sout)
{
double a, v [3], p [3], dots, max;
TRI *t, *e;
int k;
max = -DBL_MAX;
SET (v, 0.0);
SET (point, 0.0);
SET (normal, 0.0);
*area = 0.0;
dots = 0.0;
for (t = tri, e = t + m; t != e; t ++)
{
if ((negative && t->flg < 0) ||
(!negative && t->flg > 0))
{
TRIANGLE_AREA (t->ver[0], t->ver[1], t->ver[2], a);
SCALE (t->out, a); /* scale here and reuse there (#) */
ADD (normal, t->out, normal); /* resultant normal */
MID3 (t->ver[0], t->ver[1], t->ver[2], v); /* triangle midpoint */
ADDMUL (point, a, v, point); /* integrate */
*area += a;
if (a > max)
{
k = ABS (t->flg) - 1;
ASSERT_DEBUG (k >= 0, "A negative face index: %d\n", k);
if (k < nsurf) (*sout) = surf [k]; /* identifier of surface with maximal area */
else (*sout) = INT_MAX; /* set an invalid index */
max = a;
}
}
}
DIV (point, *area, point); /* point as surface mass center */
TRI_Char (tri, m, p); /* point as volume mass center */
for (t = tri, e = t + m; t != e; t ++)
{
SUB (t->ver [0], p, v);
if (DOT (t->out, v) < 0.0) break; /* test whether it falls outside */
}
if (t == e) /* does not fall outside of the volume */
{
COPY (p, point); /* use volumetric point instead */
}
for (t = tri, e = t + m; t != e; t ++) /* compute normal variance */
{
if ((negative && t->flg < 0) ||
(!negative && t->flg > 0))
{
SUB (t->out, normal, v); /* (#) scaling reused here */
dots += DOT (v, v);
}
}
return dots;
}
/* detect contact between two convex polyhedrons 'a' and 'b', where
* va, nva, vb, nbv: vertices and vertex counts
* pa, npa, pb, npb: 6-coord planes (normal, point) and plane counts
* sa, nsa, sb, nsb: surface identifiers and surface planes counts
* (the first nsa, nsb planes are on the surface)
* ----------------------------------------------------------------
* ramaining paramteres behave like in gobjcontact routine
*/
static int detect_convex_convex (
double *va, int nva, double *pa, int npa, int *sa, int nsa,
double *vb, int nvb, double *pb, int npb, int *sb, int nsb,
double onepnt [3],
double twopnt [3],
double normal [3],
double *gap,
double *area,
int spair [2])
{
double a, b, an [3], bn [3], ap [3], bp [3], aa, ba, sanity;
TRI *tri;
int m;
*gap = gjk (va, nva, vb, nvb, onepnt, twopnt);
if (*gap < GEOMETRIC_EPSILON)
{
if (!(tri = cvi (va, nva, pa, npa, vb, nvb, pb, npb, NON_REGULARIZED, &m))) return 0;
a = point_and_normal (0, tri, m, sa, nsa, ap, an, &aa, &spair [0]);
b = point_and_normal (1, tri, m, sb, nsb, bp, bn, &ba, &spair [1]);
if (a < b)
{
NORMALIZE (an);
COPY (an, normal);
COPY (ap, onepnt);
COPY (ap, twopnt);
*area = aa;
*gap = convex_convex_gap (tri, m, ap, an);
free (tri);
sanity = (ap[0]+ap[1]+ap[2]+an[0]+an[1]+an[2]+aa+(*gap));
if (!isfinite (sanity)) return 0;
else return 1;
}
else
{
NORMALIZE (bn);
COPY (bn, normal);
COPY (bp, onepnt);
COPY (bp, twopnt);
*area = ba;
*gap = convex_convex_gap (tri, m, bp, bn);
free (tri);
sanity = (bp[0]+bp[1]+bp[2]+bn[0]+bn[1]+bn[2]+ba+(*gap));
if (!isfinite (sanity)) return 0;
else return 2;
}
}
return 0;
}
/* detect contact between a convex and a sphere */
static int detect_convex_sphere (
double *vc, int nvc, double *pc, int npc, int *sc, int nsc, /* same as above */
double *c, double r, int s, /* center, radius, surface */
double onepnt [3],
double twopnt [3],
double normal [3],
double *gap,
double *area,
int spair [2])
{
double g, h;
if (gjk_convex_sphere (vc, nvc, c, r, onepnt, twopnt) < GEOMETRIC_EPSILON)
{
for (h = r; g < GEOMETRIC_EPSILON && h > GEOMETRIC_EPSILON; h *= 0.5)
g = gjk_convex_sphere (vc, nvc, c, h, onepnt, twopnt); /* shrink sphere and redo => find projection
of the sphere center on the convex surface */
SUB (c, onepnt, normal);
NORMALIZE (normal);
ADDMUL (c, -r, normal, twopnt);
spair [0] = nearest_surface (onepnt, pc, sc, nsc);
spair [1] = s;
*area = 1.0;
*gap = convex_sphere_gap (pc, npc, c, r, normal);
return 1;
}
return 0;
}
/* compare two points */
inline static int pntcmp (double *a, double *b)
{
for (int i = 0; i < 3 ; i ++)
{
if (a [i] < b [i]) return -1;
else if (a [i] > b [i]) return 1;
}
return 0;
}
/* detect contact between spheres 'a' and 'b' */
static int detect_sphere_sphere (
double *ca, double ra, int sa, /* center, radius, surface */
double *cb, double rb, int sb,
double onepnt [3],
double twopnt [3],
double normal [3],
double *gap,
double *area,
int spair [2])
{
if (((*gap) = gjk_sphere_sphere (ca, ra, cb, rb, onepnt, twopnt)) < GEOMETRIC_EPSILON)
{
spair [0] = sa;
spair [1] = sb;
*area = 1.0;
if (pntcmp (ca, cb) <= 0) /* same normal orientation regardless of sphere processing order */
{
SUB (onepnt, ca, normal);
NORMALIZE (normal);
*gap = sphere_sphere_gap (ca, ra, cb, rb, normal);
return 1;
}
else
{
SUB (twopnt, cb, normal);
NORMALIZE (normal);
*gap = sphere_sphere_gap (cb, rb, ca, ra, normal);
return 2;
}
}
return 0;
}
/* update contact between two convex polyhedrons 'a' and 'b', where
* va, nva, vb, nbv: vertices and vertex counts
* pa, npa, pb, npb: 6-coord planes (normal, point) and plane counts
* sa, nsa, sb, nsb: surface identifiers and surface planes counts
* (the first nsa, nsb planes are on the surface)
* ----------------------------------------------------------------
* ramaining paramteres behave like in gobjcontact routine
*/
static int update_convex_convex (
double *va, int nva, double *pa, int npa, int *sa, int nsa,
double *vb, int nvb, double *pb, int npb, int *sb, int nsb,
double onepnt [3],
double twopnt [3],
double normal [3], /* outward with restpect to the 'a' body (master) */
double *gap,
double *area,
int spair [2])
{
double a, b, an [3], bn [3], ap [3], bp [3], aa, ba, sanity;
int s [2];
TRI *tri;
int m;
*gap = gjk (va, nva, vb, nvb, onepnt, twopnt);
if (*gap < GEOMETRIC_EPSILON)
{
if (!(tri = cvi (va, nva, pa, npa, vb, nvb, pb, npb, NON_REGULARIZED, &m))) return 0;
s [0] = spair [0];
s [1] = spair [1];
a = point_and_normal (0, tri, m, sa, nsa, ap, an, &aa, &spair [0]);
b = point_and_normal (1, tri, m, sb, nsb, bp, bn, &ba, &spair [1]);
NORMALIZE (an);
COPY (an, normal);
COPY (ap, onepnt);
COPY (ap, twopnt);
*area = aa;
*gap = convex_convex_gap (tri, m, ap, an);
free (tri);
sanity = (ap[0]+ap[1]+ap[2]+an[0]+an[1]+an[2]+aa+(*gap));
if (!isfinite (sanity)) return 0;
else if (s [0] == spair [0] && s [1] == spair [1]) return 1;
else return 2;
}
else if (*gap < GEOMETRIC_EPSILON * MAGNIFY)
{
SUB (twopnt, onepnt, normal);
NORMALIZE (normal);
s [0] = spair [0];
s [1] = spair [1];
spair [0] = nearest_surface (onepnt, pa, sa, nsa);
spair [1] = nearest_surface (onepnt, pb, sb, nsb);
sanity = (normal[0]+normal[1]+normal[2]+(*gap));
if (!isfinite (sanity)) return 0;
else if (s [0] == spair [0] && s [1] == spair [1]) return 1;
else return 2;
}
return 0;
}
/* update contact between a convex and a sphere */
static int update_convex_sphere (
double *vc, int nvc, double *pc, int npc, int *sc, int nsc, /* same as above */
double *c, double r, int s, /* center, radius, surface */
double onepnt [3],
double twopnt [3],
double normal [3],
double *gap,
double *area,
int spair [2])
{
double g, h;
int s0;
if (((*gap) = gjk_convex_sphere (vc, nvc, c, r, onepnt, twopnt)) < GEOMETRIC_EPSILON * MAGNIFY)
{
for (h = r, g = *gap; g < GEOMETRIC_EPSILON && h > GEOMETRIC_EPSILON; h *= 0.5)
g = gjk_convex_sphere (vc, nvc, c, h, onepnt, twopnt); /* shrink sphere and redo => find projection
of the sphere center on the convex surface */
SUB (c, onepnt, normal);
NORMALIZE (normal);
ADDMUL (c, -r, normal, twopnt);
s0 = spair [0];
spair [0] = nearest_surface (onepnt, pc, sc, nsc);
if ((*gap) < GEOMETRIC_EPSILON)
*gap = convex_sphere_gap (pc, npc, c, r, normal);
if (s0 == spair [0]) return 1;
else return 2;
}
return 0;
}
/* update contact between spheres 'a' and 'b' */
static int update_sphere_sphere (
double *ca, double ra, int sa, /* center, radius, surface */
double *cb, double rb, int sb,
double onepnt [3],
double twopnt [3],
double normal [3],
double *gap,
double *area,
int spair [2])
{
if (((*gap) = gjk_sphere_sphere (ca, ra, cb, rb, onepnt, twopnt)) < GEOMETRIC_EPSILON * MAGNIFY)
{
SUB (onepnt, ca, normal);
NORMALIZE (normal);
if ((*gap) < GEOMETRIC_EPSILON)
*gap = sphere_sphere_gap (ca, ra, cb, rb, normal);
return 1;
}
return 0;
}
/* initialize convex a convex representation */
inline static void convex_init (CONVEX *cvx, double **v, int *nv, double **p, int *np, int **s, int *ns)
{
*v = cvx->cur;
*nv = cvx->nver;
*p = CONVEX_Planes (cvx);
*np = cvx->nfac;
*s = cvx->surface;
*ns = cvx->nfac;
}
/* finalize a convex representation */
inline static void convex_done (CONVEX *cvx, double **v, int *nv, double **p, int *np, int **s, int *ns)
{
free (*p);
}
/* swap surface pairs */
inline static void swap (int spair [2])
{
int tmp = spair [0];
spair [0] = spair [1];
spair [1] = tmp;
}
/* swap back surface pair and swap renturn value */
inline static int detect_swap (int ret, int spair [2])
{
int tmp = spair [0];
spair [0] = spair [1];
spair [1] = tmp;
return (ret == 1 ? 2 : (ret == 2 ? 1 : 0));
}
/* swap back surface pair and copy return */
inline static int update_swap (int ret, int spair [2])
{
int tmp = spair [0];
spair [0] = spair [1];
spair [1] = tmp;
return ret;
}
/* detect contact */
static int detect (
short paircode,
SHAPE *oneshp, void *onegobj,
SHAPE *twoshp, void *twogobj,
double onepnt [3],
double twopnt [3],
double normal [3],
double *gap,
double *area,
int spair [2])
{
switch (paircode)
{
case AABB_ELEMENT_ELEMENT:
{
double va [24], pa [36],
vb [24], pb [36];
int nva, npa, sa [6], nsa,
nvb, npb, sb [6], nsb;
nva = ELEMENT_Vertices (oneshp->data, onegobj, va);
npa = ELEMENT_Planes (oneshp->data, onegobj, pa, sa, &nsa);
nvb = ELEMENT_Vertices (twoshp->data, twogobj, vb);
npb = ELEMENT_Planes (twoshp->data, twogobj, pb, sb, &nsb);
return detect_convex_convex (va, nva, pa, npa, sa, nsa,
vb, nvb, pb, npb, sb, nsb,
onepnt, twopnt, normal,
gap, area, spair);
}
break;
case AABB_CONVEX_CONVEX:
{
double *va, *pa,
*vb, *pb;
int nva, npa, *sa, nsa,
nvb, npb, *sb, nsb,
ret;
convex_init (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
convex_init (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
ret = detect_convex_convex (va, nva, pa, npa, sa, nsa,
vb, nvb, pb, npb, sb, nsb,
onepnt, twopnt, normal,
gap, area, spair);
convex_done (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
convex_done (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
return ret;
}
break;
case AABB_SPHERE_SPHERE:
{
SPHERE *a = onegobj,
*b = twogobj;
return detect_sphere_sphere (a->cur_center, a->cur_radius, a->surface,
b->cur_center, b->cur_radius, b->surface,
onepnt, twopnt, normal,
gap, area, spair);
}
break;
case AABB_ELEMENT_CONVEX:
{
double va [24], pa [36],
*vb, *pb;
int nva, npa, sa [6], nsa,
nvb, npb, *sb, nsb,
ret;
nva = ELEMENT_Vertices (oneshp->data, onegobj, va);
npa = ELEMENT_Planes (oneshp->data, onegobj, pa, sa, &nsa);
convex_init (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
ret = detect_convex_convex (va, nva, pa, npa, sa, nsa,
vb, nvb, pb, npb, sb, nsb,
onepnt, twopnt, normal,
gap, area, spair);
convex_done (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
return ret;
}
break;
case AABB_CONVEX_ELEMENT:
{
double *va, *pa,
vb [24], pb [36];
int nva, npa, *sa, nsa,
nvb, npb, sb [6], nsb,
ret;
convex_init (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
nvb = ELEMENT_Vertices (twoshp->data, twogobj, vb);
npb = ELEMENT_Planes (twoshp->data, twogobj, pb, sb, &nsb);
ret = detect_convex_convex (va, nva, pa, npa, sa, nsa,
vb, nvb, pb, npb, sb, nsb,
onepnt, twopnt, normal,
gap, area, spair);
convex_done (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
return ret;
}
break;
case AABB_ELEMENT_SPHERE:
{
double va [24], pa [36];
int nva, npa, sa [6], nsa;
SPHERE *b = twogobj;
nva = ELEMENT_Vertices (oneshp->data, onegobj, va);
npa = ELEMENT_Planes (oneshp->data, onegobj, pa, sa, &nsa);
return detect_convex_sphere (va, nva, pa, npa, sa, nsa,
b->cur_center, b->cur_radius, b->surface,
onepnt, twopnt, normal,
gap, area, spair);
}
break;
case AABB_SPHERE_ELEMENT:
{
SPHERE *a = onegobj;
double vb [24], pb [36];
int nvb, npb, sb [6], nsb,
ret;
nvb = ELEMENT_Vertices (twoshp->data, twogobj, vb);
npb = ELEMENT_Planes (twoshp->data, twogobj, pb, sb, &nsb);
swap (spair);
ret = detect_convex_sphere (vb, nvb, pb, npb, sb, nsb,
a->cur_center, a->cur_radius, a->surface,
twopnt, onepnt, normal,
gap, area, spair);
return detect_swap (ret, spair);
}
break;
case AABB_CONVEX_SPHERE:
{
double *va, *pa;
SPHERE *b = twogobj;
int nva, npa, *sa, nsa,
ret;
convex_init (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
ret = detect_convex_sphere (va, nva, pa, npa, sa, nsa,
b->cur_center, b->cur_radius, b->surface,
onepnt, twopnt, normal,
gap, area, spair);
convex_done (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
return ret;
}
break;
case AABB_SPHERE_CONVEX:
{
SPHERE *a = onegobj;
double *vb, *pb;
int nvb, npb, *sb, nsb,
ret;
convex_init (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
swap (spair);
ret = detect_convex_sphere (vb, nvb, pb, npb, sb, nsb,
a->cur_center, a->cur_radius, a->surface,
twopnt, onepnt, normal,
gap, area, spair);
convex_done (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
return detect_swap (ret, spair);
}
break;
}
return 0;
}
/* update contact */
static int update (
short paircode,
SHAPE *oneshp, void *onegobj,
SHAPE *twoshp, void *twogobj,
double onepnt [3],
double twopnt [3],
double normal [3],
double *gap,
double *area,
int spair [2])
{
switch (paircode)
{
case AABB_ELEMENT_ELEMENT:
{
double va [24], pa [36],
vb [24], pb [36];
int nva, npa, sa [6], nsa,
nvb, npb, sb [6], nsb;
nva = ELEMENT_Vertices (oneshp->data, onegobj, va);
npa = ELEMENT_Planes (oneshp->data, onegobj, pa, sa, &nsa);
nvb = ELEMENT_Vertices (twoshp->data, twogobj, vb);
npb = ELEMENT_Planes (twoshp->data, twogobj, pb, sb, &nsb);
return update_convex_convex (va, nva, pa, npa, sa, nsa,
vb, nvb, pb, npb, sb, nsb,
onepnt, twopnt, normal,
gap, area, spair);
}
break;
case AABB_CONVEX_CONVEX:
{
double *va, *pa,
*vb, *pb;
int nva, npa, *sa, nsa,
nvb, npb, *sb, nsb,
ret;
convex_init (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
convex_init (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
ret = update_convex_convex (va, nva, pa, npa, sa, nsa,
vb, nvb, pb, npb, sb, nsb,
onepnt, twopnt, normal,
gap, area, spair);
convex_done (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
convex_done (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
return ret;
}
break;
case AABB_SPHERE_SPHERE:
{
SPHERE *a = onegobj,
*b = twogobj;
return update_sphere_sphere (a->cur_center, a->cur_radius, a->surface,
b->cur_center, b->cur_radius, b->surface,
onepnt, twopnt, normal,
gap, area, spair);
}
break;
case AABB_ELEMENT_CONVEX:
{
double va [24], pa [36],
*vb, *pb;
int nva, npa, sa [6], nsa,
nvb, npb, *sb, nsb,
ret;
nva = ELEMENT_Vertices (oneshp->data, onegobj, va);
npa = ELEMENT_Planes (oneshp->data, onegobj, pa, sa, &nsa);
convex_init (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
ret = update_convex_convex (va, nva, pa, npa, sa, nsa,
vb, nvb, pb, npb, sb, nsb,
onepnt, twopnt, normal,
gap, area, spair);
convex_done (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
return ret;
}
break;
case AABB_CONVEX_ELEMENT:
{
double *va, *pa,
vb [24], pb [36];
int nva, npa, *sa, nsa,
nvb, npb, sb [6], nsb,
ret;
convex_init (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
nvb = ELEMENT_Vertices (twoshp->data, twogobj, vb);
npb = ELEMENT_Planes (twoshp->data, twogobj, pb, sb, &nsb);
ret = update_convex_convex (va, nva, pa, npa, sa, nsa,
vb, nvb, pb, npb, sb, nsb,
onepnt, twopnt, normal,
gap, area, spair);
convex_done (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
return ret;
}
break;
case AABB_ELEMENT_SPHERE:
{
double va [24], pa [36];
int nva, npa, sa [6], nsa;
SPHERE *b = twogobj;
nva = ELEMENT_Vertices (oneshp->data, onegobj, va);
npa = ELEMENT_Planes (oneshp->data, onegobj, pa, sa, &nsa);
return update_convex_sphere (va, nva, pa, npa, sa, nsa,
b->cur_center, b->cur_radius, b->surface,
onepnt, twopnt, normal,
gap, area, spair);
}
break;
case AABB_SPHERE_ELEMENT:
{
SPHERE *a = onegobj;
double vb [24], pb [36];
int nvb, npb, sb [6], nsb,
ret;
nvb = ELEMENT_Vertices (twoshp->data, twogobj, vb);
npb = ELEMENT_Planes (twoshp->data, twogobj, pb, sb, &nsb);
swap (spair);
ret = update_convex_sphere (vb, nvb, pb, npb, sb, nsb,
a->cur_center, a->cur_radius, a->surface,
twopnt, onepnt, normal,
gap, area, spair);
return update_swap (ret, spair);
}
break;
case AABB_CONVEX_SPHERE:
{
double *va, *pa;
SPHERE *b = twogobj;
int nva, npa, *sa, nsa,
ret;
convex_init (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
ret = update_convex_sphere (va, nva, pa, npa, sa, nsa,
b->cur_center, b->cur_radius, b->surface,
onepnt, twopnt, normal,
gap, area, spair);
convex_done (onegobj, &va, &nva, &pa, &npa, &sa, &nsa);
return ret;
}
break;
case AABB_SPHERE_CONVEX:
{
SPHERE *a = onegobj;
double *vb, *pb;
int nvb, npb, *sb, nsb,
ret;
convex_init (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
swap (spair);
ret = update_convex_sphere (vb, nvb, pb, npb, sb, nsb,
a->cur_center, a->cur_radius, a->surface,
twopnt, onepnt, normal,
gap, area, spair);
convex_done (twogobj, &vb, &nvb, &pb, &npb, &sb, &nsb);
return update_swap (ret, spair);
}
break;
}
return 0;
}
/* detect or update contact data
* between two geometric objects */
int gobjcontact (
GOCDO action, short paircode,
SHAPE *oneshp, void *onegobj,
SHAPE *twoshp, void *twogobj,
double onepnt [3],
double twopnt [3],
double normal [3],
double *gap,
double *area,
int spair [2])
{
if (action == CONTACT_DETECT)
return detect (paircode, oneshp, onegobj, twoshp,
twogobj, onepnt, twopnt, normal, gap, area, spair);
else return update (paircode, oneshp, onegobj, twoshp,
twogobj, onepnt, twopnt, normal, gap, area, spair);
}
/* get distance between two objects (output closest point pair in p, q) */
double gobjdistance (short paircode, SGP *one, SGP *two, double *p, double *q)
{
switch (paircode)
{
case AABB_ELEMENT_ELEMENT:
{
double va [24],
vb [24];
int nva,
nvb;
nva = ELEMENT_Vertices (one->shp->data, one->gobj, va);
nvb = ELEMENT_Vertices (two->shp->data, two->gobj, vb);
return gjk (va, nva, vb, nvb, p, q);
}
break;
case AABB_CONVEX_CONVEX:
{
CONVEX *a = one->gobj,
*b = two->gobj;
return gjk (a->cur, a->nver, b->cur, b->nver, p, q);
}
break;
case AABB_SPHERE_SPHERE:
{
SPHERE *a = one->gobj,
*b = two->gobj;
return gjk_sphere_sphere (a->cur_center, a->cur_radius, b->cur_center, b->cur_radius, p, q);
}
break;
case AABB_ELEMENT_CONVEX:
{
double va [24];
int nva;
CONVEX *b = two->gobj;
nva = ELEMENT_Vertices (one->shp->data, one->gobj, va);
return gjk (va, nva, b->cur, b->nver, p, q);
}
break;
case AABB_CONVEX_ELEMENT:
{
CONVEX *a = one->gobj;
double vb [24];
int nvb;
nvb = ELEMENT_Vertices (two->shp->data, two->gobj, vb);
return gjk (a->cur, a->nver, vb, nvb, p, q);
}
break;
case AABB_ELEMENT_SPHERE:
{
double va [24];
int nva;
SPHERE *b = two->gobj;
nva = ELEMENT_Vertices (one->shp->data, one->gobj, va);
return gjk_convex_sphere (va, nva, b->cur_center, b->cur_radius, p, q);
}
break;
case AABB_SPHERE_ELEMENT:
{
SPHERE *a = one->gobj;
double vb [24];
int nvb;
nvb = ELEMENT_Vertices (two->shp->data, two->gobj, vb);
return gjk_convex_sphere (vb, nvb, a->cur_center, a->cur_radius, q, p);
}
break;
case AABB_CONVEX_SPHERE:
{
CONVEX *a = one->gobj;
SPHERE *b = two->gobj;
return gjk_convex_sphere (a->cur, a->nver, b->cur_center, b->cur_radius, p, q);
}
break;
case AABB_SPHERE_CONVEX:
{
SPHERE *a = one->gobj;
CONVEX *b = two->gobj;
return gjk_convex_sphere (b->cur, b->nver, a->cur_center, a->cur_radius, q, p);
}
break;
}
return 0;
}