Side PredWrapper::doInsphereAdapt( Tet tet, int v ) const { const RealType* p[] = { getPoint( tet._v[0] )._p, getPoint( tet._v[1] )._p, getPoint( tet._v[2] )._p, getPoint( tet._v[3] )._p, getPoint( v )._p }; if ( v == _infIdx ) { const RealType det = -orient3d( p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] ); return sphToSide( det ); } if ( tet.has( _infIdx ) ) { const int infVi = tet.getIndexOf( _infIdx ); const int* ord = TetViAsSeenFrom[ infVi ]; // Check convexity, looking from inside const RealType det = -orient3d( p[ ord[0] ], p[ ord[2] ], p[ ord[1] ], p[4] ); return sphToSide( det); } const RealType det = insphere( p[0], p[1], p[2], p[3], p[4] ); const Side s = sphToSide( det ); return s; }
inline bool sameSide(Vec3r P, Vec3r Q, Vec3r R, Vec3r A1, Vec3r A2) { bool a1side = orient3d(P,Q,R,A1) > 0; bool a2side = orient3d(P,Q,R,A2) > 0; return a1side == a2side; }
void tetcircumcenter(double*a, double*b, double*c, double*d, double*circumcenter,double*cond) { double xba, yba, zba, xca, yca, zca, xda, yda, zda; double balength, calength, dalength; double xcrosscd, ycrosscd, zcrosscd; double xcrossdb, ycrossdb, zcrossdb; double xcrossbc, ycrossbc, zcrossbc; double denominator; double xcirca, ycirca, zcirca; /* Use coordinates relative to point `a' of the tetrahedron. */ xba = b[0] - a[0]; yba = b[1] - a[1]; zba = b[2] - a[2]; xca = c[0] - a[0]; yca = c[1] - a[1]; zca = c[2] - a[2]; xda = d[0] - a[0]; yda = d[1] - a[1]; zda = d[2] - a[2]; /* Squares of lengths of the edges incident to `a'. */ balength = xba * xba + yba * yba + zba * zba; calength = xca * xca + yca * yca + zca * zca; dalength = xda * xda + yda * yda + zda * zda; /* Cross products of these edges. */ xcrosscd = yca * zda - yda * zca; ycrosscd = zca * xda - zda * xca; zcrosscd = xca * yda - xda * yca; xcrossdb = yda * zba - yba * zda; ycrossdb = zda * xba - zba * xda; zcrossdb = xda * yba - xba * yda; xcrossbc = yba * zca - yca * zba; ycrossbc = zba * xca - zca * xba; zcrossbc = xba * yca - xca * yba; /* Calculate the denominator of the formulae. */ #ifdef EXACT /* Use orient3d() from http://www.cs.cmu.edu/~quake/robust.html */ /* to ensure a correctly signed (and reasonably accurate) result, */ /* avoiding any possibility of division by zero. */ *cond = orient3d(b,c,d,a); denominator = 0.5 / (*cond); #else /* Take your chances with floating-point roundoff. */ denominator = 0.5 / (xba * xcrosscd + yba * ycrosscd + zba * zcrosscd); #endif /* Calculate offset (from `a') of circumcenter. */ xcirca = (balength * xcrosscd + calength * xcrossdb + dalength * xcrossbc) * denominator; ycirca = (balength * ycrosscd + calength * ycrossdb + dalength * ycrossbc) * denominator; zcirca = (balength * zcrosscd + calength * zcrossdb + dalength * zcrossbc) * denominator; circumcenter[0] = xcirca; circumcenter[1] = ycirca; circumcenter[2] = zcirca; }
/** * \brief Determine whether p is internal to the wedge defined by * the area between the planes defined by a,b,c and a,b,d * angle abc, where ab is the apex of the angle. * * @param[in] a * @param[in] b * @param[in] c * @param[in] d * @param[in] p * * @return true, if p is contained in the wedge defined by the * area between the planes defined by a,b,c and * a,b,d. If the wedge is reflex, p is considered to * be contained if it lies on either plane. Acute * wdges do not contain p if p lies on either * plane. This is so that internalToWedge(a,b,c,d,p) = * !internalToWedge(a,b,d,c,p) */ inline bool internalToWedge(const Vector &a, const Vector &b, const Vector &c, const Vector &d, const Vector &p) { bool reflex = (c < d) ? orient3d(a, b, c, d) >= 0.0 : orient3d(a, b, d, c) < 0.0; double d1 = orient3d(a, b, c, p); double d2 = orient3d(a, b, d, p); if (reflex) { // above a,b,c or below a,b,d (or coplanar with either) return d1 <= 0.0 || d2 >= 0.0; } else { // above a,b,c and below a,b,d return d1 < 0.0 && d2 > 0.0; } }
/* returns true if the tet (1,2,3,4) has positive orientation, and false otherwise */ bool positivetet(tetcomplex *mesh, tag v1, tag v2, tag v3, tag v4) { return (orient3d(&behave, ((struct vertex *) tetcomplextag2vertex(mesh, v1))->coord, ((struct vertex *) tetcomplextag2vertex(mesh, v2))->coord, ((struct vertex *) tetcomplextag2vertex(mesh, v3))->coord, ((struct vertex *) tetcomplextag2vertex(mesh, v4))->coord) > 0); }
/* robust orientation */ static double orient (face *f, double *d) { double *a, *b, *c; edge *e1, *e2; e1 = f->e; e2 = e1->n; a = e1->v[0]; b = e1->v[1]; c = e2->v[1]; return orient3d (c, b, a, d); }
// determine if segment pq intersects triangle uvw, setting approximate // barycentric coordinates if so. static bool segment_tri_intersect(const Vec3d& p, const Vec3d& q, const Vec3d& u, const Vec3d& v, const Vec3d& w, double* s, double* t, double* a, double* b, double* c) { // find where segment hits plane of triangle double puvw=orient3d(p.v, u.v, v.v, w.v), uvwq=orient3d(u.v, v.v, w.v, q.v); if((puvw<=0 && uvwq>=0) || (puvw>=0 && uvwq<=0)) return false; // either no intersection, or a degenerate one if(puvw<0 || uvwq<0){ double pqvw=orient3d(p.v, q.v, v.v, w.v); if(pqvw>0) return false; double puqw=orient3d(p.v, u.v, q.v, w.v); if(puqw>0) return false; double puvq=orient3d(p.v, u.v, v.v, q.v); if(puvq>0) return false; *s=uvwq/(puvw+uvwq); *t=puvw/(puvw+uvwq); *a=pqvw/(pqvw+puqw+puvq); *b=puqw/(pqvw+puqw+puvq); *c=puvq/(pqvw+puqw+puvq); return true; }else{ //(puvw>0 || uvwq>0) double pqvw=orient3d(p.v, q.v, v.v, w.v); if(pqvw<0) return false; double puqw=orient3d(p.v, u.v, q.v, w.v); if(puqw<0) return false; double puvq=orient3d(p.v, u.v, v.v, q.v); if(puvq<0) return false; *s=uvwq/(puvw+uvwq); *t=puvw/(puvw+uvwq); *a=pqvw/(pqvw+puqw+puvq); *b=puqw/(pqvw+puqw+puvq); *c=puvq/(pqvw+puqw+puvq); return true; } }
Orient PredWrapper::doOrient3DAdapt( int v0, int v1, int v2, int v3 ) const { assert( ( v0 != v1 ) && ( v0 != v2 ) && ( v0 != v3 ) && ( v1 != v2 ) && ( v1 != v3 ) && ( v2 != v3 ) && "Duplicate indices in orientation!" ); const Point3 p[] = { getPoint( v0 ), getPoint( v1 ), getPoint( v2 ), getPoint( v3 ) }; RealType det = orient3d( p[0]._p, p[1]._p, p[2]._p, p[3]._p ); if ( (v0 == _infIdx) || (v1 == _infIdx) || (v2 == _infIdx) || (v3 == _infIdx) ) det = -det; return ortToOrient( det ); }
// helper function for tri_zcast below... // Here we are given a robust 2d orientation of qrs in xy projection, which // must be positive. static bool tri_zcast_inner(const Vec3d& p, double qrs, const Vec3d& q, const Vec3d& r, const Vec3d& s) { assert(qrs>0); // first check if point is above or below triangle in z double pqrs=orient3d(p.v, q.v, r.v, s.v); if(pqrs>=0) return false; // point is on or above triangle - no intersection // then check if point lies outside triangle in 2D xy projection double pqr=orient2d(p.v, q.v, r.v); if(pqr<0) return false; double prs=orient2d(p.v, r.v, s.v); if(prs<0) return false; double psq=orient2d(p.v, s.v, q.v); if(psq<0) return false; // note: the following tests are somewhat redundant, but it's a pretty // tiny optimization to eliminate the redundancy compared to the loss in // clarity. // check if point is strictly inside the triangle in xy if(pqr>0 && prs>0 && psq>0) return true; // check if point is strictly on edge qr if(pqr==0 && prs>0 && psq>0){ if(q[1]<r[1]) return false; if(q[1]>r[1]) return true; if(q[0]<r[0]) return true; assert(q[0]>r[0]); // q!=r because triangle is not degenerate return false; } // check if point is strictly on edge rs if(prs==0 && pqr>0 && psq>0){ if(r[1]<s[1]) return false; if(r[1]>s[1]) return true; if(r[0]<s[0]) return true; assert(r[0]>s[0]); // r!=s because triangle is not degenerate return false; } // check if point is strictly on edge sq if(psq==0 && pqr>0 && prs>0){ if(s[1]<q[1]) return false; if(s[1]>q[1]) return true; if(s[0]<q[0]) return true; assert(s[0]>q[0]); // r!=s because triangle is not degenerate return false; } // check if point is on vertex q if(p[0]==q[0] && p[1]==q[1]){ return q[1]>=r[1] && q[1]<s[1]; } // check if point is on vertex r if(p[0]==r[0] && p[1]==r[1]){ return r[1]>=s[1] && r[1]<q[1]; } // check if point is on vertex s if(p[0]==s[0] && p[1]==s[1]){ return s[1]>=q[1] && s[1]<r[1]; } assert(false); // we should have covered all cases at this point return false; // just to quiet compiler warnings }