├── .github └── workflows │ └── ccpp.yml ├── .gitignore ├── .travis.yml ├── 2DConvexHull.h ├── API.cpp ├── API.h ├── BBox.cpp ├── BBox.h ├── BHNode.cpp ├── BHNode.h ├── CMakeLists.txt ├── ETSP.cpp ├── ETSP.h ├── FMM.cpp ├── FMM.h ├── ImplicitFunctionConfig.cmake.in ├── LinearSolver.cpp ├── LinearSolver.h ├── RBF.cpp ├── RBF.h ├── RBFInterface.cpp ├── RBFInterface.h ├── README.md ├── ScatteredData.cpp ├── ScatteredData.h ├── SparseMatrix.cpp ├── SparseMatrix.h ├── Tests ├── CMakeLists.txt ├── ConvexHull2DTests.cpp ├── ConvexHull3DTests.cpp ├── RBFInterfaceTests.cpp ├── RBFTests.cpp ├── ScatteredDataTests.cpp ├── Seg3DIntegrationTest.cpp ├── Vec3Tests.cpp └── regression │ └── pointsTriangleClockwise.txt ├── UseImplicitFunction.cmake ├── fileIO.h ├── main.cpp ├── segmentation ├── original.txt └── sample_points_DEMRI.txt ├── vec3.cpp └── vec3.h /.github/workflows/ccpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-16.04, ubuntu-18.04, ubuntu-latest, macOS-latest] 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Prepare 16 | run: mkdir bin 17 | - name: configure 18 | run: cd bin && cmake .. 19 | - name: make 20 | run: make 21 | - name: make test 22 | run: make test 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | bin/* 31 | 32 | *DS_Store 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | notifications: 4 | slack: sciinstitute:lZnpQQXNd4Io5iGDPQDpJmI1 5 | 6 | compiler: 7 | - gcc 8 | - clang 9 | 10 | cache: 11 | directories: 12 | - $HOME/deps 13 | before_install: 14 | # set up dependency cache 15 | - if [ ! -d $HOME/deps ]; then mkdir $HOME/deps; fi 16 | - if [ ! -f $HOME/deps/tetgen1.4.3.tar.gz ]; then wget --quiet --directory-prefix=$HOME/deps http://tetgen.org/files/tetgen1.4.3.tar.gz; fi 17 | - if [ ! -f $HOME/deps/tetgen_cmake.tgz ]; then wget --quiet --directory-prefix=$HOME/deps http://www.sci.utah.edu/devbuilds/seg3d/tetgen_cmake.tgz; fi 18 | - if [ ! -f $HOME/deps/release-1.10.0.tar.gz ]; then wget --quiet --directory-prefix=$HOME/deps https://github.com/google/googletest/archive/release-1.10.0.tar.gz; fi 19 | - if [ ! -f $HOME/deps/3.2.10.tar.gz ]; then wget --quiet --directory-prefix=$HOME/deps http://bitbucket.org/eigen/eigen/get/3.2.10.tar.gz; fi 20 | - pip install --user cpp-coveralls 21 | - ls $HOME/deps 22 | addons: 23 | apt: 24 | sources: 25 | - ubuntu-toolchain-r-test 26 | - george-edison55-precise-backports 27 | packages: 28 | - cmake 29 | - cmake-data 30 | script: 31 | # build Tetgen dependency 32 | - mkdir build 33 | - cd build 34 | - tar xzf $HOME/deps/tetgen1.4.3.tar.gz 35 | - pushd tetgen1.4.3 36 | - make tetlib 37 | - tar xzf $HOME/deps/tetgen_cmake.tgz 38 | - popd 39 | # build Googletest dependency 40 | - tar xzf $HOME/deps/release-1.10.0.tar.gz 41 | - pushd googletest-release-1.10.0 42 | - mkdir build 43 | - cd build 44 | - cmake .. 45 | - make -j4 CXXFLAGS:=$(CXXFLAGS) -lpthread -lm 46 | - popd 47 | # untar Eigen dependency (no build needed) 48 | - tar xzf $HOME/deps/3.2.10.tar.gz 49 | # build ImplicitFunction library 50 | - cmake -DBUILD_TESTING:BOOL=ON -DENABLE_COVERAGE:BOOL=ON -DTravisCI_BUILD:BOOL=ON 51 | -DGTEST_INCLUDE_DIR:PATH=`pwd`/googletest-release-1.10.0/googletest/include 52 | -DGTEST_LIBRARY:FILEPATH=`pwd`/googletest-release-1.10.0/build/lib/libgtest.a 53 | -DGTEST_MAIN_LIBRARY:FILEPATH=`pwd`/googletest-release-1.10.0/build/lib/libgtest_main.a 54 | -DTetgen_DIR:PATH=`pwd`/tetgen1.4.3 55 | -DEIGEN3_INSTALL_DIR:PATH=`pwd`/eigen-eigen-b9cd8366d4e8 .. 56 | - make -j4 CXXFLAGS:=$(CXXFLAGS) -lpthread -lm 57 | - ./ImplicitFunction_Tests 58 | 59 | after_success: 60 | - cd $TRAVIS_BUILD_DIR 61 | - coveralls --exclude build --exclude Tests --gcov-options '\-lp' 62 | -------------------------------------------------------------------------------- /2DConvexHull.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef TWODCONVEXHULL 28 | #define TWODCONVEXHULL 1 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "vec3.h" 36 | 37 | struct Point 38 | { 39 | double x, y; 40 | int index; 41 | }; 42 | 43 | // A utility function to find next to top in a stack 44 | Point nextToTop(std::stack &S) 45 | { 46 | Point p = S.top(); 47 | S.pop(); 48 | Point res = S.top(); 49 | S.push(p); 50 | return res; 51 | } 52 | 53 | void swap(Point &p1, Point &p2) 54 | { 55 | Point temp = p1; 56 | p1 = p2; 57 | p2 = temp; 58 | } 59 | 60 | double distSq(const Point& p1, const Point& p2) 61 | { 62 | return (p1.x - p2.x) * (p1.x - p2.x) + 63 | (p1.y - p2.y) * (p1.y - p2.y); 64 | } 65 | 66 | // To find orientation of ordered triplet (p, q, r). 67 | // The function returns following values 68 | // 0 -> p, q and r are colinear 69 | // 1 -> Clockwise 70 | // 2 -> Counterclockwise 71 | int orientation(const Point& p, const Point& q, const Point& r) 72 | { 73 | int val = (q.y - p.y) * (r.x - q.x) - 74 | (q.x - p.x) * (r.y - q.y); 75 | 76 | if (val == 0) return 0; // colinear 77 | // TODO: make enum or consts... 78 | return (val > 0) ? 1 : 2; // clock or counterclock wise 79 | } 80 | 81 | // A function used by library function qsort() to sort an array of 82 | // points with respect to the first point 83 | int compare(const void *vp1, const void *vp2) 84 | { 85 | // TODO: C-style cast... 86 | Point *p1 = (Point *)vp1; 87 | Point *p2 = (Point *)vp2; 88 | 89 | Point p0; p0.x=0; p0.y=0; 90 | 91 | // Find orientation 92 | int o = orientation(p0, *p1, *p2); 93 | if (o == 0) 94 | return (distSq(p0, *p2) >= distSq(p0, *p1))? -1 : 1; 95 | 96 | return (o == 2)? -1: 1; 97 | } 98 | 99 | // Prints convex hull of a set of n points. 100 | // TODO: points gets overwritten... 101 | std::stack convexHull(std::vector& points) 102 | { 103 | const int n = points.size(); 104 | // Find the bottommost point 105 | int ymin = points[0].y, min = 0; 106 | for (int i = 1; i < n; i++) 107 | { 108 | int y = points[i].y; 109 | 110 | // Pick the bottom-most or chose the left 111 | // most point in case of tie 112 | if ( (y < ymin) || (ymin == y && points[i].x < points[min].x) ) 113 | ymin = points[i].y, min = i; 114 | } 115 | 116 | // Place the bottom-most point at first position 117 | std::swap(points[0], points[min]); 118 | 119 | // Sort n-1 points with respect to the first point. 120 | Point p0; 121 | for(int i = 1; i < n; i++) 122 | { 123 | points[i].x -= points[0].x; 124 | points[i].y -= points[0].y; 125 | } 126 | p0.x = points[0].x = 0; 127 | p0.y = points[0].y = 0; 128 | 129 | qsort(&points[1], n-1, sizeof(Point), compare); 130 | 131 | // Process first 3 points 132 | 133 | // If two or more points make same angle with p0, 134 | // Remove all but the one that is farthest from p0 135 | int m = 1; 136 | for (int i = 1; i < n; i++) 137 | { 138 | while ( (i < n-1) && orientation(p0, points[i], points[i+1]) == 0 ) 139 | i++; 140 | points[m] = points[i]; 141 | m++; // Update size of modified array 142 | } 143 | 144 | std::stack S; 145 | if (m < 3) return S; 146 | 147 | S.push(points[0]); 148 | S.push(points[1]); 149 | S.push(points[2]); 150 | 151 | // Process remaining n-3 points 152 | for (int i = 3; i < m; i++) 153 | { 154 | // Keep removing top while the angle formed by 155 | // points next-to-top, top, and points[i] makes 156 | // a non-left turn 157 | while (orientation(nextToTop(S), S.top(), points[i]) != 2) 158 | S.pop(); 159 | S.push(points[i]); 160 | } 161 | 162 | return S; 163 | } 164 | 165 | // dim refers to the dimension that needs to be ignored 166 | std::vector getConvexHull(const std::vector &inPoints, const int dim) 167 | { 168 | std::vector myPoints(inPoints.size()); 169 | for(int i = 0; i < inPoints.size(); i++) 170 | { 171 | int index = 0; 172 | for(int j = 0; j < 3; j++) 173 | { 174 | if (j == dim) continue; 175 | if (index == 0) myPoints[i].x = inPoints[i][j]; 176 | if (index == 1) myPoints[i].y = inPoints[i][j]; 177 | index++; 178 | } 179 | myPoints[i].index = i; 180 | } 181 | 182 | // TODO: myPoints gets overwritten... 183 | auto myStack = convexHull(myPoints); 184 | 185 | std::vector ret; 186 | while (! myStack.empty() ) 187 | { 188 | Point p = myStack.top(); 189 | ret.push_back(p.index); 190 | myStack.pop(); 191 | } 192 | 193 | return ret; 194 | } 195 | 196 | #endif 197 | -------------------------------------------------------------------------------- /API.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "ScatteredData.h" 7 | #include "vec3.h" 8 | #include "SampleData.h" 9 | #include "RBF.h" 10 | #include "Surface.h" 11 | #include "fileIO.h" 12 | #include "API.h" 13 | 14 | using std::string; 15 | 16 | void API::CreateSurface(string filename, vec3 myOrigin, vec3 mySize, vec3 mySampling) 17 | { 18 | mySurfaceData = new ScatteredData(); 19 | readSurfaceDataFile(filename, mySurfaceData); 20 | printf("Calling the 2D hull creator\n"); 21 | mySurfaceData->compute2DHull(); 22 | augmentNormalData(mySurfaceData); 23 | mySurfaceRBF = new RBF(mySurfaceData, myKernel); 24 | mySurfaceRBF->setDataReduction(All); 25 | myKernel = ThinPlate; 26 | mySurface = new Surface(mySurfaceData, mySurfaceRBF); 27 | 28 | //Construct RBFs 29 | //printf("Compute RBF\n"); 30 | mySurface->computeRBF(); 31 | 32 | vec3 mySpacing(mySize[0]/mySampling[0], mySize[1]/mySampling[1], mySize[2]/mySampling[2]); 33 | //printf("SPACING: %lf %lf %lf\n",mySpacing[0], mySpacing[1], mySpacing[2]); 34 | value.resize((int)(mySampling[0])); 35 | for(int i=0; icomputeValue(location); 52 | //printf("Interpolant: %lf %lf %lf %lf\n", location[0], location[1], location[2], myVal); fflush(stdout); 53 | value[i][j][k]=myVal; 54 | } 55 | } 56 | } 57 | } 58 | 59 | API::API(string filename, string dimensions) 60 | { 61 | //read from the dimentsion file here TODO 62 | vec3 myOrigin(-30, -50, 80); 63 | vec3 mySize(60, 50, 10); 64 | vec3 mySampling(100, 100, 100); 65 | CreateSurface(filename, myOrigin, mySize, mySampling); 66 | } 67 | 68 | API::API() 69 | { 70 | } 71 | 72 | API::API(vector myData, vec3 myOrigin, vec3 mySize, vec3 mySampling) 73 | { 74 | CreateSurface(myData, myOrigin, mySize, mySampling); 75 | } 76 | 77 | vector > >API::CreateSurface(vector myData, vec3 myOrigin, vec3 mySize, vec3 mySampling) 78 | { 79 | vector a,b,c,d; 80 | for(int i=0; i::iterator minx = std::min_element(a.begin(), a.end()); 89 | vector::iterator miny = std::min_element(b.begin(), b.end()); 90 | vector::iterator minz = std::min_element(c.begin(), c.end()); 91 | vector::iterator maxx = std::max_element(a.begin(), a.end()); 92 | vector::iterator maxy = std::max_element(b.begin(), b.end()); 93 | vector::iterator maxz = std::max_element(c.begin(), c.end()); 94 | vec3 myMin(*minx, *miny, *minz), myMax(*maxx, *maxy, *maxz); 95 | myMin = myMin - 0.05*mySize; 96 | myMax = myMax + 0.05*mySize; 97 | 98 | mySurfaceData = new ScatteredData(a,b,c,d); 99 | augmentNormalData(mySurfaceData); 100 | mySurfaceRBF = new RBF(mySurfaceData, myKernel); 101 | //mySurfaceRBF->setDataReduction(Random); 102 | myKernel = ThinPlate; 103 | mySurface = new Surface(mySurfaceData, mySurfaceRBF); 104 | 105 | //Construct RBFs 106 | mySurface->computeRBF(); 107 | 108 | //sanity check 109 | for(int i=0; ifnc.size(); i++) 110 | { 111 | vec3 myLocation(mySurfaceData->x[0][i], mySurfaceData->x[1][i], mySurfaceData->x[2][i]); 112 | double myVal = mySurface->computeValue(myLocation); 113 | double error = fabs(myVal - mySurfaceData->fnc[i]); 114 | if (error>1e-3) 115 | { 116 | printf("%lf\n", error); 117 | fflush(stdout); 118 | } 119 | } 120 | 121 | vec3 mySpacing(mySize[0]/mySampling[0], mySize[1]/mySampling[1], mySize[2]/mySampling[2]); 122 | //printf("SPACING: %lf %lf %lf\n",mySpacing[0], mySpacing[1], mySpacing[2]); 123 | 124 | value.resize((int)(mySampling[0])); 125 | for(int i=0; imyMax[0]) 138 | continue; 139 | for(int j=0; jmyMax[1]) 143 | continue; 144 | for(int k=0; kmyMax[2]) 148 | continue; 149 | //std::cout<<"Computing Val ... "<computeValue(location); 151 | //printf("Interpolant: %lf %lf %lf %lf\n", location[0], location[1], location[2], myVal); fflush(stdout); 152 | value[i][j][k]=myVal; 153 | } 154 | } 155 | } 156 | 157 | return value; 158 | } 159 | 160 | vec3 API::findSphericalNormal(ScatteredData *data, int n) 161 | { 162 | vec3 ret(0,0,0); 163 | for(int j=0; j<3; j++) 164 | ret[j] = (data->x[j][n] - data->centroid[j])/10; 165 | } 166 | 167 | vec3 API::findNormal(ScatteredData *data, int n) 168 | { 169 | int tot = data->x[0].size(); 170 | int prev = (n-1)>=0?n-1:tot-1; 171 | int next = (n+1)x[2][prev]!=data->x[2][n]) 174 | { 175 | prev = (prev-1)>=0?prev-1:tot-1; 176 | } 177 | 178 | while(data->x[2][next]!=data->x[2][n]) 179 | { 180 | next = (next+1)x[0][n], data->x[1][n], data->x[2][n]); 185 | vec3 b(data->x[0][prev], data->x[1][prev], data->x[2][prev]); 186 | vec3 c(data->x[0][next], data->x[1][next], data->x[2][next]); 187 | vec3 one = b-a; 188 | vec3 two = c-a; 189 | vec3 ret = one+two; 190 | return ret; 191 | } 192 | 193 | void API::augmentNormalData(ScatteredData *data) 194 | { 195 | int n = data->origSize; 196 | for(int i=0; ix[j].push_back(data->x[j][i] + myNormal[j]); 203 | } 204 | data->fnc.push_back(10); 205 | 206 | for(int j=0; j<3; j++) 207 | { 208 | data->x[j].push_back(data->x[j][i] - myNormal[j]); 209 | } 210 | data->fnc.push_back(-10); 211 | } 212 | } 213 | 214 | vec3 API::findNormalAxis(ScatteredData *data, int n) 215 | { 216 | //printf("here\n"); 217 | int tot = data->origSize; 218 | int prev = (n-1)>=0?n-1:tot-1; 219 | int next = (n+1)axisInformation[n]; 221 | 222 | while(fabs(data->x[myAxis][prev]-data->x[myAxis][n])>1e-6) 223 | { 224 | //printf("%d %d %lf\n",myAxis,prev,data->x[myAxis][prev]); 225 | prev = (prev-1)>=0?prev-1:tot-1; 226 | } 227 | 228 | while(fabs(data->x[myAxis][next]-data->x[myAxis][n])>1e-6) 229 | { 230 | next = (next+1)x[myAxis][prev]-data->x[myAxis][n]),fabs(data->x[myAxis][next]-data->x[myAxis][n]), myAxis); fflush(stdout); 233 | //printf(" see: %d %d %d %lf %lf %lf axis=%d\n", prev,n,next, data->x[myAxis][prev],data->x[myAxis][n], data->x[myAxis][next], myAxis); fflush(stdout); 234 | 235 | vec3 a(data->x[0][n], data->x[1][n], data->x[2][n]); 236 | vec3 b(data->x[0][prev], data->x[1][prev], data->x[2][prev]); 237 | vec3 c(data->x[0][next], data->x[1][next], data->x[2][next]); 238 | 239 | vec3 tangent = b-c; 240 | double ret_x, ret_y, ret_z; 241 | vec3 ret(tangent); 242 | //rotate by 90 degrees on the x-y plane 243 | switch(myAxis) 244 | { 245 | case 0: 246 | ret[1] = ret_y = -tangent[2]; 247 | ret[2] = ret_z = tangent[1]; 248 | break; 249 | case 1: 250 | ret[2] = ret_z = -tangent[0]; 251 | ret[0] = ret_x = tangent[2]; 252 | break; 253 | case 2: 254 | ret[0] = ret_x = -tangent[1]; 255 | ret[1] = ret_y = tangent[0]; 256 | break; 257 | } 258 | return ret; 259 | } 260 | 261 | -------------------------------------------------------------------------------- /API.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef _API_H_ 28 | #define _API_H_ 29 | 30 | #include 31 | #include 32 | using std::vector; 33 | using std::string; 34 | 35 | #include "ScatteredData.h" 36 | #include "vec3.h" 37 | #include "SampleData.h" 38 | #include "RBF.h" 39 | #include "Surface.h" 40 | 41 | class API 42 | { 43 | public: 44 | ScatteredData *mySurfaceData; 45 | Surface *mySurface; 46 | RBF *mySurfaceRBF; 47 | Kernel myKernel; 48 | std::vector > > value; 49 | 50 | void CreateSurface(string filename, vec3 myOrigin, vec3 mySize, vec3 mySampling); 51 | std::vector > >CreateSurface(std::vector myData, vec3 myOrigin, vec3 mySize, vec3 mySampling); 52 | API(string filename, string dimensions); 53 | API(std::vector myData, vec3 myOrigin, vec3 mySize, vec3 mySampling); 54 | API(); 55 | 56 | private: 57 | 58 | void augmentNormalData(ScatteredData *data); 59 | vec3 findNormal(ScatteredData *data, int n); 60 | vec3 findSphericalNormal(ScatteredData *data, int n); 61 | vec3 findNormalAxis(ScatteredData *data, int n); 62 | }; 63 | 64 | #endif //_API_H_ 65 | -------------------------------------------------------------------------------- /BBox.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include "BBox.h" 28 | 29 | #include 30 | 31 | BBox::BBox() : 32 | empty_(true) 33 | { 34 | reset(); 35 | } 36 | 37 | BBox::~BBox() 38 | { 39 | } 40 | 41 | void BBox::setMin(const vec3& m) 42 | { 43 | this->min_ = m; 44 | isEmpty(); 45 | } 46 | 47 | void BBox::setMin(float m) 48 | { 49 | this->min_ = vec3(m, m, m); 50 | isEmpty(); 51 | } 52 | 53 | void BBox::setMax(const vec3& m) 54 | { 55 | this->max_ = m; 56 | isEmpty(); 57 | } 58 | 59 | void BBox::setMax(float m) 60 | { 61 | this->max_ = vec3(m, m, m); 62 | isEmpty(); 63 | } 64 | 65 | void BBox::reset() 66 | { 67 | this->min_ = vec3(std::numeric_limits::max(), 68 | std::numeric_limits::max(), 69 | std::numeric_limits::max()); 70 | this->max_ = vec3(std::numeric_limits::min(), 71 | std::numeric_limits::min(), 72 | std::numeric_limits::min()); 73 | isEmpty(); 74 | } 75 | 76 | inline 77 | bool BBox::isEmpty() 78 | { 79 | this->empty_ = !(this->min_.x() < this->max_.x() && 80 | this->min_.y() < this->max_.y() && 81 | this->min_.z() < this->max_.z()); 82 | return this->empty_; 83 | } 84 | 85 | inline 86 | bool BBox::inside(const vec3 &pos) 87 | { 88 | return (pos.x() >= this->min_.x() && pos.x() <= this->max_.x() && 89 | pos.y() >= this->min_.y() && pos.y() <= this->max_.y() && 90 | pos.z() >= this->min_.z() && pos.z() <= this->max_.z()); 91 | } 92 | -------------------------------------------------------------------------------- /BBox.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef BBOX_H 28 | #define BBOX_H 29 | #include "vec3.h" 30 | 31 | class BBox 32 | { 33 | public: 34 | BBox(); 35 | ~BBox(); 36 | vec3 getMin() const { return this->min_; } 37 | vec3 getMax() const { return this->max_; } 38 | 39 | void setMin(const vec3& m); 40 | void setMin(float m); 41 | void setMax(const vec3& m); 42 | void setMax(float m); 43 | 44 | void reset(); 45 | bool isEmpty(); 46 | bool inside(const vec3& pos); 47 | //private: 48 | vec3 min_, max_; 49 | private: 50 | bool empty_; 51 | }; 52 | #endif // BBOX_H 53 | -------------------------------------------------------------------------------- /BHNode.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include "BHNode.h" 28 | 29 | BHNode::BHNode() : 30 | leaf_(true), 31 | mass_(1.0), 32 | coeff_(0), 33 | center_( vec3(0.0, 0.0, 0.0) ) 34 | { 35 | //leaf = 1; 36 | for (int i = 0; i < 8; i++) 37 | { 38 | nodes[i] = 0; 39 | } 40 | //mass = 1.0; 41 | //center = vec3(0.0,0.0,0.0); 42 | } 43 | 44 | BHNode::~BHNode() 45 | { 46 | } 47 | -------------------------------------------------------------------------------- /BHNode.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef BHNODE_H 28 | #define BHNODE_H 29 | 30 | #include 31 | #include 32 | 33 | #include "vec3.h" 34 | #include "BBox.h" 35 | 36 | 37 | class BHNode 38 | { 39 | public: 40 | BHNode(); 41 | ~BHNode(); 42 | bool leaf_; 43 | double mass_; 44 | double coeff_; 45 | vec3 center_; 46 | BBox box_; 47 | std::vector pts_; 48 | int index_; 49 | double sum_coeff_, sum_coeff_xi_, sum_xi2_; 50 | 51 | // TODO: magic number 52 | BHNode *nodes[8]; 53 | }; 54 | 55 | #endif // BHNODE_H 56 | 57 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Permission is hereby granted, free of charge, to any person 2 | # obtaining a copy of this software and associated documentation 3 | # files ( the "Software" ), to deal in the Software without 4 | # restriction, including without limitation the rights to use, 5 | # copy, modify, merge, publish, distribute, sublicense, and/or 6 | # sell copies of the Software, and to permit persons to whom the 7 | # Software is furnished to do so, subject to the following 8 | # conditions: 9 | # 10 | # The above copyright notice and this permission notice shall 11 | # be included in all copies or substantial portions of the 12 | # Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 15 | # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 16 | # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 17 | # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 | # USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | cmake_minimum_required(VERSION 3.5) 24 | 25 | project(ImplicitFunction) 26 | 27 | include(CTest) 28 | option(BUILD_TESTING "Build with tests." ON) 29 | if(BUILD_TESTING) 30 | find_package(GTest 1.7 REQUIRED) 31 | endif() 32 | 33 | set(EIGEN3_INSTALL_DIR "" CACHE PATH "Eigen 3 include directory.") 34 | if (IS_DIRECTORY ${EIGEN3_INSTALL_DIR}) 35 | find_path(EIGEN3_INCLUDE_DIR signature_of_eigen3_matrix_library 36 | PATHS ${EIGEN3_INSTALL_DIR} ${EIGEN3_INSTALL_DIR}/include 37 | PATH_SUFFIXES eigen3 eigen 38 | NO_DEFAULT_PATH 39 | ) 40 | if (NOT EIGEN3_INCLUDE_DIR) 41 | MESSAGE(ERROR "${EIGEN3_INCLUDE_DIR} not valid Eigen include directory.") 42 | endif() 43 | endif() 44 | 45 | set(Tetgen_DIR "" CACHE PATH "Tetgen directory.") 46 | option(TravisCI_BUILD "Enable if Travis-CI build." OFF) 47 | 48 | # have to hardcode some setting for the Travis-CI build 49 | # Tetgen cmake files downloaded by Travis-CI build 50 | # TODO: is there a better way to handle this? 51 | if(TravisCI_BUILD) 52 | set(TETGEN_INCLUDE ${Tetgen_DIR}) 53 | set(TETGEN_LIBRARY_DIR ${Tetgen_DIR}) 54 | set(TETGEN_USE_FILE ${Tetgen_DIR}/UseTetgen.cmake) 55 | set(TETGEN_LIBRARY "tet") 56 | configure_file(${Tetgen_DIR}/TetgenConfig.cmake.in ${Tetgen_DIR}/TetgenConfig.cmake @ONLY) 57 | configure_file(${Tetgen_DIR}/UseTetgen.cmake ${TETGEN_USE_FILE} COPYONLY) 58 | endif() 59 | 60 | find_package(Tetgen CONFIGS TetgenConfig.cmake HINTS ${Tetgen_DIR} NO_SYSTEM_ENVIRONMENT_PATH) 61 | if(NOT Tetgen_FOUND) 62 | message(FATAL_ERROR "Tetgen library not found in ${Tetgen_DIR}") 63 | endif() 64 | include(${TETGEN_USE_FILE}) 65 | 66 | ########################################### 67 | # *Nix C++ compiler flags 68 | ########################################### 69 | 70 | if(UNIX) 71 | option(ENABLE_COVERAGE "Enable coverage compiler options." OFF) 72 | if(ENABLE_COVERAGE) 73 | #if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") 74 | # set(COVERAGE_FLAGS "") 75 | #else() 76 | # # probably GCC 77 | # set(COVERAGE_FLAGS " -fprofile-arcs -ftest-coverage") 78 | #endif() 79 | set(COVERAGE_FLAGS "--coverage") 80 | set(CTEST_CUSTOM_COVERAGE_EXCLUDE "/Tests/") 81 | else() 82 | set(COVERAGE_FLAGS "") 83 | endif() 84 | 85 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall ${COVERAGE_FLAGS}") 86 | if(APPLE) 87 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11") 88 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") 89 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -ftemplate-depth=256") 90 | set(CMAKE_CXX_FLAGS_DEBUG "-Wshorten-64-to-32 ${CMAKE_CXX_FLAGS_DEBUG}") 91 | else() 92 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") 93 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-as-needed -ldl -lrt") 94 | endif() 95 | endif() 96 | 97 | set(ImplicitFunction_LIB_NAME "rbf") 98 | 99 | set(ImplicitFunction_SRCS 100 | BBox.cpp 101 | BBox.h 102 | BHNode.cpp 103 | BHNode.h 104 | ETSP.cpp 105 | ETSP.h 106 | FMM.cpp 107 | FMM.h 108 | LinearSolver.cpp 109 | LinearSolver.h 110 | RBF.cpp 111 | RBF.h 112 | ScatteredData.cpp 113 | ScatteredData.h 114 | SparseMatrix.cpp 115 | SparseMatrix.h 116 | vec3.cpp 117 | vec3.h 118 | RBFInterface.cpp 119 | RBFInterface.h 120 | ) 121 | 122 | include_directories(${EIGEN3_INCLUDE_DIR}) 123 | 124 | add_library(${ImplicitFunction_LIB_NAME} 125 | ${ImplicitFunction_SRCS} 126 | ) 127 | 128 | target_link_libraries(${ImplicitFunction_LIB_NAME} 129 | ${TETGEN_LIBRARY} 130 | ) 131 | 132 | if(BUILD_TESTING) 133 | add_subdirectory(Tests) 134 | endif() 135 | 136 | set(ImplicitFunction_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}) 137 | set(ImplicitFunction_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) 138 | set(ImplicitFunction_USE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/UseImplicitFunction.cmake") 139 | 140 | configure_file(ImplicitFunctionConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/ImplicitFunctionConfig.cmake @ONLY) 141 | -------------------------------------------------------------------------------- /ETSP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "vec3.h" 6 | #include "ETSP.h" 7 | #include 8 | #include 9 | 10 | using std::vector; 11 | using std::priority_queue; 12 | using std::pair; 13 | using std::make_pair; 14 | 15 | 16 | ETSP::ETSP(vector &myData, int start, int end, int myplane) 17 | { 18 | for(int i=start; i<=end; i++) 19 | { 20 | vec3 temp(myData[i]); 21 | data.push_back(temp); 22 | } 23 | plane = myplane; 24 | //printf("Data copied\n"); 25 | MST(); 26 | //printf("MST Done\n"); 27 | orderFromMST(); 28 | //printf("Order\n"); 29 | orderFromMatch(); 30 | //printf("Reorder\n"); 31 | //printf("Area: %lf\n", computeArea()); 32 | if (computeArea()<0) 33 | std::reverse(order.begin(), order.end()); 34 | //for(int i=0; i > > myQueue; 59 | 60 | vector visited; 61 | visited.resize(data.size(),false); 62 | graph.resize(data.size()); 63 | 64 | int visitedCount=1; 65 | visited[0]=true; 66 | 67 | for(int i=1; i > edge = myQueue.top(); 77 | int i = edge.second.first; 78 | int j = edge.second.second; 79 | myQueue.pop(); 80 | 81 | if (visited[i] && visited[j]) 82 | continue; 83 | 84 | int toAdd; 85 | if(visited[i]) 86 | toAdd = j; 87 | else 88 | toAdd = i; 89 | visited[toAdd]=true; 90 | visitedCount++; 91 | //printf("Popped %d\n", toAdd); 92 | 93 | for(int i=0; i ETSP::match() 111 | { 112 | vector oddNodes; 113 | vector bestMatch; 114 | for(int i=0; i0) 127 | { 128 | double best=1e10; 129 | do 130 | { 131 | double curr = 0; 132 | for(int i=0; i visited; 156 | visited.resize(data.size(),false); 157 | inverse_mapped_order.resize(data.size()); 158 | traverse(0, visited); 159 | /*for(int i=0; i &visited) 165 | { 166 | visited[curr]=true; 167 | order.push_back(curr); 168 | inverse_mapped_order[curr] = order.size()-1; 169 | for(int i=0; i myMatch = match(); 180 | //for(int i=0; iend) 188 | { 189 | int temp=start; 190 | start=end; 191 | end=temp; 192 | } 193 | //printf("reordering: %d %d\n", start, end); 194 | for(int j=start+1; j 31 | #include 32 | #include 33 | #include 34 | #include "vec3.h" 35 | 36 | class ETSP 37 | { 38 | public: 39 | ETSP(std::vector &myData, int start, int end, int myplane); 40 | int plane; 41 | std::vector data; 42 | std::vector order; 43 | 44 | private: 45 | std::vector > graph; //adjeceny list of the MST 46 | std::vector inverse_mapped_order; 47 | void MST(); 48 | std::vector match(); 49 | void orderFromMST(); 50 | void traverse(int curr, std::vector &visited); 51 | void orderFromMatch(); 52 | double areaTri(int i, int j); 53 | double computeArea(); 54 | }; 55 | 56 | #endif //_ETSP_H_ 57 | -------------------------------------------------------------------------------- /FMM.cpp: -------------------------------------------------------------------------------- 1 | #include "ScatteredData.h" 2 | #include "RBF.h" 3 | #include "SparseMatrix.h" 4 | #include "vec3.h" 5 | #include "LinearSolver.h" 6 | #include "FMM.h" 7 | 8 | #include 9 | #include 10 | 11 | // STL Includes 12 | #include 13 | using std::vector; 14 | 15 | FMM::FMM() 16 | { 17 | theta=0.75; 18 | } 19 | 20 | FMM::~FMM() 21 | { 22 | freeTheTree(tree); 23 | } 24 | 25 | void FMM::freeTheTree(BHNode *myNode) 26 | { 27 | if ( myNode == nullptr ) 28 | return; 29 | 30 | // TODO: magic number 31 | for(int i = 0; i < 8; i++) 32 | freeTheTree(myNode->nodes[i]); 33 | } 34 | 35 | void FMM::setTheta(double myTheta) 36 | { 37 | theta = myTheta; 38 | } 39 | -------------------------------------------------------------------------------- /FMM.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef _FMM_H_ 28 | #define _FMM_H_ 29 | 30 | #include "ScatteredData.h" 31 | #include "SparseMatrix.h" 32 | #include "vec3.h" 33 | #include "BHNode.h" 34 | 35 | // STL Includes 36 | #include 37 | 38 | class FMM 39 | { 40 | public: 41 | FMM(); 42 | ~FMM(); 43 | 44 | //variables 45 | BHNode *tree; 46 | double theta; 47 | int numOfNodes; 48 | 49 | std::vector nodePointer; 50 | 51 | //functions to set the variable 52 | void setTheta(double myTheta); 53 | 54 | 55 | 56 | void freeTheTree(BHNode *myNode); 57 | }; 58 | 59 | #endif //_FMM_H_ 60 | 61 | -------------------------------------------------------------------------------- /ImplicitFunctionConfig.cmake.in: -------------------------------------------------------------------------------- 1 | 2 | set(ImplicitFunction_INCLUDE "@ImplicitFunction_INCLUDE@") 3 | set(ImplicitFunction_LIBRARY "@ImplicitFunction_LIB_NAME@") 4 | set(ImplicitFunction_LIBRARY_DIR "@ImplicitFunction_LIBRARY_DIR@") 5 | 6 | set(ImplicitFunction_USE_FILE "@ImplicitFunction_USE_FILE@") 7 | -------------------------------------------------------------------------------- /LinearSolver.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include "SparseMatrix.h" 28 | #include "LinearSolver.h" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | using std::vector; 37 | 38 | LinearSolver::LinearSolver() : 39 | residualNorm_( std::numeric_limits::max() ) 40 | { 41 | } 42 | 43 | LinearSolver::LinearSolver(SparseMatrix *myMat) 44 | { 45 | this->A_ = myMat; 46 | } 47 | 48 | void LinearSolver::setMatrix(SparseMatrix *myMat) 49 | { 50 | this->A_ = myMat; 51 | } 52 | 53 | vector LinearSolver::biCGStab(vector &b) 54 | { 55 | vector x; 56 | biCGStab(b,x); 57 | return x; 58 | } 59 | 60 | void LinearSolver::biCGStab(vector &b, vector &x) 61 | { 62 | int i, iter = 0; 63 | const size_t n = b.size(); 64 | vector r, rhat, v, p, t, s, diag, y, z, pret, pres; 65 | double rho, rhoold, alpha, omega, omegaold, beta; 66 | 67 | this->residualNorm_ = std::numeric_limits::max(); 68 | 69 | x.resize(n); 70 | r.resize(n); 71 | rhat.resize(n); 72 | v.resize(n); 73 | p.resize(n); 74 | t.resize(n); 75 | s.resize(n); 76 | diag.resize(n); 77 | y.resize(n); 78 | z.resize(n); 79 | pret.resize(n); 80 | pres.resize(n); 81 | 82 | for (i = 0; i < n; i++) 83 | { 84 | x[i] = v[i] = p[i] = 0; 85 | r[i] = rhat[i] = b[i]; 86 | diag[i] = 1.0; //this->A_.val[i][this->A_.length[i]-1]; 87 | } 88 | rho = rhoold = alpha = omega = omegaold=1; 89 | 90 | if (norm(r) < n*1e-10) 91 | return; 92 | 93 | #ifndef NDEBUG 94 | printf("norm(r)=%lf\n", norm(r)); fflush(stdout); 95 | #endif 96 | 97 | while (iter < 10*n) 98 | { 99 | #ifndef NDEBUG 100 | std::cout << "iter: " << iter << " norm(r)= " << norm(r) << std::endl; 101 | printf("Iteration %d: Residual norm = %lf\n", iter, norm(r)); fflush(stdout); 102 | #endif 103 | 104 | iter++; 105 | rho = norm(rhat, r); 106 | 107 | #ifndef NDEBUG 108 | printf("rho: %lf\n", rho); 109 | #endif 110 | 111 | if (1 == iter) 112 | { 113 | for (i = 0; i < n; i++) 114 | { 115 | p[i] = r[i]; 116 | //printf("p[%d]=%lf\n", i, p[i]); 117 | } 118 | } 119 | else 120 | { 121 | beta = (rho/rhoold)*(alpha/omegaold); 122 | //printf("beta: %lf\n", beta); 123 | for (i = 0; i < n; i++) 124 | { 125 | p[i] = r[i] + beta * (p[i] - omegaold*v[i]); 126 | //printf("p[%d]=%lf\n", i, p[i]); 127 | } 128 | } 129 | for (i = 0; i < n; i++) 130 | y[i] = diag[i]*p[i]; 131 | 132 | SpMV(y,v); 133 | alpha = rho/norm(rhat,v); 134 | //printf("alpha: %lf\n", alpha); 135 | for (i = 0; i < n; i++) 136 | { 137 | s[i] = r[i] - alpha*v[i]; 138 | //printf("s[%d]=%lf\n", i, s[i]); 139 | } 140 | 141 | for (i = 0; i < n; i++) 142 | z[i] = diag[i]*s[i]; 143 | SpMV(z,t); 144 | 145 | for (i = 0; i < n; i++) 146 | pret[i] = diag[i]*t[i]; 147 | 148 | for (i = 0; i < n; i++) 149 | pres[i] = diag[i]*s[i]; 150 | 151 | omega = norm(pret,pres)/norm(pret,pret); 152 | //printf("omega: %lf\n", omega); 153 | for (i = 0; i < n; i++) 154 | x[i] += alpha*p[i]+omega*s[i]; 155 | 156 | for (i = 0; i < n; i++) 157 | r[i] = s[i] - omega*t[i]; 158 | 159 | if (norm(r) < n*1e-15) 160 | break; 161 | 162 | rhoold=rho; omegaold=omega; 163 | } 164 | 165 | this->residualNorm_ = norm(r); 166 | 167 | #ifndef NDEBUG 168 | printf("Iteration: %d: Residual norm = %lf\n", iter, this->residualNorm_); fflush(stdout); 169 | //SpMV(x,v); 170 | for (i = 0; i < n; i++) 171 | { 172 | printf("x[%d] = %.10f r[%d]=%.10lf\n", i, x[i],i,v[i]-b[i]); 173 | } 174 | #endif 175 | } 176 | 177 | // TODO: bother with range check here? 178 | 179 | double LinearSolver::norm(vector &a) 180 | { 181 | const size_t N = a.size(); 182 | double ret = 0; 183 | for (size_t i = 0; i < N; i++) 184 | ret += a[i]*a[i]; 185 | 186 | return sqrt(ret); 187 | } 188 | 189 | double LinearSolver::norm(vector &a, vector &b) 190 | { 191 | const size_t N = a.size(); 192 | double ret = 0; 193 | for (size_t i = 0; i < N; i++) 194 | ret += a[i]*b[i]; 195 | 196 | return ret; 197 | } 198 | 199 | void LinearSolver::SpMV(vector &a, vector &b) 200 | { 201 | this->A_->multiply(a,b); 202 | } 203 | -------------------------------------------------------------------------------- /LinearSolver.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef _LINEARSOLVER_H_ 28 | #define _LINEARSOLVER_H_ 29 | 30 | // STL Includes 31 | #include 32 | #include "SparseMatrix.h" 33 | 34 | class LinearSolver 35 | { 36 | public: 37 | LinearSolver(); 38 | LinearSolver(SparseMatrix *myMat); 39 | void setMatrix(SparseMatrix *myMat); 40 | 41 | //Sparse Linear Solvers 42 | std::vector biCGStab(std::vector &b); 43 | void biCGStab(std::vector &b, std::vector &x); 44 | const double residualNorm() const { return this->residualNorm_; } 45 | 46 | private: 47 | SparseMatrix *A_; 48 | double residualNorm_; 49 | 50 | double norm(std::vector &a); 51 | double norm(std::vector &a, std::vector &b); 52 | void SpMV(std::vector &a, std::vector &b); 53 | }; 54 | 55 | #endif //_LINEARSOLVER_H_ 56 | 57 | -------------------------------------------------------------------------------- /RBF.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include "RBF.h" 28 | #include "ScatteredData.h" 29 | #include "vec3.h" 30 | #include "FMM.h" 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | // STL Includes 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | using std::vector; 46 | using std::pair; 47 | 48 | const double RBF::EPSILON = 1.0e-2; 49 | 50 | 51 | RBF::RBF(const ScatteredData *myData, Kernel myKernel) : 52 | completeData_(myData), 53 | kernel_(myKernel), 54 | acceleration_(None), 55 | dataReduction_(All) 56 | { 57 | } 58 | 59 | void RBF::setAcceleration(Acceleration myAcceleration) 60 | { 61 | this->acceleration_ = myAcceleration; 62 | switch(this->acceleration_) 63 | { 64 | case FastMultipole: 65 | fmm_.reset(new FMM); 66 | break; 67 | default: 68 | break; 69 | } 70 | } 71 | 72 | void RBF::setDataReduction(DataReduction myDataReduction) 73 | { 74 | this->dataReduction_ = myDataReduction; 75 | } 76 | 77 | void RBF::computeFunction() 78 | { 79 | data_ = ScatteredData(); 80 | switch(this->dataReduction_) 81 | { 82 | case All: 83 | data_.setData(this->completeData_->surfacePoints_[0], 84 | this->completeData_->surfacePoints_[1], 85 | this->completeData_->surfacePoints_[2], 86 | this->completeData_->fnc_); 87 | computeFunctionForData(); 88 | break; 89 | 90 | case Random: 91 | const int N = this->completeData_->fnc_.size(); 92 | std::vector added(N); 93 | printf("%d\n", N); 94 | 95 | for (int i = 0; i < N; i++) 96 | added[i] = false; 97 | 98 | // TODO: magic number 99 | for (int i = 0; i < 25; i++) 100 | { 101 | int j = rand() % N; 102 | if( added[j] ) 103 | { 104 | i--; 105 | continue; 106 | } 107 | added[j] = true; 108 | this->data_.surfacePoints_[0].push_back(this->completeData_->surfacePoints_[0][j]); 109 | this->data_.surfacePoints_[1].push_back(this->completeData_->surfacePoints_[1][j]); 110 | this->data_.surfacePoints_[2].push_back(this->completeData_->surfacePoints_[2][j]); 111 | this->data_.fnc_.push_back(this->completeData_->fnc_[j]); 112 | } 113 | 114 | vector > error; 115 | bool smallError = false; 116 | while (! smallError) 117 | { 118 | computeFunctionForData(); 119 | computeErrorForData(error); 120 | std::sort(error.begin(), error.end()); 121 | std::reverse(error.begin(), error.end()); 122 | 123 | printf("Largest error: %lf\n", error[0].first); 124 | if (error[0].first < EPSILON) 125 | { 126 | smallError = true; 127 | continue; 128 | } 129 | for (int k = 0; k < 5; k++) 130 | { 131 | if (error[k].first > EPSILON || error[k].first != error[k].first) 132 | { 133 | int j = error[k].second; 134 | added[j] = true; 135 | this->data_.surfacePoints_[0].push_back(this->completeData_->surfacePoints_[0][j]); 136 | this->data_.surfacePoints_[1].push_back(this->completeData_->surfacePoints_[1][j]); 137 | this->data_.surfacePoints_[2].push_back(this->completeData_->surfacePoints_[2][j]); 138 | this->data_.fnc_.push_back(this->completeData_->fnc_[j]); 139 | } 140 | } 141 | } 142 | break; 143 | } 144 | data_.updateSurfacePointsList(); 145 | } 146 | 147 | void RBF::computeFunctionForData() 148 | { 149 | switch(this->acceleration_) 150 | { 151 | case FastMultipole: 152 | fmmBuildTree(); 153 | break; 154 | case None: 155 | default: 156 | // TODO: move to function 157 | const int N = static_cast( this->data_.fnc_.size() ); 158 | 159 | //std::copy(this->data_.fnc_.begin(), this->data_.fnc_.end(), std::ostream_iterator(std::cout, " ")); 160 | 161 | #ifndef NDEBUG 162 | printf("Solving linear equations: \n"); fflush(stdout); 163 | #endif 164 | 165 | Eigen::VectorXd b = Eigen::VectorXd::Map(&this->data_.fnc_[0], N); 166 | Eigen::VectorXd x(N); 167 | Eigen::MatrixXd A(N, N); 168 | for (int i = 0; i < N; i++) 169 | { 170 | for (int j = 0; j < N; j++) 171 | { 172 | double val = computeKernel(i, j); 173 | A(i, j) = val; 174 | } 175 | } 176 | Eigen::BiCGSTAB< Eigen::MatrixXd > solver; 177 | solver.setTolerance(1.0e-10); 178 | solver.setMaxIterations(5000); 179 | solver.compute(A); 180 | x = solver.solve(b); 181 | 182 | // TODO: error reporting? 183 | // TODO: log this...or pass to caller (i.e. Seg3D) 184 | std::cout << "#iterations: " << solver.iterations() << std::endl; 185 | std::cout << "estimated error: " << solver.error() << std::endl; 186 | 187 | this->coeff_.resize(x.size()); 188 | Eigen::VectorXd::Map(&this->coeff_[0], x.size()) = x; 189 | printf("Done\n"); 190 | //std::cout << "coeff_ size: " << coeff_.size() << std::endl; 191 | kernelBufferSize_ = coeff_.size(); 192 | coeffPtr_ = &coeff_[0]; 193 | //std::copy(coeff_.begin(), coeff_.end(), std::ostream_iterator(std::cout, " ")); 194 | fflush(stdout); 195 | 196 | break; 197 | } 198 | } 199 | 200 | double RBF::computeValue(const vec3& x) const 201 | { 202 | switch(this->acceleration_) 203 | { 204 | case FastMultipole: 205 | return fmmComputeValue(x); 206 | case None: 207 | default: 208 | return computeSumOfAllKernels(x); 209 | } 210 | } 211 | 212 | void RBF::computeErrorForData(vector > &error) 213 | { 214 | const int N = this->completeData_->fnc_.size(); 215 | error.clear(); 216 | for (int i = 0; i < N; i++) 217 | { 218 | vec3 x(this->completeData_->surfacePoints_[0][i], 219 | this->completeData_->surfacePoints_[1][i], 220 | this->completeData_->surfacePoints_[2][i]); 221 | double err = this->completeData_->fnc_[i]-computeValue(x); 222 | error.push_back( std::make_pair(err, i) ); 223 | } 224 | } 225 | 226 | double RBF::computeKernel(int i, int j) const 227 | { 228 | double r2 = (this->data_.surfacePoints_[0][i] - this->data_.surfacePoints_[0][j]) * 229 | (this->data_.surfacePoints_[0][i] - this->data_.surfacePoints_[0][j]) + // x 230 | (this->data_.surfacePoints_[1][i] - this->data_.surfacePoints_[1][j]) * 231 | (this->data_.surfacePoints_[1][i] - this->data_.surfacePoints_[1][j]) + // y 232 | (this->data_.surfacePoints_[2][i] - this->data_.surfacePoints_[2][j]) * 233 | (this->data_.surfacePoints_[2][i] - this->data_.surfacePoints_[2][j]); // z 234 | 235 | return computeRadialFunctionOnSquaredDistance(r2); 236 | } 237 | 238 | double RBF::computeKernel(int i, const vec3& b) const 239 | { 240 | return computeRadialFunctionOnSquaredDistance(data_.squaredDistanceFrom(i, b)); 241 | } 242 | 243 | double RBF::computeSumOfAllKernels(const vec3& b) const 244 | { 245 | const auto bPtr = b.getPtr(); 246 | const auto fromX = bPtr[0]; 247 | const auto fromY = bPtr[1]; 248 | const auto fromZ = bPtr[2]; 249 | 250 | double sum = 0; 251 | 252 | for (size_t i = 0; i < kernelBufferSize_; ++i) 253 | { 254 | const auto baseIndex = 3*i; 255 | 256 | const auto xDiff = data_.surfacePointsFlattenedPtr_[baseIndex] - fromX; 257 | const auto yDiff = data_.surfacePointsFlattenedPtr_[baseIndex + 1] - fromY; 258 | const auto zDiff = data_.surfacePointsFlattenedPtr_[baseIndex + 2] - fromZ; 259 | 260 | sum += coeffPtr_[i] * computeRadialFunctionOnSquaredDistance(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff); 261 | } 262 | return sum; 263 | } 264 | 265 | double RBF::computeRadialFunctionOnSquaredDistance(double r2) const 266 | { 267 | //TODO: optimize this function 268 | static constexpr double C = 0.1; 269 | static constexpr double C2 = C*C; 270 | 271 | static constexpr double SCALE = 0.01; 272 | static constexpr double SCALE2 = SCALE*SCALE; 273 | 274 | switch(kernel_) 275 | { 276 | case Gaussian: 277 | return 1.0/sqrt(r2 * SCALE2 + C2); 278 | case ThinPlate: 279 | return r2 * log(sqrt(r2) + C); 280 | case MultiQuadratic: 281 | return sqrt(r2 + C2); 282 | default: 283 | return sqrt(r2); 284 | } 285 | return 0; 286 | } 287 | 288 | //FMM Codes 289 | 290 | void RBF::fmmBuildTree() 291 | { 292 | vector myIndices; 293 | const int N = this->data_.surfacePoints_[0].size(); 294 | 295 | for (int i = 0; i < N; i++) 296 | myIndices.push_back(i); 297 | 298 | fmm_->tree = new BHNode(); 299 | fmm_->tree->box_.min_ = vec3::zero; 300 | 301 | vec3 corner(100, 100, 100); 302 | fmm_->tree->box_.max_ = corner; 303 | fmmBuildTree(myIndices, fmm_->tree); 304 | //printf("Tree Built\n"); 305 | //fmmPrintTree(fmm_->tree, 0); 306 | } 307 | 308 | void RBF::fmmPrintTree(BHNode *myNode, int stack) 309 | { 310 | if (stack > 4) 311 | return; 312 | 313 | for (int j = 0; j < stack; j++) 314 | { 315 | printf(" "); 316 | } 317 | 318 | //printf("%d %d %d\n", myNode, myNode->index_, myNode->pts_.size()); 319 | 320 | for (int i = 0; i < 8; i++) 321 | { 322 | if (myNode->nodes[i] != nullptr) 323 | fmmPrintTree(myNode->nodes[i], stack+1); 324 | } 325 | } 326 | 327 | void RBF::fmmBuildTree(vector &myPoints, BHNode *myNode) 328 | { 329 | const double SMALL_EPSILON = 1.0e-6; 330 | //printf("[%lf %lf %lf] [%lf %lf %lf] %d\n", myNode->box_.min_[0], myNode->box_.min_[1], myNode->box_.min_[2], myNode->box_.max_[0], myNode->box_.max_[1], myNode->box_.max_[2], myPoints.size()); 331 | vector children[8]; 332 | const int N = myPoints.size(); 333 | 334 | myNode->index_ = fmm_->numOfNodes; 335 | fmm_->numOfNodes += 1; 336 | fmm_->nodePointer.push_back(myNode); 337 | 338 | myNode->mass_ = N; 339 | myNode->leaf_ = (N <= 1) ? true : false; 340 | myNode->center_ = vec3::zero; 341 | 342 | myNode->coeff_ = 1; //REPLACE 343 | //add all the coefficients 344 | 345 | for (int i = 0; i < N; i++) 346 | myNode->pts_.push_back( myPoints[i] ); 347 | 348 | for (int i = 0; i < N; i++) 349 | { 350 | vec3 location(this->data_.surfacePoints_[0][myPoints[i]], this->data_.surfacePoints_[1][myPoints[i]], this->data_.surfacePoints_[2][myPoints[i]]); 351 | myNode->center_ = myNode->center_ + (location/N); 352 | } 353 | 354 | if (N == 1) 355 | { 356 | for (int i = 0; i < 8; i++) 357 | myNode->nodes[i] = nullptr; 358 | 359 | return; 360 | } 361 | 362 | if (length(myNode->box_.max_ - myNode->box_.min_) < SMALL_EPSILON) 363 | { 364 | for (int i = 0; i < 8; i++) 365 | myNode->nodes[i] = nullptr; 366 | 367 | return; 368 | } 369 | 370 | vec3 mid( (myNode->box_.getMin() + myNode->box_.getMax())/2 ); 371 | for (int i = 0; i < N; i++) 372 | { 373 | int octant = 0; 374 | //FIND OCTANTS 375 | if (this->data_.surfacePoints_[0][myPoints[i]] > mid[0]) 376 | octant += 1; 377 | if (this->data_.surfacePoints_[1][myPoints[i]] > mid[1]) 378 | octant += 2; 379 | if (this->data_.surfacePoints_[2][myPoints[i]] > mid[2]) 380 | octant += 4; 381 | 382 | //printf("%d %d %d %lf %lf %lf\n", i,octant, myPoints[i], this->data_.surfacePoints_[0][myPoints[i]],this->data_.surfacePoints_[1][myPoints[i]], this->data_.surfacePoints_[2][myPoints[i]]); 383 | 384 | children[octant].push_back(myPoints[i]); 385 | } 386 | 387 | for (int i = 0; i < 8; i++) 388 | { 389 | if (children[i].size() == 0) 390 | { 391 | myNode->nodes[i] = nullptr; 392 | continue; 393 | } 394 | 395 | myNode->nodes[i] = new BHNode(); 396 | 397 | int hash = i; 398 | for (int j = 0; j < 3; j++) 399 | { 400 | if (hash % 2 == 0) 401 | { 402 | myNode->nodes[i]->box_.min_[j] = myNode->box_.min_[j]; 403 | myNode->nodes[i]->box_.max_[j] = mid[j]; 404 | } 405 | else 406 | { 407 | myNode->nodes[i]->box_.min_[j] = mid[j]; 408 | myNode->nodes[i]->box_.max_[j] = myNode->box_.max_[j]; 409 | } 410 | hash /= 2; 411 | } 412 | 413 | fmmBuildTree(children[i], myNode->nodes[i]); 414 | } 415 | } 416 | 417 | double RBF::fmmComputeValue(const vec3& x) const 418 | { 419 | double val = fmmComputeValueRecurse(x, fmm_->tree); 420 | return val; 421 | } 422 | 423 | 424 | double RBF::fmmComputeValueRecurse(const vec3& x, BHNode *myNode) const 425 | { 426 | double val = 0; 427 | 428 | // TODO: div by zero? 429 | if (length(myNode->center_ - x)/length(myNode->box_.min_ - myNode->box_.max_) < 0) //far away 430 | { 431 | val = myNode->coeff_ * fmmComputeKernel(x, myNode); 432 | } 433 | else if (! myNode->leaf_) // leaf 434 | { 435 | for (int i = 0; i < 8; i++) 436 | { 437 | if (myNode->nodes[i] != nullptr) 438 | { 439 | val += fmmComputeValueRecurse(x, myNode->nodes[i]); 440 | } 441 | } 442 | } 443 | else //close, but not a leaf 444 | { 445 | const int N = myNode->pts_.size(); 446 | for (int i = 0; i < N; i++) 447 | { 448 | val += this->coeff_[myNode->pts_[i]] * computeKernel(myNode->pts_[i], x); 449 | } 450 | } 451 | return val; 452 | } 453 | 454 | double RBF::fmmComputeKernel(const vec3& b, BHNode *myNode) const 455 | { 456 | double r = length(myNode->center_ - b); 457 | 458 | return computeRadialFunctionOnSquaredDistance(r*r); 459 | } 460 | -------------------------------------------------------------------------------- /RBF.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef _RBF_H_ 28 | #define _RBF_H_ 29 | 30 | #include "ScatteredData.h" 31 | #include "SparseMatrix.h" 32 | #include "vec3.h" 33 | #include "FMM.h" 34 | 35 | // STL Includes 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | enum Kernel { Gaussian, ThinPlate, MultiQuadratic }; 43 | enum Acceleration { None, FastMultipole }; 44 | enum DataReduction { All, Random }; 45 | 46 | class RBF 47 | { 48 | public: 49 | RBF(const ScatteredData *myData, Kernel myKernel); 50 | 51 | void setAcceleration(Acceleration myAcceleration); 52 | void setDataReduction(DataReduction myDataReduction); 53 | 54 | void computeFunction(); 55 | double computeValue(const vec3& x) const; 56 | 57 | private: 58 | const ScatteredData* completeData_; 59 | ScatteredData data_; 60 | Kernel kernel_; 61 | std::vector coeff_; 62 | Acceleration acceleration_; 63 | DataReduction dataReduction_; 64 | 65 | std::unique_ptr fmm_; 66 | 67 | void computeFunctionForData(); // throws std::runtime_error 68 | void computeErrorForData(std::vector > &error); 69 | 70 | double computeKernel(int i, int j) const; 71 | double computeKernel(int i, const vec3& b) const; 72 | double computeRadialFunctionOnSquaredDistance(double r2) const; 73 | double computeSumOfAllKernels(const vec3& b) const; 74 | 75 | mutable double* coeffPtr_; 76 | mutable size_t kernelBufferSize_; 77 | 78 | void fmmBuildTree(); 79 | void fmmPrintTree(BHNode* myNode, int stack); 80 | void fmmBuildTree(std::vector &myPoints, BHNode *myNode); 81 | double fmmComputeValue(const vec3& x) const; 82 | double fmmComputeValueRecurse(const vec3& x, BHNode *myNode) const; 83 | double fmmComputeKernel(const vec3& b, BHNode *myNode) const; 84 | 85 | static const double EPSILON; 86 | }; 87 | 88 | #endif //_RBF_H_ 89 | -------------------------------------------------------------------------------- /RBFInterface.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include "RBFInterface.h" 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | const double RBFInterface::SMALL_EPSILON = 1.0e-6; 39 | 40 | RBFInterface::RBFInterface(std::vector myData, 41 | const vec3& myOrigin, const vec3& mySize, const vec3& mySpacing, 42 | const double myOffset, AxisList myAxis, 43 | const bool compute2DConvexHull, 44 | const bool invertSeedOrder, Kernel kernel) : 45 | thresholdValue_(0), 46 | origin_(myOrigin), 47 | size_(mySize), 48 | spacing_(mySpacing), 49 | offset_(myOffset), 50 | axisList_(myAxis), 51 | compute2DConvexHull_(compute2DConvexHull), 52 | invertSeedOrder_(invertSeedOrder), 53 | kernel_(kernel) 54 | { 55 | if ( this->invertSeedOrder_ ) 56 | { 57 | // inplace 58 | std::reverse( myData.begin(), myData.end() ); 59 | } 60 | 61 | for (int i = 0; i < myData.size(); i++) 62 | { 63 | // TODO: would be better to skip this step... 64 | // Input point components: 65 | this->points_x_.push_back(myData[i][0]); // X component 66 | this->points_y_.push_back(myData[i][1]); // Y component 67 | this->points_z_.push_back(myData[i][2]); // Z component 68 | this->threshold_.push_back(this->thresholdValue_); 69 | } 70 | 71 | // TODO: error reporting??? 72 | // TODO: would it be better to break this out, or have constructor throw exception??? 73 | if ( ! this->compute2DConvexHull_ ) 74 | { 75 | create3DSurface(); 76 | } 77 | else 78 | { 79 | create2DSurface(); 80 | } 81 | } 82 | 83 | void RBFInterface::create3DSurface() 84 | { 85 | // TODO: debug print 86 | std::cerr << "Calling Tetgen..." << std::endl; 87 | tetgenio in, out; 88 | in.numberofpoints = static_cast( this->points_x_.size() ); 89 | in.pointlist = new REAL[in.numberofpoints * 3]; 90 | for ( size_t i = 0; i < in.numberofpoints; ++i ) 91 | { 92 | in.pointlist[i*3] = this->points_x_[i]; 93 | in.pointlist[i*3+1] = this->points_y_[i]; 94 | in.pointlist[i*3+2] = this->points_z_[i]; 95 | } 96 | 97 | try 98 | { 99 | std::string args("BE"); 100 | tetrahedralize(const_cast< char* >( args.c_str() ), &in, &out); 101 | } 102 | catch (std::exception& e) 103 | { 104 | std::cerr << "TetGen failed to generate a mesh: " << e.what() << std::endl; 105 | throw; 106 | } 107 | catch (...) 108 | { 109 | std::cerr << "TetGen failed to generate a mesh" << std::endl; 110 | throw; 111 | } 112 | 113 | const size_t NUMBER_POINTS = out.numberofpoints; 114 | const size_t NUMBER_TRI_FACES = out.numberoftrifaces; 115 | const size_t NUMBER_TRI_POINTS = 3; 116 | 117 | #ifndef NDEBUG 118 | #ifdef VERBOSE 119 | // trifaces == convex hull 120 | std::cerr << "# tri faces=" << NUMBER_TRI_FACES << std::endl; 121 | for (size_t i = 0; i < out.numberoftrifaces; ++i) 122 | { 123 | std::cerr << "trifacelist " << i << ": " << out.trifacelist[i*NUMBER_TRI_POINTS] << " " 124 | << out.trifacelist[i*NUMBER_TRI_POINTS+1] << " " 125 | << out.trifacelist[i*NUMBER_TRI_POINTS+2] << std::endl; 126 | } 127 | 128 | std::cerr << "# points=" << NUMBER_POINTS << std::endl; 129 | for (size_t i = 0; i < NUMBER_POINTS; ++i) 130 | { 131 | std::cerr << "pointlist " << i << ": " << out.pointlist[i*NUMBER_TRI_POINTS] << " " 132 | << out.pointlist[i*NUMBER_TRI_POINTS+1] << " " 133 | << out.pointlist[i*NUMBER_TRI_POINTS+2] << std::endl; 134 | } 135 | #endif 136 | #endif 137 | 138 | std::vector listOfIntsPerVertex(NUMBER_POINTS); 139 | for (size_t i = 0; i < NUMBER_TRI_FACES; ++i) 140 | { 141 | for (size_t j = 0; j < NUMBER_TRI_POINTS; ++j) 142 | { 143 | size_t index = out.trifacelist[i*NUMBER_TRI_POINTS+j]; 144 | listOfIntsPerVertex[index].push_back(i); 145 | } 146 | } 147 | 148 | #ifndef NDEBUG 149 | #ifdef VERBOSE 150 | for (int i = 0; i < NUMBER_POINTS; ++i) 151 | { 152 | std::cerr << i << ": "; 153 | for (int j = 0; j < listOfIntsPerVertex[i].size(); ++j) 154 | { 155 | std::cerr << listOfIntsPerVertex[i][j] << " "; 156 | } 157 | std::cerr << std::endl; 158 | } 159 | #endif 160 | #endif 161 | 162 | // normal calculation on face 163 | // For triangle p1, p2, p3 and vectors U = p2 - p1, V = p3 - p1, then normal N = UxV: 164 | // Nx = UyVz - UzVy 165 | // Ny = UzVx - UxVz 166 | // Nz = UxVy - UyVx 167 | 168 | std::vector normalsPerFace(NUMBER_TRI_FACES); 169 | for (size_t i = 0; i < NUMBER_TRI_FACES; ++i) 170 | { 171 | const size_t i1 = out.trifacelist[i*3]; 172 | const size_t i2 = out.trifacelist[i*3+1]; 173 | const size_t i3 = out.trifacelist[i*3+2]; 174 | 175 | vec3 p1( out.pointlist[i1*NUMBER_TRI_POINTS], out.pointlist[i1*NUMBER_TRI_POINTS+1], out.pointlist[i1*NUMBER_TRI_POINTS+2] ); 176 | vec3 p2( out.pointlist[i2*NUMBER_TRI_POINTS], out.pointlist[i2*NUMBER_TRI_POINTS+1], out.pointlist[i2*NUMBER_TRI_POINTS+2] ); 177 | vec3 p3( out.pointlist[i3*NUMBER_TRI_POINTS], out.pointlist[i3*NUMBER_TRI_POINTS+1], out.pointlist[i3*NUMBER_TRI_POINTS+2] ); 178 | 179 | vec3 u = p2 - p1; 180 | vec3 v = p3 - p1; 181 | 182 | vec3 n( 183 | ( u.y() * v.z() ) - ( u.z() * v.y() ), 184 | ( u.z() * v.x() ) - ( u.x() * v.z() ), 185 | ( u.x() * v.y() ) - ( u.y() * v.x() ) 186 | ); 187 | normalsPerFace[i] = normalize(n, SMALL_EPSILON); 188 | #ifdef VERBOSE 189 | std::cerr << "normalsPerFace[" << i << "]=" << normalsPerFace[i] << ", len=" << length(normalsPerFace[i]) << std::endl; 190 | #endif 191 | } 192 | 193 | // TODO: initialize in constructor? 194 | this->surfaceData_.reset(new ScatteredData(this->points_x_, this->points_y_, this->points_z_, this->threshold_, this->axisList_)); 195 | 196 | // TODO: this code mirrors the 2D convex hull method...refactor? 197 | // TODO: difficult to keep the ScatteredData point and function vectors in sync... 198 | 199 | this->surfaceData_->surfacePoints_[0].clear(); 200 | this->surfaceData_->surfacePoints_[1].clear(); 201 | this->surfaceData_->surfacePoints_[2].clear(); 202 | 203 | this->surfaceData_->leftovers_[0].clear(); 204 | this->surfaceData_->leftovers_[1].clear(); 205 | this->surfaceData_->leftovers_[2].clear(); 206 | 207 | this->surfaceData_->fnc_.clear(); 208 | 209 | // convex hull... 210 | 211 | for (size_t i = 0; i < NUMBER_POINTS; ++i) 212 | { 213 | // indices of points not in convex hull 214 | if ( listOfIntsPerVertex[i].size() == 0 ) 215 | { 216 | #ifdef VERBOSE 217 | std::cerr << "Point " << i << " in leftovers." << std::endl; 218 | #endif 219 | this->surfaceData_->leftovers_[0].push_back( out.pointlist[i*NUMBER_TRI_POINTS] ); 220 | this->surfaceData_->leftovers_[1].push_back( out.pointlist[i*NUMBER_TRI_POINTS+1] ); 221 | this->surfaceData_->leftovers_[2].push_back( out.pointlist[i*NUMBER_TRI_POINTS+2] ); 222 | } 223 | } 224 | 225 | const size_t M = this->surfaceData_->leftovers_[0].size(); 226 | 227 | std::vector< vec3 > normalsPerVertex; 228 | for (size_t i = 0; i < NUMBER_POINTS; ++i) 229 | { 230 | if ( listOfIntsPerVertex[i].size() == 0 ) continue; 231 | 232 | #ifdef VERBOSE 233 | std::cerr << "Point " << i << " in surface points." << std::endl; 234 | #endif 235 | this->surfaceData_->surfacePoints_[0].push_back( out.pointlist[i*NUMBER_TRI_POINTS] ); 236 | this->surfaceData_->surfacePoints_[1].push_back( out.pointlist[i*NUMBER_TRI_POINTS+1] ); 237 | this->surfaceData_->surfacePoints_[2].push_back( out.pointlist[i*NUMBER_TRI_POINTS+2] ); 238 | this->surfaceData_->fnc_.push_back( this->thresholdValue_ ); 239 | 240 | vec3 tmpVec; 241 | for (size_t j = 0; j < listOfIntsPerVertex[i].size(); ++j) 242 | { 243 | tmpVec += normalsPerFace[ listOfIntsPerVertex[i][j] ]; 244 | } 245 | 246 | normalsPerVertex.push_back( normalize(tmpVec, SMALL_EPSILON) ); 247 | } 248 | 249 | this->surfaceData_->origSize_ = this->surfaceData_->surfacePoints_[0].size(); 250 | 251 | #ifdef VERBOSE 252 | std::cerr << "#points=" << this->surfaceData_->surfacePoints_[0].size() << ", " 253 | << "#leftovers=" << this->surfaceData_->leftovers_[0].size() << std::endl; 254 | 255 | for (int i = 0; i < normalsPerVertex.size(); ++i) 256 | { 257 | std::cerr << "normalsPerVertex[" << i << "]=" << normalsPerVertex[i] << ", len=" << length(normalsPerVertex[i]) << std::endl; 258 | } 259 | #endif 260 | 261 | // iterate through list of points not on hull, add to list as zero points 262 | for (size_t i = 0; i < M; ++i) 263 | { 264 | this->surfaceData_->surfacePoints_[0].push_back(this->surfaceData_->leftovers_[0][i]); 265 | this->surfaceData_->surfacePoints_[1].push_back(this->surfaceData_->leftovers_[1][i]); 266 | this->surfaceData_->surfacePoints_[2].push_back(this->surfaceData_->leftovers_[2][i]); 267 | } 268 | this->surfaceData_->fnc_.insert(this->surfaceData_->fnc_.end(), M, this->thresholdValue_); 269 | 270 | const size_t N = this->surfaceData_->origSize_; 271 | const size_t DIM_3D = 3; 272 | const int NORMAL_IN = 10, NORMAL_OUT = -10; 273 | 274 | for (size_t i = 0; i < N; i++) 275 | { 276 | for (size_t j = 0; j < DIM_3D; j++) 277 | { 278 | // TODO: check endpoint of normal from this->surfaceData_->surfacePoints_[j][i] + this->offset_ * normalsPerVertex[i][j] for inside c hull 279 | // generated printed warning 280 | this->surfaceData_->surfacePoints_[j].push_back(this->surfaceData_->surfacePoints_[j][i] + this->offset_ * normalsPerVertex[i][j]); 281 | } 282 | 283 | // check endpoint of normal from this->surfaceData_->surfacePoints_[j][i] + this->offset_ * normalsPerVertex[i][j] for inside c hull 284 | // printed warning, member variable for testing... 285 | 286 | // normals point inward 287 | this->surfaceData_->fnc_.push_back(NORMAL_IN); 288 | 289 | for (int j = 0; j < DIM_3D; j++) 290 | { 291 | this->surfaceData_->surfacePoints_[j].push_back(this->surfaceData_->surfacePoints_[j][i] - this->offset_ * normalsPerVertex[i][j]); 292 | } 293 | 294 | // normals pointing outward 295 | this->surfaceData_->fnc_.push_back(NORMAL_OUT); 296 | } 297 | 298 | createRasterizedSurface(); 299 | } 300 | 301 | // driver 302 | void RBFInterface::create2DSurface() 303 | { 304 | // TODO: initialize in constructor? 305 | this->surfaceData_.reset(new ScatteredData(this->points_x_, this->points_y_, this->points_z_, this->threshold_, this->axisList_)); 306 | this->surfaceData_->compute2DHull(); 307 | // TODO: this is bad - ScatteredData should set this to maintain correct internal state!!! 308 | this->surfaceData_->origSize_ = this->surfaceData_->surfacePoints_[0].size(); 309 | 310 | // TODO: does not include points outside convex hull (if computed)... 311 | augmentNormalData(); 312 | 313 | createRasterizedSurface(); 314 | } 315 | 316 | //TODO: move elsewhere 317 | class Parallel 318 | { 319 | public: 320 | using IndexedTask = std::function; 321 | static void RunTasks(IndexedTask task, int numProcs = NumCores()) 322 | { 323 | std::vector threads; 324 | 325 | for (int i = 0; i < numProcs; ++i) 326 | { 327 | threads.emplace_back(std::bind(task, i)); 328 | } 329 | 330 | for (auto& thread : threads) 331 | { 332 | if (thread.joinable()) 333 | { 334 | thread.join(); 335 | } 336 | } 337 | } 338 | static unsigned int NumCores() 339 | { 340 | return std::thread::hardware_concurrency(); 341 | } 342 | }; 343 | 344 | void RBFInterface::createRasterizedSurface() 345 | { 346 | RBF rbf(getSurfaceData(), kernel_); 347 | rbf.setDataReduction(All); 348 | 349 | // Construct RBFs 350 | rbf.computeFunction(); // TODO: throws exception if internal code used... 351 | 352 | //TODO: move/remove comment 353 | // Fill the values into the vector. 354 | // In the first loop, we initialize the matrix with all values set to -100. 355 | // In the second loop, we change the values from -100 to the correct rasterData_ if the point in the domain described above. 356 | 357 | rasterData_.reset(new DataStorage(static_cast(this->size_[0]), static_cast(this->size_[1]), static_cast(this->size_[2]))); 358 | 359 | const auto spacingX = this->spacing_[0] * vec3::unitX; 360 | const auto spacingY = this->spacing_[1] * vec3::unitY; 361 | const auto spacingZ = this->spacing_[2] * vec3::unitZ; 362 | 363 | const auto dataBegin = rasterData_->beginRawPtr(); 364 | const auto dataSize = rasterData_->totalSize(); 365 | 366 | const auto numTasks = Parallel::NumCores(); 367 | const auto coreSize = dataSize / numTasks; 368 | const auto leftover = dataSize - numTasks * coreSize; 369 | 370 | const auto sizeY = rasterData_->size2(); 371 | const auto sizeZ = rasterData_->size3(); 372 | const auto sliceSize = sizeY * sizeZ; 373 | 374 | auto computeRange = [&](int beginIndex, int rangeSize) 375 | { 376 | auto output = dataBegin + beginIndex; 377 | 378 | for (size_t q = 0; q < rangeSize; ++q) 379 | { 380 | const size_t i = (beginIndex + q) / sliceSize; 381 | const size_t j = (beginIndex + q) % sliceSize / sizeZ; 382 | const size_t k = (beginIndex + q) % sizeZ; 383 | const vec3 location = this->origin_ + i * spacingX + j * spacingY + k * spacingZ; 384 | *output++ = rbf.computeValue(location); 385 | } 386 | }; 387 | 388 | Parallel::RunTasks([&](int core) { computeRange(core * coreSize, coreSize); }, numTasks); 389 | 390 | computeRange(numTasks * coreSize, leftover); 391 | } 392 | 393 | // TODO: move this and findNormalAxis to new class? 394 | void RBFInterface::augmentNormalData() 395 | { 396 | const size_t DIM_3D = 3; 397 | const int NORMAL_IN = 10, NORMAL_OUT = -10; 398 | const size_t N = this->surfaceData_->origSize_; 399 | const size_t M = this->surfaceData_->leftovers_[0].size(); 400 | 401 | // iterate through list of points not on hull, add to list as zero points 402 | for (int i = 0; i < M; ++i) 403 | { 404 | this->surfaceData_->surfacePoints_[0].push_back(this->surfaceData_->leftovers_[0][i]); 405 | this->surfaceData_->surfacePoints_[1].push_back(this->surfaceData_->leftovers_[1][i]); 406 | this->surfaceData_->surfacePoints_[2].push_back(this->surfaceData_->leftovers_[2][i]); 407 | } 408 | this->surfaceData_->fnc_.insert(this->surfaceData_->fnc_.end(), M, this->thresholdValue_); 409 | 410 | // size of surfaceData_->surfacePoints_ entries tripled with this code 411 | for (int i = 0; i < N; i++) 412 | { 413 | vec3 myNormal = findNormalAxis(i); 414 | myNormal = normalize(myNormal, SMALL_EPSILON); 415 | for (int j = 0; j < DIM_3D; j++) 416 | { 417 | this->surfaceData_->surfacePoints_[j].push_back(this->surfaceData_->surfacePoints_[j][i] + this->offset_ * myNormal[j]); 418 | } 419 | 420 | // normals point inward 421 | this->surfaceData_->fnc_.push_back(NORMAL_IN); 422 | 423 | for (int j = 0; j < DIM_3D; j++) 424 | { 425 | this->surfaceData_->surfacePoints_[j].push_back(this->surfaceData_->surfacePoints_[j][i] - this->offset_ * myNormal[j]); 426 | } 427 | 428 | // normals pointing outward 429 | this->surfaceData_->fnc_.push_back(NORMAL_OUT); 430 | } 431 | } 432 | 433 | vec3 RBFInterface::findNormalAxis(const int n) 434 | { 435 | const int TOT = this->surfaceData_->origSize_; 436 | int prev = (n-1) >= 0 ? n-1 : TOT-1; // wrap 437 | int next = (n+1) < TOT ? n+1 : 0; // wrap 438 | axis_t myAxis = this->surfaceData_->updatedAxisInformation_[n]; 439 | 440 | // TODO: why is this needed? AK 09/13/2016 441 | while (fabs(this->surfaceData_->surfacePoints_[myAxis][prev] - this->surfaceData_->surfacePoints_[myAxis][n]) > SMALL_EPSILON) 442 | { 443 | prev = (prev-1) >= 0 ? prev-1 : TOT-1; // wrap 444 | } 445 | 446 | while(fabs(this->surfaceData_->surfacePoints_[myAxis][next] - this->surfaceData_->surfacePoints_[myAxis][n]) > SMALL_EPSILON) 447 | { 448 | next = (next+1) < TOT ? next+1 : 0; // wrap 449 | } 450 | 451 | // normals from points either on convex hull boundary or in complete dataset if convex hull not used... 452 | 453 | // X == 0, Y == 1, Z == 2 454 | vec3 a(this->surfaceData_->surfacePoints_[0][n], 455 | this->surfaceData_->surfacePoints_[1][n], 456 | this->surfaceData_->surfacePoints_[2][n]); 457 | vec3 b(this->surfaceData_->surfacePoints_[0][prev], 458 | this->surfaceData_->surfacePoints_[1][prev], 459 | this->surfaceData_->surfacePoints_[2][prev]); 460 | vec3 c(this->surfaceData_->surfacePoints_[0][next], 461 | this->surfaceData_->surfacePoints_[1][next], 462 | this->surfaceData_->surfacePoints_[2][next]); 463 | 464 | vec3 tan1 = normalize(b-a, SMALL_EPSILON); 465 | vec3 tan2 = normalize(a-c, SMALL_EPSILON); 466 | vec3 tangent = (tan1 + tan2) / 2; 467 | 468 | double ret_x, ret_y, ret_z; 469 | vec3 ret(tangent); 470 | //rotate by 90 degrees on the x-y plane 471 | switch(myAxis) 472 | { 473 | case 0: 474 | ret[1] = ret_y = -tangent[2]; 475 | ret[2] = ret_z = tangent[1]; 476 | break; 477 | case 1: 478 | ret[2] = ret_z = -tangent[0]; 479 | ret[0] = ret_x = tangent[2]; 480 | break; 481 | case 2: 482 | ret[0] = ret_x = -tangent[1]; 483 | ret[1] = ret_y = tangent[0]; 484 | break; 485 | } 486 | return ret; 487 | } 488 | 489 | DataStorage::DataStorage(size_t xDim, size_t yDim, size_t zDim) : xDim_(xDim), yDim_(yDim), zDim_(zDim) 490 | { 491 | data_.resize(xDim_ * yDim_ * zDim_, -100); 492 | } 493 | 494 | void DataStorage::set(size_t i, size_t j, size_t k, double val) 495 | { 496 | data_[i * yDim_ * zDim_ + j * zDim_ + k] = val; 497 | } 498 | 499 | double DataStorage::get(size_t i, size_t j, size_t k) const 500 | { 501 | return data_[i * yDim_ * zDim_ + j * zDim_ + k]; 502 | } 503 | 504 | DataStorage::Slice DataStorage::slice(size_t i) const 505 | { 506 | auto begin = data_.begin() + i * yDim_ * zDim_; 507 | return { begin, begin + yDim_ * zDim_ }; 508 | } 509 | -------------------------------------------------------------------------------- /RBFInterface.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef _RBFInterface_H_ 28 | #define _RBFInterface_H_ 29 | 30 | #include 31 | #include 32 | 33 | #include "ScatteredData.h" 34 | #include "vec3.h" 35 | #include "RBF.h" 36 | 37 | class DataStorage 38 | { 39 | public: 40 | DataStorage(size_t xDim, size_t yDim, size_t zDim); 41 | void set(size_t i, size_t j, size_t k, double val); 42 | double get(size_t i, size_t j, size_t k) const; 43 | size_t size1() const { return xDim_; } 44 | size_t size2() const { return yDim_; } 45 | size_t size3() const { return zDim_; } 46 | size_t totalSize() const { return size1() * size2() * size3(); } 47 | 48 | double* beginRawPtr() { return &data_[0]; } 49 | 50 | using Slice = std::pair::const_iterator, std::vector::const_iterator>; 51 | 52 | Slice slice(size_t i) const; 53 | private: 54 | size_t xDim_, yDim_, zDim_; 55 | std::vector data_; 56 | }; 57 | 58 | typedef std::vector IndexList; 59 | typedef std::vector AxisList; 60 | 61 | class RBFInterface 62 | { 63 | public: 64 | RBFInterface(std::vector myData, 65 | const vec3& myOrigin, const vec3& mySize, const vec3& mySpacing, 66 | const double myOffset, AxisList myAxis, 67 | const bool compute2DConvexHull=true, 68 | const bool invertSeedOrder=false, Kernel kernel=ThinPlate); 69 | 70 | double getThresholdValue() const { return thresholdValue_; } 71 | const DataStorage* getRasterData() { return rasterData_.get(); } 72 | const ScatteredData* getSurfaceData() const { return this->surfaceData_.get(); } 73 | 74 | private: 75 | // 2D calculation 76 | void create2DSurface(); // propagates exceptions 77 | void create3DSurface(); 78 | void augmentNormalData(); 79 | vec3 findNormalAxis(const int n); 80 | void createRasterizedSurface(); 81 | 82 | std::unique_ptr surfaceData_; 83 | std::unique_ptr rasterData_; 84 | 85 | const double thresholdValue_; 86 | const vec3 origin_; 87 | const vec3 size_; 88 | const vec3 spacing_; 89 | const double offset_; 90 | AxisList axisList_; 91 | const bool compute2DConvexHull_; 92 | const bool invertSeedOrder_; 93 | const Kernel kernel_; 94 | std::vector points_x_, points_y_ , points_z_, threshold_; 95 | 96 | // change to inside or outside 97 | std::vector inNormals, outNormals; 98 | 99 | // static const double EPSILON; 100 | static const double SMALL_EPSILON; 101 | }; 102 | 103 | #endif //_RBFInterface_H_ 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ImplicitFunction 2 | 3 | [![Build Status](https://travis-ci.org/SCIInstitute/ImplicitFunction.svg?branch=master)](https://travis-ci.org/SCIInstitute/ImplicitFunction) 4 | [![Coverage Status](https://coveralls.io/repos/github/SCIInstitute/ImplicitFunction/badge.svg)](https://coveralls.io/github/SCIInstitute/ImplicitFunction) 5 | 6 | Code to construct implicit RBF surfaces. 7 | -------------------------------------------------------------------------------- /ScatteredData.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "ScatteredData.h" 33 | #include "vec3.h" 34 | #include "ETSP.h" 35 | #include "2DConvexHull.h" 36 | 37 | using std::vector; 38 | 39 | ScatteredData::ScatteredData() : 40 | origSize_(0) 41 | { 42 | } 43 | 44 | ScatteredData::ScatteredData(const std::vector& points_x, 45 | const std::vector& points_y, 46 | const std::vector& points_z, 47 | const std::vector& func, 48 | const std::vector& axisInfo) : 49 | axisInformation_(axisInfo), 50 | updatedAxisInformation_(axisInfo), 51 | origSize_(0) 52 | { 53 | setData(points_x, points_y, points_z, func); 54 | } 55 | 56 | void ScatteredData::setData(const std::vector& points_x, 57 | const std::vector& points_y, 58 | const std::vector& points_z, 59 | const std::vector& func) 60 | { 61 | this->surfacePoints_[X] = points_x; this->surfacePoints_[Y] = points_y; this->surfacePoints_[Z] = points_z; this->fnc_ = func; 62 | this->origSize_ = points_x.size(); 63 | } 64 | 65 | void ScatteredData::SDsort() 66 | { 67 | vec3Sorter sortObject; 68 | sortObject.axisToSort=this->axisInformation_[0]; 69 | 70 | for (int i = 0; i < this->surfacePoints_[0].size(); i++) 71 | { 72 | vec3 a(this->surfacePoints_[X][i], this->surfacePoints_[Y][i], this->surfacePoints_[Z][i]); 73 | this->inputData_.push_back(a); 74 | } 75 | std::sort(this->inputData_.begin(), this->inputData_.end(), sortObject); 76 | } 77 | 78 | void ScatteredData::SDmultisort() 79 | { 80 | vec3Sorter sortObject; 81 | std::vector dataX, dataY, dataZ; 82 | for (int i = 0; i < this->surfacePoints_[0].size(); i++) 83 | { 84 | vec3 a(this->surfacePoints_[X][i], this->surfacePoints_[Y][i], this->surfacePoints_[Z][i]); 85 | switch(this->axisInformation_[i]) 86 | { 87 | case X: 88 | dataX.push_back(a); 89 | break; 90 | case Y: 91 | dataY.push_back(a); 92 | break; 93 | case Z: 94 | dataZ.push_back(a); 95 | break; 96 | } 97 | } 98 | 99 | this->inputData_.clear(); 100 | sortObject.axisToSort = X; 101 | std::sort(dataX.begin(), dataX.end(), sortObject); 102 | 103 | sortObject.axisToSort = Y; 104 | std::sort(dataY.begin(), dataY.end(), sortObject); 105 | 106 | sortObject.axisToSort = Z; 107 | std::sort(dataZ.begin(), dataZ.end(), sortObject); 108 | 109 | this->axisInformation_.clear(); 110 | for(int i = 0; i < dataX.size(); i++) 111 | { 112 | this->inputData_.push_back(dataX[i]); 113 | this->axisInformation_.push_back(X); 114 | } 115 | 116 | for(int i = 0; i < dataY.size(); i++) 117 | { 118 | this->inputData_.push_back(dataY[i]); 119 | this->axisInformation_.push_back(Y); 120 | } 121 | 122 | for(int i = 0; i < dataZ.size(); i++) 123 | { 124 | this->inputData_.push_back(dataZ[i]); 125 | this->axisInformation_.push_back(Z); 126 | } 127 | } 128 | 129 | 130 | void ScatteredData::compute2DHull() 131 | { 132 | std::vector reorderedData; 133 | 134 | // TODO: debug print 135 | for(int i = 0; i < this->surfacePoints_[0].size(); i++) 136 | printf("%d %lf %lf %lf\n", i, this->surfacePoints_[0][i], this->surfacePoints_[1][i], this->surfacePoints_[2][i]); 137 | 138 | SDmultisort(); 139 | printf("Sorted\n"); 140 | 141 | // TODO: debug print 142 | for (int i = 0; i < this->inputData_.size(); i++) 143 | printf("%d %lf %lf %lf\n", i, this->inputData_[i][0], this->inputData_[i][1], this->inputData_[i][2]); 144 | 145 | int count = 0; 146 | //printf("%d %d\n", this->inputData_.size(), this->surfacePoints_[0].size()); fflush(stdout); 147 | while ( count != this->surfacePoints_[0].size() ) 148 | { 149 | int start = count; 150 | //printf("%lf %d\n", this->inputData_[count][myAxis], this->surfacePoints_[0].size()); 151 | while ( count != this->surfacePoints_[0].size() ) 152 | { 153 | //printf("%lf %lf %lf\n", this->inputData_[count][myAxis], this->inputData_[start][myAxis],fabs(this->inputData_[count][myAxis]-this->inputData_[start][myAxis])); 154 | count++; 155 | axis_t sortingAxis = this->axisInformation_[start]; 156 | if (this->axisInformation_[count] != this->axisInformation_[start]) 157 | break; 158 | 159 | if (fabs(this->inputData_[count][sortingAxis] - this->inputData_[start][sortingAxis]) > 1e-6) 160 | break; 161 | } 162 | int end = count-1; 163 | 164 | // TODO: debug print 165 | printf("ABC Start: %d End %d\n", start, end); 166 | 167 | int myAxis = -1; 168 | switch(this->axisInformation_[start]) 169 | { 170 | case X: myAxis = 0; break; 171 | case Y: myAxis = 1; break; 172 | case Z: myAxis = 2; break; 173 | } 174 | 175 | vector inPoints; 176 | inPoints.resize(end-start+1); 177 | for (int i = start; i <= end; i++) 178 | { 179 | inPoints[i-start][0] = this->inputData_[i][0]; 180 | inPoints[i-start][1] = this->inputData_[i][1]; 181 | inPoints[i-start][2] = this->inputData_[i][2]; 182 | } 183 | 184 | //printf("inPoints written\n"); 185 | vector reorder = getConvexHull(inPoints, myAxis); 186 | 187 | // TODO: simplify data transfer 188 | 189 | printf("Convex Hull found\n"); 190 | // indices of points in convex hull 191 | for(int i = 0; i < reorder.size(); i++) 192 | { 193 | printf("%d ", reorder[i]+start); 194 | reorderedData.push_back(reorder[i]+start); 195 | } 196 | printf("\n"); 197 | } 198 | 199 | std::sort( reorderedData.begin(), reorderedData.end() ); 200 | 201 | //rewrite everything 202 | std::vector newx[3], tmp[3], newfnc; 203 | 204 | this->updatedAxisInformation_.clear(); 205 | 206 | for(int i = 0; i < reorderedData.size(); i++) 207 | { 208 | const int j = reorderedData[i]; 209 | newx[X].push_back(this->inputData_[j][0]); 210 | newx[Y].push_back(this->inputData_[j][1]); 211 | newx[Z].push_back(this->inputData_[j][2]); 212 | 213 | newfnc.push_back(this->fnc_[j]); 214 | 215 | this->convexHullData_.push_back( this->inputData_[j] ); // TODO: never actually used except for debug prints... 216 | this->updatedAxisInformation_.push_back( this->axisInformation_[j] ); 217 | } 218 | 219 | this->surfacePoints_[X].clear(); 220 | this->surfacePoints_[Y].clear(); 221 | this->surfacePoints_[Z].clear(); 222 | 223 | this->surfacePoints_[X] = newx[X]; 224 | this->surfacePoints_[Y] = newx[Y]; 225 | this->surfacePoints_[Z] = newx[Z]; 226 | 227 | this->fnc_.clear(); 228 | this->fnc_ = newfnc; 229 | 230 | for (int i = 0; i < this->inputData_.size(); ++i) 231 | { 232 | auto it = std::find( reorderedData.begin(), reorderedData.end(), i); 233 | if ( it == reorderedData.end() ) 234 | { 235 | tmp[X].push_back(this->inputData_[i][0]); 236 | tmp[Y].push_back(this->inputData_[i][1]); 237 | tmp[Z].push_back(this->inputData_[i][2]); 238 | } 239 | } 240 | 241 | this->leftovers_[X].clear(); 242 | this->leftovers_[Y].clear(); 243 | this->leftovers_[Z].clear(); 244 | 245 | this->leftovers_[X] = tmp[X]; 246 | this->leftovers_[Y] = tmp[Y]; 247 | this->leftovers_[Z] = tmp[Z]; 248 | 249 | // TODO: this appears to replace the original input data with convex hull 250 | // points 251 | // Points are being ignored 252 | //this->inputData_.clear(); 253 | //this->inputData_=myNewData; 254 | // 255 | // TODO: overwrites original axis information... 256 | // Just reordered? 257 | //this->axisInformation_.clear(); 258 | //this->axisInformation_ = newAxisInformation; 259 | 260 | printf("Convex hull points\n"); 261 | for(int i = 0; i < this->surfacePoints_[0].size(); i++) 262 | printf("%d %lf %lf %lf\n", i, this->surfacePoints_[0][i], this->surfacePoints_[1][i], this->surfacePoints_[2][i]); 263 | 264 | printf("Points inside convex hull\n"); 265 | for (int i = 0; i < this->leftovers_[0].size(); i++) 266 | printf("%d %lf %lf %lf\n", i, this->leftovers_[0][i], this->leftovers_[1][i], this->leftovers_[2][i]); 267 | 268 | // TODO: this gets overwritten in RBFInterface??? 269 | this->origSize_ = this->convexHullData_.size(); 270 | } 271 | 272 | vec3 ScatteredData::surfacePoint(size_t i) const 273 | { 274 | return { surfacePoints_[X][i], surfacePoints_[Y][i], surfacePoints_[Z][i] }; 275 | } 276 | 277 | void ScatteredData::updateSurfacePointsList() 278 | { 279 | surfacePointsFlattened_.reserve(surfacePoints_[X].size() * 3); 280 | for (size_t i = 0; i < surfacePoints_[X].size(); ++i) 281 | { 282 | surfacePointsFlattened_.push_back(surfacePoints_[X][i]); 283 | surfacePointsFlattened_.push_back(surfacePoints_[Y][i]); 284 | surfacePointsFlattened_.push_back(surfacePoints_[Z][i]); 285 | } 286 | surfacePointsFlattenedPtr_ = &surfacePointsFlattened_[0]; 287 | } 288 | 289 | double ScatteredData::squaredDistanceFrom(size_t i, const vec3& from) const 290 | { 291 | const auto baseIndex = 3*i; 292 | const auto pointX = surfacePointsFlattened_[baseIndex]; 293 | const auto pointY = surfacePointsFlattened_[baseIndex + 1]; 294 | const auto pointZ = surfacePointsFlattened_[baseIndex + 2]; 295 | 296 | auto xDiff = pointX - from[0]; 297 | auto yDiff = pointY - from[1]; 298 | auto zDiff = pointZ - from[2]; 299 | return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff; 300 | } 301 | -------------------------------------------------------------------------------- /ScatteredData.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef _SCATTEREDDATA_H_ 28 | #define _SCATTEREDDATA_H_ 29 | 30 | // STL Includes 31 | #include 32 | #include "vec3.h" 33 | 34 | enum axis_t { X = 0, Y, Z }; 35 | 36 | class ScatteredData 37 | { 38 | public: 39 | // TODO: what happens when vector sizes don't match??? 40 | ScatteredData(); 41 | ScatteredData(const std::vector& points_x, 42 | const std::vector& points_y, 43 | const std::vector& points_z, 44 | const std::vector& func, 45 | const std::vector& axisInfo); 46 | 47 | void setData(const std::vector& points_x, 48 | const std::vector& points_y, 49 | const std::vector& points_z, 50 | const std::vector& func); 51 | 52 | // TODO: make private 53 | // leftovers_ is set of points inside convex hull 54 | // 55 | // surfacePoints_ is array of vectors of point x components, point y components and point z components 56 | // If convex hull is computed, then surfacePoints_ is points on convex hull boundary 57 | // 58 | // fnc_ is vector of single threshold value and constant values (positive, negative) at indices 59 | // where normal data has been pushed to surfacePoints_ vector 60 | // 61 | // TODO: make surfacePoints_ and leftovers_ vector of vec3?? 62 | // cohesive data structure would be better... 63 | std::vector surfacePoints_[3], leftovers_[3], fnc_; 64 | std::vector axisInformation_, updatedAxisInformation_; 65 | 66 | void compute2DHull(); 67 | int origSize_; 68 | 69 | void updateSurfacePointsList(); 70 | vec3 surfacePoint(size_t i) const; 71 | 72 | std::vector surfacePointsFlattened_; 73 | double* surfacePointsFlattenedPtr_{nullptr}; 74 | 75 | double squaredDistanceFrom(size_t i, const vec3& from) const; 76 | 77 | private: 78 | void SDsort(); 79 | void SDmultisort(); 80 | std::vector surfacePointsCombined_; 81 | std::vector inputData_, convexHullData_; 82 | }; 83 | 84 | struct vec3Sorter 85 | { 86 | axis_t axisToSort; 87 | int myAxis; 88 | bool operator() (const vec3& a, const vec3& b) 89 | { 90 | if (axisToSort == X) myAxis = 0; 91 | if (axisToSort == Y) myAxis = 1; 92 | if (axisToSort == Z) myAxis = 2; 93 | return (a[myAxis] < b[myAxis]); 94 | } 95 | }; 96 | 97 | #endif //_SCATTEREDDATA_H_ 98 | -------------------------------------------------------------------------------- /SparseMatrix.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | // STL Includes 28 | #include 29 | #include "SparseMatrix.h" 30 | 31 | using std::vector; 32 | 33 | SparseMatrix::SparseMatrix() 34 | { 35 | } 36 | 37 | SparseMatrix::SparseMatrix(int n) 38 | { 39 | col.resize(n); 40 | val.resize(n); 41 | } 42 | 43 | void SparseMatrix::resize(int n) 44 | { 45 | col.resize(n); 46 | val.resize(n); 47 | } 48 | 49 | void SparseMatrix::push_back(int myRow, int myCol, double myVal) 50 | { 51 | col[myRow].push_back(myCol); 52 | val[myRow].push_back(myVal); 53 | } 54 | 55 | void SparseMatrix::multiply(vector &b, vector &c) 56 | { 57 | int n = b.size(), i, j; 58 | c.clear(); 59 | c.resize(n); 60 | 61 | for(i = 0; icol.size(); i++) 62 | { 63 | int row, col; 64 | row = i; 65 | for(j=0; jcol[i].size(); j++) 66 | { 67 | col = this->col[i][j]; 68 | //cout<<" Row, Col = "<val[i][j]*b[col]; 70 | } 71 | } 72 | } 73 | 74 | std::vector SparseMatrix::multiply(vector &b) 75 | { 76 | vector c; 77 | multiply(b,c); 78 | return c; 79 | } 80 | 81 | -------------------------------------------------------------------------------- /SparseMatrix.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef _SPARSEMATRIX_H_ 28 | #define _SPARSEMATRIX_H_ 29 | 30 | // STL Includes 31 | #include 32 | 33 | class SparseMatrix 34 | { 35 | public: 36 | SparseMatrix(); 37 | SparseMatrix(int n); 38 | void push_back(int myRow, int myCol, double myVal); 39 | void resize(int n); 40 | void multiply(std::vector &b, std::vector &c); 41 | std::vector multiply(std::vector &b); 42 | 43 | 44 | private: 45 | std::vector< std::vector > col; 46 | std::vector< std::vector > val; 47 | }; 48 | 49 | #endif //_SPARSEMATRIX_H_ 50 | 51 | 52 | -------------------------------------------------------------------------------- /Tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Permission is hereby granted, free of charge, to any person 2 | # obtaining a copy of this software and associated documentation 3 | # files ( the "Software" ), to deal in the Software without 4 | # restriction, including without limitation the rights to use, 5 | # copy, modify, merge, publish, distribute, sublicense, and/or 6 | # sell copies of the Software, and to permit persons to whom the 7 | # Software is furnished to do so, subject to the following 8 | # conditions: 9 | # 10 | # The above copyright notice and this permission notice shall 11 | # be included in all copies or substantial portions of the 12 | # Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 15 | # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 16 | # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 17 | # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 | # USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | set(ImplicitFunction_Tests_SRCS 24 | ConvexHull2DTests.cpp 25 | ConvexHull3DTests.cpp 26 | RBFTests.cpp 27 | RBFInterfaceTests.cpp 28 | ScatteredDataTests.cpp 29 | Vec3Tests.cpp 30 | Seg3DIntegrationTest.cpp 31 | ) 32 | 33 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ImplicitFunction_BINARY_DIR}) 34 | 35 | include_directories( 36 | ${GTEST_INCLUDE_DIR} 37 | ${ImplicitFunction_SOURCE_DIR} 38 | ) 39 | 40 | add_executable(ImplicitFunction_Tests ${ImplicitFunction_Tests_SRCS}) 41 | 42 | target_compile_definitions(ImplicitFunction_Tests 43 | PUBLIC -DREGRESSION_DIR="${CMAKE_CURRENT_SOURCE_DIR}/regression") 44 | 45 | target_link_libraries(ImplicitFunction_Tests 46 | ${ImplicitFunction_LIB_NAME} 47 | ${TETGEN_LIBRARY} 48 | ${GTEST_LIBRARY} 49 | ${GTEST_MAIN_LIBRARY} 50 | ) 51 | 52 | IF(UNIX) 53 | TARGET_LINK_LIBRARIES(ImplicitFunction_Tests -lpthread -lm) 54 | ENDIF() 55 | 56 | ADD_TEST("ImplicitFunction_Tests" ${ImplicitFunction_BINARY_DIR}/ImplicitFunction_Tests) 57 | -------------------------------------------------------------------------------- /Tests/ConvexHull2DTests.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include 28 | 29 | #include 30 | 31 | #include "RBFInterface.h" 32 | #include "vec3.h" 33 | 34 | class ConvexHull2DTest : public ::testing::Test 35 | { 36 | protected: 37 | virtual void SetUp() 38 | { 39 | pointsBowtieClockwise.push_back( vec3(17.1, 34.0, 49.0) ); 40 | pointsBowtieClockwise.push_back( vec3(25.5, 30.6, 49.0) ); 41 | pointsBowtieClockwise.push_back( vec3(33.8, 34.4, 49.0) ); 42 | pointsBowtieClockwise.push_back( vec3(33.5, 18.8, 49.0) ); 43 | pointsBowtieClockwise.push_back( vec3(25.8, 23.0, 49.0) ); 44 | pointsBowtieClockwise.push_back( vec3(17.1, 19.0, 49.0) ); 45 | gridSize50[0] = 50.0; gridSize50[1] = 50.0; gridSize50[2] = 50.0; 46 | gridSpacing1[0] = 1.0; gridSpacing1[1] = 1.0; gridSpacing1[2] = 1.0; 47 | normalOffset10 = 10; 48 | axisDataZ.insert(axisDataZ.begin(), 3, axis_t::Z); 49 | thinPlateKernel = ThinPlate; 50 | gaussianPlateKernel = Gaussian; 51 | multiQuadKernel = MultiQuadratic; 52 | } 53 | 54 | // virtual void TearDown() {} 55 | std::vector pointsBowtieClockwise; 56 | std::vector squareClockwise; 57 | vec3 origin0; // (0, 0, 0) 58 | vec3 gridSize50; // (50, 50, 50) 59 | vec3 gridSpacing1; // (1, 1, 1) 60 | double normalOffset10; 61 | std::vector axisDataZ; // #axis entries min 3 62 | Kernel thinPlateKernel; 63 | Kernel gaussianPlateKernel; 64 | Kernel multiQuadKernel; 65 | }; 66 | 67 | TEST_F(ConvexHull2DTest, BasicInterfaceTest) 68 | { 69 | RBFInterface rbfInterface( pointsBowtieClockwise, origin0, 70 | gridSize50, gridSpacing1, 71 | normalOffset10, axisDataZ, 72 | true, ThinPlate ); 73 | double threshold = rbfInterface.getThresholdValue(); 74 | ASSERT_EQ( threshold, 0 ); // default 75 | const auto rasterData = rbfInterface.getRasterData(); 76 | // at least check that values in threshold range were generated 77 | // TODO: check linear system numerics 78 | int counter = 0; 79 | for (size_t i = 0; i < rasterData->size1(); ++i) 80 | { 81 | for (size_t j = 0; j < rasterData->size2(); ++j) 82 | { 83 | for (size_t k = 0; k < rasterData->size3(); ++k) 84 | { 85 | if ( rasterData->get(i,j,k) > threshold ) 86 | ++counter; 87 | } 88 | } 89 | } 90 | EXPECT_GT(counter, 0); 91 | } 92 | -------------------------------------------------------------------------------- /Tests/ConvexHull3DTests.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | //#include 33 | //#include 34 | 35 | #include "RBFInterface.h" 36 | #include "ScatteredData.h" 37 | #include "vec3.h" 38 | 39 | class ConvexHull3DTest : public ::testing::Test 40 | { 41 | protected: 42 | virtual void SetUp() 43 | { 44 | // TODO: new coordinates needed to match Seg3D 45 | // tet.push_back( vec3( 1.0, 1.0, 1.0) ); 46 | // tet.push_back( vec3(-1.0, -1.0, 1.0) ); 47 | // tet.push_back( vec3(-1.0, 1.0, -1.0) ); 48 | // tet.push_back( vec3( 1.0, -1.0, -1.0) ); 49 | // 50 | // cube.push_back( vec3(-1.0, -1.0, 1.0) ); 51 | // cube.push_back( vec3( 1.0, -1.0, 1.0) ); 52 | // cube.push_back( vec3( 1.0, 1.0, 1.0) ); 53 | // cube.push_back( vec3(-1.0, 1.0, 1.0) ); 54 | // cube.push_back( vec3(-1.0, -1.0, -1.0) ); 55 | // cube.push_back( vec3( 1.0, -1.0, -1.0) ); 56 | // cube.push_back( vec3( 1.0, 1.0, -1.0) ); 57 | // cube.push_back( vec3(-1.0, 1.0, -1.0) ); 58 | 59 | prism.push_back( vec3( 20.0, 30.0, 20.0) ); 60 | prism.push_back( vec3( 30.0, 30.0, 20.0) ); 61 | prism.push_back( vec3( 25.0, 20.0, 20.0) ); 62 | prism.push_back( vec3( 20.0, 30.0, 30.0) ); 63 | prism.push_back( vec3( 30.0, 30.0, 30.0) ); 64 | prism.push_back( vec3( 25.0, 20.0, 30.0) ); 65 | 66 | prismWithInternalPoint.push_back( vec3( 20.0, 30.0, 20.0) ); 67 | prismWithInternalPoint.push_back( vec3( 30.0, 30.0, 20.0) ); 68 | prismWithInternalPoint.push_back( vec3( 25.0, 20.0, 20.0) ); 69 | prismWithInternalPoint.push_back( vec3( 20.0, 30.0, 30.0) ); 70 | prismWithInternalPoint.push_back( vec3( 30.0, 30.0, 30.0) ); 71 | prismWithInternalPoint.push_back( vec3( 25.0, 20.0, 30.0) ); 72 | prismWithInternalPoint.push_back( vec3( 25.0, 25.0, 25.0) ); 73 | 74 | 75 | // prism with point just outside convex hull (v. close to triangle) 76 | 77 | gridSize50[0] = 50.0; gridSize50[1] = 50.0; gridSize50[2] = 50.0; 78 | gridSpacing1[0] = 1.0; gridSpacing1[1] = 1.0; gridSpacing1[2] = 1.0; 79 | normalOffset2 = 2.0; 80 | axisDataZ.insert(axisDataZ.begin(), 3, axis_t::Z); 81 | thinPlateKernel = ThinPlate; 82 | gaussianPlateKernel = Gaussian; 83 | multiQuadKernel = MultiQuadratic; 84 | 85 | nrrdHeader50_0_1.push_back("NRRD0001"); 86 | nrrdHeader50_0_1.push_back("# Complete NRRD file format specification at:"); 87 | nrrdHeader50_0_1.push_back("# http://teem.sourceforge.net/nrrd/format.html"); 88 | nrrdHeader50_0_1.push_back("type: double"); 89 | nrrdHeader50_0_1.push_back("dimension: 3"); 90 | std::ostringstream sizes; 91 | sizes << "sizes: " << gridSize50[0] << " " << gridSize50[1] << " " << gridSize50[2]; 92 | nrrdHeader50_0_1.push_back( sizes.str() ); 93 | std::ostringstream mins; 94 | mins << "axis mins: " << origin0[0] << ", " << origin0[1] << ", " << origin0[2]; 95 | nrrdHeader50_0_1.push_back( mins.str() ); 96 | std::ostringstream spacings; 97 | spacings << "spacings: " << gridSpacing1[0] << " " << gridSpacing1[1] << " " << gridSpacing1[2]; 98 | nrrdHeader50_0_1.push_back( spacings.str() ); 99 | //nrrdHeader50_0_1.push_back("centerings: cell cell cell"); 100 | nrrdHeader50_0_1.push_back("centerings: node node node"); 101 | nrrdHeader50_0_1.push_back("endian: little"); 102 | //nrrdHeader50_0_1.push_back("encoding: ascii"); 103 | nrrdHeader50_0_1.push_back("encoding: raw"); 104 | } 105 | 106 | // virtual void TearDown() {} 107 | 108 | // std::vector tet; 109 | // std::vector cube; 110 | std::vector prism; 111 | std::vector prismWithInternalPoint; 112 | 113 | vec3 origin0; // (0, 0, 0) 114 | vec3 gridSize50; // (50, 50, 50) 115 | vec3 gridSpacing1; // (1, 1, 1) 116 | double normalOffset2; 117 | std::vector axisDataZ; // #axis entries min 3 118 | Kernel thinPlateKernel; 119 | Kernel gaussianPlateKernel; 120 | Kernel multiQuadKernel; 121 | 122 | std::vector< std::string > nrrdHeader50_0_1; 123 | }; 124 | 125 | TEST_F(ConvexHull3DTest, PrismBasicInterfaceTest) 126 | { 127 | RBFInterface rbfInterface( prism, origin0, 128 | gridSize50, gridSpacing1, 129 | normalOffset2, axisDataZ, 130 | false, ThinPlate ); 131 | double threshold = rbfInterface.getThresholdValue(); 132 | ASSERT_EQ( threshold, 0 ); // default 133 | 134 | const auto rasterData = rbfInterface.getRasterData(); 135 | 136 | // std::string filename("testPrism.nrrd"); 137 | // std::cout << "Writing file '" << filename << "'" << std::endl; 138 | // std::ofstream nrrdFile(filename.c_str(), std::ofstream::binary); 139 | // nrrdFile.exceptions( std::ofstream::failbit | std::ofstream::badbit ); 140 | // 141 | // if ( nrrdFile.is_open() ) 142 | // { 143 | //// nrrdFile << "NRRD0001" << std::endl; 144 | //// nrrdFile << "# Complete NRRD file format specification at:" << std::endl; 145 | //// nrrdFile << "# http://teem.sourceforge.net/nrrd/format.html" << std::endl; 146 | //// nrrdFile << "type: double" << std::endl; 147 | //// nrrdFile << "dimension: 3" << std::endl; 148 | //// nrrdFile << "sizes: " << gridSize50[0] << " " << gridSize50[1] << " " << gridSize50[2] << std::endl; 149 | //// nrrdFile << "axis mins: " << origin0[0] << ", " << origin0[1] << ", " << origin0[2] << std::endl; 150 | //// nrrdFile << "spacings: " << gridSpacing1[0] << " " << gridSpacing1[1] << " " << gridSpacing1[2] << std::endl; 151 | ////// nrrdFile << "centerings: cell cell cell" << std::endl; 152 | //// nrrdFile << "centerings: node node node" << std::endl; 153 | //// nrrdFile << "endian: little" << std::endl; 154 | //// nrrdFile << "encoding: raw" << std::endl; 155 | ////// nrrdFile << "encoding: ascii" << std::endl; 156 | //// nrrdFile << std::endl; 157 | // 158 | // // write data portion 159 | // for (size_t i = 0; i < gridSize50[0]; ++i) 160 | // { 161 | // for (size_t j = 0; j < gridSize50[1]; ++j) 162 | // { 163 | // for (size_t k = 0; k < gridSize50[2]; ++k) 164 | // { 165 | // double val = rasterData[i][j][k]; 166 | // nrrdFile.write((char*)&val, sizeof(double)); 167 | //// nrrdFile << std::setprecision(std::numeric_limits::digits10 + 1) << val << " "; 168 | // } 169 | // } 170 | // } 171 | // 172 | // nrrdFile.close(); 173 | // } 174 | // 175 | // std::ifstream baselineNrrdFile; 176 | // std::ostringstream oss; 177 | // oss << REGRESSION_DIR << "/testPrism.nrrd"; 178 | // baselineNrrdFile.open( oss.str().c_str(), std::ios::binary ); 179 | // baselineNrrdFile.exceptions( std::ofstream::failbit | std::ofstream::badbit ); 180 | // 181 | // std::string line; 182 | // if ( baselineNrrdFile.is_open() ) 183 | // { 184 | // std::getline(baselineNrrdFile, line); 185 | // std::cout << line << std::endl; 186 | // std::getline(baselineNrrdFile, line); 187 | // std::cout << line << std::endl; 188 | // std::getline(baselineNrrdFile, line); 189 | // std::cout << line << std::endl; 190 | // std::getline(baselineNrrdFile, line); 191 | // std::cout << line << std::endl; 192 | // std::getline(baselineNrrdFile, line); 193 | // std::cout << line << std::endl; 194 | // std::getline(baselineNrrdFile, line); 195 | // std::cout << line << std::endl; 196 | // std::getline(baselineNrrdFile, line); 197 | // std::cout << line << std::endl; 198 | // std::getline(baselineNrrdFile, line); 199 | // std::cout << line << std::endl; 200 | // std::getline(baselineNrrdFile, line); 201 | // std::cout << line << std::endl; 202 | // std::getline(baselineNrrdFile, line); 203 | // std::cout << line << std::endl; 204 | // std::getline(baselineNrrdFile, line); 205 | // std::cout << line << std::endl; 206 | // std::cout << baselineNrrdFile.tellg() << std::endl; 207 | // } 208 | } 209 | 210 | TEST_F(ConvexHull3DTest, PrismWithInternalPointBasicInterfaceTest) 211 | { 212 | RBFInterface rbfInterface( prismWithInternalPoint, origin0, 213 | gridSize50, gridSpacing1, 214 | normalOffset2, axisDataZ, 215 | true, false, ThinPlate ); 216 | 217 | const ScatteredData *data = rbfInterface.getSurfaceData(); 218 | ASSERT_TRUE( data != nullptr ); 219 | 220 | // // check scattered data setup, normal calculation for stability 221 | // std::vector x = { -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 0.0, -0.2265412489744628, -1.7734587510255371, 0.2058958485078267, 1.7941041514921734, 0.0, 0.0, -0.4384836277759048, -1.5615163722240952, 0.6029479320322761, 1.3970520679677239, 0.0, 0.0 }; 222 | // std::vector y = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.5, 0.3203771272650137, -0.3203771272650137, -0.2325877093742827, 0.2325877093742827, 0.1835037736389938, 1.8164962263610063, 0.2325877133161922, -0.2325877133161922, 0.7259807942675245, -0.7259807942675245, 0.0571912277167201, 1.9428087722832799}; 223 | // std::vector z = { 10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 5.0, 9.4530823069676728, 10.5469176930323272, 9.4384838105643816, 10.5615161894356184, 9.4226502293769805, 10.5773497706230195, 0.7941037281936285, -0.7941037281936285, 0.5615161784353572, -0.5615161784353572, 0.3333330950255075, -0.3333330950255075 }; 224 | // std::vector f = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 10.0, -10.0, 10.0, -10.0, 10.0, -10.0, 10.0, -10.0, 10.0, -10.0, 10.0, -10.0 }; 225 | // 226 | // ASSERT_EQ( x.size(), data->surfacePoints_[0].size() ); 227 | // ASSERT_EQ( y.size(), data->surfacePoints_[1].size() ); 228 | // ASSERT_EQ( z.size(), data->surfacePoints_[2].size() ); 229 | // ASSERT_EQ( f.size(), data->fnc_.size() ); 230 | // 231 | // for (size_t i = 0; i < x.size(); ++i ) 232 | // { 233 | // ASSERT_NEAR( x[i], data->surfacePoints_[0][i], 1.0e-10 ); 234 | // } 235 | // 236 | // for (size_t i = 0; i < y.size(); ++i ) 237 | // { 238 | // ASSERT_NEAR( y[i], data->surfacePoints_[1][i], 1.0e-10 ); 239 | // } 240 | // 241 | // for (size_t i = 0; i < z.size(); ++i ) 242 | // { 243 | // ASSERT_NEAR( z[i], data->surfacePoints_[2][i], 1.0e-10 ); 244 | // } 245 | // 246 | // for (size_t i = 0; i < f.size(); ++i ) 247 | // { 248 | // ASSERT_NEAR( f[i], data->fnc_[i], 1.0e-10 ); 249 | // } 250 | 251 | 252 | double threshold = rbfInterface.getThresholdValue(); 253 | ASSERT_EQ( threshold, 0 ); // default 254 | 255 | const auto rasterData = rbfInterface.getRasterData(); 256 | 257 | // std::string filename("testPrismWithInternalPoint.nrrd"); 258 | // std::cout << "Writing file '" << filename << "'" << std::endl; 259 | // std::ofstream nrrdFile(filename.c_str(), std::ofstream::binary); 260 | // nrrdFile.exceptions( std::ofstream::failbit | std::ofstream::badbit ); 261 | // 262 | // if ( nrrdFile.is_open() ) 263 | // { 264 | // nrrdFile << "NRRD0001" << std::endl; 265 | // nrrdFile << "# Complete NRRD file format specification at:" << std::endl; 266 | // nrrdFile << "# http://teem.sourceforge.net/nrrd/format.html" << std::endl; 267 | // nrrdFile << "type: double" << std::endl; 268 | // nrrdFile << "dimension: 3" << std::endl; 269 | // nrrdFile << "sizes: " << gridSize50[0] << " " << gridSize50[1] << " " << gridSize50[2] << std::endl; 270 | // nrrdFile << "axis mins: " << origin0[0] << ", " << origin0[1] << ", " << origin0[2] << std::endl; 271 | // nrrdFile << "spacings: " << gridSpacing1[0] << " " << gridSpacing1[1] << " " << gridSpacing1[2] << std::endl; 272 | //// nrrdFile << "centerings: cell cell cell" << std::endl; 273 | // nrrdFile << "centerings: node node node" << std::endl; 274 | // nrrdFile << "endian: little" << std::endl; 275 | // nrrdFile << "encoding: raw" << std::endl; 276 | // nrrdFile << std::endl; 277 | // 278 | // // write data portion 279 | // for (size_t i = 0; i < gridSize50[0]; ++i) 280 | // { 281 | // for (size_t j = 0; j < gridSize50[1]; ++j) 282 | // { 283 | // for (size_t k = 0; k < gridSize50[2]; ++k) 284 | // { 285 | // double val = rasterData[i][j][k]; 286 | // nrrdFile.write((char*)&val, sizeof(double)); 287 | // } 288 | // } 289 | // } 290 | // 291 | // nrrdFile.close(); 292 | // } 293 | // 294 | // std::ifstream baselineNrrdFile; 295 | // std::ostringstream oss; 296 | // oss << REGRESSION_DIR << "/testPrismWithInternalPoint.nrrd"; 297 | // baselineNrrdFile.open( oss.str().c_str(), std::ios::binary ); 298 | // baselineNrrdFile.exceptions( std::ofstream::failbit | std::ofstream::badbit ); 299 | // 300 | // std::string line; 301 | // if ( baselineNrrdFile.is_open() ) 302 | // { 303 | // std::getline(baselineNrrdFile, line); 304 | // std::cout << line << std::endl; 305 | // } 306 | } 307 | 308 | //TEST_F(ConvexHull3DTest, CubeBasicInterfaceTest) 309 | //{ 310 | // RBFInterface rbfInterface( cube, origin0, 311 | // gridSize50, gridSpacing1, 312 | // normalOffset10, axisDataZ, 313 | // true, false, ThinPlate ); 314 | // double threshold = rbfInterface.getThresholdValue(); 315 | // ASSERT_EQ( threshold, 0 ); // default 316 | //} 317 | // 318 | //TEST_F(ConvexHull3DTest, TetBasicInterfaceTest) 319 | //{ 320 | // RBFInterface rbfInterface( tet, origin0, 321 | // gridSize50, gridSpacing1, 322 | // normalOffset10, axisDataZ, 323 | // true, false, ThinPlate ); 324 | // double threshold = rbfInterface.getThresholdValue(); 325 | // ASSERT_EQ( threshold, 0 ); // default 326 | //} 327 | -------------------------------------------------------------------------------- /Tests/RBFInterfaceTests.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "RBFInterface.h" 34 | #include "vec3.h" 35 | 36 | // Note: empty point vector results in segfault 37 | // TODO: should be an error... 38 | 39 | class RBFInterfaceTest : public ::testing::Test 40 | { 41 | protected: 42 | virtual void SetUp() 43 | { 44 | pointsTriangleClockwise.push_back( vec3(9.02381, 36.8638, 10.0) ); 45 | pointsTriangleClockwise.push_back( vec3(34.8002, 36.8638, 10.0) ); 46 | pointsTriangleClockwise.push_back( vec3(20.2824, 14.4397, 10.0) ); 47 | gridSize50[0] = 50.0; gridSize50[1] = 50.0; gridSize50[2] = 50.0; 48 | gridSpacing1[0] = 1.0; gridSpacing1[1] = 1.0; gridSpacing1[2] = 1.0; 49 | normalOffset10 = 10; 50 | axisDataZ.insert(axisDataZ.begin(), 3, axis_t::Z); 51 | thinPlateKernel = ThinPlate; 52 | gaussianKernel = Gaussian; 53 | multiQuadKernel = MultiQuadratic; 54 | } 55 | 56 | // virtual void TearDown() {} 57 | std::vector pointsTriangleClockwise; // triangle 58 | vec3 origin0; // (0, 0, 0) 59 | vec3 gridSize50; // (50, 50, 50) 60 | vec3 gridSpacing1; // (1, 1, 1) 61 | double normalOffset10; 62 | std::vector axisDataZ; // #axis entries min 3 63 | Kernel thinPlateKernel; 64 | Kernel gaussianKernel; 65 | Kernel multiQuadKernel; 66 | }; 67 | 68 | TEST_F(RBFInterfaceTest, BasicInterfaceTestThinPlate) 69 | { 70 | RBFInterface rbfInterface( pointsTriangleClockwise, origin0, 71 | gridSize50, gridSpacing1, 72 | normalOffset10, axisDataZ, 73 | false, thinPlateKernel ); 74 | double threshold = rbfInterface.getThresholdValue(); 75 | ASSERT_EQ( threshold, 0 ); // default 76 | const auto rasterData = rbfInterface.getRasterData(); 77 | 78 | // TODO: check linear system numerics 79 | std::ifstream in; 80 | std::ostringstream oss; 81 | oss << REGRESSION_DIR << "/pointsTriangleClockwise.txt"; 82 | in.open( oss.str().c_str(), std::ios::binary ); 83 | in.exceptions( std::ofstream::failbit | std::ofstream::badbit ); 84 | 85 | for (size_t i = 0; i < gridSize50[0]; ++i) 86 | { 87 | for (size_t j = 0; j < gridSize50[1]; ++j) 88 | { 89 | for (size_t k = 0; k < gridSize50[2]; ++k) 90 | { 91 | std::string line; 92 | std::getline(in, line); 93 | //std::cerr << line << " vs " << rasterData[i][j][k] << std::endl; 94 | //double d = std::stod(line); 95 | } 96 | } 97 | } 98 | in.close(); 99 | } 100 | 101 | TEST_F(RBFInterfaceTest, BasicInterfaceTestGaussian) 102 | { 103 | RBFInterface rbfInterface( pointsTriangleClockwise, origin0, 104 | gridSize50, gridSpacing1, 105 | normalOffset10, axisDataZ, 106 | false, gaussianKernel ); 107 | double threshold = rbfInterface.getThresholdValue(); 108 | ASSERT_EQ( threshold, 0 ); // default 109 | const auto rasterData = rbfInterface.getRasterData(); 110 | 111 | // TODO: check linear system numerics 112 | std::ifstream in; 113 | std::ostringstream oss; 114 | oss << REGRESSION_DIR << "/pointsTriangleClockwise.txt"; 115 | in.open( oss.str().c_str(), std::ios::binary ); 116 | in.exceptions( std::ofstream::failbit | std::ofstream::badbit ); 117 | 118 | for (size_t i = 0; i < gridSize50[0]; ++i) 119 | { 120 | for (size_t j = 0; j < gridSize50[1]; ++j) 121 | { 122 | for (size_t k = 0; k < gridSize50[2]; ++k) 123 | { 124 | std::string line; 125 | std::getline(in, line); 126 | //std::cerr << line << " vs " << rasterData[i][j][k] << std::endl; 127 | //double d = std::stod(line); 128 | } 129 | } 130 | } 131 | in.close(); 132 | } 133 | 134 | TEST_F(RBFInterfaceTest, BasicInterfaceTestMultiQuad) 135 | { 136 | RBFInterface rbfInterface( pointsTriangleClockwise, origin0, 137 | gridSize50, gridSpacing1, 138 | normalOffset10, axisDataZ, 139 | false, multiQuadKernel ); 140 | double threshold = rbfInterface.getThresholdValue(); 141 | ASSERT_EQ( threshold, 0 ); // default 142 | const auto rasterData = rbfInterface.getRasterData(); 143 | 144 | // TODO: check linear system numerics 145 | std::ifstream in; 146 | std::ostringstream oss; 147 | oss << REGRESSION_DIR << "/pointsTriangleClockwise.txt"; 148 | in.open( oss.str().c_str(), std::ios::binary ); 149 | in.exceptions( std::ofstream::failbit | std::ofstream::badbit ); 150 | 151 | for (size_t i = 0; i < gridSize50[0]; ++i) 152 | { 153 | for (size_t j = 0; j < gridSize50[1]; ++j) 154 | { 155 | for (size_t k = 0; k < gridSize50[2]; ++k) 156 | { 157 | std::string line; 158 | std::getline(in, line); 159 | //std::cerr << line << " vs " << rasterData[i][j][k] << std::endl; 160 | //double d = std::stod(line); 161 | } 162 | } 163 | } 164 | in.close(); 165 | } 166 | -------------------------------------------------------------------------------- /Tests/RBFTests.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include 28 | 29 | #include "RBF.h" 30 | 31 | class RBFTest : public ::testing::Test 32 | { 33 | protected: 34 | virtual void SetUp() 35 | { 36 | std::vector xCoords10, yCoords10, zCoords10, func10; 37 | std::vector axisInfo10; 38 | for ( size_t i = 0; i < 10; ++i ) 39 | { 40 | xCoords10.push_back( static_cast(i) ); 41 | yCoords10.push_back( static_cast(i) ); 42 | zCoords10.push_back( static_cast(i) ); 43 | } 44 | 45 | func10.insert(func10.begin(), 10, 0); 46 | axisInfo10.insert(axisInfo10.begin(), 10, axis_t::Z); 47 | data.reset(new ScatteredData( xCoords10, yCoords10, zCoords10, func10, axisInfo10 )); 48 | } 49 | 50 | std::unique_ptr data; 51 | }; 52 | 53 | TEST_F(RBFTest, BasicSetup) 54 | { 55 | // TODO: need to expose getters to test RBF state 56 | RBF rbf(data.get(), ThinPlate); 57 | } 58 | -------------------------------------------------------------------------------- /Tests/ScatteredDataTests.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include 28 | 29 | #include "ScatteredData.h" 30 | 31 | class ScatteredDataTest : public ::testing::Test 32 | { 33 | protected: 34 | virtual void SetUp() 35 | { 36 | for ( size_t i = 0; i < 10; ++i ) 37 | { 38 | xCoords10.push_back( static_cast(i) ); 39 | yCoords10.push_back( static_cast(i) ); 40 | zCoords10.push_back( static_cast(i) ); 41 | } 42 | 43 | func10.insert(func10.begin(), 10, 0); 44 | axisInfo10.insert(axisInfo10.begin(), 10, axis_t::Z); 45 | } 46 | 47 | // virtual void TearDown() {} 48 | 49 | std::vector xCoords10, yCoords10, zCoords10, func10; 50 | std::vector axisInfo10; 51 | }; 52 | 53 | // TODO: what happens if vector sizes don't match??? 54 | 55 | TEST_F(ScatteredDataTest, DefaultConstructor) 56 | { 57 | ScatteredData data; 58 | ASSERT_EQ( data.surfacePoints_[0].size(), 0 ); 59 | ASSERT_EQ( data.surfacePoints_[1].size(), 0 ); 60 | ASSERT_EQ( data.surfacePoints_[2].size(), 0 ); 61 | ASSERT_EQ( data.leftovers_[0].size(), 0 ); 62 | ASSERT_EQ( data.leftovers_[1].size(), 0 ); 63 | ASSERT_EQ( data.leftovers_[2].size(), 0 ); 64 | ASSERT_EQ( data.fnc_.size(), 0 ); 65 | ASSERT_EQ( data.axisInformation_.size(), 0 ); 66 | ASSERT_EQ( data.updatedAxisInformation_.size(), 0 ); 67 | ASSERT_EQ( data.origSize_, 0 ); 68 | } 69 | 70 | TEST_F(ScatteredDataTest, SimpleSetup10) 71 | { 72 | ScatteredData data( xCoords10, yCoords10, zCoords10, func10, axisInfo10 ); 73 | ASSERT_EQ( data.surfacePoints_[0].size(), 10 ); 74 | ASSERT_EQ( data.surfacePoints_[1].size(), 10 ); 75 | ASSERT_EQ( data.surfacePoints_[2].size(), 10 ); 76 | ASSERT_EQ( data.leftovers_[0].size(), 0 ); 77 | ASSERT_EQ( data.leftovers_[1].size(), 0 ); 78 | ASSERT_EQ( data.leftovers_[2].size(), 0 ); 79 | ASSERT_EQ( data.fnc_.size(), 10 ); 80 | ASSERT_EQ( data.axisInformation_.size(), 10 ); 81 | ASSERT_EQ( data.updatedAxisInformation_.size(), 10 ); 82 | ASSERT_EQ( data.origSize_, 10 ); 83 | 84 | for (size_t i = 0; i < 10; ++i) 85 | { 86 | ASSERT_EQ( data.surfacePoints_[0][i], static_cast(i) ); 87 | ASSERT_EQ( data.surfacePoints_[1][i], static_cast(i) ); 88 | ASSERT_EQ( data.surfacePoints_[2][i], static_cast(i) ); 89 | ASSERT_EQ( data.fnc_[i], 0 ); 90 | ASSERT_EQ( data.axisInformation_[i], axis_t::Z ); 91 | ASSERT_EQ( data.updatedAxisInformation_[i], axis_t::Z ); 92 | } 93 | } 94 | 95 | TEST_F(ScatteredDataTest, SimpleSetData10) 96 | { 97 | ScatteredData data( xCoords10, yCoords10, zCoords10, func10, axisInfo10 ); 98 | ASSERT_EQ( data.surfacePoints_[0].size(), 10 ); 99 | ASSERT_EQ( data.surfacePoints_[1].size(), 10 ); 100 | ASSERT_EQ( data.surfacePoints_[2].size(), 10 ); 101 | ASSERT_EQ( data.leftovers_[0].size(), 0 ); 102 | ASSERT_EQ( data.leftovers_[1].size(), 0 ); 103 | ASSERT_EQ( data.leftovers_[2].size(), 0 ); 104 | ASSERT_EQ( data.fnc_.size(), 10 ); 105 | ASSERT_EQ( data.axisInformation_.size(), 10 ); 106 | ASSERT_EQ( data.updatedAxisInformation_.size(), 10 ); 107 | ASSERT_EQ( data.origSize_, 10 ); 108 | 109 | for (size_t i = 0; i < 10; ++i) 110 | { 111 | ASSERT_EQ( data.surfacePoints_[0][i], static_cast(i) ); 112 | ASSERT_EQ( data.surfacePoints_[1][i], static_cast(i) ); 113 | ASSERT_EQ( data.surfacePoints_[2][i], static_cast(i) ); 114 | ASSERT_EQ( data.fnc_[i], 0 ); 115 | ASSERT_EQ( data.axisInformation_[i], axis_t::Z ); 116 | ASSERT_EQ( data.updatedAxisInformation_[i], axis_t::Z ); 117 | } 118 | 119 | double newVal = 501.0; 120 | std::vector newXCoords10(xCoords10); 121 | newXCoords10[5] = newVal; 122 | 123 | data.setData( newXCoords10, yCoords10, zCoords10, func10 ); 124 | ASSERT_EQ( data.surfacePoints_[0].size(), 10 ); 125 | ASSERT_EQ( data.surfacePoints_[1].size(), 10 ); 126 | ASSERT_EQ( data.surfacePoints_[2].size(), 10 ); 127 | ASSERT_EQ( data.leftovers_[0].size(), 0 ); 128 | ASSERT_EQ( data.leftovers_[1].size(), 0 ); 129 | ASSERT_EQ( data.leftovers_[2].size(), 0 ); 130 | ASSERT_EQ( data.fnc_.size(), 10 ); 131 | ASSERT_EQ( data.axisInformation_.size(), 10 ); 132 | ASSERT_EQ( data.updatedAxisInformation_.size(), 10 ); 133 | ASSERT_EQ( data.origSize_, 10 ); 134 | 135 | for (size_t i = 0; i < 10; ++i) 136 | { 137 | if (i == 5) 138 | { 139 | ASSERT_EQ( data.surfacePoints_[0][i], newVal ); 140 | } 141 | else 142 | { 143 | ASSERT_EQ( data.surfacePoints_[0][i], static_cast(i) ); 144 | } 145 | ASSERT_EQ( data.surfacePoints_[1][i], static_cast(i) ); 146 | ASSERT_EQ( data.surfacePoints_[2][i], static_cast(i) ); 147 | ASSERT_EQ( data.fnc_[i], 0 ); 148 | ASSERT_EQ( data.axisInformation_[i], axis_t::Z ); 149 | ASSERT_EQ( data.updatedAxisInformation_[i], axis_t::Z ); 150 | } 151 | } -------------------------------------------------------------------------------- /Tests/Seg3DIntegrationTest.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "RBFInterface.h" 36 | #include "vec3.h" 37 | 38 | typedef std::vector< std::string > ViewModeList; 39 | 40 | class Seg3DIntegrationTest : public ::testing::Test 41 | { 42 | protected: 43 | virtual void SetUp() 44 | { 45 | view_modes_.assign(modelPointData.size(), "axial"); 46 | 47 | for ( const auto& mode : view_modes_ ) 48 | { 49 | if ( mode == "sagittal" ) // X 50 | { 51 | axisData_.push_back(axis_t::X); 52 | } 53 | else if (mode == "coronal" ) // Y 54 | { 55 | axisData_.push_back(axis_t::Y); 56 | } 57 | else if ( mode == "axial" ) // Z 58 | { 59 | axisData_.push_back(axis_t::Z); 60 | } 61 | else 62 | { 63 | throw "Invalid viewer mode"; 64 | } 65 | } 66 | } 67 | 68 | //TODO: loop this [0,20] 69 | double normalOffset_ {2.0}; 70 | //TODO: loop over these bools 71 | bool compute2DConvexHull_ {false}, invertSeedOrder_ {false}; 72 | //TODO: loop over kernels 73 | //enum Kernel { Gaussian, ThinPlate, MultiQuadratic }; 74 | Kernel kernel_ {ThinPlate}; 75 | 76 | std::vector expected_data_{-2701.018664769188, -1880.7781485604355, 77 | -1491.0771375730401, -604.78687230695505, -14.501352507455977, 78 | -631.7780323674524, -2885.3566775373765, 1.297055274867603}; 79 | 80 | std::vector modelPointData = { 81 | {329.27408562074709, -3.1975149796730840, 477.29595999999998 } 82 | , {312.11090641613799, -17.909120331180826, 477.29595999999998 } 83 | , {311.62052986743487, -40.630377485176155, 477.29595999999998 } 84 | , {324.86069668241902, -53.707360019849709, 477.29595999999998 } 85 | , {326.65874402766383, -46.515019625779246, 477.29595999999998 } 86 | , {324.69723783285133, -25.918772133668394, 477.29595999999998 } 87 | , {311.78398871700256, -39.486141513392205, 478.19439699999998 } 88 | , {313.09165951354419, -19.380280866331621, 478.19439699999998 } 89 | , {330.58175641728877, -4.6686755148238497, 478.19439699999998 } 90 | , {325.35107323112214, -25.264923006934715, 478.19439699999998 } 91 | , {326.65874402766383, -44.880396808945051, 478.19439699999998 } 92 | , {323.71648473544508, -53.543897738166287, 478.19439699999998 } 93 | , {329.92792101901790, -5.8129114866077956, 479.09283399999998 } 94 | , {313.90895376138275, -21.341828246532643, 479.09283399999998 } 95 | , {313.58203606224731, -36.707282724774082, 479.09283399999998 } 96 | , {323.71648473544508, -49.784265259447636, 479.09283399999998 } 97 | , {326.82220287723152, -43.409236273794278, 479.09283399999998 } 98 | , {324.86069668241902, -25.918772133668394, 479.09283399999998 } 99 | }; 100 | 101 | ViewModeList view_modes_; 102 | std::vector axisData_; 103 | 104 | vec3 modelOrigin_ {229.25999999999999, -126.41900000000000, 405.42099999999999 }; 105 | vec3 modelGridSize_ {160.00000000000000, 232.00000000000000, 160.00000000000000 }; 106 | vec3 modelGridSpacing_ {1.0000000000000000, 0.89843700000000004, 0.89843700000000004 }; 107 | }; 108 | 109 | TEST_F(Seg3DIntegrationTest, ImplicitModel) 110 | { 111 | RBFInterface modelAlgo( modelPointData, 112 | modelOrigin_, modelGridSize_, modelGridSpacing_, 113 | normalOffset_, axisData_, 114 | compute2DConvexHull_, invertSeedOrder_, kernel_ ); 115 | 116 | auto thresholdValue = modelAlgo.getThresholdValue(); 117 | 118 | EXPECT_EQ(0.0, thresholdValue); 119 | 120 | const auto rasterData = modelAlgo.getRasterData(); 121 | 122 | EXPECT_EQ(rasterData->size1(), 160); 123 | EXPECT_EQ(rasterData->size2(), 232); 124 | EXPECT_EQ(rasterData->size3(), 160); 125 | 126 | EXPECT_NEAR(rasterData->get(0,0,0), expected_data_[0], 1.0e-7); 127 | EXPECT_NEAR(rasterData->get(3,12,80), expected_data_[1], 1.0e-7); 128 | EXPECT_NEAR(rasterData->get(7,31,92), expected_data_[2], 1.0e-7); 129 | EXPECT_NEAR(rasterData->get(39,57,39), expected_data_[3], 1.0e-7); 130 | EXPECT_NEAR(rasterData->get(79,115,79), expected_data_[4], 1.0e-7); 131 | EXPECT_NEAR(rasterData->get(119,173,119), expected_data_[5], 1.0e-7); 132 | EXPECT_NEAR(rasterData->get(159,231,159), expected_data_[6], 1.0e-7); 133 | EXPECT_NEAR(rasterData->get(90,112,80), expected_data_[7], 1.0e-7); 134 | 135 | auto numPositiveInSlice = [](const DataStorage::Slice& slice) 136 | { 137 | return std::count_if( 138 | slice.first, slice.second, 139 | [](double x) {return x > 0;}); 140 | }; 141 | 142 | EXPECT_EQ(0, numPositiveInSlice(rasterData->slice(3))); 143 | EXPECT_EQ(0, numPositiveInSlice(rasterData->slice(80))); 144 | EXPECT_EQ(954, numPositiveInSlice(rasterData->slice(90))); 145 | EXPECT_EQ(297, numPositiveInSlice(rasterData->slice(100))); 146 | EXPECT_EQ(0, numPositiveInSlice(rasterData->slice(159))); 147 | 148 | // for (auto i = 0; i < rasterData.size(); ++i) 149 | // { 150 | // std::cout << "#positive[" << i << "]:" << 151 | // numPositiveInSlice(rasterData[i]) 152 | // << std::endl; 153 | // } 154 | 155 | // for(auto i = 0; i < rasterData[90].size(); ++i) 156 | // for(auto j = 0; j < rasterData[90][i].size(); ++j) 157 | // { 158 | // if(rasterData[90][i][j] > 0) 159 | // { 160 | // std::cout << std::setprecision(16) << i << " " << j << " " << rasterData[90][i][j] << std::endl; 161 | // break; 162 | // } 163 | // } 164 | 165 | //TODO: convert to move semantics for seg3d datablock usage 166 | #if 0 167 | for (size_t i = 0; i < dstDataBlock->get_nx(); ++i) 168 | { 169 | for (size_t j = 0; j < dstDataBlock->get_ny(); ++j) 170 | { 171 | for (size_t k = 0; k < dstDataBlock->get_nz(); ++k) 172 | { 173 | dstDataBlock->set_data_at( i, j, k, rasterData[i][j][k] ); 174 | } 175 | } 176 | } 177 | #endif 178 | } 179 | -------------------------------------------------------------------------------- /Tests/Vec3Tests.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #include 28 | 29 | #include 30 | 31 | #include "vec3.h" 32 | 33 | class Vec3Test : public ::testing::Test 34 | { 35 | protected: 36 | virtual void SetUp() 37 | { 38 | sample1Vec[0] = 1.0, sample1Vec[1] = 2.0, sample1Vec[2] = 3.0; 39 | sample2Vec[0] = 1.5, sample2Vec[1] = 2.0, sample2Vec[2] = 3.0; 40 | sample3Vec[0] = 1.01, sample3Vec[1] = 2.01, sample3Vec[2] = 3.01; 41 | } 42 | 43 | // virtual void TearDown() {} 44 | vec3 emptyVec, sampleSetterVec, sample1Vec, sample2Vec, sample3Vec; 45 | }; 46 | 47 | TEST_F(Vec3Test, EmptyVec) 48 | { 49 | ASSERT_EQ( emptyVec[0], 0 ); 50 | ASSERT_EQ( emptyVec[1], 0 ); 51 | ASSERT_EQ( emptyVec[2], 0 ); 52 | } 53 | 54 | TEST_F(Vec3Test, ZeroVec) 55 | { 56 | ASSERT_EQ( vec3::zero[0], 0 ); 57 | ASSERT_EQ( vec3::zero[1], 0 ); 58 | ASSERT_EQ( vec3::zero[2], 0 ); 59 | } 60 | 61 | TEST_F(Vec3Test, UnitXVec) 62 | { 63 | ASSERT_EQ( vec3::unitX[0], 1 ); 64 | ASSERT_EQ( vec3::unitX[1], 0 ); 65 | ASSERT_EQ( vec3::unitX[2], 0 ); 66 | } 67 | 68 | TEST_F(Vec3Test, UnitYVec) 69 | { 70 | ASSERT_EQ( vec3::unitY[0], 0 ); 71 | ASSERT_EQ( vec3::unitY[1], 1 ); 72 | ASSERT_EQ( vec3::unitY[2], 0 ); 73 | } 74 | 75 | TEST_F(Vec3Test, UnitZVec) 76 | { 77 | ASSERT_EQ( vec3::unitZ[0], 0 ); 78 | ASSERT_EQ( vec3::unitZ[1], 0 ); 79 | ASSERT_EQ( vec3::unitZ[2], 1 ); 80 | } 81 | 82 | TEST_F(Vec3Test, Sample1Vec) 83 | { 84 | ASSERT_EQ( sample1Vec[0], 1.0 ); 85 | ASSERT_EQ( sample1Vec[1], 2.0 ); 86 | ASSERT_EQ( sample1Vec[2], 3.0 ); 87 | } 88 | 89 | TEST_F(Vec3Test, Sample2VecGetters) 90 | { 91 | ASSERT_EQ( sample2Vec.x(), 1.5 ); 92 | ASSERT_EQ( sample2Vec.y(), 2.0 ); 93 | ASSERT_EQ( sample2Vec.z(), 3.0 ); 94 | } 95 | 96 | TEST_F(Vec3Test, Sample2VecSetters) 97 | { 98 | sampleSetterVec.x( 141.0 ); 99 | sampleSetterVec.y( 400.0 ); 100 | sampleSetterVec.z( 999.98 ); 101 | 102 | ASSERT_EQ( sampleSetterVec.x(), 141.0 ); 103 | ASSERT_EQ( sampleSetterVec.y(), 400.0 ); 104 | ASSERT_EQ( sampleSetterVec.z(), 999.98 ); 105 | } 106 | 107 | TEST_F(Vec3Test, NotEqual) 108 | { 109 | ASSERT_TRUE( sample1Vec != sample2Vec ); 110 | } 111 | 112 | TEST_F(Vec3Test, GreaterThanEq) 113 | { 114 | ASSERT_TRUE( sample2Vec >= sample1Vec ); 115 | } 116 | 117 | TEST_F(Vec3Test, GreaterThan) 118 | { 119 | ASSERT_TRUE( sample3Vec > sample1Vec ); 120 | ASSERT_TRUE( sample2Vec > sample1Vec ); 121 | } 122 | 123 | TEST_F(Vec3Test, LessThanEq) 124 | { 125 | ASSERT_TRUE( sample1Vec <= sample2Vec ); 126 | } 127 | 128 | TEST_F(Vec3Test, LessThan) 129 | { 130 | ASSERT_TRUE( sample1Vec < sample3Vec ); 131 | ASSERT_TRUE( sample1Vec < sample2Vec ); 132 | } 133 | -------------------------------------------------------------------------------- /UseImplicitFunction.cmake: -------------------------------------------------------------------------------- 1 | include_directories(${ImplicitFunction_INCLUDE}) 2 | link_directories(${ImplicitFunction_LIBRARY_DIR}) 3 | -------------------------------------------------------------------------------- /fileIO.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | #ifndef _FILEIO_H_ 28 | #define _FILEIO_H_ 29 | 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "vec3.h" 37 | 38 | using std::vector; 39 | using std::string; 40 | 41 | void writeNrrdFile(string filename, vector > > &myArray, vec3 myDim, vec3 mySpacing) 42 | { 43 | std::cout << "Writing file '" << filename << "'" << std::endl; 44 | std::ofstream nrrd_file(filename.c_str(), std::ofstream::binary); 45 | 46 | if(nrrd_file.is_open()) 47 | { 48 | nrrd_file << "NRRD0001" << std::endl; 49 | nrrd_file << "# Complete NRRD file format specification at:" << std::endl; 50 | nrrd_file << "# http://teem.sourceforge.net/nrrd/format.html" << std::endl; 51 | nrrd_file << "type: float" << std::endl; 52 | nrrd_file << "dimension: 3" << std::endl; 53 | nrrd_file << "sizes: " << myDim[0] << " " << myDim[1] << " " << myDim[2] << std::endl; 54 | nrrd_file << "axis mins: " << 0 << ", " << 0 << ", " << 0 << std::endl; 55 | nrrd_file << "spacings: " << mySpacing[0] << " " << mySpacing[1] << " " << mySpacing[2] << std::endl; 56 | nrrd_file << "centerings: cell cell cell" << std::endl; 57 | nrrd_file << "endian: little" << std::endl; 58 | nrrd_file << "encoding: raw" << std::endl; 59 | nrrd_file << std::endl; 60 | 61 | // write data portion 62 | for(int k=0; k < myDim[2]; k++) 63 | { 64 | for(int j=0; j < myDim[1]; j++) 65 | { 66 | for(int i=0; i < myDim[0]; i++) 67 | { 68 | float val = myArray[i][j][k]; 69 | nrrd_file.write((char*)&val, sizeof(float)); 70 | } 71 | } 72 | } 73 | 74 | nrrd_file.close(); 75 | } 76 | } 77 | 78 | void augmentData(ScatteredData *data) 79 | { 80 | int n = data->x[0].size(); 81 | int increment[] = {0,0,100}; 82 | for(int i=0; ix[j].push_back(data->x[j][i] + increment[j]); 87 | } 88 | data->fnc.push_back(10); 89 | } 90 | for(int i=0; ix[j].push_back(data->x[j][i] - increment[j]); 95 | } 96 | data->fnc.push_back(-10); 97 | } 98 | } 99 | 100 | vec3 findNormal(ScatteredData *data, int n) 101 | { 102 | int tot = data->x[0].size(); 103 | int prev = (n-1)>=0?n-1:tot-1; 104 | int next = (n+1)x[2][prev]!=data->x[2][n]) 107 | { 108 | prev = (prev-1)>=0?prev-1:tot-1; 109 | } 110 | 111 | while(data->x[2][next]!=data->x[2][n]) 112 | { 113 | next = (next+1)x[0][n], data->x[1][n], data->x[2][n]); 118 | vec3 b(data->x[0][prev], data->x[1][prev], data->x[2][prev]); 119 | vec3 c(data->x[0][next], data->x[1][next], data->x[2][next]); 120 | /*vec3 one = b-a; 121 | vec3 two = c-a; 122 | vec3 ret = one+two;*/ 123 | 124 | vec3 tangent = b-c; 125 | //rotate by 90 degrees on the x-y plane 126 | double ret_x = -tangent[1]; 127 | double ret_y = tangent[0]; 128 | vec3 ret(ret_x, ret_y, tangent[2]); 129 | return ret; 130 | } 131 | 132 | void augmentNormalData(ScatteredData *data) 133 | { 134 | int n = data->x[0].size(); 135 | for(int i=0; ix[j].push_back(data->x[j][i] + myNormal[j]); 142 | } 143 | data->fnc.push_back(10); 144 | 145 | for(int j=0; j<3; j++) 146 | { 147 | data->x[j].push_back(data->x[j][i] - myNormal[j]); 148 | } 149 | data->fnc.push_back(-10); 150 | } 151 | } 152 | 153 | void readDataFile(string filename, ScatteredData *data) 154 | { 155 | std::cout <<"Reading file '" << filename <<"'"<>myData[0]>>myData[1]>>myData[2]; 164 | for(int i=0; i<3; i++) 165 | data->x[i].push_back(myData[i]); 166 | data->fnc.push_back(0); 167 | } 168 | std::cout<<"Done"<>myData[0]>>myData[1]>>myData[2]; 191 | for(int i=0; i<3; i++) 192 | data->x[i].push_back(myData[i]); 193 | data->fnc.push_back(0); 194 | data->axisInformation.push_back(Z); 195 | } 196 | for(int i=0; i<3; i++) 197 | data->x[i].pop_back(); 198 | data->fnc.pop_back(); 199 | std::cout<<"Done"<computeOrdering(); 201 | int n = data->origSize = data->x[0].size(); 202 | vec3 sum(0,0,0); 203 | for(int i=0; ix[j][i]; 208 | } 209 | } 210 | for(int j=0; j<3; j++) 211 | { 212 | sum[j]/=n; 213 | } 214 | //std::cout<<"Augmenting data here B"< 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ScatteredData.h" 10 | #include "vec3.h" 11 | #include "SampleData.h" 12 | #include "SparseMatrix.h" 13 | #include "LinearSolver.h" 14 | #include "RBF.h" 15 | #include "fault.h" 16 | #include "Surface.h" 17 | #include "structure.h" 18 | #include "API.h" 19 | 20 | 21 | using std::vector; 22 | using std::string; 23 | 24 | void constructRBFforSampleData() 25 | { 26 | ScatteredData *myData; 27 | vector > > value; 28 | value.resize(100); 29 | 30 | myData = new ScatteredData(); 31 | 32 | readFunctionData(myData); 33 | Kernel myKernel = ThinPlate; 34 | RBF myRBF(myData, myKernel); 35 | myRBF.setAcceleration(FastMultipole); 36 | myRBF.setDataReduction(Random); 37 | myRBF.computeFunction(); 38 | for(int i=0; i<100; i++) 39 | { 40 | if(i%10==0) 41 | printf("%d/100 done\n", i); fflush(stdout); 42 | value[i].resize(100); 43 | for(int j=0; j<100; j++) 44 | { 45 | value[i][j].resize(100); 46 | for(int k=0; k<100; k++) 47 | { 48 | vec3 location = i*vec3::unitX + j*vec3::unitY + k*vec3::unitZ; 49 | double val = myRBF.computeValue(location); 50 | value[i][j][k]=val; 51 | //printf("Interpolant: %lf %lf %lf %lf\n", location[0], location[1], location[2], val); fflush(stdout); 52 | } 53 | } 54 | } 55 | 56 | vec3 dim(100,100,100); 57 | vec3 spacing(1,1,1); 58 | string filename = "sphere.nrrd"; 59 | //writeNrrdFile(filename, value, dim, spacing); 60 | } 61 | 62 | void aSimpleCase() 63 | { 64 | //Take the input 65 | ScatteredData *mySurfaceData; 66 | mySurfaceData = new ScatteredData(); 67 | 68 | //readSurfaceDataFile("./segmentation/sample_points_DEMRI.txt", mySurfaceData); 69 | vector mySurface; 70 | 71 | RBF *mySurfaceRBF; 72 | Kernel myKernel = ThinPlate; 73 | 74 | mySurfaceRBF = new RBF(mySurfaceData, myKernel); 75 | mySurfaceRBF->setDataReduction(Random); 76 | 77 | mySurface.push_back(new Surface(mySurfaceData, mySurfaceRBF)); 78 | 79 | 80 | //Construct RBFs 81 | mySurface[0]->computeRBF(); 82 | 83 | 84 | //Compute material 85 | vector > > value; 86 | value.resize(100); 87 | vec3 myOrigin(-30, -50, 80); 88 | for(int i=0; i<100; i++) 89 | { 90 | if(i%10==0) 91 | printf("%d/100 done\n", i); fflush(stdout); 92 | value[i].resize(100); 93 | for(int j=0; j<100; j++) 94 | { 95 | //if(j%10==0) 96 | // printf("\t%d/100 done\n", j); fflush(stdout); 97 | value[i][j].resize(100); 98 | for(int k=0; k<100; k++) 99 | { 100 | //if(k%10==0) 101 | // printf("\t\t%d/100 done\n", k); fflush(stdout); 102 | vec3 location = myOrigin + 0.6*i*vec3::unitX + 0.5*j*vec3::unitY + 0.1*k*vec3::unitZ; 103 | //std::cout<<"Computing Val ... "<computeValue(location); 105 | //printf("Interpolant: %lf %lf %lf %lf\n", location[0], location[1], location[2], myVal); fflush(stdout); 106 | value[i][j][k]=myVal; 107 | } 108 | } 109 | } 110 | 111 | vec3 dim(100,100,100); 112 | vec3 spacing(0.6,0.5,0.1); 113 | string filename = "surface.nrrd"; 114 | //writeNrrdFile(filename, value, dim, spacing); 115 | } 116 | 117 | void getAPI() 118 | { 119 | API *myAPI; 120 | myAPI = new API("./segmentation/sample_points_DEMRI.txt", "dummy"); 121 | } 122 | 123 | 124 | int main() 125 | { 126 | //constructRBFforSampleData(); 127 | //aSimpleCase(); 128 | getAPI(); 129 | //aComplicatedCase(); 130 | //aSimpleCase2(); 131 | //aComplicatedCase2(); 132 | return 0; 133 | } 134 | 135 | -------------------------------------------------------------------------------- /segmentation/original.txt: -------------------------------------------------------------------------------- 1 | -0.009749965466282262 -9.912165437127271 87.26 2 | 20.374263742141693 -22.382373895334435 87.26 3 | 15.817837148676354 -36.531264261377174 87.26 4 | 5.745736257858331 -42.28674508824203 87.26 5 | -6.484671966706447 -39.88862807704833 87.26 6 | -14.158653597805905 -29.81653663003486 87.26 7 | -12.00034626405919 -20.463880286379492 87.26 8 | -7.923543522537589 -13.029717551679063 84.76 9 | 7.184607813689474 -10.391788839366003 84.76 10 | 15.338213296732652 -14.22877605727591 84.76 11 | 19.894639890197954 -27.658231319960535 84.76 12 | 11.021598629239204 -39.88862807704833 84.76 13 | -1.2088095953255547 -41.80712168600328 84.76 14 | -12.240158190031039 -36.051640859138445 84.76 15 | -15.117901301693347 -26.21936111324434 84.76 16 | -11.280910486143618 -16.147269666230855 84.76 17 | -------------------------------------------------------------------------------- /segmentation/sample_points_DEMRI.txt: -------------------------------------------------------------------------------- 1 | -6.484671966706447 -39.88862807704833 87.26 2 | -10.484671966706447 -10.88862807704833 87.26 3 | -0.484671966706447 -0.88862807704833 87.26 4 | -0.484671966706447 -100.88862807704833 87.26 5 | -100.484671966706447 -0.88862807704833 87.26 6 | -100.484671966706447 -100.88862807704833 87.26 7 | -1.2088095953255547 -41.80712168600328 84.76 8 | -12.240158190031039 -36.051640859138445 84.76 9 | 19.894639890197954 -27.658231319960535 84.76 10 | -12.00034626405919 -20.463880286379492 87.26 11 | -7.923543522537589 -13.029717551679063 84.76 12 | 7.184607813689474 -10.391788839366003 84.76 13 | 15.338213296732652 -14.22877605727591 84.76 14 | -0.009749965466282262 -9.912165437127271 87.26 15 | 20.374263742141693 -22.382373895334435 87.26 16 | 11.021598629239204 -39.88862807704833 84.76 17 | -15.117901301693347 -26.21936111324434 84.76 18 | -11.280910486143618 -16.147269666230855 84.76 19 | -14.158653597805905 -29.81653663003486 87.26 20 | 15.817837148676354 -36.531264261377174 87.26 21 | 5.745736257858331 -42.28674508824203 87.26 22 | -0.484671966706447 -0.88862807704833 88.26 23 | -0.484671966706447 -100.88862807704833 88.26 24 | -100.484671966706447 -0.88862807704833 89.26 25 | -100.484671966706447 -100.88862807704833 89.26 26 | -0.484671966706447 -0.88862807704833 89.26 27 | -0.484671966706447 -100.88862807704833 89.26 28 | -100.484671966706447 -0.88862807704833 88.26 29 | -100.484671966706447 -100.88862807704833 88.26 30 | -50.484671966706447 -50.88862807704833 88.26 31 | -------------------------------------------------------------------------------- /vec3.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | //------------------------------------------------------------------- 3 | // 4 | // Permission is hereby granted, free of charge, to any person 5 | // obtaining a copy of this software and associated documentation 6 | // files ( the "Software" ), to deal in the Software without 7 | // restriction, including without limitation the rights to use, 8 | // copy, modify, merge, publish, distribute, sublicense, and/or 9 | // sell copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following 11 | // conditions: 12 | // 13 | // The above copyright notice and this permission notice shall 14 | // be included in all copies or substantial portions of the 15 | // Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 18 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 19 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 20 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | //------------------------------------------------------------------- 26 | //------------------------------------------------------------------- 27 | 28 | 29 | #include "vec3.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | using namespace std; 36 | 37 | 38 | // static variables 39 | vec3 vec3::zero(0,0,0); 40 | vec3 vec3::unitX(1,0,0); 41 | vec3 vec3::unitY(0,1,0); 42 | vec3 vec3::unitZ(0,0,1); 43 | const double vec3::PI = 3.14159265; 44 | 45 | vec3::vec3() : data_{0,0,0} 46 | { 47 | } 48 | 49 | vec3::vec3(double x, double y, double z) : data_{x,y,z} 50 | { 51 | } 52 | 53 | bool vec3::operator!=(const vec3 &a) const 54 | { 55 | if(this->x() != a.x() || 56 | this->y() != a.y() || 57 | this->z() != a.z()) 58 | return true; 59 | else 60 | return false; 61 | } 62 | 63 | bool vec3::operator==(const vec3 &a) const 64 | { 65 | return(this->x() == a.x() && 66 | this->y() == a.y() && 67 | this->z() == a.z()); 68 | } 69 | 70 | bool vec3::operator<=(const vec3 &a) const 71 | { 72 | return *this < a || *this == a; 73 | } 74 | 75 | bool vec3::operator>=(const vec3 &a) const 76 | { 77 | return *this > a || *this == a; 78 | } 79 | 80 | bool vec3::operator<(const vec3 &a) const 81 | { 82 | if (x() < a.x()) 83 | return true; 84 | if (x() > a.x()) 85 | return false; 86 | 87 | // equal x 88 | if (y() < a.y()) 89 | return true; 90 | if (y() > a.y()) 91 | return false; 92 | 93 | // equal x and y 94 | if (z() < a.z()) 95 | return true; 96 | if (z() > a.z()) 97 | return false; 98 | 99 | return false; 100 | } 101 | 102 | bool vec3::operator>(const vec3 &a) const 103 | { 104 | return a < *this; 105 | } 106 | 107 | vec3& vec3::operator=(const vec3 &a) 108 | { 109 | this->x() = a.x(); 110 | this->y() = a.y(); 111 | this->z() = a.z(); 112 | 113 | return *this; 114 | } 115 | 116 | vec3& vec3::operator+=(const vec3 &a) 117 | { 118 | this->x() += a.x(); 119 | this->y() += a.y(); 120 | this->z() += a.z(); 121 | 122 | return *this; 123 | } 124 | 125 | vec3& vec3::operator*=(double c) 126 | { 127 | this->x() *= c; 128 | this->y() *= c; 129 | this->z() *= c; 130 | 131 | return *this; 132 | } 133 | 134 | vec3& vec3::operator/=(double c) 135 | { 136 | // TODO: throw exception if c == 0 137 | this->x() /= c; 138 | this->y() /= c; 139 | this->z() /= c; 140 | return *this; 141 | } 142 | 143 | double& vec3::operator[](const size_t idx) 144 | { 145 | return data_[idx]; 146 | } 147 | 148 | // TODO: Restructure this class so this lookup is FASTER 149 | double vec3::operator[](const size_t idx) const 150 | { 151 | return data_[idx]; 152 | } 153 | 154 | double vec3::dot(const vec3 &b) const 155 | { 156 | return this->x()*b.x() + this->y()*b.y() + this->z()*b.z(); 157 | } 158 | 159 | vec3 vec3::cross(const vec3 &b) 160 | { 161 | return vec3(this->y()*b.z() - this->z()*b.y(), this->z()*b.x() - this->x()*b.z(), this->x()*b.y() - this->y()*b.x()); 162 | } 163 | 164 | vec3 cross(const vec3 &a, const vec3 &b) 165 | { 166 | return vec3(a.y()*b.z() - a.z()*b.y(), a.z()*b.x() - a.x()*b.z(), a.x()*b.y() - a.y()*b.x()); 167 | } 168 | 169 | double dot(const vec3 &a, const vec3 &b) 170 | { 171 | return a.x()*b.x() + a.y()*b.y() + a.z()*b.z(); 172 | } 173 | 174 | double length(const vec3 &a) 175 | { 176 | return sqrt(a.x()*a.x() + a.y()*a.y() + a.z()*a.z()); 177 | } 178 | 179 | double lengthSquared(const vec3 &a) 180 | { 181 | return a.x()*a.x() + a.y()*a.y() + a.z()*a.z(); 182 | } 183 | 184 | double distance(const vec3 &a, const vec3 &b) 185 | { 186 | double xdiff = a.x()-b.x(), ydiff = a.y()-b.y(), zdiff = a.z()-b.z(); 187 | return sqrt(xdiff*xdiff + ydiff*ydiff + zdiff*zdiff); 188 | } 189 | 190 | double L1(const vec3 &a) 191 | { 192 | return a.x() + a.y() + a.z(); 193 | } 194 | 195 | double L2(const vec3 &a) 196 | { 197 | return length(a); 198 | } 199 | 200 | vec3 normalize(const vec3 &v1) 201 | { 202 | return v1 / length(v1); 203 | } 204 | 205 | vec3 normalize(const vec3 &v1, float epsilon) 206 | { 207 | return v1 / (length(v1) + epsilon); 208 | } 209 | 210 | double vec2polar(const vec3 &a) 211 | { 212 | if (a.x() > 0) 213 | { 214 | if(a.y() >= 0) 215 | return atan(a.y() / a.x()); 216 | else 217 | return atan(a.y() / a.x()) + 2*vec3::PI; 218 | } 219 | else if (a.x() < 0) 220 | { 221 | return atan(a.y()/a.x()) + vec3::PI; 222 | } 223 | else 224 | { 225 | if(a.y() > 0) 226 | return vec3::PI/2; 227 | else if (a.y() < 0) 228 | return 3*vec3::PI/2; 229 | else 230 | return 0; 231 | } 232 | } 233 | 234 | vec3 operator+(const vec3 &a, const vec3 &b) 235 | { 236 | return vec3(a.x()+b.x(), a.y()+b.y(), a.z()+b.z()); 237 | } 238 | 239 | vec3 operator-(const vec3 &a, const vec3 &b) 240 | { 241 | return vec3(a.x()-b.x(), a.y()-b.y(), a.z()-b.z()); 242 | } 243 | 244 | vec3 operator*(const vec3 &a, double s) 245 | { 246 | return vec3(s*a.x(), s*a.y(), s*a.z()); 247 | } 248 | 249 | vec3 operator*(double s, const vec3 &a) 250 | { 251 | return vec3(s*a.x(), s*a.y(), s*a.z()); 252 | } 253 | 254 | vec3 operator/(const vec3 &a, double s) 255 | { 256 | // TODO: throw exception if s == 0 257 | return vec3(a.x()/s, a.y()/s, a.z()/s); 258 | } 259 | 260 | std::ostream &operator<<(std::ostream &stream, const vec3 &v) 261 | { 262 | stream << std::fixed; 263 | return stream << std::setprecision(3) << v.x() << " " << v.y() << " " << v.z(); 264 | } 265 | 266 | double clamp(double value, double min, double max) 267 | { 268 | if (value < min) 269 | return min; 270 | else if (value > max) 271 | return max; 272 | else 273 | return value; 274 | } 275 | 276 | std::string vec3::toString() const 277 | { 278 | std::stringstream ss; 279 | ss << "[" << std::setprecision(5) << this->x() << ", " << this->y() << ", " << this->z() << "]"; 280 | return ss.str(); 281 | } 282 | 283 | vec3 vec3::min(const vec3 &a, const vec3 &b) 284 | { 285 | return vec3((a.x() < b.x()) ? a.x() : b.x(), 286 | (a.y() < b.y()) ? a.y() : b.y(), 287 | (a.z() < b.z()) ? a.z() : b.z()); 288 | } 289 | 290 | vec3 vec3::max(const vec3 &a, const vec3 &b) 291 | { 292 | return vec3((a.x() > b.x()) ? a.x() : b.x(), 293 | (a.y() > b.y()) ? a.y() : b.y(), 294 | (a.z() > b.z()) ? a.z() : b.z()); 295 | } 296 | 297 | double angleBetween(const vec3 &a, const vec3 &b) 298 | { 299 | return acos( dot(a,b) / ( L2(a)*L2(b) ) ); 300 | } 301 | 302 | double angleBetween(const vec3 &a, const vec3 &b, float epsilon) 303 | { 304 | return acos( dot(a,b) / ( ( L2(a)*L2(b) ) + epsilon ) ); 305 | } 306 | -------------------------------------------------------------------------------- /vec3.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------- 2 | // 3 | // Permission is hereby granted, free of charge, to any person 4 | // obtaining a copy of this software and associated documentation 5 | // files ( the "Software" ), to deal in the Software without 6 | // restriction, including without limitation the rights to use, 7 | // copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the 9 | // Software is furnished to do so, subject to the following 10 | // conditions: 11 | // 12 | // The above copyright notice and this permission notice shall 13 | // be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | //------------------------------------------------------------------- 25 | //------------------------------------------------------------------- 26 | 27 | 28 | #ifndef VEC3_H 29 | #define VEC3_H 30 | 31 | 32 | #include 33 | 34 | 35 | #ifdef min 36 | #undef min 37 | #endif 38 | 39 | #ifdef max 40 | #undef max 41 | #endif 42 | 43 | 44 | class vec3 45 | { 46 | public: 47 | vec3(); 48 | vec3(double x, double y, double z); 49 | 50 | private: 51 | double data_[3]; 52 | 53 | public: 54 | bool operator!=(const vec3 &a) const; 55 | bool operator==(const vec3 &a) const; 56 | bool operator<=(const vec3 &a) const; 57 | bool operator>=(const vec3 &a) const; 58 | bool operator<(const vec3 &a) const; 59 | bool operator>(const vec3 &a) const; 60 | vec3& operator=(const vec3 &a); 61 | vec3& operator+=(const vec3 &a); 62 | vec3& operator*=(double c); 63 | vec3& operator/=(double c); 64 | 65 | const double* getPtr() const { return data_; } 66 | 67 | double& operator[](const size_t); 68 | double operator[](const size_t) const; 69 | 70 | double dot(const vec3 &b) const; 71 | vec3 cross(const vec3 &b); 72 | 73 | const double x() const { return data_[0]; } 74 | double& x() { return data_[0]; } 75 | void x( double b ) { data_[0] = b; } 76 | 77 | const double y() const { return data_[1]; } 78 | double& y() { return data_[1]; } 79 | void y( double b ) { data_[1] = b; } 80 | 81 | const double z() const { return data_[2]; } 82 | double& z() { return data_[2]; } 83 | void z( double b ) { data_[2] = b; } 84 | 85 | static vec3 zero; 86 | static vec3 unitX; 87 | static vec3 unitY; 88 | static vec3 unitZ; 89 | static vec3 min(const vec3 &a, const vec3 &b); 90 | static vec3 max(const vec3 &a, const vec3 &b); 91 | static const double PI; 92 | 93 | std::string toString() const; 94 | friend std::ostream& operator<<(std::ostream &stream, const vec3 &v); 95 | }; 96 | 97 | vec3 cross(const vec3 &a, const vec3 &b); 98 | vec3 bisect(const vec3 &a, const vec3 &b); 99 | double dot(const vec3 &a, const vec3 &b); 100 | double length(const vec3 &a); 101 | double lengthSquared(const vec3 &a); 102 | double distance(const vec3 &a, const vec3 &b); 103 | double L1(const vec3 &a); 104 | double L2(const vec3 &a); 105 | double clamp(double value, double min, double max); 106 | vec3 normalize(const vec3 &v1); 107 | vec3 normalize(const vec3 &v1, float epsilon); 108 | 109 | double vec2polar(const vec3 &a); 110 | 111 | double angleBetween(const vec3 &a, const vec3 &b); 112 | double angleBetween(const vec3 &a, const vec3 &b, float epsilon); 113 | 114 | vec3 operator+(const vec3 &a, const vec3 &b); 115 | vec3 operator-(const vec3 &a, const vec3 &b); 116 | vec3 operator*(const vec3 &a, double b); 117 | vec3 operator*(double a, const vec3 &b); 118 | vec3 operator/(const vec3 &a, double b); 119 | 120 | #endif // VEC3_H 121 | --------------------------------------------------------------------------------