geokdtree 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in geokdtree.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2013 Colin Surprenant <colin.surprenant@gmail.com>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,121 @@
1
+ # Ruby/FFI Geokdtree v0.1.0
2
+
3
+ Ruby & JRuby gem with a fast **k-d tree** C implementation using FFI bindings with support for latitude/longitude and **geo distance range search**.
4
+
5
+ A [k-d tree](https://en.wikipedia.org/wiki/K-d_tree) is a space-partitioning data structure for organizing points in a k-dimensional space and are useful for very **fast range searches** and **nearest neighbor searches**. k-d trees are a special case of binary space partitioning trees.
6
+
7
+ ## Installation
8
+
9
+ Tested on OSX 10.8.2 with
10
+ - MRI Ruby 1.9.3 p362
11
+ - MRI Ruby 1.9.3 p385
12
+ - JRuby 1.7.2 (1.9.3 p327)
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'geokdtree'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install geokdtree
25
+
26
+ ## JRuby Notes
27
+
28
+ if the gem installation fails with the following error message, this is because JRuby disabled native extensions by default.
29
+ ```
30
+ Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension
31
+ ```
32
+
33
+ To fix this simply set the following JRuby runtime option
34
+ ``` sh
35
+ $ export JRUBY_OPTS=-Xcext.enabled=true
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ``` ruby
41
+ # simplest 2d tree
42
+ tree = Geokdtree::Tree.new(2)
43
+ tree.insert([1, 0])
44
+ tree.insert([2, 0])
45
+ tree.insert([3, 0])
46
+
47
+ result = tree.nearest([0, 0])
48
+ puts(result.point.inspect) # => [1.0, 0.0]
49
+ puts(result.data.inspect) # => nil
50
+
51
+ # simple 2d tree with point payload.
52
+ # abritary objects can be attached to each inserted point
53
+ tree = Geokdtree::Tree.new(2)
54
+ tree.insert([1, 0], "point 1")
55
+ tree.insert([2, 0], "point 2")
56
+ tree.insert([3, 0], "point 3")
57
+
58
+ # single nearest using standard/Euclidean relative distance
59
+ result = tree.nearest([0, 0])
60
+ puts(result.point.inspect) # => [1.0, 0.0]
61
+ puts(result.data.inspect) # => "point 1"
62
+
63
+ # nearests within range using standard/Euclidean relative distance
64
+ results = tree.nearest_range([0, 0], 2)
65
+ puts(results.size) # => 2
66
+ puts(results[0].point.inspect) # => [2.0, 0.0]
67
+ puts(results[0].data.inspect) # => "point 2"
68
+ puts(results[1].point.inspect) # => [1.0, 0.0]
69
+ puts(results[1].data.inspect) # => "point 1"
70
+
71
+ # 2d tree with lat/lng points
72
+ tree = Geokdtree::Tree.new(2)
73
+ tree.insert([40.7, -74.0], "New York")
74
+ tree.insert([37.77, -122.41], "San Francisco")
75
+ tree.insert([45.50, -73.55], "Montreal")
76
+
77
+ # single nearest using standard/Euclidean relative distance
78
+ result = tree.nearest([34.1, -118.2]) # Los Angeles
79
+ puts(result.point.inspect) # => [37.77, -122.41]
80
+ puts(result.data.inspect) # => "San Francisco"
81
+
82
+
83
+ # nearests within range using miles relative geo distance
84
+ results = tree.nearest_geo_range([47.6, -122.3], 800) # Seattle, within 800 mi
85
+ puts(results.size) # => 1
86
+ puts(results[0].point.inspect) # => [37.77, -122.41]
87
+ puts(results[0].data.inspect) # => "San Francisco"
88
+
89
+ # nearests within range using kilometer relative geo distance
90
+ results = tree.nearest_geo_range([42.35, -71.06], 500, :km) # Boston, within 500 km
91
+ puts(results.size) # => 2
92
+ puts(results[0].point.inspect) # => [45.5, -73.55]
93
+ puts(results[0].data.inspect) # => "Montreal"
94
+ puts(results[1].point.inspect) # => [40.7, -74.0]
95
+ puts(results[1].data.inspect) # => "New York"
96
+
97
+ # compute standard/Euclidean distance between two points
98
+ d = Geokdtree::Tree.distance([-1, 1], [1, 1])
99
+ puts(d) # => 2
100
+
101
+ # compute geo distance between two points (Montreal, Boston)
102
+ d = Geokdtree::Tree.geo_distance([45.5, -73.55], [42.35, -71.06], :km).round(0)
103
+ puts(d.inspect) # => 403
104
+ ```
105
+
106
+ ## Contributing
107
+
108
+ 1. Fork it
109
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
110
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
111
+ 4. Push to the branch (`git push origin my-new-feature`)
112
+ 5. Create new Pull Request
113
+
114
+ ## Credits
115
+ - [John Tsiombikas](http://nuclear.mutantstargoat.com/) for writing the [original C kdtree](https://code.google.com/p/kdtree/).
116
+
117
+ ## Author
118
+ Colin Surprenant, [@colinsurprenant](http://twitter.com/colinsurprenant), [http://github.com/colinsurprenant](http://github.com/colinsurprenant), colin.surprenant@gmail.com
119
+
120
+ ## License
121
+ Ruby/FFI Geokdtree is distributed under the Apache License, Version 2.0.
@@ -0,0 +1,30 @@
1
+ require 'bundler/setup'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'bundler/gem_tasks'
5
+ require 'rspec/core/rake_task'
6
+
7
+ task :default => :spec
8
+
9
+ desc "clean, make and run specsrkae"
10
+ task :spec do
11
+ RSpec::Core::RakeTask.new
12
+ end
13
+
14
+ desc "compile C ext and FFI ext and copy objects into lib"
15
+ task :make => [:clean] do
16
+ Dir.chdir("ext/geokdtree") do
17
+ ruby jruby? ? "-Xcext.enabled=true extconf.rb" : "extconf.rb"
18
+ sh "make"
19
+ end
20
+ cp "ext/geokdtree/geokdtree.bundle", "lib/"
21
+ end
22
+
23
+ CLEAN.include('ext/**/*{.o,.log,.so,.bundle}')
24
+ CLEAN.include('lib/**/*{.o,.log,.so,.bundle}')
25
+ CLEAN.include('ext/**/Makefile')
26
+
27
+ def jruby?
28
+ !!(defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby')
29
+ end
30
+
@@ -0,0 +1,65 @@
1
+ require 'bundler/setup'
2
+ require 'geokdtree'
3
+
4
+ # simplest 2d tree
5
+ tree = Geokdtree::Tree.new(2)
6
+ tree.insert([1, 0])
7
+ tree.insert([2, 0])
8
+ tree.insert([3, 0])
9
+
10
+ result = tree.nearest([0, 0])
11
+ puts(result.point.inspect) # => [1.0, 0.0]
12
+ puts(result.data.inspect) # => nil
13
+
14
+ # simple 2d tree with point payload. abritary objects can be attached to each inserted point
15
+ tree = Geokdtree::Tree.new(2)
16
+ tree.insert([1, 0], "point 1")
17
+ tree.insert([2, 0], "point 2")
18
+ tree.insert([3, 0], "point 3")
19
+
20
+ # single nearest using standard/Euclidean relative distance
21
+ result = tree.nearest([0, 0])
22
+ puts(result.point.inspect) # => [1.0, 0.0]
23
+ puts(result.data.inspect) # => "point 1"
24
+
25
+ # nearests within range using standard/Euclidean relative distance
26
+ results = tree.nearest_range([0, 0], 2)
27
+ puts(results.size) # => 2
28
+ puts(results[0].point.inspect) # => [2.0, 0.0]
29
+ puts(results[0].data.inspect) # => "point 2"
30
+ puts(results[1].point.inspect) # => [1.0, 0.0]
31
+ puts(results[1].data.inspect) # => "point 1"
32
+
33
+ # 2d tree with lat/lng points
34
+ tree = Geokdtree::Tree.new(2)
35
+ tree.insert([40.7, -74.0], "New York")
36
+ tree.insert([37.77, -122.41], "San Francisco")
37
+ tree.insert([45.50, -73.55], "Montreal")
38
+
39
+ # single nearest using standard/Euclidean relative distance
40
+ result = tree.nearest([34.1, -118.2]) # Los Angeles
41
+ puts(result.point.inspect) # => [37.77, -122.41]
42
+ puts(result.data.inspect) # => "San Francisco"
43
+
44
+
45
+ # nearests within range using miles relative geo distance
46
+ results = tree.nearest_geo_range([47.6, -122.3], 800) # Seattle, within 800 miles
47
+ puts(results.size) # => 1
48
+ puts(results[0].point.inspect) # => [37.77, -122.41]
49
+ puts(results[0].data.inspect) # => "San Francisco"
50
+
51
+ # nearests within range using kilometer relative geo distance
52
+ results = tree.nearest_geo_range([42.35, -71.06], 500, :km) # Boston, within 500 kilometer
53
+ puts(results.size) # => 2
54
+ puts(results[0].point.inspect) # => [45.5, -73.55]
55
+ puts(results[0].data.inspect) # => "Montreal"
56
+ puts(results[1].point.inspect) # => [40.7, -74.0]
57
+ puts(results[1].data.inspect) # => "New York"
58
+
59
+ # compute standard/Euclidean distance between two points
60
+ d = Geokdtree::Tree.distance([-1, 1], [1, 1])
61
+ puts(d) # => 2
62
+
63
+ # compute geo distance between two points
64
+ d = Geokdtree::Tree.geo_distance([45.5, -73.55], [42.35, -71.06], :km).round(0) # Montreal, Boston
65
+ puts(d.inspect) # => 403
@@ -0,0 +1,70 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <math.h>
5
+ #include "distance.h"
6
+
7
+ static double RADIAN_PER_DEGREE = M_PI / 180.0;
8
+
9
+ /* return the square Euclidean distance from two points in k dimensions */
10
+ double square_euclidean_distance(const double *a, const double *b, int k) {
11
+ double d = 0, diff;
12
+ while (--k >= 0) {
13
+ diff = (a[k] - b[k]);
14
+ d += diff * diff;
15
+ }
16
+ return d;
17
+ }
18
+
19
+ /* return the Euclidean distance from two points in k dimensions */
20
+ double euclidean_distance(const double *a, const double *b, int k) {
21
+ return sqrt(square_euclidean_distance(a, b, k));
22
+ }
23
+
24
+ /* return the Euclidean distance from two points in two dimensions */
25
+ double euclidean_distance2(double ax, double ay, double bx, double by) {
26
+ double a[2];
27
+ double b[2];
28
+ a[0] = ax;
29
+ a[1] = ay;
30
+ b[0] = bx;
31
+ b[1] = by;
32
+ return sqrt(square_euclidean_distance(a, b, 2));
33
+ }
34
+
35
+ /* return the geo distance from two lat/lng points using the spherical law of cosines */
36
+ double slc_distance(const double *a, const double *b, double radius) {
37
+ double rlat1 = RADIAN_PER_DEGREE * a[0];
38
+ double rlng1 = RADIAN_PER_DEGREE * a[1];
39
+ double rlat2 = RADIAN_PER_DEGREE * b[0];
40
+ double rlng2 = RADIAN_PER_DEGREE * b[1];
41
+ return acos(sin(rlat1) * sin(rlat2) + cos(rlat1) * cos(rlat2) * cos(rlng2 - rlng1)) * radius;
42
+ }
43
+
44
+ /* return the geo distance from two lat/lng points using the spherical law of cosines */
45
+ double slc_distance2(double lat1, double lng1, double lat2, double lng2, double radius) {
46
+ double a[2];
47
+ double b[2];
48
+ a[0] = lat1, a[1] = lng1;
49
+ b[0] = lat2, b[1] = lng2;
50
+ return slc_distance(a, b, radius);
51
+ }
52
+
53
+ /* return the geo distance from two lat/lng points using the haversine formula */
54
+ double haversine_distance2(double lat1, double lng1, double lat2, double lng2, double radius) {
55
+ double rlat1 = RADIAN_PER_DEGREE * lat1;
56
+ double rlat2 = RADIAN_PER_DEGREE * lat2;
57
+ double rdistlat = RADIAN_PER_DEGREE * (lat2 - lat1);
58
+ double rdistlng = RADIAN_PER_DEGREE * (lng2 - lng1);
59
+ double a = SQ(sin(rdistlat / 2.0)) + cos(rlat1) * cos(rlat2) * SQ(sin(rdistlng / 2.0));
60
+ double c = 2.0 * atan2(sqrt(a), sqrt(1 - a));
61
+ return c * radius;
62
+ }
63
+
64
+ int bsq_compare(double a, double b) {
65
+ return (a > SQ(b)) - (a < SQ(b));
66
+ }
67
+
68
+ int std_compare(double a, double b) {
69
+ return (a > b) - (a < b);
70
+ }
@@ -0,0 +1,38 @@
1
+ #ifndef _DISTANCE_H_
2
+ #define _DISTANCE_H_
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ #define RADIUS_MI 3958.760
9
+ #define RADIUS_KM 6371.0
10
+ #define KM_PER_MI 1.609
11
+ #define SQ(x) ((x) * (x))
12
+
13
+ /* return the square Euclidean distance from two points in k dimensions */
14
+ double square_euclidean_distance(const double *a, const double *b, int k);
15
+
16
+ /* return the Euclidean distance from two points in k dimensions */
17
+ double euclidean_distance(const double *a, const double *b, int k);
18
+
19
+ /* return the Euclidean distance from two points in two dimensions */
20
+ double euclidean_distance2(double ax, double ay, double bx, double by);
21
+
22
+ /* return the geo distance from two lat/lng points using the spherical law of cosines */
23
+ double slc_distance(const double *a, const double *b, double radius);
24
+
25
+ /* return the geo distance from two lat/lng points using the spherical law of cosines */
26
+ double slc_distance2(double lat1, double lng1, double lat2, double lng2, double radius);
27
+
28
+ /* return the geo distance from two lat/lng points using the haversine formula */
29
+ double haversine_distance2(double lat1, double lng1, double lat2, double lng2, double radius);
30
+
31
+ int bsq_compare(double a, double b);
32
+ int std_compare(double a, double b);
33
+
34
+ #ifdef __cplusplus
35
+ }
36
+ #endif
37
+
38
+ #endif /* _DISTANCE_H_ */
@@ -0,0 +1,7 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS = "-pedantic -Wall -g -O3 -fPIC -g -DUSE_LIST_NODE_ALLOCATOR"
4
+
5
+ have_library("pthread")
6
+
7
+ create_makefile 'geokdtree'
@@ -0,0 +1,782 @@
1
+ /*
2
+ This file is part of ``kdtree'', a library for working with kd-trees.
3
+ Copyright (C) 2007-2011 John Tsiombikas <nuclear@member.fsf.org>
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+ 3. The name of the author may not be used to endorse or promote products
14
+ derived from this software without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
+ EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25
+ OF SUCH DAMAGE.
26
+ */
27
+
28
+ /* single nearest neighbor search written by Tamas Nepusz <tamas@cs.rhul.ac.uk> */
29
+
30
+ /*
31
+ Feb 2013 - Colin Surprenant <colin.surprenant@gmail.com>
32
+ - inclusion in the ruby-ffi-kdtree gem
33
+ - added kd_nearest2
34
+ - added kd_nearest_range2
35
+ - added kd_insert2
36
+ - refactored find_nearest to externalize the distance computation and distance comparison
37
+ - refactored kd_nearest_range into kd_generic_nearest_range to externalize the distance computation and distance comparison
38
+ - added kd_nearest_geo_range
39
+ - added distance.[ch]
40
+ - removed all float functions
41
+
42
+ original source code from https://code.google.com/p/kdtree/
43
+ using version 0.5.6 dated Nov 2011
44
+ */
45
+
46
+ #include <stdio.h>
47
+ #include <stdlib.h>
48
+ #include <string.h>
49
+ #include <math.h>
50
+ #include "kdtree.h"
51
+ #include "distance.h"
52
+
53
+ #if defined(WIN32) || defined(__WIN32__)
54
+ #include <malloc.h>
55
+ #endif
56
+
57
+ #ifdef USE_LIST_NODE_ALLOCATOR
58
+
59
+ #ifndef NO_PTHREADS
60
+ #include <pthread.h>
61
+ #else
62
+
63
+ #ifndef I_WANT_THREAD_BUGS
64
+ #error "You are compiling with the fast list node allocator, with pthreads disabled! This WILL break if used from multiple threads."
65
+ #endif /* I want thread bugs */
66
+
67
+ #endif /* pthread support */
68
+ #endif /* use list node allocator */
69
+
70
+ struct kdhyperrect {
71
+ int dim;
72
+ double *min, *max; /* minimum/maximum coords */
73
+ };
74
+
75
+ struct kdnode {
76
+ double *pos;
77
+ int dir;
78
+ void *data;
79
+
80
+ struct kdnode *left, *right; /* negative/positive side */
81
+ };
82
+
83
+ struct res_node {
84
+ struct kdnode *item;
85
+ double dist_sq;
86
+ struct res_node *next;
87
+ };
88
+
89
+ struct kdtree {
90
+ int dim;
91
+ struct kdnode *root;
92
+ struct kdhyperrect *rect;
93
+ void (*destr)(void*);
94
+ };
95
+
96
+ struct kdres {
97
+ struct kdtree *tree;
98
+ struct res_node *rlist, *riter;
99
+ int size;
100
+ };
101
+
102
+ #define SQ(x) ((x) * (x))
103
+
104
+
105
+ static int find_nearest(struct kdnode *node, const double *pos, double range, struct res_node *list, int ordered, int dim, double (*distance_function)(const double *, const double *, int k), int (*compare_function)(double, double));
106
+ static void kd_nearest_i(struct kdnode *node, const double *pos, struct kdnode **result, double *result_dist_sq, struct kdhyperrect* rect);
107
+ static double geo_distance_mi(const double *a, const double *b, int k);
108
+ static double geo_distance_km(const double *a, const double *b, int k);
109
+
110
+ static void clear_rec(struct kdnode *node, void (*destr)(void*));
111
+ static int insert_rec(struct kdnode **node, const double *pos, void *data, int dir, int dim);
112
+ static int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq);
113
+ static void clear_results(struct kdres *set);
114
+
115
+ static struct kdhyperrect* hyperrect_create(int dim, const double *min, const double *max);
116
+ static void hyperrect_free(struct kdhyperrect *rect);
117
+ static struct kdhyperrect* hyperrect_duplicate(const struct kdhyperrect *rect);
118
+ static void hyperrect_extend(struct kdhyperrect *rect, const double *pos);
119
+ static double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos);
120
+
121
+ #ifdef USE_LIST_NODE_ALLOCATOR
122
+ static struct res_node *alloc_resnode(void);
123
+ static void free_resnode(struct res_node*);
124
+ #else
125
+ #define alloc_resnode() malloc(sizeof(struct res_node))
126
+ #define free_resnode(n) free(n)
127
+ #endif
128
+
129
+
130
+ struct kdtree *kd_create(int k)
131
+ {
132
+ struct kdtree *tree;
133
+
134
+ if(!(tree = malloc(sizeof *tree))) {
135
+ return 0;
136
+ }
137
+
138
+ tree->dim = k;
139
+ tree->root = 0;
140
+ tree->destr = 0;
141
+ tree->rect = 0;
142
+
143
+ return tree;
144
+ }
145
+
146
+ void kd_free(struct kdtree *tree)
147
+ {
148
+ if(tree) {
149
+ kd_clear(tree);
150
+ free(tree);
151
+ }
152
+ }
153
+
154
+ static void clear_rec(struct kdnode *node, void (*destr)(void*))
155
+ {
156
+ if(!node) return;
157
+
158
+ clear_rec(node->left, destr);
159
+ clear_rec(node->right, destr);
160
+
161
+ if(destr) {
162
+ destr(node->data);
163
+ }
164
+ free(node->pos);
165
+ free(node);
166
+ }
167
+
168
+ void kd_clear(struct kdtree *tree)
169
+ {
170
+ clear_rec(tree->root, tree->destr);
171
+ tree->root = 0;
172
+
173
+ if (tree->rect) {
174
+ hyperrect_free(tree->rect);
175
+ tree->rect = 0;
176
+ }
177
+ }
178
+
179
+ void kd_data_destructor(struct kdtree *tree, void (*destr)(void*))
180
+ {
181
+ tree->destr = destr;
182
+ }
183
+
184
+
185
+ static int insert_rec(struct kdnode **nptr, const double *pos, void *data, int dir, int dim)
186
+ {
187
+ int new_dir;
188
+ struct kdnode *node;
189
+
190
+ if(!*nptr) {
191
+ if(!(node = malloc(sizeof *node))) {
192
+ return -1;
193
+ }
194
+ if(!(node->pos = malloc(dim * sizeof *node->pos))) {
195
+ free(node);
196
+ return -1;
197
+ }
198
+ memcpy(node->pos, pos, dim * sizeof *node->pos);
199
+ node->data = data;
200
+ node->dir = dir;
201
+ node->left = node->right = 0;
202
+ *nptr = node;
203
+ return 0;
204
+ }
205
+
206
+ node = *nptr;
207
+ new_dir = (node->dir + 1) % dim;
208
+ if(pos[node->dir] < node->pos[node->dir]) {
209
+ return insert_rec(&(*nptr)->left, pos, data, new_dir, dim);
210
+ }
211
+ return insert_rec(&(*nptr)->right, pos, data, new_dir, dim);
212
+ }
213
+
214
+ int kd_insert(struct kdtree *tree, const double *pos, void *data)
215
+ {
216
+ if (insert_rec(&tree->root, pos, data, 0, tree->dim)) {
217
+ return -1;
218
+ }
219
+
220
+ if (tree->rect == 0) {
221
+ tree->rect = hyperrect_create(tree->dim, pos, pos);
222
+ } else {
223
+ hyperrect_extend(tree->rect, pos);
224
+ }
225
+
226
+ return 0;
227
+ }
228
+
229
+ int kd_insert2(struct kdtree *tree, double x, double y, void *data)
230
+ {
231
+ double pos[2];
232
+ pos[0] = x;
233
+ pos[1] = y;
234
+ return kd_insert(tree, pos, data);
235
+ }
236
+
237
+ int kd_insert3(struct kdtree *tree, double x, double y, double z, void *data)
238
+ {
239
+ double pos[3];
240
+ pos[0] = x;
241
+ pos[1] = y;
242
+ pos[2] = z;
243
+ return kd_insert(tree, pos, data);
244
+ }
245
+
246
+ /* TODO: add > 16 dimensions handling */
247
+ static int find_nearest(
248
+ struct kdnode *node,
249
+ const double *pos,
250
+ double range,
251
+ struct res_node *list,
252
+ int ordered,
253
+ int dim,
254
+ double (*distance_function)(const double *, const double *, int k),
255
+ int (*compare_function)(double, double)
256
+ )
257
+ {
258
+ double dist, one_dim_dist, one_dim_relative_dist;
259
+ int i, ret, added_res = 0;
260
+ double one_dim_pos[16];
261
+
262
+ if(!node) return 0;
263
+ if(dim > 16) return -1;
264
+
265
+ dist = (*distance_function)(node->pos, pos, dim);
266
+ if((*compare_function)(dist, range) <= 0) {
267
+ if(rlist_insert(list, node, ordered ? dist : -1.0) == -1) {
268
+ return -1;
269
+ }
270
+ added_res = 1;
271
+ }
272
+
273
+ /* isolate single dimension position from node->pos into one_dim_pos for single dimension distance computation */
274
+ for(i = 0; i < dim; i++) {
275
+ one_dim_pos[i] = pos[i];
276
+ }
277
+ one_dim_pos[node->dir] = node->pos[node->dir];
278
+
279
+ one_dim_dist = (*distance_function)(pos, one_dim_pos, dim);
280
+ one_dim_relative_dist = pos[node->dir] - node->pos[node->dir];
281
+
282
+ ret = find_nearest(one_dim_relative_dist <= 0.0 ? node->left : node->right, pos, range, list, ordered, dim, distance_function, compare_function);
283
+ if(ret >= 0 && (*compare_function)(one_dim_dist, range) < 0) {
284
+ added_res += ret;
285
+ ret = find_nearest(one_dim_relative_dist <= 0.0 ? node->right : node->left, pos, range, list, ordered, dim, distance_function, compare_function);
286
+ }
287
+ if(ret == -1) {
288
+ return -1;
289
+ }
290
+ added_res += ret;
291
+
292
+ return added_res;
293
+ }
294
+
295
+ #if 0
296
+ static int find_nearest_n(struct kdnode *node, const double *pos, double range, int num, struct rheap *heap, int dim)
297
+ {
298
+ double dist_sq, dx;
299
+ int i, ret, added_res = 0;
300
+
301
+ if(!node) return 0;
302
+
303
+ /* if the photon is close enough, add it to the result heap */
304
+ dist_sq = 0;
305
+ for(i=0; i<dim; i++) {
306
+ dist_sq += SQ(node->pos[i] - pos[i]);
307
+ }
308
+ if(dist_sq <= range_sq) {
309
+ if(heap->size >= num) {
310
+ /* get furthest element */
311
+ struct res_node *maxelem = rheap_get_max(heap);
312
+
313
+ /* and check if the new one is closer than that */
314
+ if(maxelem->dist_sq > dist_sq) {
315
+ rheap_remove_max(heap);
316
+
317
+ if(rheap_insert(heap, node, dist_sq) == -1) {
318
+ return -1;
319
+ }
320
+ added_res = 1;
321
+
322
+ range_sq = dist_sq;
323
+ }
324
+ } else {
325
+ if(rheap_insert(heap, node, dist_sq) == -1) {
326
+ return =1;
327
+ }
328
+ added_res = 1;
329
+ }
330
+ }
331
+
332
+
333
+ /* find signed distance from the splitting plane */
334
+ dx = pos[node->dir] - node->pos[node->dir];
335
+
336
+ ret = find_nearest_n(dx <= 0.0 ? node->left : node->right, pos, range, num, heap, dim);
337
+ if(ret >= 0 && fabs(dx) < range) {
338
+ added_res += ret;
339
+ ret = find_nearest_n(dx <= 0.0 ? node->right : node->left, pos, range, num, heap, dim);
340
+ }
341
+
342
+ }
343
+ #endif
344
+
345
+ static void kd_nearest_i(struct kdnode *node, const double *pos, struct kdnode **result, double *result_dist_sq, struct kdhyperrect* rect)
346
+ {
347
+ int dir = node->dir;
348
+ int i;
349
+ double dummy, dist_sq;
350
+ struct kdnode *nearer_subtree, *farther_subtree;
351
+ double *nearer_hyperrect_coord, *farther_hyperrect_coord;
352
+
353
+ /* Decide whether to go left or right in the tree */
354
+ dummy = pos[dir] - node->pos[dir];
355
+ if (dummy <= 0) {
356
+ nearer_subtree = node->left;
357
+ farther_subtree = node->right;
358
+ nearer_hyperrect_coord = rect->max + dir;
359
+ farther_hyperrect_coord = rect->min + dir;
360
+ } else {
361
+ nearer_subtree = node->right;
362
+ farther_subtree = node->left;
363
+ nearer_hyperrect_coord = rect->min + dir;
364
+ farther_hyperrect_coord = rect->max + dir;
365
+ }
366
+
367
+ if (nearer_subtree) {
368
+ /* Slice the hyperrect to get the hyperrect of the nearer subtree */
369
+ dummy = *nearer_hyperrect_coord;
370
+ *nearer_hyperrect_coord = node->pos[dir];
371
+ /* Recurse down into nearer subtree */
372
+ kd_nearest_i(nearer_subtree, pos, result, result_dist_sq, rect);
373
+ /* Undo the slice */
374
+ *nearer_hyperrect_coord = dummy;
375
+ }
376
+
377
+ /* Check the distance of the point at the current node, compare it
378
+ * with our best so far */
379
+ dist_sq = 0;
380
+ for(i=0; i < rect->dim; i++) {
381
+ dist_sq += SQ(node->pos[i] - pos[i]);
382
+ }
383
+ if (dist_sq < *result_dist_sq) {
384
+ *result = node;
385
+ *result_dist_sq = dist_sq;
386
+ }
387
+
388
+ if (farther_subtree) {
389
+ /* Get the hyperrect of the farther subtree */
390
+ dummy = *farther_hyperrect_coord;
391
+ *farther_hyperrect_coord = node->pos[dir];
392
+ /* Check if we have to recurse down by calculating the closest
393
+ * point of the hyperrect and see if it's closer than our
394
+ * minimum distance in result_dist_sq. */
395
+ if (hyperrect_dist_sq(rect, pos) < *result_dist_sq) {
396
+ /* Recurse down into farther subtree */
397
+ kd_nearest_i(farther_subtree, pos, result, result_dist_sq, rect);
398
+ }
399
+ /* Undo the slice on the hyperrect */
400
+ *farther_hyperrect_coord = dummy;
401
+ }
402
+ }
403
+
404
+ struct kdres *kd_nearest(struct kdtree *kd, const double *pos)
405
+ {
406
+ struct kdhyperrect *rect;
407
+ struct kdnode *result;
408
+ struct kdres *rset;
409
+ double dist_sq;
410
+ int i;
411
+
412
+ if (!kd) return 0;
413
+ if (!kd->rect) return 0;
414
+
415
+ /* Allocate result set */
416
+ if(!(rset = malloc(sizeof *rset))) {
417
+ return 0;
418
+ }
419
+ if(!(rset->rlist = alloc_resnode())) {
420
+ free(rset);
421
+ return 0;
422
+ }
423
+ rset->rlist->next = 0;
424
+ rset->tree = kd;
425
+
426
+ /* Duplicate the bounding hyperrectangle, we will work on the copy */
427
+ if (!(rect = hyperrect_duplicate(kd->rect))) {
428
+ kd_res_free(rset);
429
+ return 0;
430
+ }
431
+
432
+ /* Our first guesstimate is the root node */
433
+ result = kd->root;
434
+ dist_sq = 0;
435
+ for (i = 0; i < kd->dim; i++)
436
+ dist_sq += SQ(result->pos[i] - pos[i]);
437
+
438
+ /* Search for the nearest neighbour recursively */
439
+ kd_nearest_i(kd->root, pos, &result, &dist_sq, rect);
440
+
441
+ /* Free the copy of the hyperrect */
442
+ hyperrect_free(rect);
443
+
444
+ /* Store the result */
445
+ if (result) {
446
+ if (rlist_insert(rset->rlist, result, -1.0) == -1) {
447
+ kd_res_free(rset);
448
+ return 0;
449
+ }
450
+ rset->size = 1;
451
+ kd_res_rewind(rset);
452
+ return rset;
453
+ } else {
454
+ kd_res_free(rset);
455
+ return 0;
456
+ }
457
+ }
458
+
459
+
460
+ struct kdres *kd_nearest2(struct kdtree *tree, double x, double y)
461
+ {
462
+ double pos[2];
463
+ pos[0] = x;
464
+ pos[1] = y;
465
+ return kd_nearest(tree, pos);
466
+ }
467
+
468
+ struct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z)
469
+ {
470
+ double pos[3];
471
+ pos[0] = x;
472
+ pos[1] = y;
473
+ pos[2] = z;
474
+ return kd_nearest(tree, pos);
475
+ }
476
+
477
+ /* ---- nearest N search ---- */
478
+ /*
479
+ static kdres *kd_nearest_n(struct kdtree *kd, const double *pos, int num)
480
+ {
481
+ int ret;
482
+ struct kdres *rset;
483
+
484
+ if(!(rset = malloc(sizeof *rset))) {
485
+ return 0;
486
+ }
487
+ if(!(rset->rlist = alloc_resnode())) {
488
+ free(rset);
489
+ return 0;
490
+ }
491
+ rset->rlist->next = 0;
492
+ rset->tree = kd;
493
+
494
+ if((ret = find_nearest_n(kd->root, pos, range, num, rset->rlist, kd->dim)) == -1) {
495
+ kd_res_free(rset);
496
+ return 0;
497
+ }
498
+ rset->size = ret;
499
+ kd_res_rewind(rset);
500
+ return rset;
501
+ }*/
502
+
503
+ struct kdres *kd_generic_nearest_range(
504
+ struct kdtree *kd,
505
+ const double *pos,
506
+ double range,
507
+ double (*distance_function)(const double *, const double *, int k),
508
+ int (*compare_function)(double, double)
509
+ )
510
+ {
511
+ int ret;
512
+ struct kdres *rset;
513
+
514
+ if(!(rset = malloc(sizeof *rset))) {
515
+ return 0;
516
+ }
517
+ if(!(rset->rlist = alloc_resnode())) {
518
+ free(rset);
519
+ return 0;
520
+ }
521
+ rset->rlist->next = 0;
522
+ rset->tree = kd;
523
+
524
+ if((ret = find_nearest(kd->root, pos, range, rset->rlist, 0, kd->dim, distance_function, compare_function)) == -1) {
525
+ kd_res_free(rset);
526
+ return 0;
527
+ }
528
+ rset->size = ret;
529
+ kd_res_rewind(rset);
530
+ return rset;
531
+ }
532
+
533
+ struct kdres *kd_nearest_range(struct kdtree *kd, const double *pos, double range)
534
+ {
535
+ return kd_generic_nearest_range(kd, pos, range, square_euclidean_distance, bsq_compare);
536
+ }
537
+
538
+ struct kdres *kd_nearest_range2(struct kdtree *tree, double x, double y, double range)
539
+ {
540
+ double pos[2];
541
+ pos[0] = x;
542
+ pos[1] = y;
543
+ return kd_nearest_range(tree, pos, range);
544
+ }
545
+
546
+ struct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range)
547
+ {
548
+ double pos[3];
549
+ pos[0] = x;
550
+ pos[1] = y;
551
+ pos[2] = z;
552
+ return kd_nearest_range(tree, pos, range);
553
+ }
554
+
555
+ static double geo_distance_mi(const double *a, const double *b, int k)
556
+ {
557
+ /* just ignore k, we know its 2d but k is required per distance function signature */
558
+ return slc_distance(a, b, RADIUS_MI);
559
+ }
560
+
561
+ static double geo_distance_km(const double *a, const double *b, int k)
562
+ {
563
+ /* just ignore k, we know its 2d but k is required per distance function signature */
564
+ return slc_distance(a, b, RADIUS_KM);
565
+ }
566
+
567
+ struct kdres *kd_nearest_geo_range(struct kdtree *kd, double lat, double lng, double range, int units)
568
+ {
569
+ double pos[2];
570
+ pos[0] = lat;
571
+ pos[1] = lng;
572
+ if(units != GEO_UNITS_MI) {
573
+ return kd_generic_nearest_range(kd, pos, range, geo_distance_km, std_compare);
574
+ }
575
+ return kd_generic_nearest_range(kd, pos, range, geo_distance_mi, std_compare);
576
+ }
577
+
578
+ void kd_res_free(struct kdres *rset)
579
+ {
580
+ clear_results(rset);
581
+ free_resnode(rset->rlist);
582
+ free(rset);
583
+ }
584
+
585
+ int kd_res_size(struct kdres *set)
586
+ {
587
+ return (set->size);
588
+ }
589
+
590
+ void kd_res_rewind(struct kdres *rset)
591
+ {
592
+ rset->riter = rset->rlist->next;
593
+ }
594
+
595
+ int kd_res_end(struct kdres *rset)
596
+ {
597
+ return rset->riter == 0;
598
+ }
599
+
600
+ int kd_res_next(struct kdres *rset)
601
+ {
602
+ rset->riter = rset->riter->next;
603
+ return rset->riter != 0;
604
+ }
605
+
606
+ void *kd_res_item(struct kdres *rset, double *pos)
607
+ {
608
+ if(rset->riter) {
609
+ if(pos) {
610
+ memcpy(pos, rset->riter->item->pos, rset->tree->dim * sizeof *pos);
611
+ }
612
+ return rset->riter->item->data;
613
+ }
614
+ return 0;
615
+ }
616
+
617
+ void *kd_res_item3(struct kdres *rset, double *x, double *y, double *z)
618
+ {
619
+ if(rset->riter) {
620
+ if(*x) *x = rset->riter->item->pos[0];
621
+ if(*y) *y = rset->riter->item->pos[1];
622
+ if(*z) *z = rset->riter->item->pos[2];
623
+ }
624
+ return 0;
625
+ }
626
+
627
+ void *kd_res_item_data(struct kdres *set)
628
+ {
629
+ return kd_res_item(set, 0);
630
+ }
631
+
632
+ /* ---- hyperrectangle helpers ---- */
633
+ static struct kdhyperrect* hyperrect_create(int dim, const double *min, const double *max)
634
+ {
635
+ size_t size = dim * sizeof(double);
636
+ struct kdhyperrect* rect = 0;
637
+
638
+ if (!(rect = malloc(sizeof(struct kdhyperrect)))) {
639
+ return 0;
640
+ }
641
+
642
+ rect->dim = dim;
643
+ if (!(rect->min = malloc(size))) {
644
+ free(rect);
645
+ return 0;
646
+ }
647
+ if (!(rect->max = malloc(size))) {
648
+ free(rect->min);
649
+ free(rect);
650
+ return 0;
651
+ }
652
+ memcpy(rect->min, min, size);
653
+ memcpy(rect->max, max, size);
654
+
655
+ return rect;
656
+ }
657
+
658
+ static void hyperrect_free(struct kdhyperrect *rect)
659
+ {
660
+ free(rect->min);
661
+ free(rect->max);
662
+ free(rect);
663
+ }
664
+
665
+ static struct kdhyperrect* hyperrect_duplicate(const struct kdhyperrect *rect)
666
+ {
667
+ return hyperrect_create(rect->dim, rect->min, rect->max);
668
+ }
669
+
670
+ static void hyperrect_extend(struct kdhyperrect *rect, const double *pos)
671
+ {
672
+ int i;
673
+
674
+ for (i=0; i < rect->dim; i++) {
675
+ if (pos[i] < rect->min[i]) {
676
+ rect->min[i] = pos[i];
677
+ }
678
+ if (pos[i] > rect->max[i]) {
679
+ rect->max[i] = pos[i];
680
+ }
681
+ }
682
+ }
683
+
684
+ static double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos)
685
+ {
686
+ int i;
687
+ double result = 0;
688
+
689
+ for (i=0; i < rect->dim; i++) {
690
+ if (pos[i] < rect->min[i]) {
691
+ result += SQ(rect->min[i] - pos[i]);
692
+ } else if (pos[i] > rect->max[i]) {
693
+ result += SQ(rect->max[i] - pos[i]);
694
+ }
695
+ }
696
+
697
+ return result;
698
+ }
699
+
700
+ /* ---- static helpers ---- */
701
+
702
+ #ifdef USE_LIST_NODE_ALLOCATOR
703
+ /* special list node allocators. */
704
+ static struct res_node *free_nodes;
705
+
706
+ #ifndef NO_PTHREADS
707
+ static pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER;
708
+ #endif
709
+
710
+ static struct res_node *alloc_resnode(void)
711
+ {
712
+ struct res_node *node;
713
+
714
+ #ifndef NO_PTHREADS
715
+ pthread_mutex_lock(&alloc_mutex);
716
+ #endif
717
+
718
+ if(!free_nodes) {
719
+ node = malloc(sizeof *node);
720
+ } else {
721
+ node = free_nodes;
722
+ free_nodes = free_nodes->next;
723
+ node->next = 0;
724
+ }
725
+
726
+ #ifndef NO_PTHREADS
727
+ pthread_mutex_unlock(&alloc_mutex);
728
+ #endif
729
+
730
+ return node;
731
+ }
732
+
733
+ static void free_resnode(struct res_node *node)
734
+ {
735
+ #ifndef NO_PTHREADS
736
+ pthread_mutex_lock(&alloc_mutex);
737
+ #endif
738
+
739
+ node->next = free_nodes;
740
+ free_nodes = node;
741
+
742
+ #ifndef NO_PTHREADS
743
+ pthread_mutex_unlock(&alloc_mutex);
744
+ #endif
745
+ }
746
+ #endif /* list node allocator or not */
747
+
748
+
749
+ /* inserts the item. if dist_sq is >= 0, then do an ordered insert */
750
+ /* TODO make the ordering code use heapsort */
751
+ static int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq)
752
+ {
753
+ struct res_node *rnode;
754
+
755
+ if(!(rnode = alloc_resnode())) {
756
+ return -1;
757
+ }
758
+ rnode->item = item;
759
+ rnode->dist_sq = dist_sq;
760
+
761
+ if(dist_sq >= 0.0) {
762
+ while(list->next && list->next->dist_sq < dist_sq) {
763
+ list = list->next;
764
+ }
765
+ }
766
+ rnode->next = list->next;
767
+ list->next = rnode;
768
+ return 0;
769
+ }
770
+
771
+ static void clear_results(struct kdres *rset)
772
+ {
773
+ struct res_node *tmp, *node = rset->rlist->next;
774
+
775
+ while(node) {
776
+ tmp = node;
777
+ node = node->next;
778
+ free_resnode(tmp);
779
+ }
780
+
781
+ rset->rlist->next = 0;
782
+ }