示例#1
0
int 
split_tris(Tri *tris, int num_tris, PQP_REAL a[3], PQP_REAL c)
{
  int i;
  int c1 = 0;
  PQP_REAL p[3];
  PQP_REAL x;
  Tri temp;

  for(i = 0; i < num_tris; i++)
  {
    // loop invariant: up to (but not including) index c1 in group 1,
    // then up to (but not including) index i in group 2
    //
    //  [1] [1] [1] [1] [2] [2] [2] [x] [x] ... [x]
    //                   c1          i
    //
    VcV(p, tris[i].p1);
    VpV(p, p, tris[i].p2);
    VpV(p, p, tris[i].p3);      
    x = VdotV(p, a);
    x /= 3.0;
    if (x <= c)
    {
	    // group 1
	    temp = tris[i];
	    tris[i] = tris[c1];
	    tris[c1] = temp;
	    c1++;
    }
    else
    {
	    // group 2 -- do nothing
    }
  }

  // split arbitrarily if one group empty

  if ((c1 == 0) || (c1 == num_tris)) c1 = num_tris/2;

  return c1;
}
示例#2
0
int
project6(PQP_REAL *ax, 
         PQP_REAL *p1, PQP_REAL *p2, PQP_REAL *p3, 
         PQP_REAL *q1, PQP_REAL *q2, PQP_REAL *q3)
{
  PQP_REAL P1 = VdotV(ax, p1);
  PQP_REAL P2 = VdotV(ax, p2);
  PQP_REAL P3 = VdotV(ax, p3);
  PQP_REAL Q1 = VdotV(ax, q1);
  PQP_REAL Q2 = VdotV(ax, q2);
  PQP_REAL Q3 = VdotV(ax, q3);
  
  PQP_REAL mx1 = max(P1, P2, P3);
  PQP_REAL mn1 = min(P1, P2, P3);
  PQP_REAL mx2 = max(Q1, Q2, Q3);
  PQP_REAL mn2 = min(Q1, Q2, Q3);

  if (mn1 > mx2) return 0;
  if (mn2 > mx1) return 0;
  return 1;
}
示例#3
0
int
project6(float *ax, 
	 float *p1, float *p2, float *p3, 
	 float *q1, float *q2, float *q3)
{
  float P1 = VdotV(ax, p1);
  float P2 = VdotV(ax, p2);
  float P3 = VdotV(ax, p3);
  float Q1 = VdotV(ax, q1);
  float Q2 = VdotV(ax, q2);
  float Q3 = VdotV(ax, q3);
  
  float mx1 = maxRapid(P1, P2, P3);
  float mn1 = min(P1, P2, P3);
  float mx2 = maxRapid(Q1, Q2, Q3);
  float mn2 = min(Q1, Q2, Q3);

  if (mn1 > mx2) return 0;
  if (mn2 > mx1) return 0;
  return 1;
}
示例#4
0
void
SegPoints(PQP_REAL VEC[3],
          PQP_REAL X[3], PQP_REAL Y[3],             // closest points
          const PQP_REAL P[3], const PQP_REAL A[3], // seg 1 origin, vector
          const PQP_REAL Q[3], const PQP_REAL B[3]) // seg 2 origin, vector
{
    PQP_REAL T[3], A_dot_A, B_dot_B, A_dot_B, A_dot_T, B_dot_T;
    PQP_REAL TMP[3];

    VmV(T,Q,P);
    A_dot_A = VdotV(A,A);
    B_dot_B = VdotV(B,B);
    A_dot_B = VdotV(A,B);
    A_dot_T = VdotV(A,T);
    B_dot_T = VdotV(B,T);

    // t parameterizes ray P,A
    // u parameterizes ray Q,B

    PQP_REAL t,u;

    // compute t for the closest point on ray P,A to
    // ray Q,B

    PQP_REAL denom = A_dot_A*B_dot_B - A_dot_B*A_dot_B;

    t = (A_dot_T*B_dot_B - B_dot_T*A_dot_B) / denom;

    // clamp result so t is on the segment P,A

    if ((t < 0) || isnan(t)) t = 0; else if (t > 1) t = 1;

    // find u for point on ray Q,B closest to point at t

    u = (t*A_dot_B - B_dot_T) / B_dot_B;

    // if u is on segment Q,B, t and u correspond to
    // closest points, otherwise, clamp u, recompute and
    // clamp t

    if ((u <= 0) || isnan(u)) {

        VcV(Y, Q);

        t = A_dot_T / A_dot_A;

        if ((t <= 0) || isnan(t)) {
            VcV(X, P);
            VmV(VEC, Q, P);
        }
        else if (t >= 1) {
            VpV(X, P, A);
            VmV(VEC, Q, X);
        }
        else {
            VpVxS(X, P, A, t);
            VcrossV(TMP, T, A);
            VcrossV(VEC, A, TMP);
        }
    }
    else if (u >= 1) {

        VpV(Y, Q, B);

        t = (A_dot_B + A_dot_T) / A_dot_A;

        if ((t <= 0) || isnan(t)) {
            VcV(X, P);
            VmV(VEC, Y, P);
        }
        else if (t >= 1) {
            VpV(X, P, A);
            VmV(VEC, Y, X);
        }
        else {
            VpVxS(X, P, A, t);
            VmV(T, Y, P);
            VcrossV(TMP, T, A);
            VcrossV(VEC, A, TMP);
        }
    }
    else {

        VpVxS(Y, Q, B, u);

        if ((t <= 0) || isnan(t)) {
            VcV(X, P);
            VcrossV(TMP, T, B);
            VcrossV(VEC, B, TMP);
        }
        else if (t >= 1) {
            VpV(X, P, A);
            VmV(T, Q, X);
            VcrossV(TMP, T, B);
            VcrossV(VEC, B, TMP);
        }
        else {
            VpVxS(X, P, A, t);
            VcrossV(VEC, A, B);
            if (VdotV(VEC, T) < 0) {
                VxS(VEC, VEC, -1);
            }
        }
    }
}
示例#5
0
PQP_REAL
TriDist(PQP_REAL P[3], PQP_REAL Q[3],
        const PQP_REAL S[3][3], const PQP_REAL T[3][3])
{
    // Compute vectors along the 6 sides

    PQP_REAL Sv[3][3], Tv[3][3];
    PQP_REAL VEC[3];

    VmV(Sv[0],S[1],S[0]);
    VmV(Sv[1],S[2],S[1]);
    VmV(Sv[2],S[0],S[2]);

    VmV(Tv[0],T[1],T[0]);
    VmV(Tv[1],T[2],T[1]);
    VmV(Tv[2],T[0],T[2]);

    // For each edge pair, the vector connecting the closest points
    // of the edges defines a slab (parallel planes at head and tail
    // enclose the slab). If we can show that the off-edge vertex of
    // each triangle is outside of the slab, then the closest points
    // of the edges are the closest points for the triangles.
    // Even if these tests fail, it may be helpful to know the closest
    // points found, and whether the triangles were shown disjoint

    PQP_REAL V[3];
    PQP_REAL Z[3];
    PQP_REAL minP[3], minQ[3], mindd;
    int shown_disjoint = 0;

    mindd = VdistV2(S[0],T[0]) + 1; // Set first minimum safely high

    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            // Find closest points on edges i & j, plus the
            // vector (and distance squared) between these points

            SegPoints(VEC,P,Q,S[i],Sv[i],T[j],Tv[j]);

            VmV(V,Q,P);
            PQP_REAL dd = VdotV(V,V);

            // Verify this closest point pair only if the distance
            // squared is less than the minimum found thus far.

            if (dd <= mindd)
            {
                VcV(minP,P);
                VcV(minQ,Q);
                mindd = dd;

                VmV(Z,S[(i+2)%3],P);
                PQP_REAL a = VdotV(Z,VEC);
                VmV(Z,T[(j+2)%3],Q);
                PQP_REAL b = VdotV(Z,VEC);

                if ((a <= 0) && (b >= 0)) return sqrt(dd);

                PQP_REAL p = VdotV(V, VEC);

                if (a < 0) a = 0;
                if (b > 0) b = 0;
                if ((p - a + b) > 0) shown_disjoint = 1;
            }
        }
    }

    // No edge pairs contained the closest points.
    // either:
    // 1. one of the closest points is a vertex, and the
    //    other point is interior to a face.
    // 2. the triangles are overlapping.
    // 3. an edge of one triangle is parallel to the other's face. If
    //    cases 1 and 2 are not true, then the closest points from the 9
    //    edge pairs checks above can be taken as closest points for the
    //    triangles.
    // 4. possibly, the triangles were degenerate.  When the
    //    triangle points are nearly colinear or coincident, one
    //    of above tests might fail even though the edges tested
    //    contain the closest points.

    // First check for case 1

    PQP_REAL Sn[3], Snl;
    VcrossV(Sn,Sv[0],Sv[1]); // Compute normal to S triangle
    Snl = VdotV(Sn,Sn);    // Compute square of length of normal

    // If cross product is long enough,

    if (Snl > 1e-15)
    {
        // Get projection lengths of T points

        PQP_REAL Tp[3];

        VmV(V,S[0],T[0]);
        Tp[0] = VdotV(V,Sn);

        VmV(V,S[0],T[1]);
        Tp[1] = VdotV(V,Sn);

        VmV(V,S[0],T[2]);
        Tp[2] = VdotV(V,Sn);

        // If Sn is a separating direction,
        // find point with smallest projection

        int point = -1;
        if ((Tp[0] > 0) && (Tp[1] > 0) && (Tp[2] > 0))
        {
            if (Tp[0] < Tp[1]) point = 0; else point = 1;
            if (Tp[2] < Tp[point]) point = 2;
        }
        else if ((Tp[0] < 0) && (Tp[1] < 0) && (Tp[2] < 0))
        {
            if (Tp[0] > Tp[1]) point = 0; else point = 1;
            if (Tp[2] > Tp[point]) point = 2;
        }

        // If Sn is a separating direction,

        if (point >= 0)
        {
            shown_disjoint = 1;

            // Test whether the point found, when projected onto the
            // other triangle, lies within the face.

            VmV(V,T[point],S[0]);
            VcrossV(Z,Sn,Sv[0]);
            if (VdotV(V,Z) > 0)
            {
                VmV(V,T[point],S[1]);
                VcrossV(Z,Sn,Sv[1]);
                if (VdotV(V,Z) > 0)
                {
                    VmV(V,T[point],S[2]);
                    VcrossV(Z,Sn,Sv[2]);
                    if (VdotV(V,Z) > 0)
                    {
                        // T[point] passed the test - it's a closest point for
                        // the T triangle; the other point is on the face of S

                        VpVxS(P,T[point],Sn,Tp[point]/Snl);
                        VcV(Q,T[point]);
                        return sqrt(VdistV2(P,Q));
                    }
                }
            }
        }
    }

    PQP_REAL Tn[3], Tnl;
    VcrossV(Tn,Tv[0],Tv[1]);
    Tnl = VdotV(Tn,Tn);

    if (Tnl > 1e-15)
    {
        PQP_REAL Sp[3];

        VmV(V,T[0],S[0]);
        Sp[0] = VdotV(V,Tn);

        VmV(V,T[0],S[1]);
        Sp[1] = VdotV(V,Tn);

        VmV(V,T[0],S[2]);
        Sp[2] = VdotV(V,Tn);

        int point = -1;
        if ((Sp[0] > 0) && (Sp[1] > 0) && (Sp[2] > 0))
        {
            if (Sp[0] < Sp[1]) point = 0; else point = 1;
            if (Sp[2] < Sp[point]) point = 2;
        }
        else if ((Sp[0] < 0) && (Sp[1] < 0) && (Sp[2] < 0))
        {
            if (Sp[0] > Sp[1]) point = 0; else point = 1;
            if (Sp[2] > Sp[point]) point = 2;
        }

        if (point >= 0)
        {
            shown_disjoint = 1;

            VmV(V,S[point],T[0]);
            VcrossV(Z,Tn,Tv[0]);
            if (VdotV(V,Z) > 0)
            {
                VmV(V,S[point],T[1]);
                VcrossV(Z,Tn,Tv[1]);
                if (VdotV(V,Z) > 0)
                {
                    VmV(V,S[point],T[2]);
                    VcrossV(Z,Tn,Tv[2]);
                    if (VdotV(V,Z) > 0)
                    {
                        VcV(P,S[point]);
                        VpVxS(Q,S[point],Tn,Sp[point]/Tnl);
                        return sqrt(VdistV2(P,Q));
                    }
                }
            }
        }
    }

    // Case 1 can't be shown.
    // If one of these tests showed the triangles disjoint,
    // we assume case 3 or 4, otherwise we conclude case 2,
    // that the triangles overlap.

    if (shown_disjoint)
    {
        VcV(P,minP);
        VcV(Q,minQ);
        return sqrt(mindd);
    }
    else return 0;
}
示例#6
0
int
box::split_recurse(int *t)
{
  // For a single triangle, orientation is easily determined.
  // The major axis is parallel to the longest edge.
  // The minor axis is normal to the triangle.
  // The in-between axis is determine by these two.

  // this->pR, this->d, and this->pT are set herein.

  P = N = 0;
  tri *ptr = RAPID_tri + t[0];

  // Find the major axis: parallel to the longest edge.
  double u12[3], u23[3], u31[3];

  // First compute the squared-lengths of each edge
  VmV(u12, ptr->p1, ptr->p2);  
  double d12 = VdotV(u12,u12);
  VmV(u23, ptr->p2, ptr->p3);  
  double d23 = VdotV(u23,u23);
  VmV(u31, ptr->p3, ptr->p1);  
  double d31 = VdotV(u31,u31);

  // Find the edge of longest squared-length, normalize it to
  // unit length, and put result into a0.
  double a0[3];
  double l;  
  if (d12 > d23)
    {
      if (d12 > d31)
	{
	  l = 1.0 / sqrt(d12); 
	  a0[0] = u12[0] * l; 
	  a0[1] = u12[1] * l;
	  a0[2] = u12[2] * l;
	}
      else 
	{
	  l = 1.0 / sqrt(d31);
	  a0[0] = u31[0] * l;
	  a0[1] = u31[1] * l;
	  a0[2] = u31[2] * l;
	}
    }
  else 
    {
      if (d23 > d31)
	{
	  l = 1.0 / sqrt(d23);
	  a0[0] = u23[0] * l;
	  a0[1] = u23[1] * l;
	  a0[2] = u23[2] * l;
	}
      else
	{
	  l = 1.0 / sqrt(d31);
	  a0[0] = u31[0] * l;
	  a0[1] = u31[1] * l;
	  a0[2] = u31[2] * l;
	}
    }

  // Now compute unit normal to triangle, and put into a2.
  double a2[3];
  VcrossV(a2, u12, u23);
  l = 1.0 / Vlength(a2);  a2[0] *= l;  a2[1] *= l;  a2[2] *= l;

  // a1 is a2 cross a0.
  double a1[3];
  VcrossV(a1, a2, a0);

  // Now make the columns of this->pR the vectors a0, a1, and a2.
  pR[0][0] = a0[0];  pR[0][1] = a1[0];  pR[0][2] = a2[0];
  pR[1][0] = a0[1];  pR[1][1] = a1[1];  pR[1][2] = a2[1];
  pR[2][0] = a0[2];  pR[2][1] = a1[2];  pR[2][2] = a2[2];
  
  // Now compute the maximum and minimum extents of each vertex 
  // along each of the box axes.  From this we will compute the 
  // box center and box dimensions.
  double minval[3], maxval[3];
  double c[3];
  
  MTxV(c, pR, ptr->p1);
  minval[0] = maxval[0] = c[0];
  minval[1] = maxval[1] = c[1];
  minval[2] = maxval[2] = c[2];

  MTxV(c, pR, ptr->p2);
  minmax(minval[0], maxval[0], c[0]);
  minmax(minval[1], maxval[1], c[1]);
  minmax(minval[2], maxval[2], c[2]);
  
  MTxV(c, pR, ptr->p3);
  minmax(minval[0], maxval[0], c[0]);
  minmax(minval[1], maxval[1], c[1]);
  minmax(minval[2], maxval[2], c[2]);
  
  // With the max and min data, determine the center point and dimensions
  // of the box
  c[0] = (minval[0] + maxval[0])*0.5;
  c[1] = (minval[1] + maxval[1])*0.5;
  c[2] = (minval[2] + maxval[2])*0.5;

  pT[0] = c[0] * pR[0][0] + c[1] * pR[0][1] + c[2] * pR[0][2];
  pT[1] = c[0] * pR[1][0] + c[1] * pR[1][1] + c[2] * pR[1][2];
  pT[2] = c[0] * pR[2][0] + c[1] * pR[2][1] + c[2] * pR[2][2];

  d[0] = (maxval[0] - minval[0])*0.5;
  d[1] = (maxval[1] - minval[1])*0.5;
  d[2] = (maxval[2] - minval[2])*0.5;
  
  // Assign the one triangle to this box
  trp = ptr;

  return RAPID_OK;
}
示例#7
0
int
build_recurse(PQP_Model *m, int bn, int first_tri, int num_tris)
{
  BV *b = m->child(bn);

  // compute a rotation matrix

  PQP_REAL C[3][3], E[3][3], R[3][3], s[3], axis[3], mean[3], coord;

#if RAPID2_FIT
  moment *tri_moment = new moment[num_tris];
  compute_moments(tri_moment, &(m->tris[first_tri]), num_tris);  
  accum acc;
  clear_accum(acc);
  for(int i = 0; i < num_tris; i++) accum_moment(acc, tri_moment[i]);
  delete [] tri_moment;
  covariance_from_accum(C,acc);
#else
  get_covariance_triverts(C,&m->tris[first_tri],num_tris);
#endif

  Meigen(E, s, C);

  // place axes of E in order of increasing s

  int min, mid, max;
  if (s[0] > s[1]) { max = 0; min = 1; }
  else { min = 0; max = 1; }
  if (s[2] < s[min]) { mid = min; min = 2; }
  else if (s[2] > s[max]) { mid = max; max = 2; }
  else { mid = 2; }
  McolcMcol(R,0,E,max);
  McolcMcol(R,1,E,mid);
  R[0][2] = E[1][max]*E[2][mid] - E[1][mid]*E[2][max];
  R[1][2] = E[0][mid]*E[2][max] - E[0][max]*E[2][mid];
  R[2][2] = E[0][max]*E[1][mid] - E[0][mid]*E[1][max];

  // fit the BV

  b->FitToTris(R, &m->tris[first_tri], num_tris);

  if (num_tris == 1)
  {
    // BV is a leaf BV - first_child will index a triangle

    b->first_child = -(first_tri + 1);
  }
  else if (num_tris > 1)
  {
    // BV not a leaf - first_child will index a BV

    b->first_child = m->num_bvs;
    m->num_bvs+=2;

    // choose splitting axis and splitting coord

    McolcV(axis,R,0);

#if RAPID2_FIT
    mean_from_accum(mean,acc);
#else
    get_centroid_triverts(mean,&m->tris[first_tri],num_tris);
#endif
    coord = VdotV(axis, mean);

    // now split

    int num_first_half = split_tris(&m->tris[first_tri], num_tris, 
                                    axis, coord);

    // recursively build the children

    build_recurse(m, m->child(bn)->first_child, first_tri, num_first_half); 
    build_recurse(m, m->child(bn)->first_child + 1,
                  first_tri + num_first_half, num_tris - num_first_half); 
  }
  return PQP_OK;
}