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