00001 
00002 
00003 
00004 
00005 
00006 
00007 #include <stdio.h>
00008 #include <string.h> 
00009 #include <stdlib.h> 
00010 #include "cg3d.h"
00011 
00012 using namespace cg3d;
00013 
00020 double cg3d::epsilon=1.0e-10; 
00021 
00022 
00024 PointSet3d::PointSet3d() {
00025     nPts=0; nHalf=0;
00026     setPts=0;
00027 }
00028 
00029 void PointSet3d::addHalf(const CkVector3d &pt,int p) {
00030     halfset_t bit=(1u<<p);
00031     for (int h=0;h<nHalf;h++) {
00032         double side=half[h].side(pt);
00033         if (side>epsilon)  inHalf[h]|=bit;
00034         if (side<-epsilon) outHalf[h]|=bit;
00035     }
00036 }
00037 
00039 void PointSet3d::calculateHalfspaces(void) {
00040     for (int h=0;h<nHalf;h++) inHalf[h]=outHalf[h]=0;
00041     for (int p=0;p<nPts;p++) addHalf(pts[p],p);
00042     setPts=nPts+firstPt;
00043 }
00044 
00046 int PointSet3d::addHalfspace(const CkHalfspace3d &h) {
00047     int r=nHalf++;
00048 #if OSL_CG3D_DEBUG
00049     if (r>=maxHalfs) CkAbort("PointSet3d added too many halfspaces");
00050 #endif
00051     half[r]=h;
00052     return firstHalf+r;
00053 }
00054 
00056 int PointSet3d::addPoint(const CkVector3d &p) {
00057     int r=nPts++;
00058 #if OSL_CG3D_DEBUG
00059     if (r>=maxPts) CkAbort("PointSet3d added too many points");
00060 #endif
00061     pts[r]=p;
00062     return firstPt+r;
00063 }
00064 
00065 
00066 Planar3d::Planar3d(PointSet3d *ps_) {
00067     ps=ps_;
00068     nPts=0;
00069 }
00070 
00073 bool Planar3d::addConstraint(int halfspace)
00074 {
00075     
00076     bool in[maxPts];
00077     
00078     int i,outDex=-1,inDex=-1;
00079     for (i=0;i<nPts;i++) {
00080         
00081         bool isIn=!ps->isOutside(pts[i],halfspace); 
00082         in[i]=isIn;
00083         if (isIn) inDex=i;
00084         else outDex=i;
00085     }
00086     if (outDex==-1) return true;
00087     if (inDex==-1) {nPts=0;return false;}
00088 
00089     const CkHalfspace3d &h=ps->getHalfspace(halfspace);
00090     
00091     
00092     int inStart=outDex;
00093     while (!in[(inStart+1)%nPts]) inStart++;   inStart%=nPts;
00094     int startPt=ps->addPoint(h.intersectPt(
00095         getPoint(inStart),getPoint((inStart+1)%nPts)
00096     ));
00097     
00098     
00099     int inEnd=inStart;
00100     while (in[(inEnd+1)%nPts]) inEnd++;   inEnd%=nPts;  
00101     int endPt=ps->addPoint(h.intersectPt(
00102         getPoint(inEnd),getPoint((inEnd+1)%nPts)
00103     ));
00104     
00105     
00106     if (inEnd>inStart)
00107     { 
00108         memmove((void *)&pts[1],(void *)&pts[inStart+1],sizeof(pts[0])*(inEnd-inStart));
00109         pts[0]=startPt;
00110         nPts=inEnd-inStart+1;
00111         pts[nPts++]=endPt;
00112     } else 
00113     {
00114         memmove((void *)&pts[inEnd+3],(void *)&pts[inStart+1],sizeof(pts[0])*(nPts-inStart-1));
00115         pts[inEnd+1]=endPt;
00116         pts[inEnd+2]=startPt;
00117         nPts+=2-(inStart-inEnd);
00118     }
00119 #if OSL_CG3D_DEBUG
00120     if (nPts>maxPts) CkAbort("Planar3d added too many points");
00121 #endif
00122     return true;
00123 }
00124 
00125 
00126 
00127 Shape3d::~Shape3d() {}
00128 
00131 bool Shape3d::contains(const CkVector3d &pt) const {
00132     for (int f=0;f<getFaces();f++) 
00133         if (!ps->isInside(pt,getHalfspaceIndex(f))) 
00134             return false;
00135     return true;
00136 }
00137 
00140 void cg3d::testShape(const Shape3d &s) {
00141     
00142     CkVector3d sum(0);
00143     int nSum=0;
00144     int h,f,i;
00145     for (i=0;i<s.getPoints();i++) {
00146         sum+=s.getPoint(i);
00147         nSum++;
00148     }
00149     CkVector3d interior=sum/nSum;
00150     
00151     
00152     for (h=0;h<s.getFaces();h++) {
00153         const CkHalfspace3d &half=s.getHalfspace(h);
00154         if (half.side(interior)<=0)
00155             CkAbort("'interior' point doesn't satisfy halfspace!");
00156         
00157         f=h;
00158         Planar3d face(s.getSet()); s.getFace(f,face);
00159         for (i=0;i<face.getPoints();i++) {
00160             double err=half.side(face.getPoint(i));
00161             if (fabs(err)>1.0e-10)
00162                 CkAbort("Face doesn't lie in its own halfspace!");
00163         }
00164     }
00165 }
00166 
00167 
00168 
00169 Tet3d::Tet3d(PointSet3d *ps_,
00170     const CkVector3d &A,const CkVector3d &B_,const CkVector3d &C,const CkVector3d &D_)
00171     :Shape3d(ps_,4,4,h,p)
00172 {
00173     CkHalfspace3d half;
00174     half.init(A,B_,C);
00175     CkVector3d B=B_, D=D_;
00176     if (half.side(D)<0) 
00177     { 
00178         B=D_; D=B_;
00179         half.init(A,B,C);
00180     }
00181     h[0]=ps->addHalfspace(half);
00182     half.init(A,D,B); h[1]=ps->addHalfspace(half);
00183     half.init(B,D,C); h[2]=ps->addHalfspace(half);
00184     half.init(A,C,D); h[3]=ps->addHalfspace(half);
00185     p[0]=ps->addPoint(A);
00186     p[1]=ps->addPoint(B);
00187     p[2]=ps->addPoint(C);
00188     p[3]=ps->addPoint(D);
00189 }
00190 
00191 void Tet3d::getFace(int f, Planar3d &face) const {
00192     switch(f) {
00193     case 0: face.addPoint(p[0],p[1],p[2]); break; 
00194     case 1: face.addPoint(p[0],p[3],p[1]); break; 
00195     case 2: face.addPoint(p[1],p[3],p[2]); break; 
00196     case 3: face.addPoint(p[0],p[2],p[3]); break; 
00197     };
00198 }
00199 
00200 
00201 
00202 
00203 
00204 
00205 
00206 bool earlyExit(PointSet3d *pset,const Shape3d &shape0, const Shape3d &shape1) {
00207     for (int srcShape=0;srcShape<2;srcShape++) 
00208     {
00209         const Shape3d *ps=srcShape?&shape1:&shape0; 
00210         const Shape3d *hs=srcShape?&shape0:&shape1; 
00211         int h, nh=hs->getFaces();
00212         int p, np=ps->getPoints();
00213         for (h=0;h<nh;h++) { 
00214             int half=hs->getHalfspaceIndex(h);
00215             for (p=0;p<np;p++)
00216                 if (pset->isInside(ps->getPointIndex(p),half))
00217                 { 
00218                     break;
00219                 }
00220             if (p==np) return true; 
00221         }
00222     }
00223     return false; 
00224 }
00225 
00226 
00227 
00228 
00229 
00230 
00231 
00232 void cg3d::intersect(PointSet3d *ps,const Shape3d &shape0, const Shape3d &shape1, Planar3dDest &faceDest) 
00233 {
00234     ps->calculateHalfspaces(); 
00235     if (earlyExit(ps,shape0,shape1)) return;
00236     
00237     
00238     for (int srcShape=0;srcShape<2;srcShape++) 
00239     {
00240         const Shape3d *fs=srcShape?&shape1:&shape0; 
00241         const Shape3d *hs=srcShape?&shape0:&shape1; 
00242         int f,h, nf=fs->getFaces(), nh=hs->getFaces();
00243         
00244         for (f=0;f<nf;f++) {
00245             ps->pushPoints();
00246             Planar3d face(ps);
00247             fs->getFace(f,face); 
00248         
00249             for (h=0;h<nh;h++) { 
00250                 if (!face.addConstraint(hs->getHalfspaceIndex(h))) 
00251                     goto nextFace; 
00252             }
00253             
00254         
00255             if (srcShape==1)
00256                 for (h=0;h<nh;h++) {
00257                     int half=hs->getHalfspaceIndex(h);
00258                     int p;
00259                     
00260                     for (p=0;p<face.getPoints();p++) {
00261                         int pIdx=face.getPointIndex(p);
00262                         if (ps->isInside(pIdx,half)||ps->isOutside(pIdx,half))
00263                             break; 
00264                     }
00265                     if (p==face.getPoints()) 
00266                       
00267                         goto nextFace;
00268                 }
00269             
00270         
00271             faceDest.addFace(face,srcShape);
00272         nextFace:
00273             ps->popPoints(); 
00274         }
00275     }
00276 }
00277 
00278 
00279 Volume3dDest::Volume3dDest() {
00280     hasOrigin=false;
00281     volume=0;
00282 #if OSL_CG3D_DEBUG
00283     subVolume=new Volume3dDest(CkVector3d(-1,0,0));
00284 #endif
00285 }
00287 Volume3dDest::Volume3dDest(const CkVector3d &origin_) {
00288     hasOrigin=true;
00289     origin=origin_;
00290     volume=0;
00291 #if OSL_CG3D_DEBUG
00292     subVolume=NULL;
00293 #endif
00294 }
00295 #if OSL_CG3D_DEBUG
00296 Volume3dDest::~Volume3dDest() { 
00297     if (subVolume!=NULL) {
00298         double err=volume-subVolume->getVolume();
00299         if (fabs(err/(volume+1.0))>1.0e-7) 
00300             throw NonManifoldException(volume,subVolume->getVolume());
00301         delete subVolume;
00302     }
00303 }
00304 #endif
00305 
00306 double cg3d::tetVolume(const CkVector3d &A,const CkVector3d &B,
00307         const CkVector3d &C,const CkVector3d &D)
00308 {
00309     const static double oneSixth=1.0/6.0;
00310     return oneSixth*(B-A).dot((D-A).cross(C-A));
00311 }
00312 
00313 void Volume3dDest::addFace(const Planar3d &face,int src)
00314 {
00315     if (!hasOrigin) 
00316     { 
00317         hasOrigin=true;
00318         origin=face.getPoint(0);
00319     } else  {
00320         
00321         double faceVol=0.0;
00322         for (int f=1;f<face.getPoints()-1;f++) {
00323             faceVol+=tetVolume(origin,
00324                 face.getPoint(0),
00325                 face.getPoint(f),
00326                 face.getPoint(f+1));
00327         }
00328         volume+=faceVol;
00329         
00330         
00331     }
00332 #if OSL_CG3D_DEBUG
00333     if (subVolume) subVolume->addFace(face,src);
00334 #endif
00335 }
00336 
00337 
00338