├── Makefile ├── tests ├── Makefile ├── ann_knn │ ├── Makefile │ └── knn.cpp ├── sqt_knn │ ├── Makefile │ └── knn.cpp ├── cqt_knn │ ├── Makefile │ └── knn.cpp ├── qt_render_tree │ ├── Makefile │ └── render_tree.cpp ├── sqt_render_tree │ ├── Makefile │ └── render_tree.cpp ├── cqt_render_tree │ ├── Makefile │ └── render_tree.cpp ├── locate │ ├── Makefile │ └── locate.cpp └── data │ ├── knn20.txt │ └── pts50.txt ├── readme ├── bin └── readme └── include ├── quadtree.h ├── compressed_quadtree.h └── skip_quadtree.h /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | cd tests; make 4 | 5 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DIRS = ann_knn cqt_knn sqt_knn cqt_render_tree sqt_render_tree 3 | 4 | all: 5 | for dir in $(DIRS); do cd $$dir; make; cd ..; done 6 | 7 | clean: 8 | for dir in $(DIRS); do cd $$dir; make clean; cd ..; done 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/ann_knn/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCS = -I 3 | LIBS = -lann 4 | CFLAGS = -g -O2 5 | LDFLAGS = -g 6 | OBJS = knn.o 7 | TARGET = ../../bin/ann-knn 8 | 9 | all: $(OBJS) 10 | g++ $(LDFLAGS) $(LIBS) $(OBJS) -o $(TARGET) 11 | 12 | .cpp.o: 13 | g++ $(INCS) $(CFLAGS) -c $< -o $@ 14 | 15 | clean: 16 | rm *.o $(TARGET) 17 | -------------------------------------------------------------------------------- /tests/sqt_knn/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCS = -I../../include 3 | LIBS = 4 | CFLAGS = -g -O2 5 | LDFLAGS = -L../../bin 6 | OBJS = knn.o 7 | TARGET = ../../bin/sqt-knn 8 | 9 | all: $(OBJS) 10 | g++ $(LDFLAGS) $(LIBS) $(OBJS) -o $(TARGET) 11 | 12 | .cpp.o: 13 | g++ $(INCS) $(CFLAGS) -c $< -o $@ 14 | 15 | knn.o: ../../include/skip_quadtree.h 16 | 17 | clean: 18 | rm *.o $(TARGET) 19 | -------------------------------------------------------------------------------- /tests/cqt_knn/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCS = -I../../include 3 | LIBS = 4 | CFLAGS = -g -O2 5 | LDFLAGS = -L../../bin 6 | OBJS = knn.o 7 | TARGET = ../../bin/cqt-knn 8 | 9 | all: $(OBJS) 10 | g++ $(LDFLAGS) $(LIBS) $(OBJS) -o $(TARGET) 11 | 12 | .cpp.o: 13 | g++ $(INCS) $(CFLAGS) -c $< -o $@ 14 | 15 | knn.o: ../../include/compressed_quadtree.h 16 | 17 | clean: 18 | rm *.o $(TARGET) 19 | -------------------------------------------------------------------------------- /tests/qt_render_tree/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCS = -I../../include 3 | LIBS = 4 | CFLAGS = -g 5 | LDFLAGS = 6 | OBJS = render_tree.o 7 | TARGET = ../../bin/qt-render-tree 8 | 9 | all: $(OBJS) 10 | g++ $(LDFLAGS) $(LIBS) $(OBJS) -o $(TARGET) 11 | 12 | .cpp.o: 13 | g++ $(INCS) $(CFLAGS) -c $< -o $@ 14 | 15 | render_tree.o: ../../include/quadtree.h 16 | 17 | clean: 18 | rm *.o $(TARGET) 19 | -------------------------------------------------------------------------------- /tests/sqt_render_tree/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCS = -I../../include 3 | LIBS = 4 | CFLAGS = -g 5 | LDFLAGS = 6 | OBJS = render_tree.o 7 | TARGET = ../../bin/sqt-render-tree 8 | 9 | all: $(OBJS) 10 | g++ $(LDFLAGS) $(LIBS) $(OBJS) -o $(TARGET) 11 | 12 | .cpp.o: 13 | g++ $(INCS) $(CFLAGS) -c $< -o $@ 14 | 15 | render_tree.o: ../../include/skip_quadtree.h 16 | 17 | clean: 18 | rm *.o $(TARGET) 19 | -------------------------------------------------------------------------------- /tests/cqt_render_tree/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCS = -I../../include 3 | LIBS = 4 | CFLAGS = 5 | LDFLAGS = 6 | OBJS = render_tree.o 7 | TARGET = ../../bin/cqt-render-tree 8 | 9 | all: $(OBJS) 10 | g++ $(LDFLAGS) $(LIBS) $(OBJS) -o $(TARGET) 11 | 12 | .cpp.o: 13 | g++ $(INCS) $(CFLAGS) -c $< -o $@ 14 | 15 | render_tree.o: ../../include/compressed_quadtree.h 16 | 17 | clean: 18 | rm *.o $(TARGET) 19 | -------------------------------------------------------------------------------- /tests/locate/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCS = -I../../include 3 | LIBS = 4 | CFLAGS = -g -O2 5 | LDFLAGS = -L../../bin 6 | OBJS = locate.o 7 | TARGET = ../../bin/locate 8 | 9 | all: $(OBJS) 10 | g++ $(LDFLAGS) $(LIBS) $(OBJS) -o $(TARGET) 11 | 12 | .cpp.o: 13 | g++ $(INCS) $(CFLAGS) -c $< -o $@ 14 | 15 | locate.o: ../../include/compressed_quadtree.h ../../include/skip_quadtree.h 16 | 17 | clean: 18 | rm *.o $(TARGET) 19 | -------------------------------------------------------------------------------- /readme: -------------------------------------------------------------------------------- 1 | An implementation of the Compressed Quadtree and Skip Quadtree data structures to support approximate nearest neighbour searches as described in the following paper: 2 | 3 | Eppstein, D., Goodrich, M. T., Sun, J. Z. (2008) The Skip Quadtree: A Simple Dynamic Data Structure for Multidimensional Data, Int. Journal on Computational Geometry and Applications, 18(1/2), pp. 131 - 160 4 | 5 | As implemented, this is not competitive with kd-trees. 6 | -------------------------------------------------------------------------------- /bin/readme: -------------------------------------------------------------------------------- 1 | To show correctness of an implementation, use ann-knn to make a reference file, e.g. 2 | ./ann-knn ../tests/data/pts10000.txt ../tests/data/knn10000.txt > ann 3 | ./cqt-knn ../tests/data/pts10000.txt ../tests/data/knn10000.txt > cqt 4 | diff cqt ann 5 | 6 | If the files match, no output will be shown. 7 | 8 | To time a search, use the built in bash time command, e.g. 9 | time ./sqt-knn ../tests/data/pts10000.txt ../tests/data/knn10000.txt > /dev/null 10 | 11 | To display the generated compressed or skip quadtree, use: 12 | ./sqt-render-tree ../tests/data/pts50.txt tree.ps or ./cqt-render-tree ../tests/data/pts50.txt tree.ps 13 | -------------------------------------------------------------------------------- /tests/data/knn20.txt: -------------------------------------------------------------------------------- 1 | 20 2 | 315.8352017942, 113.13146660716 3 | 454.16215222988, 357.06572390956 4 | 24.077856225929, 34.075247372536 5 | 465.98995964322, 188.29578752084 6 | 253.66305408704, 130.40384376906 7 | 147.13598817919, 112.5780339877 8 | 277.35769389074, 210.44575083556 9 | 13.768231036965, 430.68852435364 10 | 323.12227474671, 90.972119286178 11 | 74.040243902262, 466.30571431774 12 | 105.32021550709, 288.25342668605 13 | 489.25939760602, 64.289466042206 14 | 126.54672522403, 457.22788081375 15 | 189.22812803147, 137.73015287599 16 | 61.98949532676, 305.40973870336 17 | 114.48220122349, 377.82469712096 18 | 418.54120531051, 68.644353220539 19 | 234.8904207977, 442.61906153644 20 | 102.71960082591, 200.88038044091 21 | 130.91484882446, 356.38265491295 22 | 331.28422420997, 278.05083700365 23 | -------------------------------------------------------------------------------- /tests/data/pts50.txt: -------------------------------------------------------------------------------- 1 | 50 2 | 420.09385857735, 197.19146340955 3 | 391.5496118793, 399.22001673804 4 | 455.82367896839, 98.775684646692 5 | 167.61137785744, 384.11479740595 6 | 138.88735540159, 276.98497789772 7 | 238.69852593108, 314.43546238096 8 | 182.39223639592, 256.70045509781 9 | 476.11486258736, 458.09753400185 10 | 317.85586397995, 358.64846471634 11 | 70.801277677902, 303.48443812853 12 | 8.1502858121648, 121.44338531487 13 | 68.615788393009, 402.0883771135 14 | 78.339544627042, 200.47219712309 15 | 64.895223390728, 54.404401012885 16 | 499.46225900178, 109.12845265545 17 | 256.4661972022, 419.5561173463 18 | 306.31991629783, 148.01580884867 19 | 318.77613385151, 262.14359503339 20 | 246.79149349536, 486.38751194178 21 | 146.25839220651, 385.67884889696 22 | 263.37248960667, 384.95691813759 23 | 200.11431104509, 445.76472600259 24 | 141.65737300257, 176.22917363245 25 | 403.86226000444, 459.51323698252 26 | 34.877638115956, 474.66353768234 27 | 262.99767511105, 43.027923928121 28 | 96.106922997212, 331.61346350406 29 | 445.11630127445, 174.44646762425 30 | 32.085660394321, 10.011524432344 31 | 228.85086863714, 31.54791916327 32 | 119.1399770878, 485.31706583934 33 | 451.1040367424, 425.45989338563 34 | 133.33287468801, 269.88017036108 35 | 187.60348818619, 380.12436818337 36 | 256.26768207004, 333.8618803927 37 | 265.80321708033, 19.640171676707 38 | 218.81879829747, 465.91752812542 39 | 465.4048976793, 360.47617153287 40 | 142.14670152503, 369.26715745091 41 | 319.98940828256, 177.02433987382 42 | 343.93069513325, 82.987083160778 43 | 220.05226380194, 440.03761813046 44 | 414.60054666484, 165.16856484356 45 | 114.48408552189, 446.68620729199 46 | 175.1800892759, 343.33495415902 47 | 478.23412645526, 294.32006659653 48 | 328.65201976553, 429.33816296483 49 | 219.77995974933, 461.98489445354 50 | 199.21833332592, 407.38344816835 51 | 342.10926263691, 455.48601539595 52 | 241.24532832822, 107.91247948441 53 | -------------------------------------------------------------------------------- /tests/ann_knn/knn.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2010 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | int main(int argc, char **argv) 33 | { 34 | if (argc < 2) { 35 | std::cout << "usage: knn [queries] [epsilon]" << std::endl; 36 | exit(1); 37 | } 38 | 39 | //read points 40 | int pt_count; 41 | 42 | std::ifstream ptf(argv[1]); 43 | 44 | if (!ptf) { 45 | std::cout << "error: could not open points file: " << argv[1] << std::endl; 46 | exit(1); 47 | } 48 | 49 | ptf >> pt_count; 50 | 51 | if (pt_count < 0) { 52 | std::cout << "error: invalid point count " << pt_count << std::endl; 53 | exit(1); 54 | } 55 | 56 | ANNpointArray pts = annAllocPts(pt_count, 2); 57 | for (int i = 0; i < pt_count; ++i) { 58 | double d; 59 | char c; 60 | 61 | ptf >> d; pts[i][0] = d; 62 | ptf >> c; 63 | ptf >> d; pts[i][1] = d; 64 | } 65 | 66 | ptf.close(); 67 | 68 | ANNkd_tree kt(pts, pt_count, 2); 69 | if (argc < 3) return 1; 70 | 71 | //read queries 72 | int q_count; 73 | 74 | std::ifstream qf(argv[2]); 75 | 76 | if (!qf) { 77 | std::cout << "error: could not open query file: " << argv[2] << std::endl; 78 | exit(1); 79 | } 80 | 81 | qf >> q_count; 82 | 83 | if (q_count < 0) { 84 | std::cout << "error: invalid query count " << q_count << std::endl; 85 | exit(1); 86 | } 87 | 88 | ANNpointArray queries = annAllocPts(q_count, 2); 89 | 90 | for (int i = 0; i < q_count; ++i) { 91 | double d; 92 | char c; 93 | 94 | qf >> d; queries[i][0] = d; 95 | qf >> c; 96 | qf >> d; queries[i][1] = d; 97 | } 98 | 99 | qf.close(); 100 | 101 | //read query epsilon 102 | double epsilon = 0.0; 103 | if (argc == 4) epsilon = atof(argv[3]); 104 | 105 | //run queries 106 | ANNidx *nn_idx = new ANNidx[5]; 107 | ANNdist *dists = new ANNdist[5]; 108 | 109 | for (int i = 0; i < q_count; ++i) { 110 | 111 | kt.annkSearch(queries[i], 5, nn_idx, dists, epsilon); 112 | 113 | std::cout << "query " << i << ": (" << queries[i][0] << ", " << queries[i][1] << ")" << std::endl; 114 | 115 | for (int j = 0; j < 5; ++j) { 116 | std::cout << "(" << pts[nn_idx[j]][0] << ", " << pts[nn_idx[j]][1] << ") " << dists[j] << std::endl; 117 | } 118 | } 119 | 120 | std::cout << "done." << std::endl; 121 | 122 | delete[] nn_idx; 123 | delete[] dists; 124 | annClose(); 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /tests/sqt_knn/knn.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2010 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "skip_quadtree.h" 32 | 33 | struct Point { 34 | double coords[2]; 35 | 36 | Point() {}; 37 | 38 | Point(const Point &other) 39 | { 40 | coords[0] = other.coords[0]; 41 | coords[1] = other.coords[1]; 42 | } 43 | 44 | double operator[](size_t idx) const {return coords[idx];} 45 | double &operator[](size_t idx) {return coords[idx];} 46 | }; 47 | 48 | 49 | int main(int argc, char **argv) 50 | { 51 | if (argc < 2) { 52 | std::cout << "usage: knn [queries] [epsilon]" << std::endl; 53 | exit(1); 54 | } 55 | 56 | //read points 57 | int pt_count; 58 | 59 | std::ifstream ptf(argv[1]); 60 | 61 | if (!ptf) { 62 | std::cout << "error: could not open points file: " << argv[1] << std::endl; 63 | exit(1); 64 | } 65 | 66 | ptf >> pt_count; 67 | 68 | if (pt_count < 0) { 69 | std::cout << "error: invalid point count " << pt_count << std::endl; 70 | exit(1); 71 | } 72 | 73 | Point *pts = new Point[pt_count]; 74 | for (int i = 0; i < pt_count; ++i) { 75 | char c; 76 | ptf >> (pts[i][0]); 77 | ptf >> c; 78 | ptf >> (pts[i][1]); 79 | } 80 | 81 | ptf.close(); 82 | 83 | //build skip quadtree 84 | SkipQuadtree sqt(2, pts, pt_count); 85 | 86 | if (argc < 3) return 0; 87 | 88 | //read queries 89 | int q_count; 90 | 91 | std::ifstream qf(argv[2]); 92 | 93 | if (!qf) { 94 | std::cout << "error: could not open query file: " << argv[2] << std::endl; 95 | exit(1); 96 | } 97 | 98 | qf >> q_count; 99 | 100 | if (q_count < 0) { 101 | std::cout << "error: invalid query count " << q_count << std::endl; 102 | exit(1); 103 | } 104 | 105 | Point *queries = new Point[q_count]; 106 | 107 | for (int i = 0; i < q_count; ++i) { 108 | char c; 109 | qf >> queries[i][0]; 110 | qf >> c; 111 | qf >> queries[i][1]; 112 | } 113 | 114 | qf.close(); 115 | 116 | //read query epsilon 117 | double epsilon = 0.0; 118 | if (argc == 4) epsilon = atof(argv[3]); 119 | 120 | //run queries 121 | for (int i = 0; i < q_count; ++i) { 122 | std::list > qr = sqt.knn(5, queries[i], epsilon); 123 | std::cout << "query " << i << ": (" << queries[i][0] << ", " << queries[i][1] << ")" << std::endl; 124 | 125 | for(std::list >::iterator itor = qr.begin(); itor != qr.end(); ++itor) { 126 | std::cout << "(" << (*itor->first)[0] << ", " << (*itor->first)[1] << ") " << itor->second << std::endl; 127 | } 128 | } 129 | 130 | std::cout << "done." << std::endl; 131 | 132 | delete[] pts; 133 | delete[] queries; 134 | 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /tests/cqt_knn/knn.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2010 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "compressed_quadtree.h" 32 | 33 | struct Point { 34 | double coords[2]; 35 | 36 | Point() {}; 37 | 38 | Point(const Point &other) 39 | { 40 | coords[0] = other.coords[0]; 41 | coords[1] = other.coords[1]; 42 | } 43 | 44 | double operator[](size_t idx) const {return coords[idx];} 45 | double &operator[](size_t idx) {return coords[idx];} 46 | }; 47 | 48 | int main(int argc, char **argv) 49 | { 50 | if (argc < 2) { 51 | std::cout << "usage: knn [queries] [epsilon]" << std::endl; 52 | exit(1); 53 | } 54 | 55 | //read points 56 | int pt_count; 57 | 58 | std::ifstream ptf(argv[1]); 59 | 60 | if (!ptf) { 61 | std::cout << "usage: knn [epsilon]" << std::endl; 62 | exit(1); 63 | } 64 | 65 | ptf >> pt_count; 66 | 67 | if (pt_count < 0) { 68 | std::cout << "error: invalid point count " << pt_count << std::endl; 69 | exit(1); 70 | } 71 | 72 | Point *pts = new Point[pt_count]; 73 | for (int i = 0; i < pt_count; ++i) { 74 | char c; 75 | ptf >> (pts[i][0]); 76 | ptf >> c; 77 | ptf >> (pts[i][1]); 78 | } 79 | 80 | ptf.close(); 81 | 82 | //build compressed quadtree 83 | CompressedQuadtree cqt(2, pts, pt_count); 84 | 85 | if (argc < 3) return 1; 86 | 87 | //read queries 88 | int q_count; 89 | 90 | std::ifstream qf(argv[2]); 91 | 92 | if (!qf) { 93 | std::cout << "error: could not open query file: " << argv[2] << std::endl; 94 | exit(1); 95 | } 96 | 97 | qf >> q_count; 98 | 99 | if (q_count < 0) { 100 | std::cout << "error: invalid query count " << q_count << std::endl; 101 | exit(1); 102 | } 103 | 104 | Point *queries = new Point[q_count]; 105 | 106 | for (int i = 0; i < q_count; ++i) { 107 | char c; 108 | qf >> queries[i][0]; 109 | qf >> c; 110 | qf >> queries[i][1]; 111 | } 112 | 113 | qf.close(); 114 | 115 | //read query epsilon 116 | double epsilon = 0.0; 117 | if (argc == 4) epsilon = atof(argv[3]); 118 | 119 | //run queries 120 | for (int i = 0; i < q_count; ++i) { 121 | 122 | std::list > qr = cqt.knn(5, queries[i], epsilon); 123 | std::cout << "query " << i << ": (" << queries[i][0] << ", " << queries[i][1] << ")" << std::endl; 124 | 125 | for(std::list >::iterator itor = qr.begin(); itor != qr.end(); ++itor) { 126 | std::cout << "(" << (*itor->first)[0] << ", " << (*itor->first)[1] << ") " << itor->second << std::endl; 127 | } 128 | } 129 | 130 | std::cout << "done." << std::endl; 131 | 132 | delete[] pts; 133 | delete[] queries; 134 | 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /tests/locate/locate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "compressed_quadtree.h" 32 | #include "skip_quadtree.h" 33 | 34 | struct Point { 35 | double coords[2]; 36 | 37 | Point() {}; 38 | 39 | Point(const Point &other) 40 | { 41 | coords[0] = other.coords[0]; 42 | coords[1] = other.coords[1]; 43 | } 44 | 45 | double operator[](size_t idx) const {return coords[idx];} 46 | double &operator[](size_t idx) {return coords[idx];} 47 | }; 48 | 49 | int main(int argc, char **argv) 50 | { 51 | if (argc < 2) { 52 | fprintf(stderr, "usage: locate \n"); 53 | exit(1); 54 | } 55 | 56 | //read points 57 | int pt_count; 58 | 59 | FILE *f = fopen(argv[1], "r"); 60 | 61 | if (!f) { 62 | printf("error: could not open points file: %s\n", argv[1]); 63 | return -1; 64 | } 65 | 66 | int result = fscanf(f, "%d", &pt_count); 67 | 68 | if (result != 1|| pt_count < 0) { 69 | fprintf(stderr, "error: invalid point count %d\n", pt_count); 70 | return -1; 71 | } 72 | 73 | Point *pts = new Point[pt_count]; 74 | 75 | double x, y; 76 | for (int i = 0; i < pt_count; ++i) { 77 | int result = fscanf(f, "%lf, %lf", &x, &y); 78 | if (result != 2) { 79 | fprintf(stderr, "error: could not read point %d\n", i); 80 | delete[] pts; 81 | return -1; 82 | } 83 | 84 | pts[i][0] = x; 85 | pts[i][1] = y; 86 | } 87 | 88 | fclose(f); 89 | 90 | CompressedQuadtree cqt(2, pts, pt_count); 91 | 92 | for (size_t i = 0; i < pt_count; ++i) { 93 | CompressedQuadtree::Node *node = cqt.locate(pts[i]); 94 | if (node) { 95 | for (size_t d = 0; d < 2; ++d) { 96 | if (node->mid[d] - node->side[d] - pts[i][d] > 0.1 || pts[i][d] - node->mid[d] - node->side[d] > 0.1) { 97 | fprintf(stderr, "error: compressed quadtree found node not containing point %d: (%.1lf, %.1lf)\n", i, pts[i][0], pts[i][1]); 98 | return -1; 99 | } 100 | } 101 | } else { 102 | fprintf(stderr, "error: compressed quadtree failed to locate point %d: (%.1lf, %.1lf)\n", i, pts[i][0], pts[i][1]); 103 | return -1; 104 | } 105 | } 106 | 107 | SkipQuadtree sqt(2, pts, pt_count); 108 | for (size_t i = 0; i < pt_count; ++i) { 109 | SkipQuadtree::Node *node = sqt.locate(pts[i]); 110 | if (node) { 111 | for (size_t d = 0; d < 2; ++d) { 112 | if (node->mid[d] - node->side[d] - pts[i][d] > 0.1 || pts[i][d] - node->mid[d] - node->side[d] > 0.1) { 113 | fprintf(stderr, "error: skip quadtree found node not containing point %d: (%.1lf, %.1lf)\n", i, pts[i][0], pts[i][1]); 114 | return -1; 115 | } 116 | } 117 | } else { 118 | fprintf(stderr, "error: skip quadtree failed to locate point %d: (%.1lf, %.1lf)\n", i, pts[i][0], pts[i][1]); 119 | return -1; 120 | } 121 | } 122 | 123 | delete[] pts; 124 | } 125 | -------------------------------------------------------------------------------- /tests/sqt_render_tree/render_tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2010 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include "skip_quadtree.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | typedef double Point[2]; 31 | 32 | void render_tree(FILE *f, struct SkipQuadtree::Node *tree, size_t depth) 33 | { 34 | 35 | double x1 = tree->mid[0] - tree->radius; 36 | double x2 = tree->mid[0] + tree->radius; 37 | double y1 = tree->mid[1] - tree->radius; 38 | double y2 = tree->mid[1] + tree->radius; 39 | 40 | //square 41 | if (depth < 1) fprintf(f, "4 setlinewidth\n"); 42 | else if (depth < 2) fprintf(f, "3 setlinewidth\n"); 43 | else if (depth < 4) fprintf(f, "2 setlinewidth\n"); 44 | else fprintf(f, "1 setlinewidth\n"); 45 | 46 | fprintf(f, "%.0f %.0f %.0f %.0f node-bounds\n", x1, x2, y1, y2); 47 | 48 | if (!tree->nodes) { 49 | fprintf(f, "%.0f %.0f draw-point\n", (*tree->pt)[0], (*tree->pt)[1]); 50 | } else { 51 | for (int i = 0; i < 4; ++i) { 52 | if (tree->nodes[i]) render_tree(f, tree->nodes[i], depth+1); 53 | } 54 | } 55 | } 56 | 57 | int main(int argc, char **argv) 58 | { 59 | if (argc != 3) { 60 | printf("usage: render_tree \n"); 61 | exit(1); 62 | } 63 | 64 | int pt_count; 65 | 66 | FILE *f = fopen(argv[1], "r"); 67 | 68 | if (!f) { 69 | printf("error: could not open points file: %s\n", argv[1]); 70 | exit(1); 71 | } 72 | 73 | fscanf(f, "%d", &pt_count); 74 | 75 | if (pt_count < 0) { 76 | printf("error: invalid point count %d\n", pt_count); 77 | exit(1); 78 | } 79 | 80 | Point *pts = new Point[pt_count]; 81 | 82 | double x, y; 83 | for (int i = 0; i < pt_count; ++i) { 84 | fscanf(f, "%lf, %lf", &x, &y); 85 | pts[i][0] = x; 86 | pts[i][1] = y; 87 | } 88 | 89 | 90 | fclose(f); 91 | 92 | SkipQuadtree sqt(2, pts, pt_count); 93 | printf("completed building tree...\n "); 94 | 95 | f = fopen(argv[2], "w"); 96 | if (!f) { 97 | printf("error: could not open output file: %s\n", argv[2]); 98 | exit(1); 99 | } 100 | 101 | fprintf(f, "%%%%!PS-Adobe-2.0\n"); 102 | fprintf(f, "%%%%Pages: %d\n", sqt.levels.size()); 103 | fprintf(f, "/page-begin {\n"); 104 | fprintf(f, "gsave\n"); 105 | fprintf(f, "} def\n"); 106 | 107 | fprintf(f, "/page-end {\n"); 108 | fprintf(f, " grestore\n"); 109 | fprintf(f, " showpage\n"); 110 | fprintf(f, "} def\n"); 111 | 112 | //define point function for later 113 | fprintf(f, "/draw-point {\n"); 114 | fprintf(f, " /y exch def\n"); 115 | fprintf(f, " /x exch def\n"); 116 | fprintf(f, " gsave\n"); 117 | fprintf(f, " newpath\n"); 118 | fprintf(f, " 0.5 0.5 0.7 setrgbcolor\n"); 119 | fprintf(f, " x y 2 0 360 arc\n"); 120 | fprintf(f, " closepath\n"); 121 | fprintf(f, " fill\n"); 122 | fprintf(f, " newpath\n"); 123 | fprintf(f, " 0.4 setgray\n"); 124 | fprintf(f, " x y 2 0 360 arc\n"); 125 | fprintf(f, " closepath\n"); 126 | fprintf(f, " stroke\n"); 127 | fprintf(f, " grestore\n"); 128 | fprintf(f, "} def\n"); 129 | 130 | //node bounding box 131 | fprintf(f, "/node-bounds {\n"); 132 | fprintf(f, " /y2 exch def\n"); 133 | fprintf(f, " /y1 exch def\n"); 134 | fprintf(f, " /x2 exch def\n"); 135 | fprintf(f, " /x1 exch def\n"); 136 | fprintf(f, " gsave\n"); 137 | fprintf(f, " 0.7 setgray\n"); 138 | fprintf(f, " newpath\n"); 139 | fprintf(f, " x2 y2 moveto\n"); 140 | fprintf(f, " x1 y2 lineto\n"); 141 | fprintf(f, " x1 y1 lineto\n"); 142 | fprintf(f, " x2 y1 lineto\n"); 143 | fprintf(f, " closepath\n"); 144 | fprintf(f, " stroke \n"); 145 | fprintf(f, " grestore\n"); 146 | fprintf(f, "} def\n"); 147 | 148 | for (size_t i = 0; i < sqt.levels.size(); ++i) { 149 | fprintf(f, "%%%%Page: %d\n", i + 1); 150 | fprintf(f, "page-begin\n"); 151 | render_tree(f, sqt.levels[i], 0); 152 | fprintf(f, "page-end\n"); 153 | } 154 | 155 | fclose(f); 156 | 157 | } 158 | -------------------------------------------------------------------------------- /tests/qt_render_tree/render_tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include "quadtree.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | typedef double Point[2]; 30 | 31 | void render_tree(FILE *f, struct Quadtree::Node *tree, size_t depth) 32 | { 33 | 34 | double x1 = tree->mid[0] - tree->radius; 35 | double x2 = tree->mid[0] + tree->radius; 36 | double y1 = tree->mid[1] - tree->radius; 37 | double y2 = tree->mid[1] + tree->radius; 38 | 39 | //square 40 | if (depth < 1) fprintf(f, "4 setlinewidth\n"); 41 | else if (depth < 2) fprintf(f, "3 setlinewidth\n"); 42 | else if (depth < 4) fprintf(f, "2 setlinewidth\n"); 43 | else fprintf(f, "1 setlinewidth\n"); 44 | 45 | fprintf(f, "%.0f %.0f %.0f %.0f node-bounds\n", x1, x2, y1, y2); 46 | 47 | if (!tree->nodes) { 48 | fprintf(f, "%.0f %.0f draw-point\n", (*tree->pt)[0], (*tree->pt)[1]); 49 | } else { 50 | for (int i = 0; i < 4; ++i) { 51 | if (tree->nodes[i]) render_tree(f, tree->nodes[i], depth+1); 52 | } 53 | } 54 | } 55 | 56 | int main(int argc, char **argv) 57 | { 58 | if (argc != 3) { 59 | printf("usage: render_tree \n"); 60 | exit(1); 61 | } 62 | 63 | int pt_count; 64 | 65 | FILE *f = fopen(argv[1], "r"); 66 | 67 | if (!f) { 68 | printf("error: could not open points file: %s\n", argv[1]); 69 | exit(1); 70 | } 71 | 72 | fscanf(f, "%d", &pt_count); 73 | 74 | if (pt_count < 0) { 75 | printf("error: invalid point count %d\n", pt_count); 76 | exit(1); 77 | } 78 | 79 | Point *pts = new Point[pt_count]; 80 | 81 | double x, y; 82 | for (int i = 0; i < pt_count; ++i) { 83 | fscanf(f, "%lf, %lf", &x, &y); 84 | pts[i][0] = x; 85 | pts[i][1] = y; 86 | } 87 | 88 | 89 | fclose(f); 90 | 91 | Quadtree cqt(2, pts, pt_count); 92 | printf("completed building tree...\n "); 93 | 94 | f = fopen(argv[2], "w"); 95 | if (!f) { 96 | printf("error: could not open output file: %s\n", argv[2]); 97 | exit(1); 98 | } 99 | 100 | fprintf(f, "%%\n"); 101 | 102 | //define point function for later 103 | fprintf(f, "/draw-point {\n"); 104 | fprintf(f, " /y exch def\n"); 105 | fprintf(f, " /x exch def\n"); 106 | fprintf(f, " gsave\n"); 107 | fprintf(f, " newpath\n"); 108 | fprintf(f, " 0.5 0.5 0.7 setrgbcolor\n"); 109 | fprintf(f, " x y 2 0 360 arc\n"); 110 | fprintf(f, " closepath\n"); 111 | fprintf(f, " fill\n"); 112 | fprintf(f, " newpath\n"); 113 | fprintf(f, " 0.4 setgray\n"); 114 | fprintf(f, " x y 2 0 360 arc\n"); 115 | fprintf(f, " closepath\n"); 116 | fprintf(f, " stroke\n"); 117 | fprintf(f, " grestore\n"); 118 | fprintf(f, "} def\n"); 119 | 120 | //node bounding box 121 | fprintf(f, "/draw-line {\n"); 122 | fprintf(f, " /y2 exch def\n"); 123 | fprintf(f, " /x2 exch def\n"); 124 | fprintf(f, " /y1 exch def\n"); 125 | fprintf(f, " /x1 exch def\n"); 126 | fprintf(f, " gsave\n"); 127 | fprintf(f, " 0.7 0.1 0.1 setrgbcolor\n"); 128 | fprintf(f, " newpath\n"); 129 | fprintf(f, " x1 y1 moveto\n"); 130 | fprintf(f, " x2 y2 lineto\n"); 131 | fprintf(f, " closepath\n"); 132 | fprintf(f, " stroke \n"); 133 | fprintf(f, " grestore\n"); 134 | fprintf(f, "} def\n"); 135 | 136 | 137 | 138 | //node bounding box 139 | fprintf(f, "/node-bounds {\n"); 140 | fprintf(f, " /y2 exch def\n"); 141 | fprintf(f, " /y1 exch def\n"); 142 | fprintf(f, " /x2 exch def\n"); 143 | fprintf(f, " /x1 exch def\n"); 144 | fprintf(f, " gsave\n"); 145 | fprintf(f, " 0.7 setgray\n"); 146 | fprintf(f, " newpath\n"); 147 | fprintf(f, " x2 y2 moveto\n"); 148 | fprintf(f, " x1 y2 lineto\n"); 149 | fprintf(f, " x1 y1 lineto\n"); 150 | fprintf(f, " x2 y1 lineto\n"); 151 | fprintf(f, " closepath\n"); 152 | fprintf(f, " stroke \n"); 153 | fprintf(f, " grestore\n"); 154 | fprintf(f, "} def\n"); 155 | 156 | fprintf(f, "60 240 translate\n"); 157 | 158 | render_tree(f, cqt.root, 0); 159 | 160 | fclose(f); 161 | 162 | } 163 | -------------------------------------------------------------------------------- /tests/cqt_render_tree/render_tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2010 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #include "compressed_quadtree.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | typedef double Point[2]; 30 | 31 | void render_tree(FILE *f, struct CompressedQuadtree::Node *tree, size_t depth) 32 | { 33 | 34 | double x1 = tree->mid[0] - tree->radius; 35 | double x2 = tree->mid[0] + tree->radius; 36 | double y1 = tree->mid[1] - tree->radius; 37 | double y2 = tree->mid[1] + tree->radius; 38 | 39 | //square 40 | if (depth < 1) fprintf(f, "4 setlinewidth\n"); 41 | else if (depth < 2) fprintf(f, "3 setlinewidth\n"); 42 | else if (depth < 4) fprintf(f, "2 setlinewidth\n"); 43 | else fprintf(f, "1 setlinewidth\n"); 44 | 45 | fprintf(f, "%.0f %.0f %.0f %.0f node-bounds\n", x1, x2, y1, y2); 46 | 47 | if (!tree->nodes) { 48 | fprintf(f, "%.0f %.0f draw-point\n", (*tree->pt)[0], (*tree->pt)[1]); 49 | } else { 50 | for (int i = 0; i < 4; ++i) { 51 | if (tree->nodes[i]) render_tree(f, tree->nodes[i], depth+1); 52 | } 53 | } 54 | } 55 | 56 | int main(int argc, char **argv) 57 | { 58 | if (argc != 3) { 59 | printf("usage: render_tree \n"); 60 | exit(1); 61 | } 62 | 63 | int pt_count; 64 | 65 | FILE *f = fopen(argv[1], "r"); 66 | 67 | if (!f) { 68 | printf("error: could not open points file: %s\n", argv[1]); 69 | exit(1); 70 | } 71 | 72 | fscanf(f, "%d", &pt_count); 73 | 74 | if (pt_count < 0) { 75 | printf("error: invalid point count %d\n", pt_count); 76 | exit(1); 77 | } 78 | 79 | Point *pts = new Point[pt_count]; 80 | 81 | double x, y; 82 | for (int i = 0; i < pt_count; ++i) { 83 | fscanf(f, "%lf, %lf", &x, &y); 84 | pts[i][0] = x; 85 | pts[i][1] = y; 86 | } 87 | 88 | 89 | fclose(f); 90 | 91 | CompressedQuadtree cqt(2, pts, pt_count); 92 | printf("completed building tree...\n "); 93 | 94 | f = fopen(argv[2], "w"); 95 | if (!f) { 96 | printf("error: could not open output file: %s\n", argv[2]); 97 | exit(1); 98 | } 99 | 100 | fprintf(f, "%\n"); 101 | 102 | //define point function for later 103 | fprintf(f, "/draw-point {\n"); 104 | fprintf(f, " /y exch def\n"); 105 | fprintf(f, " /x exch def\n"); 106 | fprintf(f, " gsave\n"); 107 | fprintf(f, " newpath\n"); 108 | fprintf(f, " 0.5 0.5 0.7 setrgbcolor\n"); 109 | fprintf(f, " x y 2 0 360 arc\n"); 110 | fprintf(f, " closepath\n"); 111 | fprintf(f, " fill\n"); 112 | fprintf(f, " newpath\n"); 113 | fprintf(f, " 0.4 setgray\n"); 114 | fprintf(f, " x y 2 0 360 arc\n"); 115 | fprintf(f, " closepath\n"); 116 | fprintf(f, " stroke\n"); 117 | fprintf(f, " grestore\n"); 118 | fprintf(f, "} def\n"); 119 | 120 | //node bounding box 121 | fprintf(f, "/draw-line {\n"); 122 | fprintf(f, " /y2 exch def\n"); 123 | fprintf(f, " /x2 exch def\n"); 124 | fprintf(f, " /y1 exch def\n"); 125 | fprintf(f, " /x1 exch def\n"); 126 | fprintf(f, " gsave\n"); 127 | fprintf(f, " 0.7 0.1 0.1 setrgbcolor\n"); 128 | fprintf(f, " newpath\n"); 129 | fprintf(f, " x1 y1 moveto\n"); 130 | fprintf(f, " x2 y2 lineto\n"); 131 | fprintf(f, " closepath\n"); 132 | fprintf(f, " stroke \n"); 133 | fprintf(f, " grestore\n"); 134 | fprintf(f, "} def\n"); 135 | 136 | 137 | 138 | //node bounding box 139 | fprintf(f, "/node-bounds {\n"); 140 | fprintf(f, " /y2 exch def\n"); 141 | fprintf(f, " /y1 exch def\n"); 142 | fprintf(f, " /x2 exch def\n"); 143 | fprintf(f, " /x1 exch def\n"); 144 | fprintf(f, " gsave\n"); 145 | fprintf(f, " 0.7 setgray\n"); 146 | fprintf(f, " newpath\n"); 147 | fprintf(f, " x2 y2 moveto\n"); 148 | fprintf(f, " x1 y2 lineto\n"); 149 | fprintf(f, " x1 y1 lineto\n"); 150 | fprintf(f, " x2 y1 lineto\n"); 151 | fprintf(f, " closepath\n"); 152 | fprintf(f, " stroke \n"); 153 | fprintf(f, " grestore\n"); 154 | fprintf(f, "} def\n"); 155 | 156 | fprintf(f, "60 240 translate\n"); 157 | 158 | render_tree(f, cqt.root, 0); 159 | 160 | fclose(f); 161 | 162 | } 163 | -------------------------------------------------------------------------------- /include/quadtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef QUADTREE_H_ 24 | #define QUADTREE_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | template class Quadtree { 34 | 35 | public: 36 | 37 | //Nodes of the quadtree 38 | struct Node { 39 | Node **nodes; //children 40 | Point mid; //midpoint 41 | double radius; //half side length 42 | Point *pt; //point, if data stored 43 | }; 44 | 45 | //Keep track of point and priority for nearest neighbour search 46 | struct NodeDistance { 47 | 48 | Node *node; 49 | double distance; 50 | 51 | NodeDistance(Node *node, double distance) : node(node), distance(distance) {}; 52 | 53 | //min-heap 54 | bool operator<(const NodeDistance &other) const 55 | { 56 | return distance > other.distance; 57 | } 58 | }; 59 | 60 | Quadtree(size_t dim, Point *pts, size_t n) : dim(dim), nnodes(1 << dim), locate_eps(0.001) 61 | { 62 | //calculate bounds 63 | Point bounds[2]; 64 | for (size_t d = 0; d < dim; ++d) { 65 | bounds[0][d] = std::numeric_limits::max(); 66 | bounds[1][d] = -std::numeric_limits::max(); 67 | } 68 | 69 | for (size_t d = 0; d < dim; ++d) { 70 | for (size_t i = 0; i < n; ++i) { 71 | if (pts[i][d] < bounds[0][d]) bounds[0][d] = pts[i][d]; 72 | if (pts[i][d] > bounds[1][d]) bounds[1][d] = pts[i][d]; 73 | } 74 | } 75 | 76 | //calculate mid point and half side length 77 | Point mid, side; 78 | double radius = 0; 79 | for (size_t d = 0; d < dim; ++d) { 80 | mid[d] = (bounds[0][d]+bounds[1][d]) / 2; 81 | double side = (bounds[1][d]-bounds[0][d]) / 2; 82 | if (side > radius) radius = side; 83 | } 84 | 85 | //set up points vector 86 | std::vector pts_vector; 87 | for (size_t i = 0; i < n; ++i) { 88 | pts_vector.push_back(&pts[i]); 89 | } 90 | 91 | root = worker(mid, radius, pts_vector); 92 | } 93 | 94 | virtual ~Quadtree() 95 | { 96 | if (root) delete_worker(root); 97 | } 98 | 99 | std::list > knn(size_t k, const Point &pt, double eps) 100 | { 101 | //setup query result vector 102 | std::list > qr; 103 | 104 | //initialize priority queue for search 105 | std::vector pq; 106 | pq.push_back(NodeDistance(root, 0.0)); 107 | 108 | while (!pq.empty()) { 109 | 110 | std::pop_heap(pq.begin(), pq.end()); 111 | Node *node = pq.back().node; 112 | double node_dist = pq.back().distance; 113 | pq.pop_back(); 114 | 115 | if (node->nodes == 0) { 116 | //calculate distance from query point to this point 117 | double dist = 0.0; 118 | for (size_t d = 0; d < dim; ++d) { 119 | dist += ((*node->pt)[d]-pt[d]) * ((*node->pt)[d]-pt[d]); 120 | } 121 | 122 | //insert point in result 123 | typename std::list >::iterator itor = qr.begin(); 124 | while (itor != qr.end() && itor->second < dist) { 125 | ++itor; 126 | } 127 | 128 | qr.insert(itor, std::make_pair(node->pt, dist)); 129 | 130 | if (qr.size() > k) qr.pop_back(); 131 | 132 | } else { 133 | 134 | //find k-th distance 135 | double kth_dist = qr.size() < k? std::numeric_limits::max() : qr.back().second; 136 | 137 | //stop searching, all further nodes farther away than k-th value 138 | if (kth_dist <= (1.0 + eps)*node_dist) { 139 | break; 140 | } 141 | 142 | for (size_t n = 0; n < nnodes; ++n) { 143 | //calculate distance to each of the non-zero children 144 | //if less than k-th distance, then visit 145 | if (node->nodes[n]) { 146 | 147 | double min_dist = min_pt_dist_to_node(pt, node->nodes[n]); 148 | 149 | //if closer than k-th distance, search 150 | if (min_dist < kth_dist) { 151 | pq.push_back(NodeDistance(node->nodes[n], min_dist)); 152 | std::push_heap(pq.begin(), pq.end()); 153 | } 154 | } 155 | } 156 | } 157 | } 158 | 159 | return qr; 160 | } 161 | 162 | Node *locate(const Point &pt) 163 | { 164 | 165 | Node *node = 0; 166 | 167 | //search for node containing the query point 168 | if (in_node(root, pt)) { 169 | node = root; 170 | 171 | while (node) { 172 | if (node->nodes) { 173 | size_t n = 0; 174 | for (size_t d = 0; d < dim; ++d) { 175 | if (pt[d] > node->mid[d]) n += 1 << d; 176 | } 177 | 178 | if (node->nodes[n] && in_node(node->nodes[n], pt)) node = node->nodes[n]; 179 | else break; 180 | 181 | } else { 182 | break; 183 | } 184 | } 185 | } 186 | 187 | return node; 188 | } 189 | 190 | Node *root; 191 | double locate_eps; 192 | 193 | private: 194 | 195 | size_t dim; 196 | size_t nnodes; 197 | 198 | Node *worker(const Point &mid, double radius, std::vector &pts) 199 | { 200 | Node *node = new Node; 201 | for (size_t d = 0; d < dim; ++d) { 202 | node->mid[d] = mid[d]; 203 | } 204 | node->radius = radius; 205 | 206 | if (pts.size() == 1) { 207 | node->nodes = 0; 208 | node->pt = pts[0]; 209 | } else { 210 | node->nodes = new Node *[nnodes]; 211 | node->pt = 0; 212 | 213 | //divide points between the nodes 214 | std::vector *node_pts = new std::vector[nnodes]; 215 | for (typename std::vector::iterator itor = pts.begin(); itor != pts.end(); ++itor) { 216 | 217 | //determine node index based upon which which side of midpoint for each dimension 218 | size_t n = 0; 219 | for (size_t d = 0; d < dim; ++d) { 220 | if ((*(*itor))[d] > mid[d]) n += 1 << d; 221 | } 222 | 223 | node_pts[n].push_back(*itor); 224 | } 225 | 226 | //create new nodes recursively 227 | for (size_t n = 0; n < nnodes; ++n) { 228 | 229 | if (node_pts[n].size()) { 230 | 231 | Point nbounds[2]; 232 | Point new_mid; 233 | double new_radius = radius / 2.0; 234 | for (size_t d = 0; d < dim; ++d) { 235 | if (n & (1 << d)) { 236 | new_mid[d] = mid[d] + new_radius; 237 | } else { 238 | new_mid[d] = mid[d] - new_radius; 239 | } 240 | } 241 | 242 | node->nodes[n] = worker(new_mid, new_radius, node_pts[n]); 243 | } else { 244 | node->nodes[n] = 0; 245 | } 246 | } 247 | 248 | delete[] node_pts; 249 | } 250 | 251 | return node; 252 | } 253 | 254 | double min_pt_dist_to_node(const Point &pt, Node *node) 255 | { 256 | bool inside = true; 257 | double min_dist = std::numeric_limits::max(); 258 | for (size_t d = 0; d < dim; ++d) { 259 | 260 | double dist; 261 | if (pt[d] < node->mid[d] - node->radius) { 262 | dist = node->mid[d] - node->radius - pt[d]; 263 | inside = false; 264 | } else if (pt[d] > node->mid[d] + node->radius) { 265 | dist = pt[d] - (node->mid[d] + node->radius); 266 | inside = false; 267 | } 268 | 269 | if (dist < min_dist) min_dist = dist; 270 | } 271 | 272 | if (inside) return 0.0; 273 | else return min_dist*min_dist; 274 | } 275 | 276 | bool in_node(const Node *node, const Point &pt) 277 | { 278 | bool in = true; 279 | 280 | for (size_t d = 0; d < dim; ++d) { 281 | if (root->mid[d] - root->radius - pt[d] > locate_eps || pt[d] - root->mid[d] - root->radius > locate_eps) { 282 | in = false; 283 | break; 284 | } 285 | } 286 | 287 | return in; 288 | } 289 | 290 | void delete_worker(Node *node) 291 | { 292 | if (node->nodes) { 293 | for (size_t n = 0; n < nnodes; ++n) { 294 | if (node->nodes[n]) delete_worker(node->nodes[n]); 295 | } 296 | 297 | delete node->nodes; 298 | } 299 | 300 | delete node; 301 | } 302 | 303 | }; 304 | 305 | #endif 306 | 307 | -------------------------------------------------------------------------------- /include/compressed_quadtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2010 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef COMPRESSED_QUADTREE_H_ 24 | #define COMPRESSED_QUADTREE_H_ 25 | 26 | /* 27 | Compressed Quadtree implementation supporting approximate nearest neighbour 28 | queries, based upon the description in: 29 | 30 | Eppstein, D., Goodrich, M. T., Sun, J. Z. (2008) The Skip Quadtree: 31 | A Simple Dynamic Data Structure for Multidimensional Data, 32 | Int. Journal on Computational Geometry and Applications, 18(1/2), pp. 131 - 160 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | template class CompressedQuadtree { 43 | 44 | public: 45 | 46 | //Nodes of the quadtree 47 | struct Node { 48 | Node **nodes; //children 49 | Point mid; //midpoint 50 | double radius; //half side length 51 | Point *pt; //point, if data stored 52 | }; 53 | 54 | //Keep track of point and priority for nearest neighbour search 55 | struct NodeDistance { 56 | 57 | Node *node; 58 | double distance; 59 | 60 | NodeDistance(Node *node, double distance) : node(node), distance(distance) {}; 61 | 62 | //min-heap 63 | bool operator<(const NodeDistance &other) const 64 | { 65 | return distance > other.distance; 66 | } 67 | }; 68 | 69 | CompressedQuadtree(size_t dim, Point *pts, size_t n) : dim(dim), nnodes(1 << dim), locate_eps(0.001) 70 | { 71 | //calculate bounds 72 | Point bounds[2]; 73 | for (size_t d = 0; d < dim; ++d) { 74 | bounds[0][d] = std::numeric_limits::max(); 75 | bounds[1][d] = -std::numeric_limits::max(); 76 | } 77 | 78 | for (size_t d = 0; d < dim; ++d) { 79 | for (size_t i = 0; i < n; ++i) { 80 | if (pts[i][d] < bounds[0][d]) bounds[0][d] = pts[i][d]; 81 | if (pts[i][d] > bounds[1][d]) bounds[1][d] = pts[i][d]; 82 | } 83 | } 84 | 85 | //calculate mid point and half side length 86 | Point mid, side; 87 | double radius = 0; 88 | for (size_t d = 0; d < dim; ++d) { 89 | mid[d] = (bounds[0][d]+bounds[1][d]) / 2; 90 | double side = (bounds[1][d]-bounds[0][d]) / 2; 91 | if (side > radius) radius = side; 92 | } 93 | 94 | //set up points vector 95 | std::vector pts_vector; 96 | for (size_t i = 0; i < n; ++i) { 97 | pts_vector.push_back(&pts[i]); 98 | } 99 | 100 | root = worker(mid, radius, pts_vector); 101 | } 102 | 103 | virtual ~CompressedQuadtree() 104 | { 105 | if (root) delete_worker(root); 106 | } 107 | 108 | std::list > knn(size_t k, const Point &pt, double eps) 109 | { 110 | //setup query result vector 111 | std::list > qr; 112 | 113 | //initialize priority queue for search 114 | std::vector pq; 115 | pq.push_back(NodeDistance(root, 0.0)); 116 | 117 | while (!pq.empty()) { 118 | 119 | std::pop_heap(pq.begin(), pq.end()); 120 | Node *node = pq.back().node; 121 | double node_dist = pq.back().distance; 122 | pq.pop_back(); 123 | 124 | if (node->nodes == 0) { 125 | //calculate distance from query point to this point 126 | double dist = 0.0; 127 | for (size_t d = 0; d < dim; ++d) { 128 | dist += ((*node->pt)[d]-pt[d]) * ((*node->pt)[d]-pt[d]); 129 | } 130 | 131 | //insert point in result 132 | typename std::list >::iterator itor = qr.begin(); 133 | while (itor != qr.end() && itor->second < dist) { 134 | ++itor; 135 | } 136 | 137 | qr.insert(itor, std::make_pair(node->pt, dist)); 138 | 139 | if (qr.size() > k) qr.pop_back(); 140 | 141 | } else { 142 | 143 | //find k-th distance 144 | double kth_dist = qr.size() < k? std::numeric_limits::max() : qr.back().second; 145 | 146 | //stop searching, all further nodes farther away than k-th value 147 | if (kth_dist <= (1.0 + eps)*node_dist) { 148 | break; 149 | } 150 | 151 | for (size_t n = 0; n < nnodes; ++n) { 152 | //calculate distance to each of the non-zero children 153 | //if less than k-th distance, then visit 154 | if (node->nodes[n]) { 155 | 156 | double min_dist = min_pt_dist_to_node(pt, node->nodes[n]); 157 | 158 | //if closer than k-th distance, search 159 | if (min_dist < kth_dist) { 160 | pq.push_back(NodeDistance(node->nodes[n], min_dist)); 161 | std::push_heap(pq.begin(), pq.end()); 162 | } 163 | } 164 | } 165 | } 166 | } 167 | 168 | return qr; 169 | } 170 | 171 | Node *locate(const Point &pt) 172 | { 173 | 174 | Node *node = 0; 175 | 176 | //search for node containing the query point 177 | if (in_node(root, pt)) { 178 | node = root; 179 | 180 | while (node) { 181 | if (node->nodes) { 182 | size_t n = 0; 183 | for (size_t d = 0; d < dim; ++d) { 184 | if (pt[d] > node->mid[d]) n += 1 << d; 185 | } 186 | 187 | if (node->nodes[n] && in_node(node->nodes[n], pt)) node = node->nodes[n]; 188 | else break; 189 | 190 | } else { 191 | break; 192 | } 193 | } 194 | } 195 | 196 | return node; 197 | } 198 | 199 | Node *root; 200 | double locate_eps; 201 | 202 | private: 203 | 204 | size_t dim; 205 | size_t nnodes; 206 | 207 | Node *worker(const Point &mid, double radius, std::vector &pts) 208 | { 209 | Node *node = new Node; 210 | for (size_t d = 0; d < dim; ++d) { 211 | node->mid[d] = mid[d]; 212 | } 213 | node->radius = radius; 214 | 215 | if (pts.size() == 1) { 216 | node->nodes = 0; 217 | node->pt = pts[0]; 218 | } else { 219 | node->nodes = new Node *[nnodes]; 220 | node->pt = 0; 221 | 222 | //divide points between the nodes 223 | std::vector *node_pts = new std::vector[nnodes]; 224 | for (typename std::vector::iterator itor = pts.begin(); itor != pts.end(); ++itor) { 225 | 226 | //determine node index based upon which which side of midpoint for each dimension 227 | size_t n = 0; 228 | for (size_t d = 0; d < dim; ++d) { 229 | if ((*(*itor))[d] > mid[d]) n += 1 << d; 230 | } 231 | 232 | node_pts[n].push_back(*itor); 233 | } 234 | 235 | //create new nodes recursively 236 | size_t ninteresting = 0; 237 | for (size_t n = 0; n < nnodes; ++n) { 238 | 239 | if (node_pts[n].size()) { 240 | 241 | Point nbounds[2]; 242 | Point new_mid; 243 | double new_radius = radius / 2.0; 244 | for (size_t d = 0; d < dim; ++d) { 245 | if (n & (1 << d)) { 246 | new_mid[d] = mid[d] + new_radius; 247 | } else { 248 | new_mid[d] = mid[d] - new_radius; 249 | } 250 | } 251 | 252 | ++ninteresting; 253 | node->nodes[n] = worker(new_mid, new_radius, node_pts[n]); 254 | } else { 255 | node->nodes[n] = 0; 256 | } 257 | } 258 | 259 | delete[] node_pts; 260 | 261 | //compress if less than 2 interesting nodes 262 | if (ninteresting < 2) { 263 | for (size_t n = 0; n < nnodes; ++n) { 264 | if (node->nodes[n]) { 265 | Node *temp = node; 266 | node = node->nodes[n]; 267 | delete temp; 268 | break; 269 | } 270 | } 271 | } 272 | } 273 | 274 | return node; 275 | } 276 | 277 | double min_pt_dist_to_node(const Point &pt, Node *node) 278 | { 279 | bool inside = true; 280 | double min_dist = std::numeric_limits::max(); 281 | for (size_t d = 0; d < dim; ++d) { 282 | 283 | double dist; 284 | if (pt[d] < node->mid[d] - node->radius) { 285 | dist = node->mid[d] - node->radius - pt[d]; 286 | inside = false; 287 | } else if (pt[d] > node->mid[d] + node->radius) { 288 | dist = pt[d] - (node->mid[d] + node->radius); 289 | inside = false; 290 | } 291 | 292 | if (dist < min_dist) min_dist = dist; 293 | } 294 | 295 | if (inside) return 0.0; 296 | else return min_dist*min_dist; 297 | } 298 | 299 | bool in_node(const Node *node, const Point &pt) 300 | { 301 | bool in = true; 302 | 303 | for (size_t d = 0; d < dim; ++d) { 304 | if (root->mid[d] - root->radius - pt[d] > locate_eps || pt[d] - root->mid[d] - root->radius > locate_eps) { 305 | in = false; 306 | break; 307 | } 308 | } 309 | 310 | return in; 311 | } 312 | 313 | void delete_worker(Node *node) 314 | { 315 | if (node->nodes) { 316 | for (size_t n = 0; n < nnodes; ++n) { 317 | if (node->nodes[n]) delete_worker(node->nodes[n]); 318 | } 319 | 320 | delete node->nodes; 321 | } 322 | 323 | delete node; 324 | } 325 | 326 | }; 327 | 328 | #endif 329 | 330 | -------------------------------------------------------------------------------- /include/skip_quadtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2010 Daniel Minor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef SKIP_QUADTREE_H_ 24 | #define SKIP_QUADTREE_H_ 25 | 26 | /* 27 | Skip Quadtree implementation supporting approximate nearest neighbour 28 | queries, based upon the description in: 29 | 30 | Eppstein, D., Goodrich, M. T., Sun, J. Z. (2008) 31 | The Skip Quadtree: A Simple Dynamic Data Structure for Multidimensional Data, 32 | Int. Journal on Computational Geometry and Applications, 18(1/2), pp. 131 - 160 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | const double EQUIDISTANT_EPSILON = 0.001; 45 | 46 | template class SkipQuadtree { 47 | 48 | public: 49 | 50 | //Nodes of the quadtree 51 | struct Node { 52 | Node *above; //pointer to same node in n+1 level of skip structure 53 | Node *below; //pointer to same node in n-1 level of skip structure 54 | Node *parent; //pointer to parent 55 | Node **ancestors; //pointers to closest ancestors in each direction 56 | Node **nodes; //children 57 | Point mid; //midpoint 58 | double radius; //half side length 59 | Point *pt; //point, if data stored 60 | 61 | size_t seq; 62 | 63 | Node() 64 | { 65 | above = below = parent = 0; 66 | ancestors = nodes = 0; 67 | pt = 0; 68 | seq = 0; 69 | } 70 | }; 71 | 72 | //Keep track of point and priority for nearest neighbour search 73 | struct NodeDistance { 74 | 75 | Node *node; 76 | double distance; 77 | 78 | NodeDistance(Node *node, double distance) : node(node), distance(distance) {}; 79 | 80 | //min-heap 81 | bool operator<(const NodeDistance &other) const 82 | { 83 | return distance > other.distance; 84 | } 85 | }; 86 | 87 | SkipQuadtree(size_t dim, Point *pts, size_t n) : dim(dim), nnodes(1 << dim), locate_eps(0.001) 88 | { 89 | //calculate bounds 90 | Point bounds[2]; 91 | for (size_t d = 0; d < dim; ++d) { 92 | bounds[0][d] = std::numeric_limits::max(); 93 | bounds[1][d] = -std::numeric_limits::max(); 94 | } 95 | 96 | for (size_t d = 0; d < dim; ++d) { 97 | for (size_t i = 0; i < n; ++i) { 98 | if (pts[i][d] < bounds[0][d]) bounds[0][d] = pts[i][d]; 99 | if (pts[i][d] > bounds[1][d]) bounds[1][d] = pts[i][d]; 100 | } 101 | } 102 | 103 | //calculate mid point and half side length 104 | Point mid; 105 | double radius = 0; 106 | for (size_t d = 0; d < dim; ++d) { 107 | mid[d] = (bounds[0][d]+bounds[1][d]) / 2; 108 | double side = (bounds[1][d]-bounds[0][d]) / 2; 109 | if (side > radius) radius = side; 110 | } 111 | 112 | //set up points vector 113 | std::vector pts_vector; 114 | for (size_t i = 0; i < n; ++i) { 115 | pts_vector.push_back(&pts[i]); 116 | } 117 | 118 | root = worker(mid, radius, pts_vector); 119 | 120 | //set ancestor pointers 121 | Node **ancestors = new Node *[2*dim]; 122 | memset(ancestors, 0, 2*dim*sizeof(Node *)); 123 | assign_ancestors(root, ancestors); 124 | delete[] ancestors; 125 | 126 | //build skip hierarchy 127 | levels.push_back(root); 128 | build_skiphierarchy(root); 129 | 130 | knn_seq = 0; 131 | } 132 | 133 | virtual ~SkipQuadtree() 134 | { 135 | for(typename std::vector::iterator itor = levels.begin(); itor != levels.end(); ++itor) { 136 | if (*itor) delete_worker(*itor); 137 | } 138 | } 139 | 140 | Node *locate(const Point &pt) 141 | { 142 | Node *node = 0; 143 | 144 | //search for node containing the query point 145 | if (in_node(root, pt)) { 146 | node = root; 147 | 148 | while (node) { 149 | if (node->nodes) { 150 | size_t n = 0; 151 | 152 | for (size_t d = 0; d < dim; ++d) { 153 | if (pt[d] > node->mid[d]) n += 1 << d; 154 | } 155 | 156 | if (node->nodes[n] && in_node(node->nodes[n], pt)) { 157 | node = node->nodes[n]; 158 | } else { 159 | if (node->below) node = node->below; 160 | else break; 161 | } 162 | } else { 163 | if (node->below) node = node->below; 164 | else break; 165 | } 166 | } 167 | } 168 | 169 | return node; 170 | } 171 | 172 | std::list > knn(size_t k, const Point &pt, double eps) 173 | { 174 | 175 | //number of nodes to backtrack during knn search 176 | size_t backtrack_nodes; 177 | if (eps > 0.0) { 178 | backtrack_nodes = ceil(log((1.0 + eps)*sqrt((double)dim)/eps)); 179 | } else { 180 | backtrack_nodes = -1; 181 | } 182 | 183 | ++knn_seq; 184 | 185 | //setup query result vector 186 | std::list > qr; 187 | 188 | //initialize priority queue for search 189 | std::vector pq; 190 | pq.push_back(NodeDistance(root, min_pt_dist_to_node(pt, root))); 191 | 192 | ++root->seq; 193 | 194 | while (!pq.empty()) { 195 | 196 | std::pop_heap(pq.begin(), pq.end()); 197 | Node *p = pq.back().node; 198 | double p_dist = pq.back().distance; 199 | pq.pop_back(); 200 | 201 | if (p->nodes == 0) { 202 | 203 | //calculate distance from query point to this point 204 | double dist = 0.0; 205 | for (size_t d = 0; d < dim; ++d) { 206 | dist += ((*p->pt)[d]-pt[d]) * ((*p->pt)[d]-pt[d]); 207 | } 208 | 209 | //insert point in result 210 | typename std::list >::iterator itor = qr.begin(); 211 | while (itor != qr.end() && itor->second < dist) { 212 | ++itor; 213 | } 214 | 215 | qr.insert(itor, std::make_pair(p->pt, dist)); 216 | 217 | if (qr.size() > k) qr.pop_back(); 218 | 219 | } else { 220 | 221 | //find k-th distance 222 | double kth_dist = qr.size() < k? std::numeric_limits::max() : qr.back().second; 223 | 224 | //stop searching, all further nodes farther away than k-th value 225 | if (kth_dist <= (1.0+eps)*p_dist) break; 226 | 227 | //If distance to furthest corner is <= (1.0 + eps) * distance to nearest 228 | //corner, we can safely insert all children and see if we've found k values 229 | //not sure if this helps too much for k-nn 230 | //if (max_pt_dist_to_node(pt, p) <= (1.0 + eps)*p_dist) break; 231 | 232 | Node *q = skip_search_equidistant(pt, p, p_dist); 233 | 234 | for (size_t n = 0; n < nnodes; ++n) { 235 | if (q->ancestors[n] && q->ancestors[n]->seq != knn_seq) { 236 | q->ancestors[n]->seq = knn_seq; 237 | 238 | double min_dist = min_pt_dist_to_node(pt, q->ancestors[n]); 239 | 240 | if (min_dist*(1.0+eps) < kth_dist) { 241 | pq.push_back(NodeDistance(q->ancestors[n], min_dist)); 242 | std::push_heap(pq.begin(), pq.end()); 243 | } 244 | } 245 | } 246 | 247 | for (size_t i = 0; i < backtrack_nodes; ++i) { 248 | 249 | if (!q || q == p->parent) break; 250 | 251 | if (q->nodes) { 252 | for (size_t n = 0; n < nnodes; ++n) { 253 | if (q->nodes[n] && q->nodes[n]->seq != knn_seq) { 254 | 255 | q->nodes[n]->seq = knn_seq; 256 | 257 | double min_dist = min_pt_dist_to_node(pt, q->nodes[n]); 258 | 259 | pq.push_back(NodeDistance(q->nodes[n], min_dist)); 260 | std::push_heap(pq.begin(), pq.end()); 261 | } 262 | } 263 | } 264 | 265 | q = q->parent; 266 | 267 | } 268 | } 269 | } 270 | 271 | return qr; 272 | } 273 | 274 | Node *root; 275 | std::vector levels; 276 | 277 | size_t knn_seq; 278 | double locate_eps; 279 | 280 | private: 281 | 282 | size_t dim; 283 | size_t nnodes; 284 | 285 | // 286 | // Worker function to recursively build compressed quadtree 287 | // 288 | Node *worker(const Point &mid, double radius, std::vector &pts) 289 | { 290 | Node *node = new Node; 291 | 292 | for (size_t d = 0; d < dim; ++d) { 293 | node->mid[d] = mid[d]; 294 | } 295 | 296 | node->radius = radius; 297 | 298 | if (pts.size() == 1) { 299 | node->nodes = 0; 300 | node->pt = pts[0]; 301 | } else { 302 | 303 | node->nodes = new Node *[nnodes]; 304 | 305 | //divide points between the nodes 306 | std::vector *node_pts = new std::vector[nnodes]; 307 | for (typename std::vector::iterator itor = pts.begin(); itor != pts.end(); ++itor) { 308 | 309 | //determine node index based upon which which side of midpoint for each dimension 310 | size_t n = 0; 311 | for (size_t d = 0; d < dim; ++d) { 312 | if ((*(*itor))[d] > mid[d]) n += 1 << d; 313 | } 314 | 315 | node_pts[n].push_back(*itor); 316 | } 317 | 318 | //create new nodes recursively 319 | size_t ninteresting = 0; 320 | Node *last_interesting = 0; 321 | for (size_t n = 0; n < nnodes; ++n) { 322 | 323 | if (node_pts[n].size()) { 324 | 325 | Point nbounds[2]; 326 | Point new_mid; 327 | double new_radius = radius / 2; 328 | for (size_t d = 0; d < dim; ++d) { 329 | if (n & (1 << d)) { 330 | new_mid[d] = mid[d] + new_radius; 331 | } else { 332 | new_mid[d] = mid[d] - new_radius; 333 | } 334 | } 335 | 336 | ++ninteresting; 337 | node->nodes[n] = worker(new_mid, new_radius, node_pts[n]); 338 | node->nodes[n]->parent = node; 339 | 340 | last_interesting = node->nodes[n]; 341 | } else { 342 | node->nodes[n] = 0; 343 | } 344 | } 345 | 346 | delete[] node_pts; 347 | 348 | //compress if less than 2 interesting nodes 349 | if (ninteresting < 2) { 350 | delete node; 351 | node = last_interesting; 352 | } 353 | } 354 | 355 | return node; 356 | } 357 | 358 | // 359 | // Recursively assign ancestor pointers 360 | // 361 | void assign_ancestors(Node *node, Node **ancestors) 362 | { 363 | 364 | node->ancestors = new Node *[2*dim]; 365 | for (size_t i = 0; i < 2*dim; ++i) { 366 | node->ancestors[i] = ancestors[i]; 367 | } 368 | 369 | if (node->nodes) { 370 | 371 | Node **new_ancestors = new Node *[2*dim]; 372 | 373 | for (size_t n = 0; n < nnodes; ++n) { 374 | if (node->nodes[n]) { 375 | for (size_t d = 0; d < dim; ++d) { 376 | if (n & (1 << d)) { 377 | new_ancestors[2*d] = node; 378 | new_ancestors[2*d+1] = ancestors[2*d+1]; 379 | } else { 380 | new_ancestors[2*d] = ancestors[2*d]; 381 | new_ancestors[2*d+1] = node; 382 | } 383 | } 384 | 385 | assign_ancestors(node->nodes[n], new_ancestors); 386 | } 387 | } 388 | 389 | delete[] new_ancestors; 390 | } 391 | 392 | } 393 | 394 | 395 | void build_skiphierarchy(Node *level) 396 | { 397 | //recursively build skip hierarchy until we get an empty level 398 | //should be O(log(n)) levels w.h.p. 399 | while (level) { 400 | 401 | level = build_skiplevel(level); 402 | 403 | //store level and continue 404 | if (level) levels.push_back(level); 405 | } 406 | } 407 | 408 | bool verify_parents(Node *node) 409 | { 410 | 411 | if (node->nodes) { 412 | for (size_t n = 0; n < nnodes; ++n) { 413 | if (node->nodes[n]) { 414 | if (node->nodes[n]->parent != node) return false; 415 | verify_parents(node->nodes[n]); 416 | } 417 | } 418 | } 419 | 420 | return true; 421 | } 422 | 423 | bool verify_node_in_level(Node *root, Node *node) 424 | { 425 | if (root == node) return true; 426 | 427 | bool result = false; 428 | if (root->nodes) { 429 | for (size_t n = 0; n < nnodes; ++n) { 430 | if (root->nodes[n]) { 431 | result |= verify_node_in_level(root->nodes[n], node); 432 | } 433 | } 434 | } 435 | 436 | return result; 437 | 438 | } 439 | 440 | Node *build_skiplevel(Node *node) 441 | { 442 | Node *copy = 0; 443 | 444 | //hit a leaf -- nothing to do 445 | if (!node->nodes) return 0; 446 | 447 | //search through children for leaf nodes 448 | //we work at the branch node level so as to avoid creating nodes without children 449 | //and then deleting them 450 | for (size_t n = 0; n < nnodes; ++n) { 451 | if (node->nodes[n]) { 452 | 453 | //hit a leaf node 454 | if (node->nodes[n]->nodes == 0) { 455 | //decide with p=0.5 whether or not to keep the node 456 | if ((double)rand() / (double)RAND_MAX < 0.5) { 457 | 458 | //if so, and we haven't made a copy yet, do so 459 | if (!copy) copy = make_branchnode(node); 460 | 461 | //create copy of existing point at proper location 462 | copy->nodes[n] = new Node; 463 | copy->nodes[n]->parent = copy; 464 | 465 | //link nodes for skip hierarchy 466 | node->nodes[n]->above = copy->nodes[n]; 467 | copy->nodes[n]->below = node->nodes[n]; 468 | 469 | //copy point in 470 | copy->nodes[n]->pt = node->nodes[n]->pt; 471 | for (size_t d = 0; d < dim; ++d) { 472 | copy->nodes[n]->mid[d] = node->nodes[n]->mid[d]; 473 | copy->nodes[n]->radius = node->nodes[n]->radius; 474 | } 475 | } 476 | } else { 477 | //build level recursively 478 | Node *child = build_skiplevel(node->nodes[n]); 479 | 480 | //found a valid child, make copy if necessary and set pointer 481 | if (child) { 482 | if (!copy) copy = make_branchnode(node); 483 | copy->nodes[n] = child; 484 | copy->nodes[n]->parent = copy; 485 | 486 | //link nodes for skip hierarchy 487 | node->nodes[n]->above = copy->nodes[n]; 488 | copy->nodes[n]->below = node->nodes[n]; 489 | } 490 | } 491 | } 492 | } 493 | 494 | return copy; 495 | } 496 | 497 | //make a new branch node and set pointers for skip hierarchy 498 | Node *make_branchnode(Node *node) 499 | { 500 | //make new branch node and zero out pointers 501 | Node *copy = new Node; 502 | copy->nodes = new Node *[nnodes]; 503 | for (size_t n = 0; n < nnodes; ++n) { 504 | copy->nodes[n] = 0; 505 | } 506 | 507 | //copy mid, side 508 | for (size_t d = 0; d < dim; ++d) { 509 | copy->mid[d] = node->mid[d]; 510 | copy->radius = node->radius; 511 | } 512 | 513 | //link nodes for skip hierarchy 514 | node->above = copy; 515 | copy->below = node; 516 | 517 | return copy; 518 | } 519 | 520 | // 521 | // Search for smallest square q inside p that is equidistant to pt 522 | // 523 | Node *skip_search_equidistant(const Point &pt, Node *p, double p_dist) 524 | { 525 | 526 | //find highest point in skip hierarchy containing p, call it q 527 | Node *q_in_q0 = p; 528 | Node *last_q_in_q0 = 0; 529 | Node *q_in_qi = p; 530 | 531 | while (q_in_qi->above != 0) { 532 | q_in_qi = q_in_qi->above; 533 | } 534 | 535 | while (true) { 536 | 537 | // if we hit a leaf, we are done 538 | if (!q_in_q0->nodes) { 539 | break; 540 | } 541 | 542 | //first check to see if q in Q0 has two equidistant children to p 543 | size_t nequidistant = 0; 544 | 545 | if (last_q_in_q0 != q_in_q0) { 546 | 547 | for (size_t n = 0; n < nnodes; ++n) { 548 | //calculate distance to each of the non-zero children 549 | if (q_in_q0->nodes[n]) { 550 | 551 | double min_dist = min_pt_dist_to_node(pt, q_in_q0->nodes[n]); 552 | 553 | //if close enough, count as equidistant 554 | if (fabs(min_dist - p_dist) < EQUIDISTANT_EPSILON) { 555 | ++nequidistant; 556 | if (nequidistant == 2) { 557 | break; 558 | } 559 | } 560 | } 561 | } 562 | 563 | last_q_in_q0 = q_in_q0; 564 | } 565 | 566 | if (nequidistant == 2) break; 567 | 568 | //if not, see if q in Qi has an equidistant child to p 569 | size_t equidistant_child = -1; 570 | if (q_in_qi->nodes) { 571 | for (size_t n = 0; n < nnodes; ++n) { 572 | if (q_in_qi->nodes[n]) { 573 | 574 | double min_dist = min_pt_dist_to_node(pt, q_in_qi->nodes[n]); 575 | 576 | //if close enough, count as equidistant 577 | if (fabs(min_dist - p_dist) < EQUIDISTANT_EPSILON) { 578 | equidistant_child = n; 579 | break; 580 | } 581 | } 582 | } 583 | } 584 | 585 | //if equidistant child exists, move to it -- otherwise drop to lower level 586 | if (equidistant_child != -1) { 587 | q_in_qi = q_in_qi->nodes[equidistant_child]; 588 | q_in_q0 = q_in_q0->nodes[equidistant_child]; 589 | } else { 590 | if (q_in_qi->below) q_in_qi = q_in_qi->below; 591 | else break; 592 | } 593 | } 594 | 595 | return q_in_q0; 596 | } 597 | 598 | double min_pt_dist_to_node(const Point &pt, Node *node) 599 | { 600 | bool inside = true; 601 | double min_dist = std::numeric_limits::max(); 602 | for (size_t d = 0; d < dim; ++d) { 603 | 604 | double dist; 605 | if (pt[d] < node->mid[d] - node->radius) { 606 | dist = node->mid[d] - node->radius - pt[d]; 607 | inside = false; 608 | } else if (pt[d] > node->mid[d] + node->radius) { 609 | dist = pt[d] - (node->mid[d] + node->radius); 610 | inside = false; 611 | } 612 | 613 | if (dist < min_dist) min_dist = dist; 614 | } 615 | 616 | if (inside) return 0.0; 617 | else return min_dist*min_dist; 618 | } 619 | 620 | double max_pt_dist_to_node(const Point &pt, Node *node) 621 | { 622 | double max_dist = std::numeric_limits::min(); 623 | for (size_t d = 0; d < dim; ++d) { 624 | double dist; 625 | dist = fabs(node->mid[d] - node->radius - pt[d]); 626 | if (dist > max_dist) max_dist = dist; 627 | 628 | dist = fabs(pt[d] - node->mid[d] + node->radius); 629 | if (dist > max_dist) max_dist = dist; 630 | } 631 | 632 | return max_dist*max_dist; 633 | } 634 | 635 | bool in_node(const Node *node, const Point &pt) 636 | { 637 | bool in = true; 638 | 639 | for (size_t d = 0; d < dim; ++d) { 640 | if (root->mid[d] - root->radius - pt[d] > locate_eps || pt[d] - root->mid[d] - root->radius > locate_eps) { 641 | in = false; 642 | break; 643 | } 644 | } 645 | 646 | return in; 647 | } 648 | 649 | void delete_worker(Node *node) 650 | { 651 | if (node->nodes) { 652 | for (size_t n = 0; n < nnodes; ++n) { 653 | if (node->nodes[n]) delete_worker(node->nodes[n]); 654 | } 655 | 656 | delete node->nodes; 657 | } 658 | 659 | delete node->ancestors; 660 | delete node; 661 | } 662 | 663 | }; 664 | 665 | #endif 666 | 667 | --------------------------------------------------------------------------------