├── .gitignore ├── README.md ├── cmake └── FindFLANN.cmake └── src ├── BinaryNode.h ├── CMakeLists.txt ├── CmdLineParser.cpp ├── CmdLineParser.h ├── Function.h ├── Geometry.h ├── Geometry.inl ├── Hash.h ├── IsoOctree.h ├── IsoOctree.inl ├── Kdtree.h ├── Kdtree.inl ├── MAT.h ├── MAT.inl ├── Main.cpp ├── MarchingCubes.h ├── MarchingCubes.inl ├── Octree.h ├── Octree.inl ├── OctreeBspline.h ├── OctreeBspline.inl ├── Ply.h ├── Ply.inl ├── PlyFile.cpp ├── PlyFile.h ├── PolygonizerHelper.cpp ├── PolygonizerHelper.h ├── Time.cpp ├── Time.h ├── VertexData.h ├── VertexData.inl ├── polygonizer.c ├── polygonizer.h ├── vtkHelper.cpp └── vtkHelper.h /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OctreeBSplines 2 | ================ 3 | 4 | original name: Implicit Hierarchical B-Splines Surface Reconstruction based on Octree Distance Field 5 | 6 | An implementation of the following paper. 7 | 8 | "Multi-scale surface reconstruction based on a curvature-adaptive signed distance field", 9 | Yizhi Tang, Jieqing Feng. Computer & Graphics (Speical issue of CAD/Graphics 2017). 10 | 11 | The vs2010_64bit executable can be found [here](http://yiztang.com/#CASD) 12 | -------------------------------------------------------------------------------- /cmake/FindFLANN.cmake: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Find Flann 3 | # 4 | # This sets the following variables: 5 | # FLANN_FOUND - True if FLANN was found. 6 | # FLANN_INCLUDE_DIRS - Directories containing the FLANN include files. 7 | # FLANN_LIBRARIES - Libraries needed to use FLANN. 8 | # FLANN_DEFINITIONS - Compiler flags for FLANN. 9 | 10 | find_package(PkgConfig) 11 | pkg_check_modules(PC_FLANN flann) 12 | set(FLANN_DEFINITIONS ${PC_FLANN_CFLAGS_OTHER}) 13 | 14 | find_path(FLANN_INCLUDE_DIR flann/flann.hpp 15 | HINTS ${PC_FLANN_INCLUDEDIR} ${PC_FLANN_INCLUDE_DIRS}) 16 | 17 | find_library(FLANN_LIBRARY_DEBUG flann_cpp_s_debug 18 | HINTS ${PC_FLANN_LIBDIR} ${PC_FLANN_LIBRARY_DIRS}) 19 | 20 | find_library(FLANN_LIBRARY_RELEASE flann_cpp_s_release 21 | HINTS ${PC_FLANN_LIBDIR} ${PC_FLANN_LIBRARY_DIRS}) 22 | 23 | set(FLANN_INCLUDE_DIRS ${FLANN_INCLUDE_DIR}) 24 | set(FLANN_LIBRARIES debug ${FLANN_LIBRARY_DEBUG} optimized ${FLANN_LIBRARY_RELEASE}) 25 | 26 | include(FindPackageHandleStandardArgs) 27 | find_package_handle_standard_args(Flann DEFAULT_MSG 28 | FLANN_LIBRARY_DEBUG FLANN_LIBRARY_RELEASE FLANN_INCLUDE_DIR) 29 | 30 | mark_as_advanced(FLANN_LIBRARY_DEBUG FLANN_LIBRARY_RELEASE FLANN_INCLUDE_DIR) 31 | 32 | -------------------------------------------------------------------------------- /src/BinaryNode.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #ifndef BINARY_NODE_INCLUDED 29 | #define BINARY_NODE_INCLUDED 30 | 31 | template 32 | class BinaryNode 33 | { 34 | public: 35 | static inline int CenterCount(int depth){return 1<>=1; 61 | depth++; 62 | } 63 | offset=(idx+1)-(1< 29 | #include 30 | #include 31 | #include 32 | #include "CmdLineParser.h" 33 | 34 | 35 | #ifdef WIN32 36 | int strcasecmp(char* c1,char* c2){return _stricmp(c1,c2);} 37 | #endif 38 | 39 | cmdLineReadable::cmdLineReadable(void){set=0;} 40 | cmdLineReadable::~cmdLineReadable(void){;} 41 | int cmdLineReadable::read(char**,int){ 42 | set=1; 43 | return 0; 44 | } 45 | 46 | cmdLineInt::cmdLineInt(void){value=0;} 47 | cmdLineInt::cmdLineInt(const int& v){value=v;} 48 | int cmdLineInt::read(char** argv,int argc){ 49 | if(argc>0){ 50 | value=atoi(argv[0]); 51 | set=1; 52 | return 1; 53 | } 54 | else{return 0;} 55 | } 56 | cmdLineFloat::cmdLineFloat(void){value=0;} 57 | cmdLineFloat::cmdLineFloat(const float& v){value=v;} 58 | int cmdLineFloat::read(char** argv,int argc){ 59 | if(argc>0){ 60 | value=(float)atof(argv[0]); 61 | set=1; 62 | return 1; 63 | } 64 | else{return 0;} 65 | } 66 | cmdLineString::cmdLineString(void){value=NULL;} 67 | cmdLineString::~cmdLineString(void){ 68 | if(value){ 69 | delete[] value; 70 | value=NULL; 71 | } 72 | } 73 | int cmdLineString::read(char** argv,int argc){ 74 | if(argc>0){ 75 | value=new char[strlen(argv[0])+1]; 76 | strcpy(value,argv[0]); 77 | set=1; 78 | return 1; 79 | } 80 | else{return 0;} 81 | } 82 | cmdLinePoint3D::cmdLinePoint3D(void){value[0]=value[1]=value[2]=0;} 83 | cmdLinePoint3D::cmdLinePoint3D(const Point3D& v){value[0]=v[0];value[1]=v[1];value[2]=v[2];} 84 | cmdLinePoint3D::cmdLinePoint3D(const float& v0,const float& v1,const float& v2){value[0]=v0;value[1]=v1;value[2]=v2;} 85 | int cmdLinePoint3D::read(char** argv,int argc){ 86 | if(argc>2){ 87 | value[0]=(float)atof(argv[0]); 88 | value[1]=(float)atof(argv[1]); 89 | value[2]=(float)atof(argv[2]); 90 | set=1; 91 | return 3; 92 | } 93 | else{return 0;} 94 | } 95 | 96 | char* GetFileExtension(char* fileName){ 97 | char* fileNameCopy; 98 | char* ext=NULL; 99 | char* temp; 100 | 101 | fileNameCopy=new char[strlen(fileName)+1]; 102 | assert(fileNameCopy); 103 | strcpy(fileNameCopy,fileName); 104 | temp=strtok(fileNameCopy,"."); 105 | while(temp!=NULL){ 106 | if(ext!=NULL){delete[] ext;} 107 | ext=new char[strlen(temp)+1]; 108 | assert(ext); 109 | strcpy(ext,temp); 110 | temp=strtok(NULL,"."); 111 | } 112 | delete[] fileNameCopy; 113 | return ext; 114 | } 115 | 116 | void cmdLineParse(int argc, char **argv,char** names,int num,cmdLineReadable** readable, 117 | int dumpError){ 118 | int i,j; 119 | 120 | while (argc > 0) { 121 | if (argv[0][0] == '-' && argv[0][1]=='-') { 122 | for(i=0;iread(argv,argc); 126 | argv+=j,argc-=j; 127 | break; 128 | } 129 | } 130 | if(i==num){ 131 | if(dumpError){ 132 | fprintf(stderr, "invalid option: %s\n",*argv); 133 | fprintf(stderr, "possible options are:\n"); 134 | for(i=0;i 31 | #include 32 | 33 | #include "Geometry.h" 34 | 35 | #ifdef WIN32 36 | int strcasecmp(char* c1,char* c2); 37 | #endif 38 | 39 | class cmdLineReadable{ 40 | public: 41 | int set; 42 | cmdLineReadable(void); 43 | virtual ~cmdLineReadable(void); 44 | virtual int read(char** argv,int argc); 45 | }; 46 | 47 | class cmdLineInt : public cmdLineReadable { 48 | public: 49 | int value; 50 | cmdLineInt(); 51 | cmdLineInt(const int& v); 52 | int read(char** argv,int argc); 53 | }; 54 | class cmdLineFloat : public cmdLineReadable { 55 | public: 56 | float value; 57 | cmdLineFloat(); 58 | cmdLineFloat(const float& f); 59 | int read(char** argv,int argc); 60 | }; 61 | class cmdLineString : public cmdLineReadable { 62 | public: 63 | char* value; 64 | cmdLineString(); 65 | ~cmdLineString(); 66 | int read(char** argv,int argc); 67 | }; 68 | class cmdLinePoint3D : public cmdLineReadable { 69 | public: 70 | Point3D value; 71 | cmdLinePoint3D(); 72 | cmdLinePoint3D(const Point3D& v); 73 | cmdLinePoint3D(const float& v0,const float& v1,const float& v2); 74 | int read(char** argv,int argc); 75 | }; 76 | 77 | // This reads the arguments in argc, matches them against "names" and sets 78 | // the values of "r" appropriately. Parameters start with "--" 79 | void cmdLineParse(int argc, char **argv,char** names,int num,cmdLineReadable** r, 80 | int dumpError=1); 81 | 82 | char* GetFileExtension(char* fileName); 83 | 84 | #endif // CMD_LINE_PARSER_INCLUDED 85 | -------------------------------------------------------------------------------- /src/Function.h: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTION_INCLUDED 2 | #define FUNCTION_INCLUDED 3 | 4 | class Function 5 | { 6 | public: 7 | virtual float eval(const float pos[3])=0; 8 | }; 9 | 10 | #endif -------------------------------------------------------------------------------- /src/Geometry.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #ifndef GEOMETRY_INCLUDED 29 | #define GEOMETRY_INCLUDED 30 | #include 31 | #include 32 | #include 33 | 34 | template 35 | Real Random(void); 36 | 37 | template 38 | struct Point3D{ 39 | Real coords[3]; 40 | 41 | Real& operator[] (const int& idx); 42 | const Real& operator[] (const int& idx) const; 43 | Point3D operator + (const Point3D& p) const; 44 | Point3D operator - (const Point3D& p) const; 45 | Point3D operator * (const Real& s) const; 46 | Point3D operator / (const Real& s) const; 47 | Point3D& operator += (const Point3D& p); 48 | Point3D& operator -= (const Point3D& p); 49 | Point3D& operator *= (const Real& s); 50 | Point3D& operator /= (const Real& s); 51 | }; 52 | 53 | template 54 | Point3D RandomBallPoint(void); 55 | 56 | template 57 | Point3D RandomSpherePoint(void); 58 | 59 | template 60 | Real Length(const Point3D& p); 61 | 62 | template 63 | Real SquareLength(const Point3D& p); 64 | 65 | template 66 | Real DotProduct(const Point3D& p,const Point3D& q); 67 | 68 | template 69 | Real Distance(const Point3D& p1,const Point3D& p2); 70 | 71 | template 72 | Real SquareDistance(const Point3D& p1,const Point3D& p2); 73 | 74 | template 75 | void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p); 76 | 77 | template 78 | Point3D Normal(const Point3D& p1,const Point3D& p2,const Point3D& p3); 79 | 80 | template 81 | Real Area(const Point3D& p1,const Point3D& p2,const Point3D& p3); 82 | 83 | template 84 | Real DistanceToEdge(const Point3D& p,const Point3D e[2]); 85 | template 86 | Real DistanceToTriangle(const Point3D& p,const Point3D t[3]); 87 | 88 | template 89 | Point3D NearestPointOnEdge(const Point3D& p,const Point3D e[2],int& vFlag); 90 | template 91 | Point3D NearestPointOnTriangle(const Point3D& p,const Point3D t[3],int& vFlag); 92 | template 93 | Point3D NearestPointOnPlane(const Point3D& p,const Point3D t,const Point3D n,int& vFlag); 94 | 95 | template 96 | int OutCode(const Point3D& ctr,const Real& w,const Point3D& p); 97 | 98 | template 99 | int PointInCube(const Point3D& ctr,const Real& w,const Point3D& p); 100 | template 101 | int EdgeInCube(const Point3D& ctr,const Real& w,const Point3D e[2]); 102 | template 103 | int TriangleInCube(const Point3D& ctr,const Real& w,const Point3D t[3]); 104 | 105 | class TriangleIndex{ 106 | public: 107 | size_t idx[3]; 108 | }; 109 | 110 | #include "Geometry.inl" 111 | 112 | #endif // GEOMETRY_INCLUDED 113 | -------------------------------------------------------------------------------- /src/Geometry.inl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #include 29 | ///////////// 30 | // Point3D // 31 | ///////////// 32 | template 33 | Real& Point3D::operator[] (const int& idx) 34 | { 35 | return coords[idx]; 36 | } 37 | template 38 | const Real& Point3D::operator[] (const int& idx) const 39 | { 40 | return coords[idx]; 41 | } 42 | template 43 | Point3D Point3D::operator + (const Point3D& p) const 44 | { 45 | Point3D q; 46 | q.coords[0]=coords[0]+p.coords[0]; 47 | q.coords[1]=coords[1]+p.coords[1]; 48 | q.coords[2]=coords[2]+p.coords[2]; 49 | return q; 50 | } 51 | template 52 | Point3D Point3D::operator - (const Point3D& p) const 53 | { 54 | Point3D q; 55 | q.coords[0]=coords[0]-p.coords[0]; 56 | q.coords[1]=coords[1]-p.coords[1]; 57 | q.coords[2]=coords[2]-p.coords[2]; 58 | return q; 59 | } 60 | template 61 | Point3D Point3D::operator * (const Real& s) const 62 | { 63 | Point3D q; 64 | q.coords[0]=coords[0]*s; 65 | q.coords[1]=coords[1]*s; 66 | q.coords[2]=coords[2]*s; 67 | return q; 68 | } 69 | template 70 | Point3D Point3D::operator / (const Real& s) const 71 | { 72 | Point3D q; 73 | q.coords[0]=coords[0]/s; 74 | q.coords[1]=coords[1]/s; 75 | q.coords[2]=coords[2]/s; 76 | return q; 77 | } 78 | template 79 | Point3D& Point3D::operator += (const Point3D& p) 80 | { 81 | coords[0]+=p.coords[0]; 82 | coords[1]+=p.coords[1]; 83 | coords[2]+=p.coords[2]; 84 | return *this; 85 | } 86 | template 87 | Point3D& Point3D::operator -= (const Point3D& p) 88 | { 89 | coords[0]-=p.coords[0]; 90 | coords[1]-=p.coords[1]; 91 | coords[2]-=p.coords[2]; 92 | return *this; 93 | } 94 | template 95 | Point3D& Point3D::operator *= (const Real& s) 96 | { 97 | coords[0]*=s; 98 | coords[1]*=s; 99 | coords[2]*=s; 100 | return *this; 101 | } 102 | template 103 | Point3D& Point3D::operator /= (const Real& s) 104 | { 105 | coords[0]/=s; 106 | coords[1]/=s; 107 | coords[2]/=s; 108 | return *this; 109 | } 110 | template 111 | Real Random(void){return Real(rand())/RAND_MAX;} 112 | 113 | template 114 | Point3D RandomBallPoint(void){ 115 | Point3D p; 116 | while(1){ 117 | p.coords[0]=Real(1.0-2.0*Random()); 118 | p.coords[1]=Real(1.0-2.0*Random()); 119 | p.coords[2]=Real(1.0-2.0*Random()); 120 | Real l=SquareLength(p); 121 | if(l<=1){return p;} 122 | } 123 | } 124 | template 125 | Point3D RandomSpherePoint(void){ 126 | Point3D p=RandomBallPoint(); 127 | return p/Length(p); 128 | } 129 | 130 | template 131 | Real SquareLength(const Point3D& p) 132 | { 133 | return DotProduct(p,p); 134 | } 135 | 136 | template 137 | Real DotProduct(const Point3D& p,const Point3D& q) 138 | { 139 | return p.coords[0]*q.coords[0]+p.coords[1]*q.coords[1]+p.coords[2]*q.coords[2]; 140 | } 141 | 142 | template 143 | Real Length(const Point3D& p) 144 | { 145 | return Real(sqrt(SquareLength(p))); 146 | } 147 | 148 | template 149 | Real SquareDistance(const Point3D& p1,const Point3D& p2) 150 | { 151 | return SquareLength(p1-p2); 152 | } 153 | 154 | template 155 | Real Distance(const Point3D& p1,const Point3D& p2){return Real(sqrt(SquareDistance(p1,p2)));} 156 | 157 | template 158 | void CrossProduct(const Point3D& p1,const Point3D& p2,Point3D& p){ 159 | p.coords[0]= p1.coords[1]*p2.coords[2]-p1.coords[2]*p2.coords[1]; 160 | p.coords[1]=-p1.coords[0]*p2.coords[2]+p1.coords[2]*p2.coords[0]; 161 | p.coords[2]= p1.coords[0]*p2.coords[1]-p1.coords[1]*p2.coords[0]; 162 | } 163 | template 164 | Point3D Normal(const Point3D& p1,const Point3D& p2,const Point3D& p3) 165 | { 166 | Point3D q1,q2,n; 167 | q1=p2-p1; 168 | q2=p3-p1; 169 | CrossProduct(q1,q2,n); 170 | return n; 171 | } 172 | template 173 | Real Area(const Point3D& p1,const Point3D& p2,const Point3D& p3) 174 | { 175 | Point3D p12=p2-p1,p13=p3-p1; 176 | Point3D tmp; 177 | CrossProduct(p12,p13,tmp); 178 | return Length(tmp); 179 | } 180 | 181 | template 182 | Real DistanceToEdge(const Point3D& p,const Point3D e[2]) 183 | { 184 | Point3D q,v; 185 | Real dot; 186 | q=p-e[0]; 187 | v=e[1]-e[0]; 188 | dot=DotProduct(q,v); 189 | if(dot<=0) 190 | return Length(q); 191 | else if (dot>SquareLength(v)) 192 | return Distance(p,e[1]); 193 | else 194 | { 195 | Real t=dot/SquareLength(v); 196 | v=e[0]*(Real(1.0)-t)+e[1]*t; 197 | return Distance(p,v); 198 | } 199 | } 200 | template 201 | Real DistanceToTriangle(const Point3D& p,const Point3D t[3]) 202 | { 203 | Point3D e[2]; 204 | Point3D q,v,n,nn; 205 | 206 | n=Normal(t[0],t[1],t[2]); 207 | for(int i=0;i<3;i++) 208 | { 209 | v=t[(i+1)%3]-t[i]; 210 | q=p-t[i]; 211 | CrossProduct(n,v,nn); 212 | if(DotProduct(q,nn)<=0) 213 | { 214 | e[0]=t[i]; 215 | e[1]=t[(i+1)%3]; 216 | return DistanceToEdge(p,e); 217 | } 218 | } 219 | return fabs(DotProduct(q,n))/Length(n); 220 | } 221 | template 222 | Point3D NearestPointOnEdge(const Point3D& p,const Point3D e[2],int& vFlag) 223 | { 224 | Point3D q,v; 225 | Real dot; 226 | 227 | q=p-e[0]; 228 | v=e[1]-e[0]; 229 | 230 | dot=DotProduct(q,v); 231 | if(dot<=0) 232 | { 233 | vFlag=1; 234 | return e[0]; 235 | } 236 | else if (dot>=SquareLength(v)) 237 | { 238 | vFlag=2; 239 | return e[1]; 240 | } 241 | else 242 | { 243 | Real t=dot/Real(SquareLength(v)); 244 | v=e[0]*(Real(1.0)-t)+e[1]*t; 245 | vFlag=3; 246 | return v; 247 | } 248 | } 249 | template 250 | Point3D NearestPointOnTriangle(const Point3D& p,const Point3D t[3],int& vFlag) 251 | { 252 | Point3D e[2]; 253 | Point3D q,v,n,nn,nearest; 254 | vFlag=0; 255 | 256 | n=Normal(t[0],t[1],t[2]); 257 | for(int i=0;i<3;i++) 258 | { 259 | v=t[(i+1)%3]-t[i]; 260 | q=p-t[i]; 261 | 262 | CrossProduct(n,v,nn); 263 | if(DotProduct(q,nn)<=0) 264 | { 265 | int tempFlag; 266 | e[0]=t[i]; 267 | e[1]=t[(i+1)%3]; 268 | nearest=NearestPointOnEdge(p,e,tempFlag); 269 | if(tempFlag&1) vFlag|=1< 281 | Point3D NearestPointOnPlane(const Point3D& p,const Point3D t,const Point3D n,int& vFlag) 282 | { 283 | Point3D q,nearest; 284 | vFlag=0; 285 | 286 | q=p-t; 287 | nearest=p-n*DotProduct(q,n); 288 | return nearest; 289 | } 290 | 291 | template 292 | int OutCode(const Point3D& ctr,const Real& w,const Point3D& p) 293 | { 294 | int oc=0; 295 | if(p.coords[0]ctr.coords[0]+w/2) 298 | oc|=2; 299 | if(p.coords[1]ctr.coords[1]+w/2) 302 | oc|=8; 303 | if(p.coords[2]ctr.coords[2]+w/2) 306 | oc|=32; 307 | return oc; 308 | } 309 | template 310 | int PointInCube(const Point3D& ctr,const Real& w,const Point3D& p) 311 | { 312 | return !OutCode(ctr,w,p); 313 | } 314 | template 315 | int EdgeInCube(const Point3D& ctr,const Real& w,const Point3D e[2]) 316 | { 317 | int oc[2],dir,off; 318 | Real t,x; 319 | oc[0]=OutCode(ctr,w,e[0]); 320 | oc[1]=OutCode(ctr,w,e[1]); 321 | if(!oc[0] || !oc[1]) return 1; 322 | if(oc[0] & oc[1]) return 0; 323 | #if 1 324 | for(dir=0;dir<3;dir++) 325 | if((oc[0]>>(dir<<1))&3) 326 | { 327 | off=( (oc[0]>>(dir<<1))&2) >> 1; 328 | t=( e[0][dir]-(ctr[dir] - w/2 + w*off) ) / (e[0][dir]-e[1][dir]); 329 | int inside=0; 330 | for(int i=1;i<3;i++) 331 | { 332 | int j=(dir+i)%3; 333 | x=e[0][j]*(Real(1.0)-t)+e[1][j]*t; 334 | if(x>=(ctr[j]-w/2) && x<=(ctr[j]+w/2)) 335 | inside++; 336 | } 337 | if(inside==2) 338 | return 1; 339 | } 340 | return 0; 341 | #else 342 | for(dir=0;dir<3;dir++) 343 | if((oc[0]>>(dir<<1))&3) 344 | break; 345 | off=( (oc[0]>>(dir<<1))&2) >> 1; 346 | t=( e[0][dir]-(ctr[dir] -w/2 + w*off) ) / (e[0][dir]-e[1][dir]); 347 | for(int i=1;i<3;i++) 348 | { 349 | int j=(dir+i)%3; 350 | x=e[0][j]*(Real(1.0)-t)+e[1][j]*t; 351 | if(x<(ctr[j]-w/2) || x>(ctr[j]+w/2)) 352 | return 0; 353 | } 354 | return 1; 355 | #endif 356 | } 357 | #ifdef ISO_OCTREE_INCLUDED 358 | template 359 | int TriangleInCube(const Point3D& ctr,const Real& w,const Point3D t[3]) 360 | { 361 | Point3D e[2],n,nn[3]; 362 | int oc[3]; 363 | oc[0]=OutCode(ctr,w,t[0]); 364 | oc[1]=OutCode(ctr,w,t[1]); 365 | oc[2]=OutCode(ctr,w,t[2]); 366 | if(!oc[0] || !oc[1] || !oc[2]) 367 | return 1; 368 | if(oc[0] & oc[1] & oc[2]) 369 | return 0; 370 | 371 | for(int i=0;i<3;i++) 372 | { 373 | e[0]=t[i]; 374 | e[1]=t[(i+1)%3]; 375 | if(EdgeInCube(ctr,w,e)) 376 | return 1; 377 | } 378 | 379 | n=Normal(t[0],t[1],t[2]); 380 | for(int i=0;i<3;i++) 381 | CrossProduct(n,t[(i+1)%3]-t[i],nn[i]); 382 | 383 | for(int i=0;i p; 388 | Cube::EdgeCorners(i,c1,c2); 389 | Cube::FactorCornerIndex(c1,x[0],x[1],x[2]); 390 | for(int j=0;j<3;j++) e[0][j]=ctr[j]-w/2+w*x[j]; 391 | 392 | Cube::FactorCornerIndex(c2,x[0],x[1],x[2]); 393 | for(int j=0;j<3;j++) e[1][j]=ctr[j]-w/2+w*x[j]; 394 | 395 | dot[0]=DotProduct(n,e[0]-t[0]); 396 | dot[1]=DotProduct(n,e[1]-t[0]); 397 | if(dot[0]*dot[1] >=0 ) continue; 398 | tt=dot[0]/(dot[0]-dot[1]); 399 | p=e[0]*(Real(1.0)-tt)+e[1]*tt; 400 | if(DotProduct(p-t[0],nn[0])>0 && DotProduct(p-t[1],nn[1])>0 && DotProduct(p-t[2],nn[2])>0 ) 401 | return 1; 402 | } 403 | return 0; 404 | } 405 | #endif 406 | 407 | 408 | -------------------------------------------------------------------------------- /src/Hash.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_INCLUDED 2 | #define HASH_INCLUDED 3 | #ifdef WIN32 4 | #include 5 | using stdext::hash_map; 6 | #else // !WIN32 7 | #include 8 | using namespace __gnu_cxx; 9 | 10 | namespace __gnu_cxx 11 | { 12 | template<> struct hash { 13 | size_t operator()(long long __x) const { return __x; } 14 | }; 15 | template<> struct hash { 16 | size_t operator()(const long long __x) const { return __x; } 17 | }; 18 | 19 | 20 | template<> struct hash { 21 | size_t operator()(unsigned long long __x) const { return __x; } 22 | }; 23 | template<> struct hash { 24 | size_t operator()(const unsigned long long __x) const { return __x; } 25 | }; 26 | } 27 | #endif // WIN32 28 | #endif // HASH_INCLUDED -------------------------------------------------------------------------------- /src/IsoOctree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007, Michael Kazhdan 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #ifndef ISO_OCTREE_INCLUDED 29 | #define ISO_OCTREE_INCLUDED 30 | 31 | #include "Hash.h" 32 | #include "MarchingCubes.h" 33 | #include "Octree.h" 34 | 35 | class EdgeKey 36 | { 37 | public: 38 | size_t key1,key2; 39 | EdgeKey(void){;} 40 | EdgeKey(const size_t& n1,const size_t &n2); 41 | 42 | EdgeKey& operator = (const EdgeKey& key); 43 | operator size_t () const; 44 | operator size_t (); 45 | bool operator < (const EdgeKey& key) const; 46 | 47 | bool operator != (const EdgeKey& key) const; 48 | }; 49 | #ifndef WIN32 50 | class HashEdgeKey 51 | { 52 | public: 53 | long long operator()(const EdgeKey &key) const 54 | { 55 | return (long long)key.key1 | (long long)key.key2 <<32; 56 | } 57 | }; 58 | #endif 59 | template 60 | class NeighborKey : public OctNode::NeighborKey 61 | { 62 | void __GetCornerNeighbors(OctNode* node,const int& depth,const int& c,OctNode* neighbors[Cube::CORNERS]); 63 | OctNode* __FaceNeighbor(OctNode* node,const int& depth,int dir,int off); 64 | OctNode* __EdgeNeighbor(OctNode* node,const int& depth,int o,int i1,int i2); 65 | OctNode* __CornerNeighbor(OctNode* node,const int& depth,int x,int y,int z); 66 | public: 67 | void GetCornerNeighbors(OctNode* node,const int& c,OctNode* neighbors[Cube::CORNERS]); 68 | OctNode* FaceNeighbor(OctNode* node,int dir,int off); 69 | OctNode* EdgeNeighbor(OctNode* node,int o,int i1,int i2); 70 | OctNode* CornerNeighbor(OctNode* node,int x,int y,int z); 71 | 72 | static void CornerIndex(const int& c,int idx[3]); 73 | static void EdgeIndex(const int& c,int idx[3]); 74 | static void FaceIndex(const int& c,int idx[3]); 75 | 76 | using OctNode::NeighborKey::depth; 77 | using OctNode::NeighborKey::neighbors; 78 | using OctNode::NeighborKey::setNeighbors; 79 | using OctNode::NeighborKey::getNeighbors; 80 | }; 81 | 82 | template 83 | class IsoOctree 84 | { 85 | protected: 86 | class TriangleIndex 87 | { 88 | public: 89 | int idx[3]; 90 | }; 91 | class RootInfo 92 | { 93 | public: 94 | const OctNode* node; 95 | int edgeIndex; 96 | long long key; 97 | typename OctNode::NodeIndex nIdx; 98 | }; 99 | template 100 | class MeshInfo 101 | { 102 | public: 103 | std::vector > vertexNormals; 104 | #ifdef WIN32 105 | stdext::hash_map > edgeNormals; 106 | #else 107 | stdext::hash_map,HashEdgeKey > edgeNormals; 108 | #endif 109 | std::vector > triangleNormals; 110 | std::vector triangles; 111 | std::vector > vertices; 112 | std::vector vertexCurvatures; 113 | 114 | template 115 | void set(const std::vector& vertices,const std::vector >& polygons,const Real& width, 116 | Point3D& translate,Real& scale,const int& noTransform); 117 | template 118 | void set2(const std::vector& vertices,const std::vector >& polygons,const Real& width, 119 | Point3D& translate,Real& scale,const int& noTransform); 120 | }; 121 | 122 | template 123 | void getRoots(OctNode* node,const typename OctNode::NodeIndex& nIdx,const Real& isoValue,stdext::hash_map& roots,std::vector& vertices); 124 | int getRootIndex(OctNode* node,const typename OctNode::NodeIndex& nIdx,const int& edgeIndex,RootInfo& ri); 125 | int getRootPosition(const OctNode* node,const typename OctNode::NodeIndex& nIdx,const int& eIndex,const Real& isoValue,Point3D& position); 126 | long long getRootKey(const typename OctNode::NodeIndex& nIdx,const int& edgeIndex); 127 | 128 | int getRootPair(const RootInfo& root,const int& maxDepth,RootInfo& pair); 129 | void getIsoFaceEdges(OctNode* node,const typename OctNode::NodeIndex& nIdx,const int& faceIndex,std::vector >& edges,const int& flip,const int& useFull); 130 | void getIsoPolygons(OctNode* node,const typename OctNode::NodeIndex& nIdx,stdext::hash_map& roots,std::vector >& polygons,const int& useFull); 131 | 132 | template 133 | void getEdgeLoops(std::vector >& edges,stdext::hash_map& roots,std::vector >& polygons); 134 | 135 | template 136 | void getEdgeLoops(std::vector >& edges,std::vector >& loops); 137 | 138 | template 139 | void setDistanceAndNormal(const std::vector& triangles,MeshInfo& mInfo,const Point3D& p, Real& v,Point3D& n); 140 | template 141 | void setChildren(OctNode* node,const typename OctNode::NodeIndex& nIdx, 142 | const std::vector& triangles,MeshInfo& mInfo,const int& maxDepth,const int& setCenter,const Real& flatness,stdext::hash_map*>* triangleMap=NULL); 143 | 144 | // Assumes NodeData::mcIndex 145 | void setMCIndex(const Real& isoValue,const int& useFull); 146 | 147 | NeighborKey nKey; 148 | public: 149 | // The maximum depth of the tree. This value must be at least as large as the true depth of the tree 150 | // as its used for assigning unique ids. (It can, however, be larger than the depth for uniqueness to still hold.) 151 | int maxDepth; 152 | // The octree itself 153 | OctNode tree; 154 | // A hash-table of data associated to the corners of the octree nodes 155 | stdext::hash_map cornerValues; 156 | 157 | // Sets an octree from a polygon mesh, generating an octree that is fully refined around the surface 158 | template 159 | int set(const std::vector& vertices,const std::vector >& polygons,const int& maxDepth,const int& setCenter,const Real& flatness,const int& noTransform); 160 | template 161 | int set(const std::vector& vertices,const std::vector >& polygons,const int& maxDepth,const int& setCenter,const Real& flatness,Point3D& translate,Real& scale,const int& noTransform); 162 | // Sets an octree from a polygon mesh, generating an octree that is fully refined around the surface 163 | template 164 | int setConforming(const std::vector& vertices,const std::vector >& polygons,const int& maxDepth,const int& setCenter,const Real& flatness,const int& noTransform); 165 | template 166 | int setConforming(const std::vector& vertices,const std::vector >& polygons,const int& maxDepth,const int& setCenter,const Real& flatness,Point3D& translate,Real& scale,const int& noTransform); 167 | 168 | // A clean-up method to remove un-needed entries in the cornerValues hash-table 169 | void resetValues(void); 170 | // Reads the octree from a file pointer 171 | int read(FILE* fp,int readData); 172 | // Writes the octree to a file pointer 173 | int write(FILE* fp,int writeData) const; 174 | 175 | void interpolateSharedValues(void); 176 | 177 | // Extracts an iso-surface from the octree 178 | template 179 | void getIsoSurface(const Real& isoValue,std::vector& vertices,std::vector >& polygons,const int& useFull); 180 | template 181 | void getIsoSoup(const Real& isoValue,std::vector& vertices,std::vector >& polygons,const int& useFull); 182 | template 183 | void getDualIsoSurface(const Real& isoValue,std::vector& vertices,std::vector >& polygons,const int& useFull); 184 | // Generates a hash-table indexed by octree node, with each entry containing two pieces of data. The first is 185 | // mean-curvature vector associated to the intersection of the iso-surface with the node. The second is the area 186 | // of the intersection of the iso-surface with the node. 187 | void setNormalFlatness(const Real& isoValue,stdext::hash_map,Real> >& curvature); 188 | 189 | // A method for determing if a node has grand-children along an edge 190 | static int HasEdgeGrandChildren(const OctNode* node,int eIndex); 191 | // A method for determing if a node has grand-children along a face 192 | static int HasFaceGrandChildren(const OctNode* node,int fIndex); 193 | }; 194 | 195 | #include "IsoOctree.inl" 196 | 197 | #endif // ISO_OCTREE_INCLUDED 198 | -------------------------------------------------------------------------------- /src/Kdtree.h: -------------------------------------------------------------------------------- 1 | #ifndef KDTREE_INCLUDED 2 | #define KDTREE_INCLUDED 3 | 4 | #include 5 | 6 | template 7 | class KDTree: public flann::Index > 8 | { 9 | using flann::Index >::knnSearch; 10 | //using flann::Index >::Index; 11 | using flann::Index >::buildIndex; 12 | public: 13 | KDTree(); 14 | void setInputPoints(Real* points, size_t npts); 15 | int KnnSearch(Real* queries, size_t nqrs, 16 | std::vector >& indices, 17 | std::vector >& dists, 18 | const size_t knn) const; 19 | 20 | }; 21 | 22 | #include "Kdtree.inl" 23 | 24 | #endif -------------------------------------------------------------------------------- /src/Kdtree.inl: -------------------------------------------------------------------------------- 1 | template 2 | KDTree::KDTree(): flann::Index >(flann::KDTreeSingleIndexParams(10)) {} 3 | 4 | template 5 | void KDTree::setInputPoints(Real* points, size_t npts) 6 | { 7 | assert(npts>0); 8 | const flann::Matrix pts(points,npts,3); 9 | buildIndex(pts); 10 | } 11 | 12 | template 13 | int KDTree::KnnSearch(Real* queries, size_t nqrs, 14 | std::vector >& indices, 15 | std::vector >& dists, 16 | const size_t knn) const 17 | { 18 | const flann::Matrix qrs(queries,nqrs,3); 19 | flann::SearchParams searchParams(32,0,true); 20 | searchParams.cores=0; 21 | return knnSearch(qrs,indices,dists,knn,searchParams); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/MAT.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007, Michael Kazhdan 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #ifndef MAT_INCLUDED 29 | #define MAT_INCLUDED 30 | #include "Geometry.h" 31 | 32 | template 33 | class MinimalAreaTriangulation 34 | { 35 | Real* bestTriangulation; 36 | int* midPoint; 37 | Real GetArea(const size_t& i,const size_t& j,const std::vector >& vertices); 38 | void GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles); 39 | public: 40 | MinimalAreaTriangulation(void); 41 | ~MinimalAreaTriangulation(void); 42 | Real GetArea(const std::vector >& vertices); 43 | void GetTriangulation(const std::vector >& vertices,std::vector& triangles); 44 | }; 45 | 46 | #include "MAT.inl" 47 | 48 | #endif // MAT_INCLUDED 49 | -------------------------------------------------------------------------------- /src/MAT.inl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007, Michael Kazhdan 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | ////////////////////////////// 29 | // MinimalAreaTriangulation // 30 | ////////////////////////////// 31 | template 32 | MinimalAreaTriangulation::MinimalAreaTriangulation(void) 33 | { 34 | bestTriangulation=NULL; 35 | midPoint=NULL; 36 | } 37 | template 38 | MinimalAreaTriangulation::~MinimalAreaTriangulation(void) 39 | { 40 | if(bestTriangulation) 41 | delete[] bestTriangulation; 42 | bestTriangulation=NULL; 43 | if(midPoint) 44 | delete[] midPoint; 45 | midPoint=NULL; 46 | } 47 | template 48 | void MinimalAreaTriangulation::GetTriangulation(const std::vector >& vertices,std::vector& triangles) 49 | { 50 | if(vertices.size()==3) 51 | { 52 | triangles.resize(1); 53 | triangles[0].idx[0]=0; 54 | triangles[0].idx[1]=1; 55 | triangles[0].idx[2]=2; 56 | return; 57 | } 58 | else if(vertices.size()==4) 59 | { 60 | TriangleIndex tIndex[2][2]; 61 | Real area[2]; 62 | 63 | area[0]=area[1]=0; 64 | triangles.resize(2); 65 | 66 | tIndex[0][0].idx[0]=0; 67 | tIndex[0][0].idx[1]=1; 68 | tIndex[0][0].idx[2]=2; 69 | tIndex[0][1].idx[0]=2; 70 | tIndex[0][1].idx[1]=3; 71 | tIndex[0][1].idx[2]=0; 72 | 73 | tIndex[1][0].idx[0]=0; 74 | tIndex[1][0].idx[1]=1; 75 | tIndex[1][0].idx[2]=3; 76 | tIndex[1][1].idx[0]=3; 77 | tIndex[1][1].idx[1]=1; 78 | tIndex[1][1].idx[2]=2; 79 | 80 | Point3D n,p1,p2; 81 | for(int i=0;i<2;i++) 82 | for(int j=0;j<2;j++) 83 | { 84 | p1=vertices[tIndex[i][j].idx[1]]-vertices[tIndex[i][j].idx[0]]; 85 | p2=vertices[tIndex[i][j].idx[2]]-vertices[tIndex[i][j].idx[0]]; 86 | CrossProduct(p1,p2,n); 87 | area[i]+=Length(n); 88 | } 89 | if(area[0]>area[1]) 90 | { 91 | triangles[0]=tIndex[1][0]; 92 | triangles[1]=tIndex[1][1]; 93 | } 94 | else 95 | { 96 | triangles[0]=tIndex[0][0]; 97 | triangles[1]=tIndex[0][1]; 98 | } 99 | return; 100 | } 101 | if(bestTriangulation) 102 | delete[] bestTriangulation; 103 | if(midPoint) 104 | delete[] midPoint; 105 | bestTriangulation=NULL; 106 | midPoint=NULL; 107 | size_t eCount=vertices.size(); 108 | bestTriangulation=new Real[eCount*eCount]; 109 | midPoint=new int[eCount*eCount]; 110 | for(size_t i=0;i 118 | Real MinimalAreaTriangulation::GetArea(const std::vector >& vertices) 119 | { 120 | if(bestTriangulation) 121 | delete[] bestTriangulation; 122 | if(midPoint) 123 | delete[] midPoint; 124 | bestTriangulation=NULL; 125 | midPoint=NULL; 126 | int eCount=vertices.size(); 127 | bestTriangulation=new double[eCount*eCount]; 128 | midPoint=new int[eCount*eCount]; 129 | for(int i=0;i 135 | void MinimalAreaTriangulation::GetTriangulation(const size_t& i,const size_t& j,const std::vector >& vertices,std::vector& triangles) 136 | { 137 | TriangleIndex tIndex; 138 | size_t eCount=vertices.size(); 139 | size_t ii=i; 140 | if(i=ii) 143 | return; 144 | ii=midPoint[i*eCount+j]; 145 | if(ii>=0) 146 | { 147 | tIndex.idx[0]=i; 148 | tIndex.idx[1]=j; 149 | tIndex.idx[2]=ii; 150 | triangles.push_back(tIndex); 151 | GetTriangulation(i,ii,vertices,triangles); 152 | GetTriangulation(ii,j,vertices,triangles); 153 | } 154 | } 155 | 156 | template 157 | Real MinimalAreaTriangulation::GetArea(const size_t& i,const size_t& j,const std::vector >& vertices) 158 | { 159 | Real a=FLT_MAX,temp; 160 | size_t eCount=vertices.size(); 161 | size_t idx=i*eCount+j; 162 | size_t ii=i; 163 | if(i=ii) 166 | { 167 | bestTriangulation[idx]=0; 168 | return 0; 169 | } 170 | if(midPoint[idx]!=-1) 171 | return bestTriangulation[idx]; 172 | int mid=-1; 173 | for(size_t r=j+1;r p,p1,p2; 178 | p1=vertices[i]-vertices[rr]; 179 | p2=vertices[j]-vertices[rr]; 180 | CrossProduct(p1,p2,p); 181 | temp=Length(p); 182 | if(bestTriangulation[idx1]>=0) 183 | { 184 | temp+=bestTriangulation[idx1]; 185 | if(temp>a) 186 | continue; 187 | if(bestTriangulation[idx2]>0) 188 | temp+=bestTriangulation[idx2]; 189 | else 190 | temp+=GetArea(rr,j,vertices); 191 | } 192 | else 193 | { 194 | if(bestTriangulation[idx2]>=0) 195 | temp+=bestTriangulation[idx2]; 196 | else 197 | temp+=GetArea(rr,j,vertices); 198 | if(temp>a) 199 | continue; 200 | temp+=GetArea(i,rr,vertices); 201 | } 202 | 203 | if(temp 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include "IsoOctree.h" 39 | #include "OctreeBspline.h" 40 | #include "CmdLineParser.h" 41 | #include "Ply.h" 42 | #include "Time.h" 43 | #include "VertexData.h" 44 | #include "Geometry.h" 45 | #include "MAT.h" 46 | #include "PolygonizerHelper.h" 47 | 48 | typedef PlyVertexWithNormal InPlyVertex; 49 | typedef PlyVertex OutPlyVertex; 50 | 51 | template 52 | class MyNodeData 53 | { 54 | public: 55 | int mcIndex; 56 | Point3D center; 57 | VertexData v; 58 | }; 59 | 60 | template 61 | int IsClippable(const IsoOctree& isoTree, 62 | OctNode* node,const typename OctNode::NodeIndex& nIndex, 63 | stdext::hash_map,Real> >& flatness, 64 | const Real& clipValue,const int& forceConforming) 65 | { 66 | if(forceConforming) 67 | { 68 | for(int i=0;i::HasFaceGrandChildren(node->faceNeighbor(i),Cube::FaceReflectFaceIndex(i,i))) 70 | return 0; 71 | for(int i=0;i::HasEdgeGrandChildren(node->edgeNeighbor(i),Cube::EdgeReflectEdgeIndex(i))) 73 | return 0; 74 | } 75 | long long key=OctNode::CenterIndex(nIndex,isoTree.maxDepth); 76 | if(flatness.find(key)!=flatness.end()) 77 | { 78 | float normalSize=Length(flatness[key].first); 79 | float areaSize=flatness[key].second; 80 | if(normalSize/areaSize>clipValue) 81 | return 1; 82 | else 83 | return 0; 84 | } 85 | else 86 | return 1; 87 | } 88 | template 89 | void PolygonToTriangleMesh(const std::vector& vertices,const std::vector< std::vector >& polygons, 90 | std::vector >& triangles) 91 | { 92 | MinimalAreaTriangulation mat; 93 | triangles.clear(); 94 | for(size_t i=0;i > loop; 97 | std::vector vertexMap; 98 | std::vector tgl; 99 | loop.resize(polygons[i].size()); 100 | vertexMap.resize(polygons[i].size()); 101 | for(size_t j=0;j 119 | void PolygonToManifoldTriangleMesh( std::vector& vertices , const std::vector< std::vector >& polygons , 120 | std::vector >& triangles ) 121 | { 122 | std::vector< int > t; 123 | t.resize( 3 ); 124 | triangles.clear(); 125 | for( int i=0 ; i3 ) 130 | { 131 | Point3D< Real > center; 132 | center *= 0; 133 | for( int j=0 ; j\n"); 153 | printf("\t\tInput oriented points (.ply) used to generate the EDT.\n\n"); 154 | 155 | printf("\t--out \n"); 156 | printf("\t\tOutput mesh (.ply)\n"); 157 | 158 | printf("\t--maxDepth \n"); 159 | printf("\t\tThis specifies the maximum depth of the\n"); 160 | printf("\t\tgenerated distance tree.\n\n"); 161 | 162 | printf("\t[--flatness ]\n"); 163 | printf("\t\tThis flag forces the octree to be clipped so the octree\n"); 164 | printf("\t\tis not refined around planar regions. (In pracice,\n"); 165 | printf("\t\ta value of about .99 works well.)\n\n"); 166 | 167 | printf("\t[--curvature ]\n"); 168 | printf("\t\tThis flag forces the generated distance/bslines octree\n"); 169 | printf("\t\tto be adaptive to the local point curvatures. (In pracice,\n"); 170 | printf("\t\ta value of about .5 works well.)\n\n"); 171 | 172 | printf("\t[--fullCaseTable]\n"); 173 | printf("\t\tIf this flag is enabled, the full marching cubes table is\n"); 174 | printf("\t\tused, diambiguating based on the esimated value at the\n"); 175 | printf("\t\tcenter of faces.\n\n"); 176 | 177 | printf("\t[--triangleMesh]\n"); 178 | printf("\t\tIf this flag is enabled and the output is a mesh, \n"); 179 | printf("\t\tthe mesh will be triangulated by computing the minimal\n"); 180 | printf("\t\tarea triangulation of the polygons in the mesh\n\n"); 181 | 182 | printf("\t[--manifold]\n"); 183 | printf("\t\tIf this flag is enabled and the output is a mesh, the mesh\n"); 184 | printf("\t\twill be triangulated by adding the barycenter to each \n"); 185 | printf("\t\tpolygon with more than three vertices.\n\n"); 186 | 187 | printf("\t[--bspline ]\n"); 188 | printf("\t\tThis flag forces the distance field to be fitted by\n"); 189 | printf("\t\ta hierarchical b-splines. The default max depth is\n"); 190 | printf("\t\tequal to the max depth of distance tree\n\n"); 191 | 192 | printf("\t[--volume ]\n"); 193 | printf("\t\tThis flag tell the program to output a signed distance volume\n"); 194 | printf("\t\t(volume.vti). Generally, we set grid resolution to 128.\n\n"); 195 | 196 | printf("\t[--smooth ]\n"); 197 | printf("\t\tThe default smooth weight is set to 0.001.\n\n"); 198 | 199 | printf("\t[--interpolate ]\n"); 200 | printf("\t\tThe default interpolate weight is set to 0.0.\n\n"); 201 | 202 | printf("\t[--minDepthTree]\n"); 203 | printf("\t\tThis flag forces the leaf node of distance tree to at least minDepthTree.\n"); 204 | printf("\t\tNote the B-Splines tree is not forced.\n\n"); 205 | 206 | printf("\t[--minDepthMC ]\n"); 207 | printf("\t\tThis flag forces the MC leaf node to at least minDepthMC.\n\n"); 208 | 209 | printf("\t[--splat ]\n"); 210 | printf("\t\tThe default splat factor is set 1.0.\n\n"); 211 | 212 | printf("\t[--noFit]\n"); 213 | printf("\t\tIf this flag is set, the isosurface is directly extracted\n"); 214 | printf("\t\tfrom the adaptive signed distance field without fitting.\n\n"); 215 | 216 | printf("\t[--octree ]\n"); 217 | printf("\t\tThis flag tell the program to output \n"); 218 | printf("\t\tthe octree grid (octree.vtk).\n"); 219 | printf("\t\tdepth=-1 output complete octree.\n"); 220 | printf("\t\tdepth>= output corresponding depth.\n\n"); 221 | 222 | printf("\t[--normal]\n"); 223 | printf("\t\tThis flag tell the program to output mesh with normal\n\n"); 224 | 225 | printf("\t[--sphereTest]\n"); 226 | printf("\t\tThis flag tell the program to perform sphereTest\n\n"); 227 | 228 | printf("\t[--isoValue ]\n"); 229 | printf("\t\tThis flag tell the program the isoValue\n\n"); 230 | 231 | printf("\t[--bloomenthal ]\n"); 232 | printf("\t\tThis flag tell the program the extract Bloomenthal's iso-surface\n\n"); 233 | } 234 | 235 | int main(int argc,char* argv[]) 236 | { 237 | MarchingCubes::SetCaseTable(); 238 | MarchingCubes::SetFullCaseTable(); 239 | 240 | typedef OctNode,float>,float> MyOctNode; 241 | 242 | cmdLineString In, Out; 243 | cmdLineReadable Conforming,FullCaseTable,TriangleMesh,Dual,Manifold,NoFit,Normal,SphereTest; 244 | cmdLineFloat Flatness(-1),Curvature(-1),Smooth(0.001),Interpolate(0.0),Splat(1.0),IsoValue(0.0); 245 | cmdLineInt MaxDepth,Bspline(-1),Volume(128),MinDepthMC(-1),Bloomenthal(128),MinDepthTree(-1),Octree(-1); 246 | char* paramNames[]= 247 | { 248 | "in","out","flatness","curvature","conforming","fullCaseTable","maxDepth","triangleMesh","dual","manifold", 249 | "bspline","smooth","interpolate","minDepthTree","minDepthMC","volume","splat","noFit","octree","normal","sphereTest", 250 | "isoValue","bloomenthal" 251 | }; 252 | cmdLineReadable* params[]= 253 | { 254 | &In,&Out,&Flatness,&Curvature,&Conforming,&FullCaseTable,&MaxDepth,&TriangleMesh,&Dual,&Manifold, 255 | &Bspline,&Smooth,&Interpolate,&MinDepthTree,&MinDepthMC,&Volume,&Splat,&NoFit,&Octree,&Normal,&SphereTest, 256 | &IsoValue,&Bloomenthal 257 | }; 258 | int paramNum=sizeof(paramNames)/sizeof(char*); 259 | cmdLineParse(argc-1,&argv[1],paramNames,paramNum,params,0); 260 | 261 | if((!SphereTest.set && !In.set) || !Out.set || !MaxDepth.set) 262 | { 263 | ShowUsage(argv[0]); 264 | return EXIT_FAILURE; 265 | } 266 | 267 | if(Bspline.set && (Bspline.value<=0 || Bspline.value>MaxDepth.value)) Bspline.value=MaxDepth.value; 268 | 269 | Point3D translate; 270 | float scale=1.f; 271 | translate[0]=translate[1]=translate[2]=0; 272 | 273 | typedef OctreeBspline,float>,float,VertexValue> OctBspline; 274 | OctBspline octreeBspline; 275 | octreeBspline.maxBsplineDepth=Bspline.value; 276 | 277 | int ft; 278 | std::vector inVertices; 279 | std::vector > polygons; 280 | double t; 281 | 282 | if(SphereTest.set) 283 | { 284 | ft=PLY_ASCII; 285 | octreeBspline.set4(MaxDepth.value,translate,scale); 286 | } 287 | else 288 | { 289 | t=Time(); 290 | printf("Loading data ...\n"); 291 | PlyReadPolygons(In.value,inVertices,polygons,ft); 292 | printf("Got data in: %f\n", Time()-t); 293 | 294 | printf("Establishing signed distance field ...\n"); 295 | printf("maxDepth: %d\n", MaxDepth.value); 296 | printf("maxBsplineDepth: %d\n", Bspline.value); 297 | t=Time(); 298 | octreeBspline.set3(inVertices,polygons,MaxDepth.value,Dual.set,Flatness.value,Curvature.value,Splat.value,MinDepthTree.value,translate,scale,0,!NoFit.set); 299 | printf("Got signed distance field in: %f\n", Time()-t); 300 | printf("Nodes In: %d / %d\n",octreeBspline.IsoOctree::tree.nodes(),octreeBspline.IsoOctree::tree.leaves()); 301 | printf("Values In: %d\n",octreeBspline.IsoOctree::cornerValues.size()); 302 | printf("Scale : %f\n",scale); 303 | printf("Translate : %f %f %f\n",translate[0],translate[1],translate[2]); 304 | 305 | std::vector emptyVertices; 306 | std::vector > emptyPolygons; 307 | 308 | inVertices.swap(emptyVertices); 309 | polygons.swap(emptyPolygons); 310 | } 311 | 312 | if(Octree.set) octreeBspline.exportOctreeGrid(scale, translate, Octree.value); 313 | 314 | if(!NoFit.set && Bspline.set && Bspline.value>0) 315 | { 316 | t=Time(); 317 | printf("Fitting data ...\n"); 318 | //octreeBspline.directBsplineFitting(Smooth.value,Interpolate.value); 319 | octreeBspline.multigridBsplineFitting(Smooth.value,Interpolate.value); 320 | printf("Got fitted in: %f\n", Time()-t); 321 | } 322 | 323 | std::vector outVertices; 324 | printf("Estracting iso-surface ...\n"); 325 | t=Time(); 326 | if(!NoFit.set && Bspline.set && Bspline.value>0) octreeBspline.updateCornerValues(); 327 | if(!NoFit.set && Bspline.set && Bspline.value>0 && MinDepthMC.set) octreeBspline.setMinDepthMCLeafNode(0,MinDepthMC.value,FullCaseTable.set); 328 | octreeBspline.getIsoSurface(IsoValue.value,outVertices,polygons,FullCaseTable.set); 329 | printf("Got iso-surface in: %f\n",Time()-t); 330 | 331 | for(size_t i=0;i > triangles; 335 | if(Manifold.set) 336 | { 337 | double t=Time(); 338 | PolygonToManifoldTriangleMesh(outVertices,polygons,triangles); 339 | printf("Converted polygons to triangles in: %f\n",Time()-t); 340 | PlyWritePolygons(Out.value,outVertices,triangles,ft); 341 | printf("Vertices: %d\n",outVertices.size()); 342 | printf("Triangles: %d\n",triangles.size()); 343 | } 344 | else if(TriangleMesh.set) 345 | { 346 | double t=Time(); 347 | PolygonToTriangleMesh(outVertices,polygons,triangles); 348 | printf("Converted polygons to triangles in: %f\n",Time()-t); 349 | PlyWritePolygons(Out.value,outVertices,triangles,ft); 350 | printf("Vertices: %d\n",outVertices.size()); 351 | printf("Triangles: %d\n",triangles.size()); 352 | } 353 | else 354 | { 355 | PlyWritePolygons(Out.value,outVertices,polygons,ft); 356 | printf("Vertices: %d\n",outVertices.size()); 357 | printf("Polygons: %d\n",polygons.size()); 358 | } 359 | 360 | if(Bspline.set && Bspline.value>0) 361 | { 362 | if(Volume.set && Volume.value>0) octreeBspline.exportVolumeData(scale,translate,Volume.value); 363 | if(SphereTest.set) 364 | { 365 | printf("Extracting SphereTest iso-surface ...\n"); 366 | t=Time(); 367 | PolygonizerHelper::polygonize((Function*)(&octreeBspline),0.0f,1.0f/64,0.5f,0.5f,0.5f); 368 | printf("Got iso-surface in: %f\n", Time()-t); 369 | PolygonizerHelper::saveSphereTest("sphereTest.ply",scale,translate); 370 | } 371 | } 372 | 373 | if(Bloomenthal.set) 374 | { 375 | printf("Extracting Bloomenthal's iso-surface ...\n"); 376 | t=Time(); 377 | PolygonizerHelper::polygonize((Function*)(&octreeBspline),IsoValue.value,1.0f/Bloomenthal.value,0.5f,0.5f,0.5f); 378 | printf("Got Bloomenthal iso-surface in: %f\n", Time()-t); 379 | PolygonizerHelper::save("bloomenthal.ply",scale,translate); 380 | } 381 | 382 | if(Normal.set) 383 | { 384 | std::vector outVertexWithNormals(outVertices.size()); 385 | 386 | for(size_t i=0;i,float>(argc,argv); 413 | else return Process,float>(argc,argv); 414 | } 415 | */ -------------------------------------------------------------------------------- /src/MarchingCubes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007, Michael Kazhdan 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #ifndef MARCHING_CUBES_INCLUDED 29 | #define MARCHING_CUBES_INCLUDED 30 | #include 31 | 32 | class Square 33 | { 34 | public: 35 | const static int CORNERS=4,EDGES=4; 36 | static int CornerIndex (const int& x,const int& y); 37 | static void FactorCornerIndex (const int& idx,int& x,int& y); 38 | static int EdgeIndex (const int& orientation,const int& i); 39 | static void FactorEdgeIndex (const int& idx,int& orientation,int& i); 40 | 41 | static int ReflectCornerIndex (const int& idx,const int& edgeIndex); 42 | static int ReflectEdgeIndex (const int& idx,const int& edgeIndex); 43 | 44 | static void EdgeCorners(const int& idx,int& c1,int &c2); 45 | static void OrientedEdgeCorners(const int& idx,int& c1,int &c2); 46 | }; 47 | 48 | class Cube 49 | { 50 | public: 51 | const static int CORNERS=8,EDGES=12,FACES=6; 52 | 53 | static int CornerIndex (const int& x,const int& y,const int& z); 54 | static void FactorCornerIndex (const int& idx,int& x,int& y,int& z); 55 | static int EdgeIndex (const int& orientation,const int& i,const int& j); 56 | static void FactorEdgeIndex (const int& idx,int& orientation,int& i,int &j); 57 | static int FaceIndex (const int& dir,const int& offSet); 58 | static int FaceIndex (const int& x,const int& y,const int& z); 59 | static void FactorFaceIndex (const int& idx,int& x,int &y,int& z); 60 | static void FactorFaceIndex (const int& idx,int& dir,int& offSet); 61 | 62 | static int AntipodalCornerIndex (const int& idx); 63 | static int FaceReflectCornerIndex (const int& idx,const int& faceIndex); 64 | static int FaceReflectEdgeIndex (const int& idx,const int& faceIndex); 65 | static int FaceReflectFaceIndex (const int& idx,const int& faceIndex); 66 | static int EdgeReflectCornerIndex (const int& idx,const int& edgeIndex); 67 | static int EdgeReflectEdgeIndex (const int& edgeIndex); 68 | 69 | static int FaceAdjacentToEdges (const int& eIndex1,const int& eIndex2); 70 | static void FacesAdjacentToEdge (const int& eIndex,int& f1Index,int& f2Index); 71 | 72 | static void EdgeCorners(const int& idx,int& c1,int &c2); 73 | static void FaceCorners(const int& idx,int& c1,int &c2,int& c3,int& c4); 74 | 75 | static int SquareToCubeCorner(const int& fIndex,const int& cIndex); 76 | static int SquareToCubeEdge(const int& fIndex,const int& eIndex); 77 | }; 78 | 79 | class MarchingSquares 80 | { 81 | public: 82 | class FaceEdges 83 | { 84 | public: 85 | int count; 86 | std::pair edge[2]; 87 | }; 88 | private: 89 | static FaceEdges __caseTable [1<<(Square::CORNERS )]; 90 | static FaceEdges __fullCaseTable[1<<(Square::CORNERS+1)]; 91 | public: 92 | static void SetCaseTable(void); 93 | static void SetFullCaseTable(void); 94 | 95 | static const FaceEdges& caseTable(const int& idx); 96 | static const FaceEdges& fullCaseTable(const int& idx); 97 | template 98 | static int GetFullIndex(const Real values[Square::CORNERS],const Real& iso); 99 | template 100 | static int GetIndex(const Real values[Square::CORNERS],const Real& iso); 101 | }; 102 | 103 | class MarchingCubes 104 | { 105 | static void GetEdgeLoops(std::vector >& edges,std::vector >& loops); 106 | static std::vector< std::vector > __caseTable[1< > > __fullCaseTable; 109 | public: 110 | static void SetCaseTable(void); 111 | static void SetFullCaseTable(void); 112 | 113 | template 114 | static int GetFullIndex(const Real values[Cube::CORNERS],const Real& iso); 115 | template 116 | static int GetIndex(const Real values[Cube::CORNERS],const Real& iso); 117 | static const std::vector< std::vector >& caseTable(const int& idx); 118 | static const std::vector< std::vector >& fullCaseTable(const int& idx); 119 | static const std::vector< std::vector >& caseTable(const int& idx,const int& useFull); 120 | 121 | static int IsAmbiguous(const int& idx); 122 | static int IsAmbiguous(const int& idx,const int& f); 123 | static int HasRoots(const int& mcIndex); 124 | static int HasEdgeRoots(const int& mcIndex,const int& edgeIndex); 125 | }; 126 | #include "MarchingCubes.inl" 127 | #endif //MARCHING_CUBES_INCLUDED 128 | -------------------------------------------------------------------------------- /src/MarchingCubes.inl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007, Michael Kazhdan 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #include 29 | //////////// 30 | // Square // 31 | //////////// 32 | int Square::CornerIndex(const int& x,const int& y){return (y<<1)|x;} 33 | void Square::FactorCornerIndex(const int& idx,int& x,int& y){ 34 | x=(idx>>0)%2; 35 | y=(idx>>1)%2; 36 | } 37 | int Square::EdgeIndex(const int& orientation,const int& i){ 38 | switch(orientation){ 39 | case 0: // x 40 | if(!i) {return 0;} // (0,0) -> (1,0) 41 | else {return 2;} // (0,1) -> (1,1) 42 | case 1: // y 43 | if(!i) {return 3;} // (0,0) -> (0,1) 44 | else {return 1;} // (1,0) -> (1,1) 45 | }; 46 | return -1; 47 | } 48 | void Square::FactorEdgeIndex(const int& idx,int& orientation,int& i){ 49 | switch(idx){ 50 | case 0: case 2: 51 | orientation=0; 52 | i=idx/2; 53 | return; 54 | case 1: case 3: 55 | orientation=1; 56 | i=((idx/2)+1)%2; 57 | return; 58 | }; 59 | } 60 | void Square::EdgeCorners(const int& idx,int& c1,int& c2){ 61 | int orientation,i; 62 | FactorEdgeIndex(idx,orientation,i); 63 | switch(orientation){ 64 | case 0: 65 | c1=CornerIndex(0,i); 66 | c2=CornerIndex(1,i); 67 | break; 68 | case 1: 69 | c1=CornerIndex(i,0); 70 | c2=CornerIndex(i,1); 71 | break; 72 | }; 73 | } 74 | void Square::OrientedEdgeCorners(const int& idx,int& c1,int& c2){ 75 | int orientation,i; 76 | FactorEdgeIndex(idx,orientation,i); 77 | switch(orientation){ 78 | case 0: 79 | c1=CornerIndex((i )&1,i); 80 | c2=CornerIndex((i+1)&1,i); 81 | break; 82 | case 1: 83 | c1=CornerIndex(i,(i+1)&1); 84 | c2=CornerIndex(i,(i )&1); 85 | break; 86 | }; 87 | } 88 | int Square::ReflectEdgeIndex(const int& idx,const int& edgeIndex){ 89 | int orientation=edgeIndex%2; 90 | int o,i; 91 | FactorEdgeIndex(idx,o,i); 92 | if(o!=orientation){return idx;} 93 | else{return EdgeIndex(o,(i+1)%2);} 94 | } 95 | int Square::ReflectCornerIndex(const int& idx,const int& edgeIndex){ 96 | int orientation=edgeIndex%2; 97 | int x,y; 98 | FactorCornerIndex(idx,x,y); 99 | switch(orientation){ 100 | case 0: return CornerIndex((x+1)%2,y); 101 | case 1: return CornerIndex(x,(y+1)%2); 102 | }; 103 | return -1; 104 | } 105 | 106 | 107 | 108 | ////////// 109 | // Cube // 110 | ////////// 111 | int Cube::CornerIndex(const int& x,const int& y,const int& z){return (z<<2)|(y<<1)|x;} 112 | void Cube::FactorCornerIndex(const int& idx,int& x,int& y,int& z){ 113 | x=(idx>>0)%2; 114 | y=(idx>>1)%2; 115 | z=(idx>>2)%2; 116 | } 117 | int Cube::EdgeIndex(const int& orientation,const int& i,const int& j){return (i | (j<<1))|(orientation<<2);} 118 | void Cube::FactorEdgeIndex(const int& idx,int& orientation,int& i,int &j){ 119 | orientation=idx>>2; 120 | i=idx&1; 121 | j=(idx&2)>>1; 122 | } 123 | int Cube::FaceIndex(const int& x,const int& y,const int& z){ 124 | if (x<0) {return 0;} 125 | else if (x>0) {return 1;} 126 | else if (y<0) {return 2;} 127 | else if (y>0) {return 3;} 128 | else if (z<0) {return 4;} 129 | else if (z>0) {return 5;} 130 | else {return -1;} 131 | } 132 | int Cube::FaceIndex(const int& dir,const int& offSet){return (dir<<1)|offSet;} 133 | 134 | void Cube::FactorFaceIndex(const int& idx,int& x,int& y,int& z){ 135 | x=y=z=0; 136 | switch(idx){ 137 | case 0: x=-1; break; 138 | case 1: x= 1; break; 139 | case 2: y=-1; break; 140 | case 3: y= 1; break; 141 | case 4: z=-1; break; 142 | case 5: z= 1; break; 143 | }; 144 | } 145 | void Cube::FactorFaceIndex(const int& idx,int& dir,int& offSet){ 146 | dir = idx>>1; 147 | offSet=idx &1; 148 | } 149 | 150 | int Cube::FaceAdjacentToEdges(const int& eIndex1,const int& eIndex2){ 151 | int f1,f2,g1,g2; 152 | FacesAdjacentToEdge(eIndex1,f1,f2); 153 | FacesAdjacentToEdge(eIndex2,g1,g2); 154 | if(f1==g1 || f1==g2){return f1;} 155 | if(f2==g1 || f2==g2){return f2;} 156 | return -1; 157 | } 158 | 159 | void Cube::FacesAdjacentToEdge(const int& eIndex,int& f1Index,int& f2Index){ 160 | int orientation,i1,i2; 161 | FactorEdgeIndex(eIndex,orientation,i1,i2); 162 | i1<<=1; 163 | i2<<=1; 164 | i1--; 165 | i2--; 166 | switch(orientation){ 167 | case 0: 168 | f1Index=FaceIndex( 0,i1, 0); 169 | f2Index=FaceIndex( 0, 0,i2); 170 | break; 171 | case 1: 172 | f1Index=FaceIndex(i1, 0, 0); 173 | f2Index=FaceIndex( 0, 0,i2); 174 | break; 175 | case 2: 176 | f1Index=FaceIndex(i1, 0, 0); 177 | f2Index=FaceIndex( 0,i2, 0); 178 | break; 179 | }; 180 | } 181 | void Cube::EdgeCorners(const int& idx,int& c1,int& c2){ 182 | int orientation,i1,i2; 183 | FactorEdgeIndex(idx,orientation,i1,i2); 184 | switch(orientation){ 185 | case 0: 186 | c1=CornerIndex(0,i1,i2); 187 | c2=CornerIndex(1,i1,i2); 188 | break; 189 | case 1: 190 | c1=CornerIndex(i1,0,i2); 191 | c2=CornerIndex(i1,1,i2); 192 | break; 193 | case 2: 194 | c1=CornerIndex(i1,i2,0); 195 | c2=CornerIndex(i1,i2,1); 196 | break; 197 | }; 198 | } 199 | void Cube::FaceCorners(const int& idx,int& c1,int& c2,int& c3,int& c4){ 200 | int i=idx%2; 201 | switch(idx/2){ 202 | case 0: 203 | c1=CornerIndex(i,0,0); 204 | c2=CornerIndex(i,1,0); 205 | c3=CornerIndex(i,0,1); 206 | c4=CornerIndex(i,1,1); 207 | return; 208 | case 1: 209 | c1=CornerIndex(0,i,0); 210 | c2=CornerIndex(1,i,0); 211 | c3=CornerIndex(0,i,1); 212 | c4=CornerIndex(1,i,1); 213 | return; 214 | case 2: 215 | c1=CornerIndex(0,0,i); 216 | c2=CornerIndex(1,0,i); 217 | c3=CornerIndex(0,1,i); 218 | c4=CornerIndex(1,1,i); 219 | return; 220 | } 221 | } 222 | int Cube::AntipodalCornerIndex(const int& idx){ 223 | int x,y,z; 224 | FactorCornerIndex(idx,x,y,z); 225 | return CornerIndex((x+1)%2,(y+1)%2,(z+1)%2); 226 | } 227 | int Cube::FaceReflectFaceIndex(const int& idx,const int& faceIndex){ 228 | if(idx/2!=faceIndex/2){return idx;} 229 | else{ 230 | if(idx%2) {return idx-1;} 231 | else {return idx+1;} 232 | } 233 | } 234 | int Cube::FaceReflectEdgeIndex(const int& idx,const int& faceIndex){ 235 | int orientation=faceIndex/2; 236 | int o,i,j; 237 | FactorEdgeIndex(idx,o,i,j); 238 | if(o==orientation){return idx;} 239 | switch(orientation){ 240 | case 0: return EdgeIndex(o,(i+1)%2,j); 241 | case 1: 242 | switch(o){ 243 | case 0: return EdgeIndex(o,(i+1)%2,j); 244 | case 2: return EdgeIndex(o,i,(j+1)%2); 245 | }; 246 | case 2: return EdgeIndex(o,i,(j+1)%2); 247 | }; 248 | return -1; 249 | } 250 | int Cube::FaceReflectCornerIndex(const int& idx,const int& faceIndex){ 251 | int orientation=faceIndex/2; 252 | int x,y,z; 253 | FactorCornerIndex(idx,x,y,z); 254 | switch(orientation){ 255 | case 0: return CornerIndex((x+1)%2,y,z); 256 | case 1: return CornerIndex(x,(y+1)%2,z); 257 | case 2: return CornerIndex(x,y,(z+1)%2); 258 | }; 259 | return -1; 260 | } 261 | int Cube::EdgeReflectCornerIndex(const int& idx,const int& edgeIndex){ 262 | int orientation,x,y,z; 263 | FactorEdgeIndex(edgeIndex,orientation,x,y); 264 | FactorCornerIndex(idx,x,y,z); 265 | switch(orientation){ 266 | case 0: return CornerIndex( x ,(y+1)%2,(z+1)%2); 267 | case 1: return CornerIndex((x+1)%2, y ,(z+1)%2); 268 | case 2: return CornerIndex((x+1)%2,(y+1)%2, z ); 269 | }; 270 | return -1; 271 | } 272 | int Cube::EdgeReflectEdgeIndex(const int& edgeIndex){ 273 | int o,i1,i2; 274 | FactorEdgeIndex(edgeIndex,o,i1,i2); 275 | return Cube::EdgeIndex(o,(i1+1)%2,(i2+1)%2); 276 | } 277 | 278 | int Cube::SquareToCubeCorner(const int& fIndex,const int& cIndex) 279 | { 280 | // Assuming that the offset is 0, this returns corners in a consistent orientation 281 | int dir,off,i1,i2; 282 | FactorFaceIndex(fIndex,dir,off); 283 | Square::FactorCornerIndex(cIndex,i1,i2); 284 | switch(dir) 285 | { 286 | case 0: 287 | return CornerIndex(off,i1,i2); 288 | case 1: 289 | return CornerIndex(i1,off,(i2+1)&1); 290 | case 2: 291 | return CornerIndex(i1,i2,off); 292 | } 293 | return -1; 294 | } 295 | int Cube::SquareToCubeEdge(const int& fIndex,const int& eIndex) 296 | { 297 | // Assuming that the offset is 0, this returns corners in a consistent orientation 298 | int dir,off,o,i; 299 | FactorFaceIndex(fIndex,dir,off); 300 | Square::FactorEdgeIndex(eIndex,o,i); 301 | switch(dir) 302 | { 303 | case 0: 304 | if(o==0) 305 | return EdgeIndex(1,off,i); 306 | else if(o==1) 307 | return EdgeIndex(2,off,i); 308 | else 309 | return -1; 310 | case 1: 311 | if(o==0) 312 | return EdgeIndex(0,off,(i+1)&1); 313 | else if(o==1) 314 | return EdgeIndex(2,i,off); 315 | else 316 | return -1; 317 | case 2: 318 | if(o==0) 319 | return EdgeIndex(0,i,off); 320 | else if(o==1) 321 | return EdgeIndex(1,i,off); 322 | else 323 | return -1; 324 | } 325 | return -1; 326 | } 327 | 328 | ///////////////////// 329 | // MarchingSquares // 330 | ///////////////////// 331 | template 332 | int MarchingSquares::GetIndex(const Real v[Square::CORNERS],const Real& iso){ 333 | int idx=0; 334 | for(int i=0;i 338 | int MarchingSquares::GetFullIndex(const Real v[Square::CORNERS],const Real& iso) 339 | { 340 | int idx=0; 341 | Real sum=0; 342 | // Corner Index 343 | for(int i=0;i 419 | int MarchingCubes::GetIndex(const Real v[Cube::CORNERS],const Real& iso){ 420 | int idx=0; 421 | for(int i=0;i 427 | int MarchingCubes::GetFullIndex(const Real values[Cube::CORNERS],const Real& iso) 428 | { 429 | int idx=0; 430 | int c1,c2,c3,c4; 431 | for(int i=0;i >& edges,std::vector >& loops) 462 | { 463 | int loopSize=0; 464 | int idx; 465 | std::pair e,temp; 466 | loops.clear(); 467 | while(edges.size()) 468 | { 469 | e=edges[0]; 470 | loops.resize(loopSize+1); 471 | edges[0]=edges[edges.size()-1]; 472 | edges.pop_back(); 473 | loops[loopSize].push_back(e.first); 474 | idx=e.second; 475 | for(int j=int(edges.size())-1;j>=0;j--){ 476 | if(edges[j].first==idx || edges[j].second==idx){ 477 | if(edges[j].first==idx) {temp=edges[j];} 478 | else {temp.first=edges[j].second;temp.second=edges[j].first;} 479 | idx=temp.second; 480 | loops[loopSize].push_back(temp.first); 481 | edges[j]=edges[edges.size()-1]; 482 | edges.pop_back(); 483 | j=int(edges.size()); 484 | } 485 | } 486 | loopSize++; 487 | } 488 | } 489 | std::vector< std::vector > MarchingCubes::__caseTable[1< >& MarchingCubes::caseTable(const int& idx) 492 | { 493 | return __caseTable[idx]; 494 | } 495 | void MarchingCubes::SetCaseTable(void) 496 | { 497 | MarchingSquares::SetCaseTable(); 498 | int dir,off; 499 | for(int idx=0;idx<(1< > edges; 502 | for(int f=0;f(Cube::SquareToCubeEdge(f,MarchingSquares::caseTable(fIdx).edge[i].first),Cube::SquareToCubeEdge(f,MarchingSquares::caseTable(fIdx).edge[i].second))); 513 | else 514 | edges.push_back(std::pair(Cube::SquareToCubeEdge(f,MarchingSquares::caseTable(fIdx).edge[i].second),Cube::SquareToCubeEdge(f,MarchingSquares::caseTable(fIdx).edge[i].first))); 515 | } 516 | __caseTable[idx].clear(); 517 | GetEdgeLoops(edges,__caseTable[idx]); 518 | } 519 | } 520 | int MarchingCubes::__fullCaseMap[1<<(Cube::CORNERS+Cube::FACES)]; 521 | std::vector< std::vector< std::vector > > MarchingCubes::__fullCaseTable; 522 | 523 | const std::vector< std::vector >& MarchingCubes::caseTable(const int& idx,const int& useFull) 524 | { 525 | if(useFull) 526 | return __fullCaseTable[__fullCaseMap[idx] ]; 527 | else 528 | return __caseTable[idx]; 529 | } 530 | const std::vector< std::vector >& MarchingCubes::fullCaseTable(const int& idx) 531 | { 532 | return __fullCaseTable[__fullCaseMap[idx] ]; 533 | } 534 | void MarchingCubes::SetFullCaseTable(void) 535 | { 536 | MarchingSquares::SetFullCaseTable(); 537 | int dir,off,tSize=0; 538 | 539 | memset(__fullCaseMap,-1,sizeof(int)*(1<<(Cube::CORNERS+Cube::FACES))); 540 | for(int idx=0;idx<(1< > edges; 587 | int aFlag=0; 588 | for(int i=0;i(Cube::SquareToCubeEdge(f,MarchingSquares::fullCaseTable(fIdx).edge[i].first),Cube::SquareToCubeEdge(f,MarchingSquares::fullCaseTable(fIdx).edge[i].second))); 605 | else 606 | edges.push_back(std::pair(Cube::SquareToCubeEdge(f,MarchingSquares::fullCaseTable(fIdx).edge[i].second),Cube::SquareToCubeEdge(f,MarchingSquares::fullCaseTable(fIdx).edge[i].first))); 607 | } 608 | for(int uaIndex=0;uaIndex<(1< 36 | //#define MAX_OCTNODE_NUM 800000 37 | 38 | template 39 | class OctNode 40 | { 41 | private: 42 | const OctNode* __faceNeighbor(const int& dir,const int& off) const; 43 | const OctNode* __edgeNeighbor(const int& o,const int i[2],const int idx[2]) const; 44 | OctNode* __faceNeighbor(const int& dir,const int& off,const int& forceChildren); 45 | OctNode* __edgeNeighbor(const int& o,const int i[2],const int idx[2],const int& forceChildren); 46 | public: 47 | class NodeIndex 48 | { 49 | public: 50 | NodeIndex(void); 51 | int depth,offset[3]; 52 | NodeIndex child(const int& cIndex) const; 53 | NodeIndex parent(void) const; 54 | NodeIndex& operator += (const int& cIndex); 55 | NodeIndex& operator -- (void); 56 | }; 57 | 58 | OctNode* parent; 59 | OctNode* children; 60 | NodeData nodeData; 61 | 62 | OctNode(void); 63 | ~OctNode(void); 64 | int initChildren(void); 65 | void deleteChildren(void); 66 | 67 | static inline void CenterAndWidth(const NodeIndex& nIndex,Point3D& center,Real& width); 68 | 69 | int leaves(void) const; 70 | //int maxDepthLeaves(const int& maxDepth) const; 71 | int nodes(void) const; 72 | int maxDepth(void) const; 73 | 74 | const OctNode* root(void) const; 75 | 76 | const OctNode* nextLeaf(const OctNode* currentLeaf) const; 77 | OctNode* nextLeaf(OctNode* currentLeaf); 78 | const OctNode* nextNode(const OctNode* currentNode) const; 79 | OctNode* nextNode(OctNode* currentNode); 80 | const OctNode* nextBranch(const OctNode* current) const; 81 | OctNode* nextBranch(OctNode* current); 82 | 83 | const OctNode* nextLeaf(const OctNode* currentLeaf,NodeIndex &nIndex) const; 84 | OctNode* nextLeaf(OctNode* currentLeaf,NodeIndex &nIndex); 85 | const OctNode* nextNode(const OctNode* currentNode,NodeIndex &nIndex) const; 86 | OctNode* nextNode(OctNode* currentNode,NodeIndex &nIndex); 87 | const OctNode* nextBranch(const OctNode* current,NodeIndex &nIndex) const; 88 | OctNode* nextBranch(OctNode* current,NodeIndex &nIndex); 89 | 90 | void setFullDepth(const int& maxDepth); 91 | void printLeaves(void) const; 92 | void printRange(void) const; 93 | 94 | OctNode* faceNeighbor(const int& faceIndex,const int& forceChildren=0); 95 | const OctNode* faceNeighbor(const int& faceIndex) const; 96 | OctNode* edgeNeighbor(const int& edgeIndex,const int& forceChildren=0); 97 | const OctNode* edgeNeighbor(const int& edgeIndex) const; 98 | OctNode* cornerNeighbor(const int& cornerIndex,const int& forceChildren=0); 99 | const OctNode* cornerNeighbor(const int& cornerIndex) const; 100 | 101 | 102 | int write(const char* fileName,int writeData) const; 103 | int write(FILE* fp,int writeData) const; 104 | int read(const char* fileName,int readData); 105 | int read(FILE* fp,int readData); 106 | 107 | static long long CenterIndex(const NodeIndex &nIndex,const int& maxDepth); 108 | static long long CenterIndex(const NodeIndex &nIndex,const int& maxDepth,int index[3]); 109 | static long long CornerIndex(const NodeIndex &nIndex,const int& cIndex,const int& maxDepth); 110 | static long long CornerIndex(const NodeIndex &nIndex,const int& cIndex,const int& maxDepth,int index[3]); 111 | static long long EdgeIndex(const NodeIndex &nIndex,const int& eIndex,const int& maxDepth); 112 | static long long EdgeIndex(const NodeIndex &nIndex,const int& eIndex,const int& maxDepth,int idx[3]); 113 | static long long FaceIndex(const NodeIndex &nIndex,const int& fIndex,const int& maxDepth); 114 | static long long FaceIndex(const NodeIndex &nIndex,const int& fIndex,const int& maxDepth,int idx[3]); 115 | 116 | class Neighbors{ 117 | public: 118 | OctNode* neighbors[3][3][3]; 119 | NodeIndex nIndex; 120 | Neighbors(void); 121 | void clear(void); 122 | }; 123 | class NeighborKey 124 | { 125 | int _depth; 126 | Neighbors& _setNeighbors(OctNode* node,const int& d); 127 | Neighbors& _getNeighbors(OctNode* node,const int& d); 128 | public: 129 | Neighbors* neighbors; 130 | int depth; 131 | 132 | NeighborKey(void); 133 | ~NeighborKey(void); 134 | 135 | void set(const int& depth); 136 | Neighbors& setNeighbors(OctNode* node); 137 | Neighbors& getNeighbors(OctNode* node); 138 | }; 139 | 140 | //void* operator new(size_t size) 141 | //{ 142 | // assert(freeList.head!=0 && freeList.cnt 29 | #include 30 | #include 31 | 32 | //////////////////////// 33 | // OctNode::NodeIndex // 34 | //////////////////////// 35 | template 36 | OctNode::NodeIndex::NodeIndex(void) 37 | { 38 | depth=offset[0]=offset[1]=offset[2]=0; 39 | } 40 | template 41 | typename OctNode::NodeIndex OctNode::NodeIndex::child(const int& cIndex) const 42 | { 43 | int x,y,z; 44 | NodeIndex idx; 45 | Cube::FactorCornerIndex(cIndex,x,y,z); 46 | idx.depth=depth+1; 47 | idx.offset[0]=(offset[0]<<1)|x; 48 | idx.offset[1]=(offset[1]<<1)|y; 49 | idx.offset[2]=(offset[2]<<1)|z; 50 | return idx; 51 | } 52 | template 53 | typename OctNode::NodeIndex OctNode::NodeIndex::parent(void) const 54 | { 55 | NodeIndex idx; 56 | idx.depth=depth-1; 57 | idx.offset[0]=offset[0]>>1; 58 | idx.offset[1]=offset[1]>>1; 59 | idx.offset[2]=offset[2]>>1; 60 | return idx; 61 | } 62 | template 63 | typename OctNode::NodeIndex& OctNode::NodeIndex::operator += (const int& cIndex) 64 | { 65 | int x,y,z; 66 | Cube::FactorCornerIndex(cIndex,x,y,z); 67 | depth++; 68 | offset[0]=(offset[0]<<1)|x; 69 | offset[1]=(offset[1]<<1)|y; 70 | offset[2]=(offset[2]<<1)|z; 71 | return *this; 72 | } 73 | template 74 | typename OctNode::NodeIndex& OctNode::NodeIndex::operator -- (void) 75 | { 76 | depth--; 77 | offset[0]>>=1; 78 | offset[1]>>=1; 79 | offset[2]>>=1; 80 | return *this; 81 | } 82 | 83 | ///////////// 84 | // OctNode // 85 | ///////////// 86 | 87 | template 88 | OctNode::OctNode(void) 89 | { 90 | parent=children=NULL; 91 | } 92 | 93 | template 94 | OctNode::~OctNode(void){ 95 | if(children){delete[] children;} 96 | parent=children=NULL; 97 | } 98 | template 99 | void OctNode::setFullDepth(const int& maxDepth){ 100 | if(maxDepth){ 101 | if(!children){initChildren();} 102 | for(int i=0;i<8;i++){children[i].setFullDepth(maxDepth-1);} 103 | } 104 | } 105 | template 106 | void OctNode::deleteChildren(void) 107 | { 108 | if(children) 109 | delete[] children; 110 | children=NULL; 111 | } 112 | template 113 | int OctNode::initChildren(void){ 114 | int i,j,k; 115 | 116 | if(children){delete[] children;} 117 | children=NULL; 118 | children=new OctNode[Cube::CORNERS]; 119 | if(!children){ 120 | fprintf(stderr,"Failed to initialize children in OctNode::initChildren\n"); 121 | exit(0); 122 | return 0; 123 | } 124 | for(i=0;i<2;i++){ 125 | for(j=0;j<2;j++){ 126 | for(k=0;k<2;k++){ 127 | int idx=Cube::CornerIndex(i,j,k); 128 | children[idx].parent=this; 129 | children[idx].children=NULL; 130 | } 131 | } 132 | } 133 | return 1; 134 | } 135 | template 136 | inline void OctNode::CenterAndWidth(const NodeIndex &nIndex,Point3D& center,Real& width) 137 | { 138 | width=Real(1.0/(1< 144 | int OctNode::maxDepth(void) const{ 145 | if(!children){return 0;} 146 | else{ 147 | int c,d; 148 | for(int i=0;ic){c=d;} 151 | } 152 | return c+1; 153 | } 154 | } 155 | template 156 | int OctNode::nodes(void) const{ 157 | if(!children){return 1;} 158 | else{ 159 | int c=0; 160 | for(int i=0;i 165 | int OctNode::leaves(void) const{ 166 | if(!children){return 1;} 167 | else{ 168 | int c=0; 169 | for(int i=0;i 174 | //int OctNode::maxDepthLeaves(const int& maxDepth) const{ 175 | // if(depth()>maxDepth){return 0;} 176 | // if(!children){return 1;} 177 | // else{ 178 | // int c=0; 179 | // for(int i=0;i 184 | const OctNode* OctNode::root(void) const{ 185 | const OctNode* temp=this; 186 | while(temp->parent){temp=temp->parent;} 187 | return temp; 188 | } 189 | 190 | 191 | template 192 | const OctNode* OctNode::nextBranch(const OctNode* current) const{ 193 | if(!current->parent || current==this){return NULL;} 194 | if(current-current->parent->children==Cube::CORNERS-1){return nextBranch(current->parent);} 195 | else{return current+1;} 196 | } 197 | template 198 | OctNode* OctNode::nextBranch(OctNode* current){ 199 | if(!current->parent || current==this){return NULL;} 200 | if(current-current->parent->children==Cube::CORNERS-1){return nextBranch(current->parent);} 201 | else{return current+1;} 202 | } 203 | template 204 | const OctNode* OctNode::nextLeaf(const OctNode* current) const{ 205 | if(!current){ 206 | const OctNode* temp=this; 207 | while(temp->children){temp=&temp->children[0];} 208 | return temp; 209 | } 210 | if(current->children){return current->nextLeaf(NULL);} 211 | const OctNode* temp=nextBranch(current); 212 | if(!temp){return NULL;} 213 | else{return temp->nextLeaf(NULL);} 214 | } 215 | template 216 | OctNode* OctNode::nextLeaf(OctNode* current){ 217 | if(!current){ 218 | OctNode* temp=this; 219 | while(temp->children){temp=&temp->children[0];} 220 | return temp; 221 | } 222 | if(current->children){return current->nextLeaf(NULL);} 223 | OctNode* temp=nextBranch(current); 224 | if(!temp){return NULL;} 225 | else{return temp->nextLeaf(NULL);} 226 | } 227 | 228 | template 229 | const OctNode* OctNode::nextNode(const OctNode* current) const{ 230 | if(!current){return this;} 231 | else if(current->children){return ¤t->children[0];} 232 | else{return nextBranch(current);} 233 | } 234 | template 235 | OctNode* OctNode::nextNode(OctNode* current){ 236 | if(!current){return this;} 237 | else if(current->children){return ¤t->children[0];} 238 | else{return nextBranch(current);} 239 | } 240 | template 241 | const OctNode* OctNode::nextBranch(const OctNode* current,NodeIndex& nIndex) const 242 | { 243 | if(!current->parent || current==this) 244 | return NULL; 245 | int c=current-current->parent->children; 246 | nIndex--; 247 | if(c==Cube::CORNERS-1) 248 | return nextBranch(current->parent,nIndex); 249 | else 250 | { 251 | nIndex+=c; 252 | return current+1; 253 | } 254 | } 255 | template 256 | OctNode* OctNode::nextBranch(OctNode* current,NodeIndex& nIndex) 257 | { 258 | if(!current->parent || current==this) 259 | return NULL; 260 | int c=int(current-current->parent->children); 261 | --nIndex; 262 | if(c==Cube::CORNERS-1) 263 | return nextBranch(current->parent,nIndex); 264 | else 265 | { 266 | nIndex+=c+1; 267 | return current+1; 268 | } 269 | } 270 | template 271 | const OctNode* OctNode::nextLeaf(const OctNode* current,NodeIndex& nIndex) const 272 | { 273 | if(!current) 274 | { 275 | const OctNode* temp=this; 276 | while(temp->children) 277 | { 278 | nIndex+=0; 279 | temp=&temp->children[0]; 280 | } 281 | return temp; 282 | } 283 | if(current->children) 284 | return current->nextLeaf(NULL,nIndex); 285 | const OctNode* temp=nextBranch(current,nIndex); 286 | if(!temp) 287 | return NULL; 288 | else 289 | return temp->nextLeaf(NULL,nIndex); 290 | } 291 | template 292 | OctNode* OctNode::nextLeaf(OctNode* current,NodeIndex& nIndex) 293 | { 294 | if(!current){ 295 | OctNode* temp=this; 296 | while(temp->children) 297 | { 298 | nIndex+=0; 299 | temp=&temp->children[0]; 300 | } 301 | return temp; 302 | } 303 | if(current->children) 304 | return current->nextLeaf(NULL,nIndex); 305 | OctNode* temp=nextBranch(current,nIndex); 306 | if(!temp) 307 | return NULL; 308 | else 309 | return temp->nextLeaf(NULL,nIndex); 310 | } 311 | template 312 | const OctNode* OctNode::nextNode(const OctNode* current,NodeIndex& nIndex) const 313 | { 314 | if(!current) 315 | return this; 316 | else if(current->children) 317 | { 318 | nIndex+=0; 319 | return ¤t->children[0]; 320 | } 321 | else 322 | return nextBranch(current,nIndex); 323 | } 324 | template 325 | OctNode* OctNode::nextNode(OctNode* current,NodeIndex& nIndex) 326 | { 327 | if(!current) 328 | return this; 329 | else if(current->children) 330 | { 331 | nIndex+=0; 332 | return ¤t->children[0]; 333 | } 334 | else 335 | return nextBranch(current,nIndex); 336 | } 337 | 338 | template 339 | void OctNode::printRange(void) const{ 340 | Point3D center; 341 | Real width; 342 | centerAndWidth(center,width); 343 | for(int dim=0;dim<3;dim++){ 344 | printf("%[%f,%f]",center[dim]-width/2,center[dim]+width/2); 345 | if(dim<3-1){printf("x");} 346 | else printf("\n"); 347 | } 348 | } 349 | 350 | template 351 | OctNode* OctNode::faceNeighbor(const int& faceIndex,const int& forceChildren){return __faceNeighbor(faceIndex>>1,faceIndex&1,forceChildren);} 352 | template 353 | const OctNode* OctNode::faceNeighbor(const int& faceIndex) const {return __faceNeighbor(faceIndex>>1,faceIndex&1);} 354 | template 355 | OctNode* OctNode::__faceNeighbor(const int& dir,const int& off,const int& forceChildren){ 356 | if(!parent){return NULL;} 357 | int pIndex=int(this-parent->children); 358 | pIndex^=(1<children[pIndex];} 360 | // if(!(((pIndex>>dir)^off)&1)){return &parent->children[pIndex];} 361 | else{ 362 | OctNode* temp=parent->__faceNeighbor(dir,off,forceChildren); 363 | if(!temp){return NULL;} 364 | if(!temp->children){ 365 | if(forceChildren){temp->initChildren();} 366 | else{return temp;} 367 | } 368 | return &temp->children[pIndex]; 369 | } 370 | } 371 | template 372 | const OctNode* OctNode::__faceNeighbor(const int& dir,const int& off) const { 373 | if(!parent){return NULL;} 374 | int pIndex=int(this-parent->children); 375 | pIndex^=(1<children[pIndex];} 377 | // if(!(((pIndex>>dir)^off)&1)){return &parent->children[pIndex];} 378 | else{ 379 | const OctNode* temp=parent->__faceNeighbor(dir,off); 380 | if(!temp || !temp->children){return temp;} 381 | else{return &temp->children[pIndex];} 382 | } 383 | } 384 | 385 | template 386 | OctNode* OctNode::edgeNeighbor(const int& edgeIndex,const int& forceChildren){ 387 | int idx[2],o,i[2]; 388 | Cube::FactorEdgeIndex(edgeIndex,o,i[0],i[1]); 389 | switch(o){ 390 | case 0: idx[0]=1; idx[1]=2; break; 391 | case 1: idx[0]=0; idx[1]=2; break; 392 | case 2: idx[0]=0; idx[1]=1; break; 393 | }; 394 | return __edgeNeighbor(o,i,idx,forceChildren); 395 | } 396 | template 397 | const OctNode* OctNode::edgeNeighbor(const int& edgeIndex) const { 398 | int idx[2],o,i[2]; 399 | Cube::FactorEdgeIndex(edgeIndex,o,i[0],i[1]); 400 | switch(o){ 401 | case 0: idx[0]=1; idx[1]=2; break; 402 | case 1: idx[0]=0; idx[1]=2; break; 403 | case 2: idx[0]=0; idx[1]=1; break; 404 | }; 405 | return __edgeNeighbor(o,i,idx); 406 | } 407 | template 408 | const OctNode* OctNode::__edgeNeighbor(const int& o,const int i[2],const int idx[2]) const{ 409 | if(!parent){return NULL;} 410 | int pIndex=int(this-parent->children); 411 | int aIndex,x[3]; 412 | 413 | Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); 414 | aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; 415 | pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0]); 418 | if(!temp || !temp->children){return NULL;} 419 | else{return &temp->children[pIndex];} 420 | } 421 | else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor 422 | const OctNode* temp=parent->__faceNeighbor(idx[1],i[1]); 423 | if(!temp || !temp->children){return NULL;} 424 | else{return &temp->children[pIndex];} 425 | } 426 | else if(aIndex==0) { // I can get the neighbor from the parent 427 | return &parent->children[pIndex]; 428 | } 429 | else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor 430 | const OctNode* temp=parent->__edgeNeighbor(o,i,idx); 431 | if(!temp || !temp->children){return temp;} 432 | else{return &temp->children[pIndex];} 433 | } 434 | else{return NULL;} 435 | } 436 | template 437 | OctNode* OctNode::__edgeNeighbor(const int& o,const int i[2],const int idx[2],const int& forceChildren){ 438 | if(!parent){return NULL;} 439 | int pIndex=int(this-parent->children); 440 | int aIndex,x[3]; 441 | 442 | Cube::FactorCornerIndex(pIndex,x[0],x[1],x[2]); 443 | aIndex=(~((i[0] ^ x[idx[0]]) | ((i[1] ^ x[idx[1]])<<1))) & 3; 444 | pIndex^=(7 ^ (1<__faceNeighbor(idx[0],i[0],0); 447 | if(!temp || !temp->children){return NULL;} 448 | else{return &temp->children[pIndex];} 449 | } 450 | else if(aIndex==2) { // I can get the neighbor from the parent's face adjacent neighbor 451 | OctNode* temp=parent->__faceNeighbor(idx[1],i[1],0); 452 | if(!temp || !temp->children){return NULL;} 453 | else{return &temp->children[pIndex];} 454 | } 455 | else if(aIndex==0) { // I can get the neighbor from the parent 456 | return &parent->children[pIndex]; 457 | } 458 | else if(aIndex==3) { // I can get the neighbor from the parent's edge adjacent neighbor 459 | OctNode* temp=parent->__edgeNeighbor(o,i,idx,forceChildren); 460 | if(!temp){return NULL;} 461 | if(!temp->children){ 462 | if(forceChildren){temp->initChildren();} 463 | else{return temp;} 464 | } 465 | return &temp->children[pIndex]; 466 | } 467 | else{return NULL;} 468 | } 469 | 470 | template 471 | const OctNode* OctNode::cornerNeighbor(const int& cornerIndex) const { 472 | int pIndex,aIndex=0; 473 | if(!parent){return NULL;} 474 | 475 | pIndex=int(this-parent->children); 476 | aIndex=(cornerIndex ^ pIndex); // The disagreement bits 477 | pIndex=(~pIndex)&7; // The antipodal point 478 | if(aIndex==7){ // Agree on no bits 479 | return &parent->children[pIndex]; 480 | } 481 | else if(aIndex==0){ // Agree on all bits 482 | const OctNode* temp=((const OctNode*)parent)->cornerNeighbor(cornerIndex); 483 | if(!temp || !temp->children){return temp;} 484 | else{return &temp->children[pIndex];} 485 | } 486 | else if(aIndex==6){ // Agree on face 0 487 | const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1); 488 | if(!temp || !temp->children){return NULL;} 489 | else{return & temp->children[pIndex];} 490 | } 491 | else if(aIndex==5){ // Agree on face 1 492 | const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1); 493 | if(!temp || !temp->children){return NULL;} 494 | else{return & temp->children[pIndex];} 495 | } 496 | else if(aIndex==3){ // Agree on face 2 497 | const OctNode* temp=((const OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2); 498 | if(!temp || !temp->children){return NULL;} 499 | else{return & temp->children[pIndex];} 500 | } 501 | else if(aIndex==4){ // Agree on edge 2 502 | const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); 503 | if(!temp || !temp->children){return NULL;} 504 | else{return & temp->children[pIndex];} 505 | } 506 | else if(aIndex==2){ // Agree on edge 1 507 | const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); 508 | if(!temp || !temp->children){return NULL;} 509 | else{return & temp->children[pIndex];} 510 | } 511 | else if(aIndex==1){ // Agree on edge 0 512 | const OctNode* temp=((const OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); 513 | if(!temp || !temp->children){return NULL;} 514 | else{return & temp->children[pIndex];} 515 | } 516 | else{return NULL;} 517 | } 518 | template 519 | OctNode* OctNode::cornerNeighbor(const int& cornerIndex,const int& forceChildren){ 520 | int pIndex,aIndex=0; 521 | if(!parent){return NULL;} 522 | 523 | pIndex=int(this-parent->children); 524 | aIndex=(cornerIndex ^ pIndex); // The disagreement bits 525 | pIndex=(~pIndex)&7; // The antipodal point 526 | if(aIndex==7){ // Agree on no bits 527 | return &parent->children[pIndex]; 528 | } 529 | else if(aIndex==0){ // Agree on all bits 530 | OctNode* temp=((OctNode*)parent)->cornerNeighbor(cornerIndex,forceChildren); 531 | if(!temp){return NULL;} 532 | if(!temp->children){ 533 | if(forceChildren){temp->initChildren();} 534 | else{return temp;} 535 | } 536 | return &temp->children[pIndex]; 537 | } 538 | else if(aIndex==6){ // Agree on face 0 539 | OctNode* temp=((OctNode*)parent)->__faceNeighbor(0,cornerIndex & 1,0); 540 | if(!temp || !temp->children){return NULL;} 541 | else{return & temp->children[pIndex];} 542 | } 543 | else if(aIndex==5){ // Agree on face 1 544 | OctNode* temp=((OctNode*)parent)->__faceNeighbor(1,(cornerIndex & 2)>>1,0); 545 | if(!temp || !temp->children){return NULL;} 546 | else{return & temp->children[pIndex];} 547 | } 548 | else if(aIndex==3){ // Agree on face 2 549 | OctNode* temp=((OctNode*)parent)->__faceNeighbor(2,(cornerIndex & 4)>>2,0); 550 | if(!temp || !temp->children){return NULL;} 551 | else{return & temp->children[pIndex];} 552 | } 553 | else if(aIndex==4){ // Agree on edge 2 554 | OctNode* temp=((OctNode*)parent)->edgeNeighbor(8 | (cornerIndex & 1) | (cornerIndex & 2) ); 555 | if(!temp || !temp->children){return NULL;} 556 | else{return & temp->children[pIndex];} 557 | } 558 | else if(aIndex==2){ // Agree on edge 1 559 | OctNode* temp=((OctNode*)parent)->edgeNeighbor(4 | (cornerIndex & 1) | ((cornerIndex & 4)>>1) ); 560 | if(!temp || !temp->children){return NULL;} 561 | else{return & temp->children[pIndex];} 562 | } 563 | else if(aIndex==1){ // Agree on edge 0 564 | OctNode* temp=((OctNode*)parent)->edgeNeighbor(((cornerIndex & 2) | (cornerIndex & 4))>>1 ); 565 | if(!temp || !temp->children){return NULL;} 566 | else{return & temp->children[pIndex];} 567 | } 568 | else{return NULL;} 569 | } 570 | //////////////////////// 571 | // OctNodeNeighborKey // 572 | //////////////////////// 573 | template 574 | OctNode::Neighbors::Neighbors(void){clear();} 575 | template 576 | void OctNode::Neighbors::clear(void){ 577 | for(int i=0;i<3;i++){for(int j=0;j<3;j++){for(int k=0;k<3;k++){neighbors[i][j][k]=NULL;}}} 578 | } 579 | template 580 | OctNode::NeighborKey::NeighborKey(void){neighbors=NULL;} 581 | template 582 | OctNode::NeighborKey::~NeighborKey(void){ 583 | if(neighbors){delete[] neighbors;} 584 | neighbors=NULL; 585 | } 586 | 587 | template 588 | void OctNode::NeighborKey::set(const int& d){ 589 | if(neighbors){delete[] neighbors;} 590 | neighbors=NULL; 591 | if(d<0){return;} 592 | _depth=d; 593 | neighbors=new Neighbors[d+1]; 594 | } 595 | template 596 | typename OctNode::Neighbors& OctNode::NeighborKey::setNeighbors(OctNode* node){ 597 | OctNode* temp=node; 598 | depth=0; 599 | while(temp->parent) 600 | { 601 | depth++; 602 | temp=temp->parent; 603 | } 604 | if(node!=neighbors[depth].neighbors[1][1][1]) 605 | for(int i=depth;i<=_depth;i++) 606 | neighbors[i].clear(); 607 | 608 | return _setNeighbors(node,depth); 609 | } 610 | template 611 | typename OctNode::Neighbors& OctNode::NeighborKey::_setNeighbors(OctNode* node,const int& d) 612 | { 613 | if(node!=neighbors[d].neighbors[1][1][1]){ 614 | neighbors[d].clear(); 615 | 616 | if(!node->parent) 617 | { 618 | neighbors[d].nIndex=OctNode::NodeIndex(); 619 | neighbors[d].neighbors[1][1][1]=node; 620 | } 621 | else 622 | { 623 | Neighbors& temp=_setNeighbors(node->parent,d-1); 624 | int i,j,k,x1,y1,z1,x2,y2,z2; 625 | int idx=int(node-node->parent->children); 626 | neighbors[d].nIndex=neighbors[d-1].nIndex.child(idx); 627 | Cube::FactorCornerIndex( idx ,x1,y1,z1); 628 | Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); 629 | for(i=0;i<2;i++){ 630 | for(j=0;j<2;j++){ 631 | for(k=0;k<2;k++){ 632 | neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)]; 633 | } 634 | } 635 | } 636 | 637 | // Set the neighbors from across the faces 638 | i=x1<<1; 639 | if(temp.neighbors[i][1][1]){ 640 | if(!temp.neighbors[i][1][1]->children){temp.neighbors[i][1][1]->initChildren();} 641 | for(j=0;j<2;j++){for(k=0;k<2;k++){neighbors[d].neighbors[i][y2+j][z2+k]=&temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)];}} 642 | } 643 | j=y1<<1; 644 | if(temp.neighbors[1][j][1]){ 645 | if(!temp.neighbors[1][j][1]->children){temp.neighbors[1][j][1]->initChildren();} 646 | for(i=0;i<2;i++){for(k=0;k<2;k++){neighbors[d].neighbors[x2+i][j][z2+k]=&temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)];}} 647 | } 648 | k=z1<<1; 649 | if(temp.neighbors[1][1][k]){ 650 | if(!temp.neighbors[1][1][k]->children){temp.neighbors[1][1][k]->initChildren();} 651 | for(i=0;i<2;i++){for(j=0;j<2;j++){neighbors[d].neighbors[x2+i][y2+j][k]=&temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)];}} 652 | } 653 | 654 | // Set the neighbors from across the edges 655 | i=x1<<1; j=y1<<1; 656 | if(temp.neighbors[i][j][1]){ 657 | if(!temp.neighbors[i][j][1]->children){temp.neighbors[i][j][1]->initChildren();} 658 | for(k=0;k<2;k++){neighbors[d].neighbors[i][j][z2+k]=&temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)];} 659 | } 660 | i=x1<<1; k=z1<<1; 661 | if(temp.neighbors[i][1][k]){ 662 | if(!temp.neighbors[i][1][k]->children){temp.neighbors[i][1][k]->initChildren();} 663 | for(j=0;j<2;j++){neighbors[d].neighbors[i][y2+j][k]=&temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)];} 664 | } 665 | j=y1<<1; k=z1<<1; 666 | if(temp.neighbors[1][j][k]){ 667 | if(!temp.neighbors[1][j][k]->children){temp.neighbors[1][j][k]->initChildren();} 668 | for(i=0;i<2;i++){neighbors[d].neighbors[x2+i][j][k]=&temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)];} 669 | } 670 | 671 | // Set the neighbor from across the corner 672 | i=x1<<1; j=y1<<1; k=z1<<1; 673 | if(temp.neighbors[i][j][k]){ 674 | if(!temp.neighbors[i][j][k]->children){temp.neighbors[i][j][k]->initChildren();} 675 | neighbors[d].neighbors[i][j][k]=&temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; 676 | } 677 | } 678 | } 679 | return neighbors[d]; 680 | } 681 | template 682 | typename OctNode::Neighbors& OctNode::NeighborKey::getNeighbors(OctNode* node){ 683 | depth=0; 684 | OctNode* temp=node; 685 | while(temp->parent) 686 | { 687 | depth++; 688 | temp=temp->parent; 689 | } 690 | if(node!=neighbors[depth].neighbors[1][1][1]) 691 | for(int i=depth;i<=_depth;i++) 692 | neighbors[i].clear(); 693 | 694 | return _getNeighbors(node,depth); 695 | } 696 | template 697 | typename OctNode::Neighbors& OctNode::NeighborKey::_getNeighbors(OctNode* node,const int& d) 698 | { 699 | if(node!=neighbors[d].neighbors[1][1][1]){ 700 | neighbors[d].clear(); 701 | 702 | if(!node->parent) 703 | { 704 | neighbors[d].neighbors[1][1][1]=node; 705 | neighbors[d].nIndex=OctNode::NodeIndex(); 706 | } 707 | else 708 | { 709 | Neighbors& temp=_getNeighbors(node->parent,d-1); 710 | int i,j,k,x1,y1,z1,x2,y2,z2; 711 | int idx=int(node-node->parent->children); 712 | neighbors[d].nIndex=neighbors[d-1].nIndex.child(idx); 713 | Cube::FactorCornerIndex( idx ,x1,y1,z1); 714 | Cube::FactorCornerIndex((~idx)&7,x2,y2,z2); 715 | for(i=0;i<2;i++){ 716 | for(j=0;j<2;j++){ 717 | for(k=0;k<2;k++){ 718 | neighbors[d].neighbors[x2+i][y2+j][z2+k]=&node->parent->children[Cube::CornerIndex(i,j,k)]; 719 | } 720 | } 721 | } 722 | 723 | // Set the neighbors from across the faces 724 | i=x1<<1; 725 | if(temp.neighbors[i][1][1] && temp.neighbors[i][1][1]->children){ 726 | for(j=0;j<2;j++){for(k=0;k<2;k++){neighbors[d].neighbors[i][y2+j][z2+k]=&temp.neighbors[i][1][1]->children[Cube::CornerIndex(x2,j,k)];}} 727 | } 728 | j=y1<<1; 729 | if(temp.neighbors[1][j][1] && temp.neighbors[1][j][1]->children){ 730 | for(i=0;i<2;i++){for(k=0;k<2;k++){neighbors[d].neighbors[x2+i][j][z2+k]=&temp.neighbors[1][j][1]->children[Cube::CornerIndex(i,y2,k)];}} 731 | } 732 | k=z1<<1; 733 | if(temp.neighbors[1][1][k] && temp.neighbors[1][1][k]->children){ 734 | for(i=0;i<2;i++){for(j=0;j<2;j++){neighbors[d].neighbors[x2+i][y2+j][k]=&temp.neighbors[1][1][k]->children[Cube::CornerIndex(i,j,z2)];}} 735 | } 736 | 737 | // Set the neighbors from across the edges 738 | i=x1<<1; j=y1<<1; 739 | if(temp.neighbors[i][j][1] && temp.neighbors[i][j][1]->children){ 740 | for(k=0;k<2;k++){neighbors[d].neighbors[i][j][z2+k]=&temp.neighbors[i][j][1]->children[Cube::CornerIndex(x2,y2,k)];} 741 | } 742 | i=x1<<1; k=z1<<1; 743 | if(temp.neighbors[i][1][k] && temp.neighbors[i][1][k]->children){ 744 | for(j=0;j<2;j++){neighbors[d].neighbors[i][y2+j][k]=&temp.neighbors[i][1][k]->children[Cube::CornerIndex(x2,j,z2)];} 745 | } 746 | j=y1<<1; k=z1<<1; 747 | if(temp.neighbors[1][j][k] && temp.neighbors[1][j][k]->children){ 748 | for(i=0;i<2;i++){neighbors[d].neighbors[x2+i][j][k]=&temp.neighbors[1][j][k]->children[Cube::CornerIndex(i,y2,z2)];} 749 | } 750 | 751 | // Set the neighbor from across the corner 752 | i=x1<<1; j=y1<<1; k=z1<<1; 753 | if(temp.neighbors[i][j][k] && temp.neighbors[i][j][k]->children){ 754 | neighbors[d].neighbors[i][j][k]=&temp.neighbors[i][j][k]->children[Cube::CornerIndex(x2,y2,z2)]; 755 | } 756 | } 757 | } 758 | return neighbors[d]; 759 | } 760 | 761 | template 762 | int OctNode::write(const char* fileName,int writeData) const{ 763 | FILE* fp=fopen(fileName,"wb"); 764 | if(!fp){return 0;} 765 | int ret=write(fp,writeData); 766 | fclose(fp); 767 | return ret; 768 | } 769 | template 770 | int OctNode::write(FILE* fp,int writeData) const 771 | { 772 | if(writeData) 773 | fwrite(this,sizeof(OctNode),1,fp); 774 | else 775 | { 776 | fwrite(&parent,sizeof(OctNode*),1,fp); 777 | fwrite(&children,sizeof(OctNode*),1,fp); 778 | } 779 | if(children){for(int i=0;i 783 | int OctNode::read(const char* fileName,int readData){ 784 | FILE* fp=fopen(fileName,"rb"); 785 | if(!fp){return 0;} 786 | int ret=read(fp,readData); 787 | fclose(fp); 788 | return ret; 789 | } 790 | template 791 | int OctNode::read(FILE* fp,int readData){ 792 | if(readData) 793 | fread(this,sizeof(OctNode),1,fp); 794 | else 795 | { 796 | fread(&parent,sizeof(OctNode*),1,fp); 797 | fread(&children,sizeof(OctNode*),1,fp); 798 | } 799 | parent=NULL; 800 | if(children) 801 | { 802 | children=NULL; 803 | initChildren(); 804 | for(int i=0;i 815 | long long OctNode::CornerIndex(const NodeIndex& nIndex,const int& cIndex,const int& maxDepth) 816 | { 817 | int idx[3]; 818 | return CornerIndex(nIndex,cIndex,maxDepth,idx); 819 | } 820 | template 821 | long long OctNode::CornerIndex(const NodeIndex& nIndex,const int& cIndex,const int& maxDepth,int idx[3]){ 822 | int x[3]; 823 | Cube::FactorCornerIndex(cIndex,x[0],x[1],x[2]); 824 | for(int i=0;i<3;i++) 825 | idx[i]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth,nIndex.offset[i],x[i]); 826 | return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30; 827 | } 828 | template 829 | long long OctNode::CenterIndex(const NodeIndex& nIndex,const int& maxDepth) 830 | { 831 | int idx[3]; 832 | return CenterIndex(nIndex,maxDepth,idx); 833 | } 834 | 835 | template 836 | long long OctNode::CenterIndex(const NodeIndex& nIndex,const int& maxDepth,int idx[3]) 837 | { 838 | for(int i=0;i<3;i++) 839 | idx[i]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth+1,nIndex.offset[i]<<1,1); 840 | return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30; 841 | } 842 | template 843 | long long OctNode::EdgeIndex(const NodeIndex& nIndex,const int& eIndex,const int& maxDepth) 844 | { 845 | int idx[3]; 846 | return EdgeIndex(nIndex,eIndex,maxDepth,idx); 847 | } 848 | template 849 | long long OctNode::EdgeIndex(const NodeIndex& nIndex,const int& eIndex,const int& maxDepth,int idx[3]) 850 | { 851 | int o,i1,i2; 852 | for(int i=0;i<3;i++){idx[i]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth+1,nIndex.offset[i]<<1,1);} 853 | Cube::FactorEdgeIndex(eIndex,o,i1,i2); 854 | switch(o){ 855 | case 0: 856 | idx[1]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth,nIndex.offset[1],i1); 857 | idx[2]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth,nIndex.offset[2],i2); 858 | break; 859 | case 1: 860 | idx[0]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth,nIndex.offset[0],i1); 861 | idx[2]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth,nIndex.offset[2],i2); 862 | break; 863 | case 2: 864 | idx[0]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth,nIndex.offset[0],i1); 865 | idx[1]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth,nIndex.offset[1],i2); 866 | break; 867 | }; 868 | return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30; 869 | } 870 | template 871 | long long OctNode::FaceIndex(const NodeIndex& nIndex,const int& fIndex,const int& maxDepth) 872 | { 873 | int idx[3]; 874 | return FaceIndex(nIndex,fIndex,maxDepth,idx); 875 | } 876 | template 877 | long long OctNode::FaceIndex(const NodeIndex& nIndex,const int& fIndex,const int& maxDepth,int idx[3]) 878 | { 879 | int dir,offset; 880 | Cube::FactorFaceIndex(fIndex,dir,offset); 881 | for(int i=0;i<3;i++) 882 | idx[i]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth+1,nIndex.offset[i]<<1,1); 883 | idx[dir]=BinaryNode::CornerIndex(maxDepth+1,nIndex.depth,nIndex.offset[dir],offset); 884 | return (long long)(idx[0]) | (long long)(idx[1])<<15 | (long long)(idx[2])<<30; 885 | } 886 | 887 | //template 888 | //typename OctNode::FreeOctNodeList OctNode::freeList; 889 | -------------------------------------------------------------------------------- /src/OctreeBspline.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_BSPLINE_INCLUDED 2 | #define OCTREE_BSPLINE_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | #include "IsoOctree.h" 8 | #include "Function.h" 9 | 10 | //Hierarchical Implicit Surface Reconstruction based on Adaptive Distance Field 11 | 12 | //This paper presents an hierarchical implicit surface reconstruction method. 13 | //Our method begins by establishing an adaptive signed distance field from the input data using an octree. 14 | //the sampling density adapts to the local curvature of data. 15 | //In this way, varying-scale geometric details are automatically preserved. 16 | //Then, the signed distance field is fitted by a hierarhcial tensor-product B-splines, 17 | //of which the basic spline 18 | 19 | template 20 | class OctreeBspline: public IsoOctree, public Function 21 | { 22 | #ifndef WIN32 23 | //using IsoOctree::MeshInfo; 24 | //typename IsoOctree::template MeshInfo mInfo; 25 | template class MeshInfo: public IsoOctree::template MeshInfo {}; 26 | using IsoOctree::cornerValues; 27 | using IsoOctree::tree; 28 | using IsoOctree::maxDepth; 29 | #endif 30 | 31 | typedef Eigen::Matrix Matrix; 32 | typedef Eigen::Matrix Vector; 33 | typedef Eigen::SparseMatrix SparseMatrix; 34 | typedef Eigen::Triplet Triplet; 35 | 36 | template 37 | void setDistanceAndNormal2(const std::vector& vindices,MeshInfo& mInfo,const Point3D& p,Real& v,Point3D& n); 38 | template 39 | int setChildren2(OctNode* node,const typename OctNode::NodeIndex& nIdx, 40 | const std::vector& vindices,MeshInfo& mInfo,const int& maxDepth,const int& setCenter,const Real& flatness, 41 | stdext::hash_map*>* triangleMap=NULL); 42 | 43 | void setDistanceAndNormal3(const Point3D& p,const Point3D& p2,const Point3D& n2,Real& dist,Point3D& n,Real& w); 44 | template 45 | int setChildren3(OctNode* node,const typename OctNode::NodeIndex& nIdx, 46 | std::vector& vindices,MeshInfo& mInfo,const int& maxDepth,const int& setCenter, 47 | const Real& flatness,const Real&curvature,const Real& splat,const int& minDepthTree, 48 | stdext::hash_map*>* triangleMap=NULL, int bFlag=1); 49 | 50 | void setCoeffValuesFromCompressedKeys(const int bsplineDepth,const std::vector >& compressedKeys, 51 | std::vector > >& coeffValues); 52 | void getCornerKeysFromCompressedKeys(const int maxDepth,const int bsplineDepth,const std::vector >& compressedKeys, 53 | std::vector& cornerKeys); 54 | 55 | inline void getPosFromCornerKey(const long long cornerKey,const float unitLen,float pos[3]); 56 | inline void getBposIntU(const int bsplineDepth,const float pos[3],int bposInt[3],float u[3]); 57 | void getCoeffIndicesWeightsValueFromPos(const Eigen::Matrix& B,const int minBsplineDepth,const int maxBsplineDepth,const float pos[3], 58 | std::vector& coeffIndices,std::vector& coeffWeights,float& value); 59 | 60 | void getCoeffIndicesWeightsValueFromPos(const Eigen::Matrix& Bx,const Eigen::Matrix& By,const Eigen::Matrix& Bz, 61 | const int minBsplineDepth,const int maxBsplineDepth,const float pos[3], 62 | std::vector& coeffIndices,std::vector& coeffWeights,float& value); 63 | 64 | void getSmoothMatrix(const Eigen::Matrix& B,const Eigen::Matrix& dB,const Eigen::Matrix& ddB, 65 | const int minBsplineDepth,const int maxBsplineDepth, SparseMatrix& smoothMatrix); 66 | void getFitMatrixVector(const Eigen::Matrix& B,const int minBsplineDepth,const int maxBsplineDepth, 67 | SparseMatrix& fitMatrix, Vector& fitVector, int& N); 68 | 69 | MeshInfo mInfoGlobal; 70 | void sortPointsByCurvatures(std::vector& beginIndices); 71 | void getInterpolateMatrixVector(const Eigen::Matrix& B,const int minBsplineDepth,const int maxBsplineDepth, 72 | SparseMatrix& interpolateMatrix, Vector& interpolateVector, int& M); 73 | 74 | // Set children according to isoValue until reaching maxDepth 75 | void setMinDepthMCLeafNode(OctNode* node,const typename OctNode::NodeIndex& nIdx,const Real& isoValue,const int& minDepth,const int& useFull); 76 | 77 | public: 78 | // The maximum depth of the hierarchical bsplines. The value must be at least 1. (>=1.) 79 | int maxBsplineDepth; 80 | // A vector of hash-table of the multi-level bsplines (coeffKey: coeffIndex,coeffValue) 81 | std::vector > > coeffValues; 82 | // A vector of vector of the compressed keys of the multi-level bsplines 83 | std::vector > compressedKeys; 84 | 85 | template 86 | int set2(const std::vector& vertices,const std::vector >& polygons,const int& maxDepth,const int& setCenter,const Real& flatness, 87 | Point3D& translate,Real& scale,const int& noTransform); 88 | 89 | template 90 | int set3(const std::vector& vertices,const std::vector >& polygons,const int& maxDepth,const int& setCenter, 91 | const Real& flatness,const Real& curvature,const Real& splat,const int& minDepthTree, 92 | Point3D& translate,Real& scale,const int& noTransform, const int& bFlag); 93 | 94 | int set4(const int& maxDepth,Point3D& translate,Real& scale); 95 | 96 | void directBsplineFitting(const Real& smooth,const Real& interpolate); 97 | void multigridBsplineFitting(const Real& smooth,const Real& interpolate); 98 | 99 | void updateCornerValues(); 100 | 101 | void exportVolumeData(const float scale,const Point3D translate,const int d=128); 102 | virtual float eval(const float pos[3]); 103 | virtual void gradient(const float pos[3],float gradient[3]); 104 | 105 | void setMinDepthMCLeafNode(const Real& isoValue,const int& minDepth,const int& useFull); 106 | 107 | void exportOctreeGrid(const float scale,const Point3D translate, const int output_depth); 108 | }; 109 | 110 | #include "OctreeBspline.inl" 111 | #endif -------------------------------------------------------------------------------- /src/Ply.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Header for PLY polygon files. 4 | 5 | - Greg Turk, March 1994 6 | 7 | A PLY file contains a single polygonal _object_. 8 | 9 | An object is composed of lists of _elements_. Typical elements are 10 | vertices, faces, edges and materials. 11 | 12 | Each type of element for a given object has one or more _properties_ 13 | associated with the element type. For instance, a vertex element may 14 | have as properties three floating-point values x,y,z and three unsigned 15 | chars for red, green and blue. 16 | 17 | --------------------------------------------------------------- 18 | 19 | Copyright (c) 1994 The Board of Trustees of The Leland Stanford 20 | Junior University. All rights reserved. 21 | 22 | Permission to use, copy, modify and distribute this software and its 23 | documentation for any purpose is hereby granted without fee, provided 24 | that the above copyright notice and this permission notice appear in 25 | all copies of this software and that you do not sell the software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, 28 | EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 29 | WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 30 | 31 | */ 32 | 33 | #ifndef PLY_INCLUDED 34 | #define PLY_INCLUDED 35 | #include "Geometry.h" 36 | #include "PlyFile.h" 37 | #include 38 | 39 | class PlyVertex 40 | { 41 | public: 42 | const static int Components=3; 43 | static PlyProperty Properties[]; 44 | 45 | Point3D point; 46 | 47 | operator Point3D& () {return point;} 48 | operator const Point3D& () const {return point;} 49 | PlyVertex(void) {point[0]=point[1]=point[2]=0;} 50 | PlyVertex(const Point3D& p) {point=p;} 51 | }; 52 | PlyProperty PlyVertex::Properties[]= 53 | { 54 | {"x", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertex,point.coords[0])), 0, 0, 0, 0}, 55 | {"y", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertex,point.coords[1])), 0, 0, 0, 0}, 56 | {"z", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertex,point.coords[2])), 0, 0, 0, 0} 57 | }; 58 | 59 | class PlyVertexWithNormal 60 | { 61 | public: 62 | const static int Components=7; 63 | static PlyProperty Properties[]; 64 | 65 | Point3D point; 66 | Point3D normal; 67 | float curvature; 68 | 69 | operator Point3D& () {return point;} 70 | operator const Point3D& () const {return point;} 71 | PlyVertexWithNormal(void) {point[0]=point[1]=point[2]=0; normal[0]=normal[1]=normal[2]=0; curvature=0;} 72 | PlyVertexWithNormal(const Point3D& p) {point=p; normal[0]=normal[1]=normal[2]=0; curvature=0;} 73 | }; 74 | PlyProperty PlyVertexWithNormal::Properties[]= 75 | { 76 | {"x", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertexWithNormal,point.coords[0])), 0, 0, 0, 0}, 77 | {"y", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertexWithNormal,point.coords[1])), 0, 0, 0, 0}, 78 | {"z", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertexWithNormal,point.coords[2])), 0, 0, 0, 0}, 79 | {"nx", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertexWithNormal,normal.coords[0])), 0, 0, 0, 0}, 80 | {"ny", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertexWithNormal,normal.coords[1])), 0, 0, 0, 0}, 81 | {"nz", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertexWithNormal,normal.coords[2])), 0, 0, 0, 0}, 82 | {"curvature", PLY_FLOAT, PLY_FLOAT, int(offsetof(PlyVertexWithNormal,curvature)), 0, 0, 0, 0} 83 | }; 84 | 85 | int PlyDefaultFileType(void){return PLY_ASCII;} 86 | template 87 | int PlyReadPolygons(char* fileName,std::vector& vertices,std::vector >& polygons,int& file_type); 88 | template 89 | int PlyWritePolygons(char* fileName,const std::vector& vertices,const std::vector >& polygons,int file_type); 90 | 91 | #include "Ply.inl" 92 | #endif // PLY_INCLUDED 93 | -------------------------------------------------------------------------------- /src/Ply.inl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #include "Ply.h" 29 | 30 | static char *elem_names[] = { "vertex", "face" }; 31 | 32 | typedef struct PlyFace { 33 | unsigned char nr_vertices; 34 | int *vertices; 35 | int segment; 36 | } PlyFace; 37 | 38 | static PlyProperty face_props[] = 39 | { 40 | {"vertex_indices", PLY_INT, PLY_INT, offsetof(PlyFace,vertices), 1, PLY_UCHAR, PLY_UCHAR, offsetof(PlyFace,nr_vertices)}, 41 | }; 42 | 43 | template 44 | int PlyWritePolygons(char* fileName,const std::vector& vertices,const std::vector >& polygons,int file_type) 45 | { 46 | int nr_vertices=int(vertices.size()); 47 | int nr_faces=int(polygons.size()); 48 | float version; 49 | PlyFile *ply = ply_open_for_writing(fileName, 2, elem_names, file_type, &version); 50 | if (!ply){return 0;} 51 | 52 | // 53 | // describe vertex and face properties 54 | // 55 | ply_element_count(ply, "vertex", nr_vertices); 56 | for(int i=0;imaxFaceVerts) 79 | { 80 | delete[] ply_face.vertices; 81 | maxFaceVerts=int(polygons[i].size()); 82 | ply_face.vertices=new int[maxFaceVerts]; 83 | } 84 | ply_face.nr_vertices=int(polygons[i].size()); 85 | for(int j=0;j 95 | int PlyReadPolygons(char* fileName,std::vector& vertices,std::vector >& polygons,int& file_type) 96 | { 97 | int nr_elems; 98 | char **elist; 99 | float version; 100 | int i,j,k; 101 | PlyFile* ply; 102 | char* elem_name; 103 | int num_elems; 104 | int nr_props; 105 | PlyProperty** plist; 106 | PlyFace ply_face; 107 | 108 | ply = ply_open_for_reading(fileName, &nr_elems, &elist, &file_type, &version); 109 | if(!ply) 110 | return 0; 111 | for (i=0; i < nr_elems; i++) { 112 | elem_name = elist[i]; 113 | plist = ply_get_element_description(ply, elem_name, &num_elems, &nr_props); 114 | if(!plist) 115 | { 116 | for(i=0;ielems[i]->name); 118 | free(ply->elems[i]->store_prop); 119 | for(j=0;jelems[i]->nprops;j++){ 120 | free(ply->elems[i]->props[j]->name); 121 | free(ply->elems[i]->props[j]); 122 | } 123 | free(ply->elems[i]->props); 124 | } 125 | for(i=0;ielems[i]);} 126 | free(ply->elems); 127 | for(i=0;inum_comments;i++){free(ply->comments[i]);} 128 | free(ply->comments); 129 | for(i=0;inum_obj_info;i++){free(ply->obj_info[i]);} 130 | free(ply->obj_info); 131 | ply_free_other_elements (ply->other_elems); 132 | 133 | for(i=0;iname); 162 | free(plist[j]); 163 | } 164 | free(plist); 165 | } // for each type of element 166 | 167 | for(i=0;ielems[i]->name); 169 | free(ply->elems[i]->store_prop); 170 | for(j=0;jelems[i]->nprops;j++){ 171 | free(ply->elems[i]->props[j]->name); 172 | free(ply->elems[i]->props[j]); 173 | } 174 | if(ply->elems[i]->props && ply->elems[i]->nprops){free(ply->elems[i]->props);} 175 | } 176 | for(i=0;ielems[i]);} 177 | free(ply->elems); 178 | for(i=0;inum_comments;i++){free(ply->comments[i]);} 179 | free(ply->comments); 180 | for(i=0;inum_obj_info;i++){free(ply->obj_info[i]);} 181 | free(ply->obj_info); 182 | ply_free_other_elements (ply->other_elems); 183 | 184 | 185 | for(i=0;i 46 | #include 47 | #include 48 | #include 49 | 50 | #define PLY_ASCII 1 /* ascii PLY file */ 51 | #define PLY_BINARY_BE 2 /* binary PLY file, big endian */ 52 | #define PLY_BINARY_LE 3 /* binary PLY file, little endian */ 53 | #define PLY_BINARY_NATIVE 4 /* binary PLY file, same endianness as current architecture */ 54 | 55 | #define PLY_OKAY 0 /* ply routine worked okay */ 56 | #define PLY_ERROR -1 /* error in ply routine */ 57 | 58 | /* scalar data types supported by PLY format */ 59 | 60 | #define PLY_START_TYPE 0 61 | #define PLY_CHAR 1 62 | #define PLY_SHORT 2 63 | #define PLY_INT 3 64 | #define PLY_UCHAR 4 65 | #define PLY_USHORT 5 66 | #define PLY_UINT 6 67 | #define PLY_FLOAT 7 68 | #define PLY_DOUBLE 8 69 | #define PLY_INT_8 9 70 | #define PLY_UINT_8 10 71 | #define PLY_INT_16 11 72 | #define PLY_UINT_16 12 73 | #define PLY_INT_32 13 74 | #define PLY_UINT_32 14 75 | #define PLY_FLOAT_32 15 76 | #define PLY_FLOAT_64 16 77 | 78 | #define PLY_END_TYPE 17 79 | 80 | #define PLY_SCALAR 0 81 | #define PLY_LIST 1 82 | 83 | 84 | typedef struct PlyProperty { /* description of a property */ 85 | 86 | char *name; /* property name */ 87 | int external_type; /* file's data type */ 88 | int internal_type; /* program's data type */ 89 | int offset; /* offset bytes of prop in a struct */ 90 | 91 | int is_list; /* 1 = list, 0 = scalar */ 92 | int count_external; /* file's count type */ 93 | int count_internal; /* program's count type */ 94 | int count_offset; /* offset byte for list count */ 95 | 96 | } PlyProperty; 97 | 98 | typedef struct PlyElement { /* description of an element */ 99 | char *name; /* element name */ 100 | int num; /* number of elements in this object */ 101 | int size; /* size of element (bytes) or -1 if variable */ 102 | int nprops; /* number of properties for this element */ 103 | PlyProperty **props; /* list of properties in the file */ 104 | char *store_prop; /* flags: property wanted by user? */ 105 | int other_offset; /* offset to un-asked-for props, or -1 if none*/ 106 | int other_size; /* size of other_props structure */ 107 | } PlyElement; 108 | 109 | typedef struct PlyOtherProp { /* describes other properties in an element */ 110 | char *name; /* element name */ 111 | int size; /* size of other_props */ 112 | int nprops; /* number of properties in other_props */ 113 | PlyProperty **props; /* list of properties in other_props */ 114 | } PlyOtherProp; 115 | 116 | typedef struct OtherData { /* for storing other_props for an other element */ 117 | void *other_props; 118 | } OtherData; 119 | 120 | typedef struct OtherElem { /* data for one "other" element */ 121 | char *elem_name; /* names of other elements */ 122 | int elem_count; /* count of instances of each element */ 123 | OtherData **other_data; /* actual property data for the elements */ 124 | PlyOtherProp *other_props; /* description of the property data */ 125 | } OtherElem; 126 | 127 | typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ 128 | int num_elems; /* number of other elements */ 129 | OtherElem *other_list; /* list of data for other elements */ 130 | } PlyOtherElems; 131 | 132 | typedef struct PlyFile { /* description of PLY file */ 133 | FILE *fp; /* file pointer */ 134 | int file_type; /* ascii or binary */ 135 | float version; /* version number of file */ 136 | int nelems; /* number of elements of object */ 137 | PlyElement **elems; /* list of elements */ 138 | int num_comments; /* number of comments */ 139 | char **comments; /* list of comments */ 140 | int num_obj_info; /* number of items of object information */ 141 | char **obj_info; /* list of object info items */ 142 | PlyElement *which_elem; /* which element we're currently writing */ 143 | PlyOtherElems *other_elems; /* "other" elements from a PLY file */ 144 | } PlyFile; 145 | 146 | /* memory allocation */ 147 | extern char *my_alloc(); 148 | #define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) 149 | 150 | #ifndef ALLOCN 151 | #define REALLOCN(PTR,TYPE,OLD_N,NEW_N) \ 152 | { \ 153 | if ((OLD_N) == 0) \ 154 | { ALLOCN((PTR),TYPE,(NEW_N));} \ 155 | else \ 156 | { \ 157 | (PTR) = (TYPE *)realloc((PTR),(NEW_N)*sizeof(TYPE)); \ 158 | if (((PTR) == NULL) && ((NEW_N) != 0)) \ 159 | { \ 160 | fprintf(stderr, "Memory reallocation failed on line %d in %s\n", \ 161 | __LINE__, __FILE__); \ 162 | fprintf(stderr, " tried to reallocate %d->%d\n", \ 163 | (OLD_N), (NEW_N)); \ 164 | exit(-1); \ 165 | } \ 166 | if ((NEW_N)>(OLD_N)) \ 167 | memset((char *)(PTR)+(OLD_N)*sizeof(TYPE), 0, \ 168 | ((NEW_N)-(OLD_N))*sizeof(TYPE)); \ 169 | } \ 170 | } 171 | 172 | #define ALLOCN(PTR,TYPE,N) \ 173 | { (PTR) = (TYPE *) calloc(((unsigned)(N)),sizeof(TYPE));\ 174 | if ((PTR) == NULL) { \ 175 | fprintf(stderr, "Memory allocation failed on line %d in %s\n", \ 176 | __LINE__, __FILE__); \ 177 | exit(-1); \ 178 | } \ 179 | } 180 | 181 | 182 | #define FREE(PTR) { free((PTR)); (PTR) = NULL; } 183 | #endif 184 | 185 | 186 | /*** delcaration of routines ***/ 187 | 188 | extern PlyFile *ply_write(FILE *, int, char **, int); 189 | extern PlyFile *ply_open_for_writing(char *, int, char **, int, float *); 190 | extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *); 191 | extern void ply_describe_property(PlyFile *, char *, PlyProperty *); 192 | extern void ply_element_count(PlyFile *, char *, int); 193 | extern void ply_header_complete(PlyFile *); 194 | extern void ply_put_element_setup(PlyFile *, char *); 195 | extern void ply_put_element(PlyFile *, void *); 196 | extern void ply_put_comment(PlyFile *, char *); 197 | extern void ply_put_obj_info(PlyFile *, char *); 198 | extern PlyFile *ply_read(FILE *, int *, char ***); 199 | extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *); 200 | extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*); 201 | extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *); 202 | extern void ply_get_property(PlyFile *, char *, PlyProperty *); 203 | extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); 204 | extern void ply_get_element(PlyFile *, void *); 205 | extern char **ply_get_comments(PlyFile *, int *); 206 | extern char **ply_get_obj_info(PlyFile *, int *); 207 | extern void ply_close(PlyFile *); 208 | extern void ply_get_info(PlyFile *, float *, int *); 209 | extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int); 210 | extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *); 211 | extern void ply_put_other_elements (PlyFile *); 212 | extern void ply_free_other_elements (PlyOtherElems *); 213 | extern void ply_describe_other_properties(PlyFile *, PlyOtherProp *, int); 214 | 215 | extern int equal_strings(char *, char *); 216 | 217 | #ifdef __cplusplus 218 | } 219 | #endif 220 | #endif // PLY_FILE_INCLUDED 221 | -------------------------------------------------------------------------------- /src/PolygonizerHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "PolygonizerHelper.h" 2 | #include "polygonizer.h" 3 | #include 4 | 5 | extern "C" int triangle2(int i1,int i2,int i3,VERTICES vertices); 6 | extern "C" char* polygonize(double (*function)(double,double,double),double size,int bounds,double x,double y,double z,int (*triproc)(int,int,int,VERTICES),int mode); 7 | extern "C" int gntris; 8 | extern "C" VERTICES gvertices; 9 | extern "C" TRIANGLES gtriangles; 10 | 11 | Function *gf; 12 | float gisovalue=0.0; 13 | 14 | double function(double x,double y,double z) 15 | { 16 | float pos[3]; 17 | pos[0]=(float)x; 18 | pos[1]=(float)y; 19 | pos[2]=(float)z; 20 | return (double)(gf->eval(pos)-gisovalue); 21 | } 22 | 23 | void PolygonizerHelper::polygonize(Function *f,float isovalue,float cellsize,float seedx,float seedy,float seedz) 24 | { 25 | ::gf=f; 26 | gisovalue=isovalue; 27 | char *err=::polygonize(::function,cellsize,(int)(1.0/cellsize),seedx,seedy,seedz,triangle2,0); 28 | if(err) 29 | { 30 | printf("%s\n",err); 31 | exit(1); 32 | } 33 | } 34 | 35 | void PolygonizerHelper::save(const char* filename,const float scale,const Point3D translate) 36 | { 37 | FILE*file=fopen(filename,"w"); 38 | fprintf(file,"ply\n" \ 39 | "format ascii 1.0\n" \ 40 | "comment polygonizer generated\n" \ 41 | "element vertex %d\n" \ 42 | "property float x\n" \ 43 | "property float y\n" \ 44 | "property float z\n" \ 45 | "property float nx\n" \ 46 | "property float ny\n" \ 47 | "property float nz\n" \ 48 | "element face %d\n" \ 49 | "property list uchar int vertex_indices\n" \ 50 | "end_header\n",::gvertices.count,::gntris); 51 | for(int i=0;i<::gvertices.count;i++) { 52 | VERTEX v; 53 | v=::gvertices.ptr[i]; 54 | Point3D point={(float)v.position.x,(float)v.position.y,(float)v.position.z}; 55 | point=point/scale-translate; 56 | Point3D normal={(float) v.normal.x,(float) v.normal.y,(float) v.normal.z}; 57 | fprintf(file,"%f %f %f %f %f %f\n",point[0], point[1],point[2],normal[0],normal[1],normal[2]); 58 | } 59 | 60 | for(int i=0;i<::gtriangles.count;i++) { 61 | TRIANGLE t; 62 | t=::gtriangles.ptr[i]; 63 | fprintf(file,"3 %d %d %d\n",t.i1,t.i3,t.i2); 64 | } 65 | } 66 | 67 | void PolygonizerHelper::saveSphereTest(const char* filename,const float scale,const Point3D translate) 68 | { 69 | FILE*file=fopen(filename,"w"); 70 | fprintf(file,"ply\n" \ 71 | "format ascii 1.0\n" \ 72 | "comment polygonizer generated\n" \ 73 | "element vertex %d\n" \ 74 | "property float x\n" \ 75 | "property float y\n" \ 76 | "property float z\n" \ 77 | "property float nx\n" \ 78 | "property float ny\n" \ 79 | "property float nz\n" \ 80 | "element face %d\n" \ 81 | "property list uchar int vertex_indices\n" \ 82 | "end_header\n",::gvertices.count,::gntris); 83 | for(int i=0;i<::gvertices.count;i++) { 84 | VERTEX v; 85 | v=::gvertices.ptr[i]; 86 | Point3D point={(float)v.position.x,(float)v.position.y,(float)v.position.z}; 87 | point=point/scale-translate; 88 | Point3D normal={(float) v.normal.x,(float) v.normal.y,(float) v.normal.z}; 89 | fprintf(file,"%f %f %f %f %f %f\n",point[0], point[1],point[2],normal[0],normal[1],normal[2]); 90 | } 91 | 92 | for(int i=0;i<::gtriangles.count;i++) { 93 | TRIANGLE t; 94 | t=::gtriangles.ptr[i]; 95 | fprintf(file,"3 %d %d %d\n",t.i1,t.i3,t.i2); 96 | } 97 | 98 | float rmsPositionError=0; 99 | float rmsNormalError=0; 100 | float meanPositionError=0; 101 | float meanNormalError=0; 102 | float totalArea=0; 103 | 104 | for(int i=0;i<::gtriangles.count;i++) { 105 | 106 | TRIANGLE t; 107 | t=::gtriangles.ptr[i]; 108 | int tr[3]={t.i1,t.i3,t.i2}; 109 | 110 | Point3D points[3],normals[3]; 111 | for(int j=0;j<3;j++) { 112 | VERTEX v; 113 | v=::gvertices.ptr[tr[j]]; 114 | Point3D point={(float)v.position.x,(float)v.position.y,(float)v.position.z}; 115 | point=point/scale-translate; 116 | points[j]=point; 117 | 118 | Point3D normal={(float) v.normal.x,(float) v.normal.y,(float) v.normal.z}; 119 | normals[j]=normal; 120 | } 121 | float area=Area(points[0],points[1],points[2]); 122 | 123 | for(int j=0;j<3;j++) { 124 | Point3D &point=points[j]; 125 | float positionDifference=Length(point)-(float)0.5; 126 | rmsPositionError+=positionDifference*positionDifference*area; 127 | meanPositionError+=fabs(positionDifference)*area; 128 | 129 | Point3D &normal=normals[j]; 130 | float normalDifference=Length(normal-point/Length(point)); 131 | rmsNormalError+=normalDifference*normalDifference*area; 132 | meanNormalError+=normalDifference*area; 133 | } 134 | totalArea+=3*area; 135 | } 136 | rmsPositionError/=totalArea; 137 | rmsPositionError=sqrtf(rmsPositionError); 138 | rmsNormalError/=totalArea; 139 | rmsNormalError=sqrtf(rmsNormalError); 140 | meanPositionError/=totalArea; 141 | meanNormalError/=totalArea; 142 | 143 | printf("rmsPositionError = %f\n", rmsPositionError); 144 | printf("rmsNormalError = %f\n", rmsNormalError); 145 | printf("meanPositionError = %f\n", meanPositionError); 146 | printf("meanNormalError = %f\n", meanNormalError); 147 | } -------------------------------------------------------------------------------- /src/PolygonizerHelper.h: -------------------------------------------------------------------------------- 1 | #ifndef POLYGONIZER_HELPER_INCLUDED 2 | #define POLYGONIZER_HELPER_INCLUDED 3 | 4 | #include "Function.h" 5 | #include "Geometry.h" 6 | 7 | class PolygonizerHelper 8 | { 9 | public: 10 | static void polygonize(Function *f,float isovalue,float cellsize,float seedx,float seedy,float seedz); 11 | static void save(const char* filename,const float scale,const Point3D translate); 12 | static void saveSphereTest(const char* filename,const float scale,const Point3D translate); 13 | }; 14 | 15 | #endif -------------------------------------------------------------------------------- /src/Time.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #include 29 | #include 30 | #ifndef WIN32 31 | #include 32 | #endif // WIN32 33 | 34 | double Time(void){ 35 | #ifdef WIN32 36 | struct _timeb t; 37 | _ftime(&t); 38 | return double(t.time)+double(t.millitm)/1000.0; 39 | #else // WIN32 40 | struct timeval t; 41 | gettimeofday(&t,NULL); 42 | return t.tv_sec+(double)t.tv_usec/1000000; 43 | #endif // WIN32 44 | } 45 | -------------------------------------------------------------------------------- /src/Time.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2006, Michael Kazhdan and Matthew Bolitho 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | #ifndef TIME_INCLUDED 29 | #define TIME_INCLUDED 30 | double Time(void); 31 | #endif // TIME_INCLUDED 32 | -------------------------------------------------------------------------------- /src/VertexData.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007, Michael Kazhdan 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | 29 | #ifndef VERTEX_DATA_INCLUDED 30 | #define VERTEX_DATA_INCLUDED 31 | 32 | #include "Function.h" 33 | 34 | template 35 | class VertexValue 36 | { 37 | public: 38 | Real v; 39 | Real w; 40 | VertexValue(void); 41 | VertexValue(const Real& v,const Point3D& n,const Real&w=0); 42 | Real value(void) const; 43 | VertexValue operator + (const VertexValue& v) const; 44 | VertexValue operator - (const VertexValue& v) const; 45 | VertexValue operator * (const Real& v) const; 46 | VertexValue operator / (const Real& v) const; 47 | static Point3D RootPosition(const Real& isoValue,const Point3D& p1,const Point3D& p2,VertexValue v1,VertexValue v2); 48 | }; 49 | #include "VertexData.inl" 50 | 51 | #endif // VERTEX_DATA_INCLUDED 52 | -------------------------------------------------------------------------------- /src/VertexData.inl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007, Michael Kazhdan 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of 9 | conditions and the following disclaimer. Redistributions in binary form must reproduce 10 | the above copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the distribution. 12 | 13 | Neither the name of the Johns Hopkins University nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES 19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 20 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26 | DAMAGE. 27 | */ 28 | ///////////////// 29 | // VertexValue // 30 | ///////////////// 31 | template 32 | VertexValue::VertexValue(void) 33 | { 34 | v=0; 35 | } 36 | template 37 | VertexValue::VertexValue(const Real& v,const Point3D& n,const Real&w) 38 | { 39 | this->v=v; 40 | this->w=w; 41 | } 42 | template 43 | Real VertexValue::value(void) const 44 | { 45 | return v; 46 | } 47 | template 48 | VertexValue VertexValue::operator + (const VertexValue& v) const 49 | { 50 | VertexValue vv; 51 | vv.v=this->v+v.v; 52 | return vv; 53 | } 54 | template 55 | VertexValue VertexValue::operator - (const VertexValue& v) const 56 | { 57 | VertexValue vv; 58 | vv.v=this->v-v.v; 59 | return vv; 60 | } 61 | template 62 | VertexValue VertexValue::operator * (const Real& v) const 63 | { 64 | VertexValue vv; 65 | vv.v=this->v*v; 66 | return vv; 67 | } 68 | template 69 | VertexValue VertexValue::operator / (const Real& v) const 70 | { 71 | VertexValue vv; 72 | vv.v=this->v/v; 73 | return vv; 74 | } 75 | template 76 | Point3D VertexValue::RootPosition(const Real& isoValue,const Point3D& p1,const Point3D& p2,VertexValue v1,VertexValue v2) 77 | { 78 | Real t=(v1.v-isoValue)/(v1.v-v2.v); 79 | return p1*(Real(1.0)-t)+p2*t; 80 | } 81 | 82 | -------------------------------------------------------------------------------- /src/polygonizer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * C code from the article 3 | * "An Implicit Surface Polygonizer" 4 | * http::www.unchainedgeometry.com/jbloom/papers/polygonizer.pdf 5 | * by Jules Bloomenthal, jules@bloomenthal.com 6 | * in "Graphics Gems IV", Academic Press, 1994 */ 7 | 8 | /* implicit.c 9 | * an implicit surface polygonizer, translated from Mesa 10 | * applications should call polygonize() 11 | * 12 | * To compile a test program for ASCII output: 13 | * cc implicit.c -o implicit -lm 14 | * 15 | * To compile a test program for display on an SGI workstation: 16 | * cc -DSGIGFX implicit.c -o implicit -lgl_s -lm 17 | * 18 | * Authored by Jules Bloomenthal, Xerox PARC. 19 | * Copyright (c) Xerox Corporation, 1991. All rights reserved. 20 | * Permission is granted to reproduce, use and distribute this code for 21 | * any and all purposes, provided that this notice appears in all copies. */ 22 | 23 | /* A Brief Explanation 24 | * The code consists of a test program and the polygonizer itself. 25 | * 26 | * In the test program: 27 | * torus(), sphere() and blob() are primitive functions used to calculate 28 | * the implicit value at a point (x,y,z) 29 | * triangle() is a 'callback' routine that is called by the polygonizer 30 | * whenever it produces a new triangle 31 | * to select torus, sphere or blob, change the argument to polygonize() 32 | * if openGL supported, open window, establish perspective and viewport, 33 | * create closed line loops, during polygonization, and slowly spin object 34 | * if openGL not supported, output vertices and triangles to stdout 35 | * 36 | * The main data structures in the polygonizer represent a hexahedral lattice, 37 | * ie, a collection of semi-adjacent cubes, represented as cube centers, corners, 38 | * and edges. The centers and corners are three-dimensional indices rerpesented 39 | * by integer i,j,k. The edges are two three-dimensional indices, represented 40 | * by integer i1,j1,k1,i2,j2,k2. These indices and associated data are stored 41 | * in hash tables. 42 | * 43 | * The client entry to the polygonizer is polygonize(), called from main(). 44 | * This routine first allocates memory for the hash tables for the cube centers, 45 | * corners, and edges that define the polygonizing lattice. It then finds a start 46 | * point, ie, the center of the first lattice cell. It pushes this cell onto an 47 | * initially empty stack of cells awaiting processing. It creates the first cell 48 | * by computing its eight corners and assigning them an implicit value. 49 | * 50 | * polygonize() then enters a loop in which a cell is popped from the stack, 51 | * becoming the 'active' cell c. c is (optionally) decomposed (ie, subdivided) 52 | * into six tetrahedra; within each transverse tetrahedron (ie, those that 53 | * intersect the surface), one or two triangles are produced. 54 | * 55 | * The six faces of c are tested for intersection with the implicit surface; for 56 | * a transverse face, a new cube is generated and placed on the stack. 57 | 58 | * Some of the more important routines include: 59 | * 60 | * testface (called by polygonize): test given face for surface intersection; 61 | * if transverse, create new cube by creating four new corners. 62 | * setcorner (called by polygonize, testface): create new cell corner at given 63 | * (i,j,k), compute its implicit value, and add to corners hash table. 64 | * find (called by polygonize): search for point with given polarity 65 | * dotet (called by polygonize) set edge vertices, output triangle by 66 | * invoking callback 67 | * 68 | * The section Cubical Polygonization contains routines to polygonize directly 69 | * from the lattice cell rather than first decompose it into tetrahedra; 70 | * dotet, however, is recommended over docube. 71 | * 72 | * The section Storage provides routines to handle the linked lists 73 | * in the hash tables. 74 | * 75 | * The section Vertices contains the following routines. 76 | * vertid (called by dotet): given two corner indices defining a cell edge, 77 | * test whether the edge has been stored in the hash table; if so, return its 78 | * associated vertex index. If not, compute intersection of edge and implicit 79 | * surface, compute associated surface normal, add vertex to mesh array, and 80 | * update hash tables 81 | * converge (called by polygonize, vertid): find surface crossing on edge */ 82 | 83 | #include 84 | #include 85 | #include 86 | #include 87 | 88 | #include "polygonizer.h" 89 | 90 | #define TET 0 /* use tetrahedral decomposition */ 91 | #define NOTET 1 /* no tetrahedral decomposition */ 92 | 93 | #define RES 10 /* # converge iterations */ 94 | 95 | #define L 0 /* left direction: -x, -i */ 96 | #define R 1 /* right direction: +x, +i */ 97 | #define B 2 /* bottom direction: -y, -j */ 98 | #define T 3 /* top direction: +y, +j */ 99 | #define N 4 /* near direction: -z, -k */ 100 | #define F 5 /* far direction: +z, +k */ 101 | #define LBN 0 /* left bottom near corner */ 102 | #define LBF 1 /* left bottom far corner */ 103 | #define LTN 2 /* left top near corner */ 104 | #define LTF 3 /* left top far corner */ 105 | #define RBN 4 /* right bottom near corner */ 106 | #define RBF 5 /* right bottom far corner */ 107 | #define RTN 6 /* right top near corner */ 108 | #define RTF 7 /* right top far corner */ 109 | 110 | /* the LBN corner of cube (i, j, k), corresponds with location 111 | * (start.x+(i-.5)*size, start.y+(j-.5)*size, start.z+(k-.5)*size) */ 112 | 113 | #define RAND() ((rand()&32767)/32767.) /* random number between 0 and 1 */ 114 | #define HASHBIT (5) 115 | #define HASHSIZE (size_t)(1<<(3*HASHBIT)) /* hash table size (32768) */ 116 | #define MASK ((1<>(bit))&1) 119 | #define FLIP(i,bit) ((i)^1<<(bit)) /* flip the given bit of i */ 120 | 121 | char *mycalloc (int nitems, int nbytes); 122 | void makecubetable (); 123 | TEST find (int sign, PROCESS *p, double x, double y, double z); 124 | void converge (POINT *p1, POINT *p2, double v, double (*function)(double,double,double), POINT *p); 125 | CORNER *setcorner (PROCESS *p, int i, int j, int k); 126 | int setcenter(CENTERLIST *table[], int i, int j, int k); 127 | int dotet (CUBE *cube, int c1, int c2, int c3, int c4, PROCESS *p); 128 | int docube (CUBE *cube, PROCESS *p); 129 | void testface (int i, int j, int k, CUBE *old, int face, int c1, int c2, int c3, int c4, PROCESS *p); 130 | int vertid (CORNER *c1, CORNER *c2, PROCESS *p); 131 | void vnormal (POINT *point, PROCESS *p, POINT *v); 132 | void addtovertices (VERTICES *vertices, VERTEX v); 133 | int addtotriangles (TRIANGLES *triangles, TRIANGLE t); 134 | void converge2 (POINT *p1, POINT *p2, double v1, double v2, POINT *p); 135 | 136 | /**** A Test Program ****/ 137 | 138 | 139 | /* torus: a torus with major, minor radii = 0.5, 0.1, try size = .05 */ 140 | 141 | double torus (double x, double y, double z) 142 | { 143 | double x2 = x*x, y2 = y*y, z2 = z*z; 144 | double a = x2+y2+z2+(0.5*0.5)-(0.1*0.1); 145 | return a*a-4.0*(0.5*0.5)*(y2+z2); 146 | } 147 | 148 | 149 | /* sphere: an inverse square function (always positive) */ 150 | 151 | double sphere (double x, double y, double z) 152 | { 153 | double rsq = x*x+y*y+z*z; 154 | return 1.0/(rsq < 0.00001? 0.00001 : rsq); 155 | } 156 | 157 | 158 | /* blob: a three-pole blend function, try size = .1 */ 159 | 160 | double blob (double x, double y, double z) 161 | { 162 | return 4.0-sphere(x+1.0,y,z)-sphere(x,y+1.0,z)-sphere(x,y,z+1.0); 163 | } 164 | 165 | /***********************************************************************/ 166 | 167 | int gntris; /* global needed by application */ 168 | VERTICES gvertices; /* global needed by application */ 169 | TRIANGLES gtriangles; /* global needed by application */ 170 | 171 | 172 | /* triangle: called by polygonize() for each triangle; write to stdout */ 173 | 174 | int triangle (int i1, int i2, int i3, VERTICES vertices) 175 | { 176 | gvertices = vertices; 177 | gntris++; 178 | fprintf(stdout, "%d %d %d\n", i1, i2, i3); 179 | return 1; 180 | } 181 | 182 | /* triangle2: called by polygonize() for each triangle; write to triangles buffer */ 183 | 184 | int triangle2 (int i1, int i2, int i3, VERTICES vertices) 185 | { 186 | TRIANGLE t = {i1, i2, i3}; 187 | gvertices = vertices; 188 | gntris++; 189 | addtotriangles(>riangles, t); 190 | return 1; 191 | } 192 | 193 | /**********************************************************************/ 194 | 195 | 196 | /**** An Implicit Surface Polygonizer ****/ 197 | 198 | 199 | /* polygonize: polygonize the implicit surface function 200 | * arguments are: 201 | * double function (x, y, z) 202 | * double x, y, z (an arbitrary 3D point) 203 | * the implicit surface function 204 | * return negative for inside, positive for outside 205 | * double size 206 | * width of the partitioning cube 207 | * int bounds 208 | * max. range of cubes (+/- on the three axes) from first cube 209 | * double x, y, z 210 | * coordinates of a starting point on or near the surface 211 | * may be defaulted to 0., 0., 0. 212 | * int triproc (i1, i2, i3, vertices) 213 | * int i1, i2, i3 (indices into the vertex array) 214 | * VERTICES vertices (the vertex array, indexed from 0) 215 | * called for each triangle 216 | * the triangle coordinates are (for i = i1, i2, i3): 217 | * vertices.ptr[i].position.x, .y, and .z 218 | * vertices are ccw when viewed from the out (positive) side 219 | * in a left-handed coordinate system 220 | * vertex normals point outwards 221 | * return 1 to continue, 0 to abort 222 | * int mode 223 | * TET: decompose cube and polygonize six tetrahedra 224 | * NOTET: polygonize cube directly 225 | * returns error or NULL 226 | */ 227 | 228 | char *polygonize (double(*function)(double,double,double), double size, int bounds, double x, double y, double z, int (*triproc)(int,int,int,VERTICES), int mode) 229 | { 230 | PROCESS p; 231 | int n, noabort; 232 | CORNER *setcorner(); 233 | TEST in, out; 234 | 235 | p.function = function; 236 | p.triproc = triproc; 237 | p.size = size; 238 | p.bounds = bounds; 239 | p.delta = size/(double)(RES*RES); 240 | 241 | /* allocate hash tables and build cube polygon table: */ 242 | p.centers = (CENTERLIST **) mycalloc(HASHSIZE,sizeof(CENTERLIST *)); 243 | p.corners = (CORNERLIST **) mycalloc(HASHSIZE,sizeof(CORNERLIST *)); 244 | p.edges = (EDGELIST **) mycalloc(2*HASHSIZE,sizeof(EDGELIST *)); 245 | makecubetable(); 246 | 247 | /* find point on surface, beginning search at (x, y, z): */ 248 | srand(1); 249 | in = find(1, &p, x, y, z); 250 | out = find(0, &p, x, y, z); 251 | if (!in.ok || !out.ok) return "can't find starting point"; 252 | converge(&in.p, &out.p, in.value, p.function, &p.start); 253 | 254 | /* push initial cube on stack: */ 255 | p.cubes = (CUBES *) mycalloc(1, sizeof(CUBES)); /* list of 1 */ 256 | p.cubes->cube.i = p.cubes->cube.j = p.cubes->cube.k = 0; 257 | p.cubes->next = NULL; 258 | 259 | /* set corners of initial cube: */ 260 | for (n = 0; n < 8; n++) 261 | p.cubes->cube.corners[n] = setcorner(&p, BIT(n,2), BIT(n,1), BIT(n,0)); 262 | 263 | p.vertices.count = p.vertices.max = 0; /* no vertices yet */ 264 | p.vertices.ptr = NULL; 265 | 266 | setcenter(p.centers, 0, 0, 0); 267 | 268 | while (p.cubes != NULL) { /* process active cubes till none left */ 269 | CUBE c; 270 | CUBES *temp = p.cubes; 271 | c = p.cubes->cube; 272 | 273 | noabort = mode == TET? 274 | /* either decompose into tetrahedra and polygonize: */ 275 | dotet(&c, LBN, LTN, RBN, LBF, &p) && 276 | dotet(&c, RTN, LTN, LBF, RBN, &p) && 277 | dotet(&c, RTN, LTN, LTF, LBF, &p) && 278 | dotet(&c, RTN, RBN, LBF, RBF, &p) && 279 | dotet(&c, RTN, LBF, LTF, RBF, &p) && 280 | dotet(&c, RTN, LTF, RTF, RBF, &p) 281 | : 282 | /* or polygonize the cube directly: */ 283 | docube(&c, &p); 284 | if (! noabort) return "aborted"; 285 | 286 | /* pop current cube from stack */ 287 | p.cubes = p.cubes->next; 288 | free((char *) temp); 289 | /* test six face directions, maybe add to stack: */ 290 | testface(c.i-1, c.j, c.k, &c, L, LBN, LBF, LTN, LTF, &p); 291 | testface(c.i+1, c.j, c.k, &c, R, RBN, RBF, RTN, RTF, &p); 292 | testface(c.i, c.j-1, c.k, &c, B, LBN, LBF, RBN, RBF, &p); 293 | testface(c.i, c.j+1, c.k, &c, T, LTN, LTF, RTN, RTF, &p); 294 | testface(c.i, c.j, c.k-1, &c, N, LBN, LTN, RBN, RTN, &p); 295 | testface(c.i, c.j, c.k+1, &c, F, LBF, LTF, RBF, RTF, &p); 296 | } 297 | return NULL; 298 | } 299 | 300 | 301 | /* testface: given cube at lattice (i, j, k), and four corners of face, 302 | * if surface crosses face, compute other four corners of adjacent cube 303 | * and add new cube to cube stack */ 304 | 305 | void testface (int i, int j, int k, CUBE *old, int face, int c1, int c2, int c3, int c4, PROCESS *p) 306 | { 307 | CUBE newcube; 308 | CUBES *oldcubes = p->cubes; 309 | CORNER *setcorner(); 310 | static int facebit[6] = {2, 2, 1, 1, 0, 0}; 311 | int n, pos = old->corners[c1]->value > 0.0 ? 1 : 0, bit = facebit[face]; 312 | 313 | /* test if no surface crossing, cube out of bounds, or already visited: */ 314 | if ((old->corners[c2]->value > 0) == pos && 315 | (old->corners[c3]->value > 0) == pos && 316 | (old->corners[c4]->value > 0) == pos) return; 317 | if (abs(i) > p->bounds || abs(j) > p->bounds || abs(k) > p->bounds) return; 318 | if (setcenter(p->centers, i, j, k)) return; 319 | 320 | /* create new cube: */ 321 | newcube.i = i; 322 | newcube.j = j; 323 | newcube.k = k; 324 | for (n = 0; n < 8; n++) newcube.corners[n] = NULL; 325 | newcube.corners[FLIP(c1, bit)] = old->corners[c1]; 326 | newcube.corners[FLIP(c2, bit)] = old->corners[c2]; 327 | newcube.corners[FLIP(c3, bit)] = old->corners[c3]; 328 | newcube.corners[FLIP(c4, bit)] = old->corners[c4]; 329 | for (n = 0; n < 8; n++) 330 | if (newcube.corners[n] == NULL) 331 | newcube.corners[n] = setcorner(p, i+BIT(n,2), j+BIT(n,1), k+BIT(n,0)); 332 | 333 | /*add cube to top of stack: */ 334 | p->cubes = (CUBES *) mycalloc(1, sizeof(CUBES)); 335 | p->cubes->cube = newcube; 336 | p->cubes->next = oldcubes; 337 | } 338 | 339 | 340 | /* setcorner: return corner with the given lattice location 341 | set (and cache) its function value */ 342 | 343 | CORNER *setcorner (PROCESS *p, int i, int j, int k) 344 | { 345 | /* for speed, do corner value caching here */ 346 | CORNER *c = (CORNER *) mycalloc(1, sizeof(CORNER)); 347 | int index = HASH(i, j, k); 348 | CORNERLIST *l = p->corners[index]; 349 | c->i = i; c->x = p->start.x+((double)i-.5)*p->size; 350 | c->j = j; c->y = p->start.y+((double)j-.5)*p->size; 351 | c->k = k; c->z = p->start.z+((double)k-.5)*p->size; 352 | for (; l != NULL; l = l->next) 353 | if (l->i == i && l->j == j && l->k == k) { 354 | c->value = l->value; 355 | return c; 356 | } 357 | l = (CORNERLIST *) mycalloc(1, sizeof(CORNERLIST)); 358 | l->i = i; l->j = j; l->k = k; 359 | l->value = c->value = p->function(c->x, c->y, c->z); 360 | l->next = p->corners[index]; 361 | p->corners[index] = l; 362 | return c; 363 | } 364 | 365 | 366 | /* find: search for point with value of given sign (0: neg, 1: pos) */ 367 | 368 | TEST find (int sign, PROCESS *p, double x, double y, double z) 369 | { 370 | int i; 371 | TEST test; 372 | double range = p->size; 373 | test.ok = 1; 374 | for (i = 0; i < 10000; i++) { 375 | test.p.x = x+range*(RAND()-0.5); 376 | test.p.y = y+range*(RAND()-0.5); 377 | test.p.z = z+range*(RAND()-0.5); 378 | test.value = p->function(test.p.x, test.p.y, test.p.z); 379 | if (sign == (test.value > 0.0)) return test; 380 | range = range*1.0005; /* slowly expand search outwards */ 381 | } 382 | test.ok = 0; 383 | return test; 384 | } 385 | 386 | 387 | /**** Tetrahedral Polygonization ****/ 388 | 389 | 390 | /* dotet: triangulate the tetrahedron 391 | * b, c, d should appear clockwise when viewed from a 392 | * return 0 if client aborts, 1 otherwise */ 393 | 394 | int dotet (CUBE *cube, int c1, int c2, int c3, int c4, PROCESS *p) 395 | { 396 | CORNER *a = cube->corners[c1]; 397 | CORNER *b = cube->corners[c2]; 398 | CORNER *c = cube->corners[c3]; 399 | CORNER *d = cube->corners[c4]; 400 | int index = 0, apos, bpos, cpos, dpos, e1, e2, e3, e4, e5, e6; 401 | if (apos = (a->value > 0.0)) index += 8; 402 | if (bpos = (b->value > 0.0)) index += 4; 403 | if (cpos = (c->value > 0.0)) index += 2; 404 | if (dpos = (d->value > 0.0)) index += 1; 405 | /* index is now 4-bit number representing one of the 16 possible cases */ 406 | if (apos != bpos) e1 = vertid(a, b, p); 407 | if (apos != cpos) e2 = vertid(a, c, p); 408 | if (apos != dpos) e3 = vertid(a, d, p); 409 | if (bpos != cpos) e4 = vertid(b, c, p); 410 | if (bpos != dpos) e5 = vertid(b, d, p); 411 | if (cpos != dpos) e6 = vertid(c, d, p); 412 | /* 14 productive tetrahedral cases (0000 and 1111 do not yield polygons */ 413 | switch (index) { 414 | case 1: return p->triproc(e5, e6, e3, p->vertices); 415 | case 2: return p->triproc(e2, e6, e4, p->vertices); 416 | case 3: return p->triproc(e3, e5, e4, p->vertices) && 417 | p->triproc(e3, e4, e2, p->vertices); 418 | case 4: return p->triproc(e1, e4, e5, p->vertices); 419 | case 5: return p->triproc(e3, e1, e4, p->vertices) && 420 | p->triproc(e3, e4, e6, p->vertices); 421 | case 6: return p->triproc(e1, e2, e6, p->vertices) && 422 | p->triproc(e1, e6, e5, p->vertices); 423 | case 7: return p->triproc(e1, e2, e3, p->vertices); 424 | case 8: return p->triproc(e1, e3, e2, p->vertices); 425 | case 9: return p->triproc(e1, e5, e6, p->vertices) && 426 | p->triproc(e1, e6, e2, p->vertices); 427 | case 10: return p->triproc(e1, e3, e6, p->vertices) && 428 | p->triproc(e1, e6, e4, p->vertices); 429 | case 11: return p->triproc(e1, e5, e4, p->vertices); 430 | case 12: return p->triproc(e3, e2, e4, p->vertices) && 431 | p->triproc(e3, e4, e5, p->vertices); 432 | case 13: return p->triproc(e6, e2, e4, p->vertices); 433 | case 14: return p->triproc(e5, e3, e6, p->vertices); 434 | } 435 | return 1; 436 | } 437 | 438 | 439 | /**** Cubical Polygonization (optional) ****/ 440 | 441 | 442 | #define LB 0 /* left bottom edge */ 443 | #define LT 1 /* left top edge */ 444 | #define LN 2 /* left near edge */ 445 | #define LF 3 /* left far edge */ 446 | #define RB 4 /* right bottom edge */ 447 | #define RT 5 /* right top edge */ 448 | #define RN 6 /* right near edge */ 449 | #define RF 7 /* right far edge */ 450 | #define BN 8 /* bottom near edge */ 451 | #define BF 9 /* bottom far edge */ 452 | #define TN 10 /* top near edge */ 453 | #define TF 11 /* top far edge */ 454 | 455 | static INTLISTS *cubetable[256]; 456 | 457 | /* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */ 458 | static int corner1[12] = {LBN,LTN,LBN,LBF,RBN,RTN,RBN,RBF,LBN,LBF,LTN,LTF}; 459 | static int corner2[12] = {LBF,LTF,LTN,LTF,RBF,RTF,RTN,RTF,RBN,RBF,RTN,RTF}; 460 | static int leftface[12] = {B, L, L, F, R, T, N, R, N, B, T, F}; 461 | /* face on left when going corner1 to corner2 */ 462 | static int rightface[12] = {L, T, N, L, B, R, R, F, B, F, N, T}; 463 | /* face on right when going corner1 to corner2 */ 464 | 465 | 466 | /* docube: triangulate the cube directly, without decomposition */ 467 | 468 | int docube (CUBE *cube, PROCESS *p) 469 | { 470 | INTLISTS *polys; 471 | int i, index = 0; 472 | for (i = 0; i < 8; i++) if (cube->corners[i]->value > 0.0) index += (1<next) { 474 | INTLIST *edges; 475 | int a = -1, b = -1, count = 0; 476 | for (edges = polys->list; edges; edges = edges->next) { 477 | CORNER *c1 = cube->corners[corner1[edges->i]]; 478 | CORNER *c2 = cube->corners[corner2[edges->i]]; 479 | int c = vertid(c1, c2, p); 480 | if (++count > 2 && ! p->triproc(a, b, c, p->vertices)) return 0; 481 | if (count < 3) a = b; 482 | b = c; 483 | } 484 | } 485 | return 1; 486 | } 487 | 488 | 489 | /* nextcwedge: return next clockwise edge from given edge around given face */ 490 | 491 | int nextcwedge (int edge, int face) 492 | { 493 | switch (edge) { 494 | case LB: return (face == L)? LF : BN; 495 | case LT: return (face == L)? LN : TF; 496 | case LN: return (face == L)? LB : TN; 497 | case LF: return (face == L)? LT : BF; 498 | case RB: return (face == R)? RN : BF; 499 | case RT: return (face == R)? RF : TN; 500 | case RN: return (face == R)? RT : BN; 501 | case RF: return (face == R)? RB : TF; 502 | case BN: return (face == B)? RB : LN; 503 | case BF: return (face == B)? LB : RF; 504 | case TN: return (face == T)? LT : RN; 505 | case TF: return (face == T)? RT : LF; 506 | } 507 | return -1; 508 | } 509 | 510 | 511 | /* otherface: return face adjoining edge that is not the given face */ 512 | 513 | int otherface (int edge, int face) 514 | { 515 | int other = leftface[edge]; 516 | return face == other? rightface[edge] : other; 517 | } 518 | 519 | 520 | /* makecubetable: create the 256 entry table for cubical polygonization */ 521 | 522 | void makecubetable () 523 | { 524 | int i, e, c, done[12], pos[8]; 525 | for (i = 0; i < 256; i++) { 526 | for (e = 0; e < 12; e++) done[e] = 0; 527 | for (c = 0; c < 8; c++) pos[c] = BIT(i, c); 528 | for (e = 0; e < 12; e++) 529 | if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) { 530 | INTLIST *ints = 0; 531 | INTLISTS *lists = (INTLISTS *) mycalloc(1, sizeof(INTLISTS)); 532 | int start = e, edge = e; 533 | /* get face that is to right of edge from pos to neg corner: */ 534 | int face = pos[corner1[e]]? rightface[e] : leftface[e]; 535 | while (1) { 536 | edge = nextcwedge(edge, face); 537 | done[edge] = 1; 538 | if (pos[corner1[edge]] != pos[corner2[edge]]) { 539 | INTLIST *tmp = ints; 540 | ints = (INTLIST *) mycalloc(1, sizeof(INTLIST)); 541 | ints->i = edge; 542 | ints->next = tmp; /* add edge to head of list */ 543 | if (edge == start) break; 544 | face = otherface(edge, face); 545 | } 546 | } 547 | lists->list = ints; /* add ints to head of table entry */ 548 | lists->next = cubetable[i]; 549 | cubetable[i] = lists; 550 | } 551 | } 552 | } 553 | 554 | 555 | /**** Storage ****/ 556 | 557 | 558 | /* mycalloc: return successful calloc or exit program */ 559 | 560 | char *mycalloc (int nitems, int nbytes) 561 | { 562 | char *ptr = (char *) calloc(nitems, nbytes); 563 | if (ptr != NULL) return ptr; 564 | fprintf(stderr, "can't calloc %d bytes\n", nitems*nbytes); 565 | exit(1); 566 | } 567 | 568 | 569 | /* setcenter: set (i,j,k) entry of table[] 570 | * return 1 if already set; otherwise, set and return 0 */ 571 | 572 | int setcenter(CENTERLIST *table[], int i, int j, int k) 573 | { 574 | int index = HASH(i, j, k); 575 | CENTERLIST *newlist, *l, *q = table[index]; 576 | for (l = q; l != NULL; l = l->next) 577 | if (l->i == i && l->j == j && l->k == k) return 1; 578 | newlist = (CENTERLIST *) mycalloc(1, sizeof(CENTERLIST)); 579 | newlist->i = i; newlist->j = j; newlist->k = k; newlist->next = q; 580 | table[index] = newlist; 581 | return 0; 582 | } 583 | 584 | 585 | /* setedge: set vertex id for edge */ 586 | 587 | void setedge (EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2, int vid) 588 | { 589 | unsigned int index; 590 | EDGELIST *newlist; 591 | if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) { 592 | int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t; 593 | } 594 | index = HASH(i1, j1, k1) + HASH(i2, j2, k2); 595 | newlist = (EDGELIST *) mycalloc(1, sizeof(EDGELIST)); 596 | newlist->i1 = i1; newlist->j1 = j1; newlist->k1 = k1; 597 | newlist->i2 = i2; newlist->j2 = j2; newlist->k2 = k2; 598 | newlist->vid = vid; 599 | newlist->next = table[index]; 600 | table[index] = newlist; 601 | } 602 | 603 | 604 | /* getedge: return vertex id for edge; return -1 if not set */ 605 | 606 | int getedge (EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2) 607 | { 608 | EDGELIST *q; 609 | if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) { 610 | int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t; 611 | }; 612 | q = table[HASH(i1, j1, k1)+HASH(i2, j2, k2)]; 613 | for (; q != NULL; q = q->next) 614 | if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 && 615 | q->i2 == i2 && q->j2 == j2 && q->k2 == k2) 616 | return q->vid; 617 | return -1; 618 | } 619 | 620 | 621 | /**** Vertices ****/ 622 | 623 | 624 | /* vertid: return index for vertex on edge: 625 | * c1->value and c2->value are presumed of different sign 626 | * return saved index if any; else compute vertex and save */ 627 | 628 | int vertid (CORNER *c1, CORNER *c2, PROCESS *p) 629 | { 630 | VERTEX v; 631 | POINT a, b; 632 | int vid = getedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k); 633 | if (vid != -1) return vid; /* previously computed */ 634 | a.x = c1->x; a.y = c1->y; a.z = c1->z; 635 | b.x = c2->x; b.y = c2->y; b.z = c2->z; 636 | //converge(&a, &b, c1->value, p->function, &v.position); /* position */ 637 | converge2(&a, &b, c1->value, c2->value, &v.position); /* position */ 638 | vnormal(&v.position, p, &v.normal); /* normal */ 639 | addtovertices(&p->vertices, v); /* save vertex */ 640 | vid = p->vertices.count-1; 641 | setedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid); 642 | return vid; 643 | } 644 | 645 | 646 | /* addtovertices: add v to sequence of vertices */ 647 | 648 | void addtovertices (VERTICES *vertices, VERTEX v) 649 | { 650 | if (vertices->count == vertices->max) { 651 | int i; 652 | VERTEX *newvertex; 653 | vertices->max = vertices->count == 0 ? 10 : 2*vertices->count; 654 | newvertex = (VERTEX *) mycalloc(vertices->max, sizeof(VERTEX)); 655 | for (i = 0; i < vertices->count; i++) newvertex[i] = vertices->ptr[i]; 656 | if (vertices->ptr != NULL) free((char *) vertices->ptr); 657 | vertices->ptr = newvertex; 658 | } 659 | vertices->ptr[vertices->count++] = v; 660 | } 661 | 662 | 663 | /* addtotriangles: add t to sequence of triangles */ 664 | 665 | int addtotriangles (TRIANGLES *triangles, TRIANGLE t) 666 | { 667 | if (triangles->count == triangles->max) { 668 | int i; 669 | TRIANGLE *newtriangle; 670 | triangles->max = triangles->count == 0 ? 10 : 2*triangles->count; 671 | newtriangle = (TRIANGLE *) mycalloc(triangles->max, sizeof(TRIANGLE)); 672 | for (i = 0; i < triangles->count; i++) newtriangle[i] = triangles->ptr[i]; 673 | if (triangles->ptr != NULL) free((char *) triangles->ptr); 674 | triangles->ptr = newtriangle; 675 | } 676 | triangles->ptr[triangles->count++] = t; 677 | return 1; 678 | } 679 | 680 | 681 | /* vnormal: compute unit length surface normal at point */ 682 | 683 | void vnormal (POINT *point, PROCESS *p, POINT *v) 684 | { 685 | double f = p->function(point->x, point->y, point->z); 686 | v->x = p->function(point->x+p->delta, point->y, point->z)-f; 687 | v->y = p->function(point->x, point->y+p->delta, point->z)-f; 688 | v->z = p->function(point->x, point->y, point->z+p->delta)-f; 689 | f = sqrt(v->x*v->x + v->y*v->y + v->z*v->z); 690 | if (f != 0.0) {v->x /= f; v->y /= f; v->z /= f;} 691 | } 692 | 693 | 694 | /* converge: from two points of differing sign, converge to zero crossing */ 695 | 696 | void converge (POINT *p1, POINT *p2, double v, double (*function)(double,double,double), POINT *p) 697 | { 698 | int i = 0; 699 | POINT pos, neg; 700 | if (v < 0) { 701 | pos.x = p2->x; pos.y = p2->y; pos.z = p2->z; 702 | neg.x = p1->x; neg.y = p1->y; neg.z = p1->z; 703 | } 704 | else { 705 | pos.x = p1->x; pos.y = p1->y; pos.z = p1->z; 706 | neg.x = p2->x; neg.y = p2->y; neg.z = p2->z; 707 | } 708 | while (1) { 709 | p->x = 0.5*(pos.x + neg.x); 710 | p->y = 0.5*(pos.y + neg.y); 711 | p->z = 0.5*(pos.z + neg.z); 712 | if (i++ == RES) return; 713 | if ((function(p->x, p->y, p->z)) > 0.0) 714 | {pos.x = p->x; pos.y = p->y; pos.z = p->z;} 715 | else {neg.x = p->x; neg.y = p->y; neg.z = p->z;} 716 | } 717 | } 718 | 719 | void converge2 (POINT *p1, POINT *p2, double v1, double v2, POINT *p) 720 | { 721 | double t = v1/(v1-v2); 722 | p->x=p1->x*(1-t)+p2->x*t; 723 | p->y=p1->y*(1-t)+p2->y*t; 724 | p->z=p1->z*(1-t)+p2->z*t; 725 | } 726 | -------------------------------------------------------------------------------- /src/polygonizer.h: -------------------------------------------------------------------------------- 1 | #ifndef POLYGONIZER_H 2 | #define POLYGONIZER_H 3 | 4 | typedef struct point { /* a three-dimensional point */ 5 | double x, y, z; /* its coordinates */ 6 | } POINT; 7 | 8 | typedef struct test { /* test the function for a signed value */ 9 | POINT p; /* location of test */ 10 | double value; /* function value at p */ 11 | int ok; /* if value is of correct sign */ 12 | } TEST; 13 | 14 | typedef struct vertex { /* surface vertex */ 15 | POINT position, normal; /* position and surface normal */ 16 | } VERTEX; 17 | 18 | typedef struct vertices { /* list of vertices in polygonization */ 19 | int count, max; /* # vertices, max # allowed */ 20 | VERTEX *ptr; /* dynamically allocated */ 21 | } VERTICES; 22 | 23 | typedef struct triangle { 24 | int i1, i2, i3; 25 | } TRIANGLE; 26 | 27 | typedef struct triangles { 28 | int count, max; 29 | TRIANGLE *ptr; 30 | } TRIANGLES; 31 | 32 | typedef struct corner { /* corner of a cube */ 33 | int i, j, k; /* (i, j, k) is index within lattice */ 34 | double x, y, z, value; /* location and function value */ 35 | } CORNER; 36 | 37 | typedef struct cube { /* partitioning cell (cube) */ 38 | int i, j, k; /* lattice location of cube */ 39 | CORNER *corners[8]; /* eight corners */ 40 | } CUBE; 41 | 42 | typedef struct cubes { /* linked list of cubes acting as stack */ 43 | CUBE cube; /* a single cube */ 44 | struct cubes *next; /* remaining elements */ 45 | } CUBES; 46 | 47 | typedef struct centerlist { /* list of cube locations */ 48 | int i, j, k; /* cube location */ 49 | struct centerlist *next; /* remaining elements */ 50 | } CENTERLIST; 51 | 52 | typedef struct cornerlist { /* list of corners */ 53 | int i, j, k; /* corner id */ 54 | double value; /* corner value */ 55 | struct cornerlist *next; /* remaining elements */ 56 | } CORNERLIST; 57 | 58 | typedef struct edgelist { /* list of edges */ 59 | int i1, j1, k1, i2, j2, k2; /* edge corner ids */ 60 | int vid; /* vertex id */ 61 | struct edgelist *next; /* remaining elements */ 62 | } EDGELIST; 63 | 64 | typedef struct intlist { /* list of integers */ 65 | int i; /* an integer */ 66 | struct intlist *next; /* remaining elements */ 67 | } INTLIST; 68 | 69 | typedef struct intlists { /* list of list of integers */ 70 | INTLIST *list; /* a list of integers */ 71 | struct intlists *next; /* remaining elements */ 72 | } INTLISTS; 73 | 74 | typedef struct process { /* parameters, function, storage */ 75 | double (*function)(double,double,double); /* implicit surface function */ 76 | int (*triproc)(int,int,int,VERTICES); /* triangle output function */ 77 | double size, delta; /* cube size, normal delta */ 78 | int bounds; /* cube range within lattice */ 79 | POINT start; /* start point on surface */ 80 | CUBES *cubes; /* active cubes */ 81 | VERTICES vertices; /* surface vertices */ 82 | CENTERLIST **centers; /* cube center hash table */ 83 | CORNERLIST **corners; /* corner value hash table */ 84 | EDGELIST **edges; /* edge and vertex id hash table */ 85 | } PROCESS; 86 | 87 | #endif -------------------------------------------------------------------------------- /src/vtkHelper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "Geometry.h" 11 | 12 | void sameVTIVolumeAndVTKMesh(const Eigen::Matrix &volume,const int dim[3],const std::string volumeFileName, 13 | const Eigen::Matrix &transform,const std::string meshFileName) 14 | { 15 | Eigen::Matrix translate=transform.topRightCorner(3,1); 16 | double scale=transform(0,0); 17 | 18 | vtkSmartPointer volumeVTK=vtkSmartPointer::New(); 19 | volumeVTK->SetDimensions(dim[0],dim[1],dim[2]); 20 | //volumeVTK->SetSpacing(1.0/dim[0],1.0/dim[1],1.0/dim[2]); 21 | //volumeVTK->SetOrigin(0,0,0); 22 | volumeVTK->SetSpacing(1.0/dim[0]*scale,1.0/dim[1]*scale,1.0/dim[2]*scale); 23 | volumeVTK->SetOrigin(translate(0),translate(1),translate(2)); 24 | volumeVTK->SetNumberOfScalarComponents(1); 25 | volumeVTK->SetScalarTypeToFloat(); 26 | volumeVTK->AllocateScalars(); 27 | float *ptr=(float*)volumeVTK->GetScalarPointer(); 28 | memcpy(ptr,volume.data(),dim[0]*dim[1]*dim[2]*sizeof(float)); 29 | 30 | vtkSmartPointer imageWriter=vtkSmartPointer::New(); 31 | imageWriter->SetFileName(volumeFileName.c_str()); 32 | imageWriter->SetInputConnection(volumeVTK->GetProducerPort()); 33 | imageWriter->Write(); 34 | 35 | vtkSmartPointer mc=vtkSmartPointer::New(); 36 | mc->SetInput(volumeVTK); 37 | mc->ComputeNormalsOn(); 38 | mc->SetValue(0,0.0); 39 | 40 | vtkSmartPointer reverse=vtkSmartPointer::New(); 41 | reverse->SetInputConnection(mc->GetOutputPort()); 42 | reverse->ReverseCellsOn(); 43 | 44 | vtkSmartPointer transformVTK=vtkSmartPointer::New(); 45 | //Eigen::Matrix transform_t=transform.transpose(); 46 | Eigen::Matrix transform_t=Eigen::Matrix::Identity(); 47 | transformVTK->SetMatrix(transform_t.data()); 48 | 49 | vtkSmartPointer filter=vtkSmartPointer::New(); 50 | filter->SetTransform(transformVTK); 51 | filter->SetInputConnection(reverse->GetOutputPort()); 52 | 53 | vtkSmartPointer plyWriter=vtkSmartPointer::New(); 54 | plyWriter->SetFileName(meshFileName.c_str()); 55 | plyWriter->SetInputConnection(filter->GetOutputPort()); 56 | plyWriter->Write(); 57 | } 58 | 59 | void sameVTKOctree(const std::vector > &vertices, const std::vector > &edges, const std::string octreeFileName) 60 | { 61 | // Open file 62 | FILE*vtkFile=fopen(octreeFileName.c_str(),"w"); 63 | 64 | int npts=vertices.size(); 65 | 66 | // Write the header information 67 | fprintf(vtkFile,"# vtk DataFile Version 3.0\n"); 68 | fprintf(vtkFile,"vtk output\n"); 69 | fprintf(vtkFile,"ASCII\n"); 70 | fprintf(vtkFile,"DATASET POLYDATA\n"); 71 | fprintf(vtkFile,"POINTS %d float\n",npts); 72 | 73 | // Iterate through the points 74 | for(int i=0;i 5 | #include 6 | #include "Geometry.h" 7 | 8 | void sameVTIVolumeAndVTKMesh(const Eigen::Matrix &volume,const int dim[3],const std::string volumeFileName, 9 | const Eigen::Matrix &transform,const std::string meshFileName); 10 | 11 | void sameVTKOctree(const std::vector > &vertices, const std::vector > &edges, const std::string octreeFileName); 12 | 13 | #endif --------------------------------------------------------------------------------