rquad 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+
2
+ /pkg/rquad-0.1.0.gem
data/CHANGES ADDED
@@ -0,0 +1,2 @@
1
+ Version 0.5
2
+ - Initial public release, base quadtree and vector classes in place, with tests.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ LICENSE
2
+
3
+ Copyright (c) 2008, Andrew Cantino, Iteration Labs, LLC, http://iterationlabs.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,7 @@
1
+ Welcome to the rQuad Ruby Quadtree library.
2
+
3
+ This package is distributed subject to the 'MIT License' found in the LICENSE file in this directory.
4
+
5
+ The source is freely available online: http://github.com/iterationlabs/rquad/tree/master
6
+
7
+ If you make modifications to this software and would be willing to contribute them back to the community, please send them in for possible inclusion in future releases!
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rquad"
8
+ gem.summary = %Q{Ruby Quadtree Library}
9
+ gem.description = %Q{Ruby Quadtree Library}
10
+ gem.email = "roman.scherer@nugg.ad"
11
+ gem.homepage = "http://github.com/r0man/rquad"
12
+ gem.authors = ["Roman Scherer"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/test_*.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+ task :test => :check_dependencies
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "rquad #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,2 @@
1
+ require "rquad/vector"
2
+ require "rquad/quadtree"
@@ -0,0 +1,353 @@
1
+ # SOFTWARE INFO
2
+ #
3
+ # This file is part of the quadtree.rb Ruby quadtree library, distributed
4
+ # subject to the 'MIT License' below. This software is available for
5
+ # download at http://iterationlabs.com/free_software/quadtree.
6
+ #
7
+ # If you make modifications to this software and would be willing to
8
+ # contribute them back to the community, please send them to us for
9
+ # possible inclusion in future releases!
10
+ #
11
+ # LICENSE
12
+ #
13
+ # Copyright (c) 2008, Iteration Labs, LLC, http://iterationlabs.com
14
+ #
15
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ # of this software and associated documentation files (the "Software"), to deal
17
+ # in the Software without restriction, including without limitation the rights
18
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ # copies of the Software, and to permit persons to whom the Software is
20
+ # furnished to do so, subject to the following conditions:
21
+ #
22
+ # The above copyright notice and this permission notice shall be included in
23
+ # all copies or substantial portions of the Software.
24
+ #
25
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
+ # THE SOFTWARE.
32
+ #
33
+ require "rquad/vector"
34
+
35
+ module RQuad
36
+
37
+ # A payload for a QuadTree. Hs accessors for vector, data, and node.
38
+ class QuadTreePayload
39
+ attr_accessor :vector, :data, :node
40
+
41
+ # Initialize a QuadTreePayload with a Vector, some data (any class).
42
+ def initialize(v, d, n = nil)
43
+ self.node = n
44
+ self.vector = v
45
+ self.data = d
46
+ end
47
+ end
48
+
49
+ # A quadtree node that can contain QuadTreePayloads and other QuadTree nodes. A quadtree is a tree that subdivides space into recursively defined quadrents that (in this implementation) can contain no more than one spacially-unique payload. Quadtrees are good for answering questions about neighborhoods of points in a space.
50
+ #
51
+ # Making a quadtree is simple, just initialize a new QuadTree with two vectors, its top left and bottom right points, then add QuadTreePayloads to it and it will store them in an efficiently constructed quadtree structure. You may then ask for all payloads in a region, all payloads near a point, etc.
52
+ #
53
+ # Example usage with longitudes and latitudes:
54
+ #
55
+ # qt = QuadTree.new(Vector.new(-180, 90), Vector.new(180, -90))
56
+ # qt.add(QuadTreePayload.new(Vector.new(lng1, lat1), entity1))
57
+ # qt.add(QuadTreePayload.new(Vector.new(lng2, lat2), entity2))
58
+ # qt.add(QuadTreePayload.new(Vector.new(lng3, lat3), entity3))
59
+ # qt.add(QuadTreePayload.new(Vector.new(lng4, lat4), entity4))
60
+ #
61
+ class QuadTree
62
+ # You may ask a QuadTree for its `payload`, `tl` point, `br` point, and `depth`.
63
+ attr_accessor :payload, :tl, :br, :depth
64
+
65
+ # Initialize a new QuadTree with two vectors: its top-left corner and its bottom-right corner. Optionally, you can also provide a reference to this node's parent node.
66
+ def initialize(tl, br, parent_node = nil)
67
+ @parent = parent_node
68
+ @tl = tl
69
+ @br = br
70
+ @size = 0
71
+ @summed_contained_vectors = Vector.new(0,0)
72
+ @depth = 0
73
+ end
74
+
75
+ # Add a QuadTreePayload to this QuadTree. If this node is empty, it will be stored in this node. If not, both the new payload and the old one will be recursively added to the appropriate one of the four children of this node. There is a special case: if this node already has a payload and the new payload has an identical position to the existing payload, then the new payload will be stored here in ddition to the existing payload.
76
+ # jitter_proc - a Proc object that, if provided, is used to jitter payloads with identical vectors (accepts and returns a QuadTreePayload).
77
+ def add(geo_data, depth = 1, jitter_proc = nil)
78
+ geo_data.node = self
79
+ if size > 0
80
+ if @payload && (@payload.first.vector == geo_data.vector)
81
+ # The vectors match.
82
+ if jitter_proc
83
+ @payload << jitter_proc.call(geo_data)
84
+ else
85
+ @payload << geo_data
86
+ end
87
+ else
88
+ # The vectors don't match.
89
+ if payload
90
+ @payload.each { |p| add_into_subtree(p, depth + 1, jitter_proc) }
91
+ @payload = nil
92
+ end
93
+ add_into_subtree(geo_data, depth + 1, jitter_proc)
94
+ end
95
+ else
96
+ @payload = [geo_data]
97
+ @depth = depth
98
+ end
99
+ @summed_contained_vectors += geo_data.vector
100
+ @size += 1
101
+ end
102
+
103
+ # This method returns the payloads contained under this node in the quadtree. It takes an options hash with the following optional keys:
104
+ # :max_count - the maximum number of payloads to return, provided via a breadth-first search.
105
+ # :details_proc - a Proc object to which every internal node at the maximum deoth achieved by the search is passed -- this is useful for providing summary statistics about subtrees that were not explored by this traversal due to a :max_count limitation.
106
+ # :requirement_proc - a Proc object that, if provided, must return true when evaluating a payload in order for that payload to be returned.
107
+ # Returns a Hash with keys :payloads, an array of all of the payloads below this node, and :details, the mapped result of applying :details_proc (if provided) to every internal node at the mximum depth achieved by the search.
108
+ def get_contained(options = {})
109
+ payloads = []
110
+ internal_nodes = []
111
+ last_depth = -1
112
+ breadth_first_each do |node, depth|
113
+ break if options[:max_count] && payloads.length >= options[:max_count] && (!options[:details_proc] || depth != last_depth)
114
+
115
+ if node.payload
116
+ internal_nodes.delete_if {|i| i.parent_of?(node)} if options[:details_proc]
117
+ node.payload.each do |entry|
118
+ if !options[:requirement_proc] || options[:requirement_proc].call(entry)
119
+ payloads << entry
120
+ end
121
+ end
122
+ elsif options[:details_proc] && (node.tlq? || node.trq? || node.blq? || node.brq?)
123
+ internal_nodes.delete_if {|i| i.parent_of?(node)}
124
+ internal_nodes << node
125
+ end
126
+ last_depth = depth
127
+ end
128
+ { :payloads => payloads, :details => (options[:details_proc] ? internal_nodes.map {|i| options[:details_proc].call(i)} : nil) }
129
+ end
130
+
131
+ # Calls get_contained and only returns the :payloads key. Accepts the same options as get_contained except for the :details_proc option.
132
+ def get_contained_payloads(options = {})
133
+ get_contained(options)[:payloads]
134
+ end
135
+
136
+ # Returns the centroid of the payloads contained in this quadtree.
137
+ def center_of_mass
138
+ @summed_contained_vectors / @size
139
+ end
140
+
141
+ # Performs a breath-first traversal of this quadtree, yielding [node, depth] for each node.
142
+ def breadth_first_each
143
+ queue = [self]
144
+ while queue.length > 0
145
+ node = queue.shift
146
+ queue << node.tlq if node.tlq?
147
+ queue << node.trq if node.trq?
148
+ queue << node.blq if node.blq?
149
+ queue << node.brq if node.brq?
150
+ yield node, node.depth
151
+ end
152
+ end
153
+
154
+ # Yields each payload in this quadtree via a breadth-first traversal.
155
+ def each_payload
156
+ breadth_first_each do |node, depth|
157
+ next unless node.payload
158
+ node.payload.each do |payload|
159
+ yield payload
160
+ end
161
+ end
162
+ end
163
+
164
+ # True if this node is a direct parent of `node`.
165
+ def parent_of?(node)
166
+ node && node == tlq(false) || node == trq(false) || node == blq(false) || node == brq(false)
167
+ end
168
+
169
+ # True if this node is a direct child of `node`.
170
+ def child_of?(node)
171
+ node.parent_of?(self)
172
+ end
173
+
174
+ # Yields all pseudo-leaves formed when the graph is cut off at a certain depth, plus any leaves encountered before that depth.
175
+ def leaves_each(leaf_depth)
176
+ stack = [self]
177
+ while stack.length > 0
178
+ node = stack.pop
179
+ start_size = stack.length
180
+ stack << node.tlq if node.tlq? && node.tlq.depth < leaf_depth + depth
181
+ stack << node.trq if node.trq? && node.trq.depth < leaf_depth + depth
182
+ stack << node.blq if node.blq? && node.blq.depth < leaf_depth + depth
183
+ stack << node.brq if node.brq? && node.brq.depth < leaf_depth + depth
184
+ if node.depth == leaf_depth + depth - 1 || (!node.tlq? && !node.trq? && !node.blq? && !node.brq?)
185
+ yield node
186
+ end
187
+ end
188
+ end
189
+
190
+ # Returns the size of this node: the number of contained payloads.
191
+ def size
192
+ @size
193
+ end
194
+
195
+ # Returns this node's parent node or nil if this node is a root node.
196
+ def parent
197
+ @parent
198
+ end
199
+
200
+ # Returns approxametly `approx_number` payloads near `location`.
201
+ def approx_near(location, approx_number)
202
+ if approx_number >= size
203
+ return get_contained_payloads
204
+ else
205
+ get_containing_quad(location).approx_near(location, approx_number)
206
+ end
207
+ end
208
+
209
+ # Returns up to `max_number` payloads inside of the region specified by `region_tl` and `region_br`.
210
+ def payloads_in_region(region_tl, region_br, max_number = nil)
211
+ quad1 = get_containing_quad(region_tl)
212
+ quad2 = get_containing_quad(region_br)
213
+ if quad1 == quad2 && payload.nil?
214
+ quad1.payloads_in_region(region_tl, region_br, max_number)
215
+ else
216
+ region_containment_proc = lambda do |i|
217
+ region_tl.x <= i.vector.x && region_br.x >= i.vector.x && region_tl.y >= i.vector.y && region_br.y <= i.vector.y
218
+ end
219
+ get_contained_payloads(:max_count => max_number, :requirement_proc => region_containment_proc)
220
+ end
221
+ end
222
+
223
+ # Returns an array of [centroid (Vector), count] pairs summarizing the set of centroids at a certain tree depth. That is, it provides centroids and counts of all of the subtrees still available at depth `depth`, plus any that terminated above that depth.
224
+ def center_of_masses_in_region(region_tl, region_br, depth)
225
+ quad1 = get_containing_quad(region_tl)
226
+ quad2 = get_containing_quad(region_br)
227
+ if quad1 == quad2 && payload.nil?
228
+ quad1.center_of_masses_in_region(region_tl, region_br, depth)
229
+ else
230
+ centers_of_mass = []
231
+ leaves_each(depth) do |node|
232
+ centers_of_mass << [node.center_of_mass, node.size]
233
+ end
234
+ centers_of_mass
235
+ end
236
+ end
237
+
238
+ # Returns a hash with keys :payloads and :details. The :payloads are payloads found, while details are for nodes that didn't get to be explored because the requisite number of payloads were already found.
239
+ def payloads_and_centers_in_region(region_tl, region_br, approx_num_to_return)
240
+ quad1 = get_containing_quad(region_tl)
241
+ quad2 = get_containing_quad(region_br)
242
+ if quad1 == quad2 && payload.nil?
243
+ quad1.payloads_and_centers_in_region(region_tl, region_br, approx_num_to_return)
244
+ else
245
+ region_containment_proc = lambda do |i|
246
+ region_tl.x <= i.vector.x && region_br.x >= i.vector.x && region_tl.y >= i.vector.y && region_br.y <= i.vector.y
247
+ end
248
+ details_proc = lambda do |i|
249
+ [i.center_of_mass, i.size]
250
+ end
251
+ get_contained(:max_count => approx_num_to_return, :requirement_proc => region_containment_proc, :details_proc => details_proc)
252
+ end
253
+ end
254
+
255
+ # The top-left quadrent of this quadtree. If `build` is true, this will make the quadrent quadtree if it doesn't alredy exist.
256
+ def tlq(build = true)
257
+ @tlq ||= QuadTree.new(Vector.new(tl), Vector.new(tl.x + (br.x - tl.x) / 2.0, br.y + (tl.y - br.y) / 2.0), self) if build
258
+ @tlq
259
+ end
260
+
261
+ # The top-right quadrent of this quadtree. If `build` is true, this will make the quadrent quadtree if it doesn't alredy exist.
262
+ def trq(build = true)
263
+ @trq ||= QuadTree.new(Vector.new(tl.x + (br.x - tl.x) / 2.0, tl.y), Vector.new(br.x, br.y + (tl.y - br.y) / 2.0), self) if build
264
+ @trq
265
+ end
266
+
267
+ # The bottom-left quadrent of this quadtree. If `build` is true, this will make the quadrent quadtree if it doesn't alredy exist.
268
+ def blq(build = true)
269
+ @blq ||= QuadTree.new(Vector.new(tl.x, br.y + (tl.y - br.y) / 2.0), Vector.new(tl.x + (br.x - tl.x) / 2.0, br.y), self) if build
270
+ @blq
271
+ end
272
+
273
+ # The bottom-right quadrent of this quadtree. If `build` is true, this will make the quadrent quadtree if it doesn't alredy exist.
274
+ def brq(build = true)
275
+ @brq ||= QuadTree.new(Vector.new(tl.x + (br.x - tl.x) / 2.0, br.y + (tl.y - br.y) / 2.0), Vector.new(br), self) if build
276
+ @brq
277
+ end
278
+
279
+ # Returns true if this quadtree has a top-left quadrent already defined.
280
+ def tlq?
281
+ @tlq && (@tlq.payload || (@tlq.tlq? || @tlq.trq? || @tlq.blq? || @tlq.brq?))
282
+ end
283
+
284
+ # Returns true if this quadtree has a top-right quadrent already defined.
285
+ def trq?
286
+ @trq && (@trq.payload || (@trq.tlq? || @trq.trq? || @trq.blq? || @trq.brq?))
287
+ end
288
+
289
+ # Returns true if this quadtree has a bottom-left quadrent already defined.
290
+ def blq?
291
+ @blq && (@blq.payload || (@blq.tlq? || @blq.trq? || @blq.blq? || @blq.brq?))
292
+ end
293
+
294
+ # Returns true if this quadtree has a bottom-right quadrent already defined.
295
+ def brq?
296
+ @brq && (@brq.payload || (@brq.tlq? || @brq.trq? || @brq.blq? || @brq.brq?))
297
+ end
298
+
299
+ # Returns true if Vector `v` falls inside of this quadtree.
300
+ def inside?(v)
301
+ # Greedy, so the order of comparison of quads will matter.
302
+ tl.x <= v.x && br.x >= v.x && tl.y >= v.y && br.y <= v.y
303
+ end
304
+
305
+ # Clips Vector `v` to the bounds of this quadtree.
306
+ def clip_vector(v)
307
+ v = v.dup
308
+ v.x = tl.x if v.x < tl.x
309
+ v.y = tl.y if v.y > tl.y
310
+ v.x = br.x if v.x > br.x
311
+ v.y = br.y if v.y < br.y
312
+ v
313
+ end
314
+
315
+ # Scans back up a quadtree from this node until a node is found that contains the region defined by `in_tl` and `in_br`, at which point the subtree size is returned from that point.
316
+ # (Only scans back up the tree, won't scan down.)
317
+ def family_size_at_width(in_tl, in_br)
318
+ if (inside?(in_tl) && inside?(in_br)) || parent.nil?
319
+ size
320
+ else
321
+ parent.family_size_at_width(in_tl, in_br)
322
+ end
323
+ end
324
+
325
+ def to_s
326
+ "[Quadtree #{object_id}, size: #{size}, depth: #{depth}]"
327
+ end
328
+
329
+ def inspect
330
+ to_s
331
+ end
332
+
333
+ private
334
+
335
+ def add_into_subtree(geo_data, depth = 1, jitter_proc = nil)
336
+ get_containing_quad(geo_data.vector).add(geo_data, depth, jitter_proc)
337
+ end
338
+
339
+ def get_containing_quad(vector)
340
+ if tlq.inside?(vector)
341
+ tlq
342
+ elsif trq.inside?(vector)
343
+ trq
344
+ elsif blq.inside?(vector)
345
+ blq
346
+ elsif brq.inside?(vector)
347
+ brq
348
+ else
349
+ raise "This shouldn't happen! #{vector} isn't in any of my quads! (#{self.to_s})"
350
+ end
351
+ end
352
+ end
353
+ end
@@ -0,0 +1,162 @@
1
+ # SOFTWARE INFO
2
+ #
3
+ # This file is part of the quadtree.rb Ruby quadtree library, distributed
4
+ # subject to the 'MIT License' below. This software is available for
5
+ # download at http://iterationlabs.com/free_software/quadtree.
6
+ #
7
+ # If you make modifications to this software and would be willing to
8
+ # contribute them back to the community, please send them to us for
9
+ # possible inclusion in future releases!
10
+ #
11
+ # LICENSE
12
+ #
13
+ # Copyright (c) 2008, Iteration Labs, LLC, http://iterationlabs.com
14
+ #
15
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ # of this software and associated documentation files (the "Software"), to deal
17
+ # in the Software without restriction, including without limitation the rights
18
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ # copies of the Software, and to permit persons to whom the Software is
20
+ # furnished to do so, subject to the following conditions:
21
+ #
22
+ # The above copyright notice and this permission notice shall be included in
23
+ # all copies or substantial portions of the Software.
24
+ #
25
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
+ # THE SOFTWARE.
32
+ #
33
+
34
+ # A class for representing a simple 2D or 3D vector. Primarily for use with the QudTree class. Very simple and minimilistic.
35
+ # irb(main):002:0> v = Vector.new(1, 2)
36
+ # => #<Vector:0xb7c8dacc @x=1.0, @y=2.0>
37
+ # irb(main):003:0> v + Vector.new(10, 11)
38
+ # => #<Vector:0xb7c86d30 @x=11.0, @y=13.0>
39
+ # irb(main):004:0> (v + Vector.new(10, 11)).length
40
+ # => 17.0293863659264
41
+ # irb(main):005:0> v * -2
42
+ # => #<Vector:0xb7c73834 @x=-2.0, @y=-4.0>
43
+ module RQuad
44
+ class Vector
45
+ # Initialize a Vector with either another Vector, an Array, or 2-3 numbers.
46
+ def initialize(x = nil, y = nil, z = nil)
47
+ if x && x.kind_of?(Vector)
48
+ @x = x.x
49
+ @y = x.y
50
+ @z = x.z
51
+ elsif x && x.kind_of?(Array)
52
+ @x = x[0]
53
+ @y = x[1]
54
+ @z = x[2]
55
+ else
56
+ @x = x.to_f if x
57
+ @y = y.to_f if y
58
+ @z = z.to_f if z
59
+ end
60
+ end
61
+
62
+ # The X component of this vector.
63
+ def x
64
+ @x
65
+ end
66
+
67
+ # The Y component of this vector.
68
+ def y
69
+ @y
70
+ end
71
+
72
+ # The Z component of this vector.
73
+ def z
74
+ @z
75
+ end
76
+
77
+ # Set the X component of this vector.
78
+ def x=(new_x)
79
+ @x = new_x.to_f if new_x
80
+ end
81
+
82
+ # Set the Y component of this vector.
83
+ def y=(new_y)
84
+ @y = new_y.to_f if new_y
85
+ end
86
+
87
+ # Set the Z component of this vector.
88
+ def z=(new_z)
89
+ @z = new_z.to_f if new_z
90
+ end
91
+
92
+ # The length of this vector in 2D or 3D space.
93
+ def length
94
+ if z
95
+ Math.sqrt(x * x + y * y + z * z)
96
+ elsif x && y
97
+ Math.sqrt(x * x + y * y)
98
+ else
99
+ nil
100
+ end
101
+ end
102
+
103
+ # The Euclidean distnce between this and another Vector `other`.
104
+ def dist_to(other)
105
+ (other - self).length
106
+ end
107
+
108
+ # This vector minus another Vector `other`.
109
+ def -(other)
110
+ self + other * -1
111
+ end
112
+
113
+ # Divide this vector by a `scalar`.
114
+ def /(scalar)
115
+ if z
116
+ Vector.new(x / scalar, y / scalar, z / scalar)
117
+ elsif x && y
118
+ Vector.new(x / scalar, y / scalar)
119
+ else
120
+ Vector.new
121
+ end
122
+ end
123
+
124
+ # Multiply this vector by a `scalar`.
125
+ def *(scalar)
126
+ if z
127
+ Vector.new(x * scalar, y * scalar, z * scalar)
128
+ elsif x && y
129
+ Vector.new(x * scalar, y * scalar)
130
+ else
131
+ Vector.new
132
+ end
133
+ end
134
+
135
+ # Add another Vector `other` to this vector.
136
+ def +(other)
137
+ if z && other.z
138
+ Vector.new(x + other.x, y + other.y, z + other.z)
139
+ elsif x && y && other.x && other.y
140
+ Vector.new(x + other.x, y + other.y)
141
+ else
142
+ Vector.new
143
+ end
144
+ end
145
+
146
+ # Test if this vector is equal to another Vector `other`.
147
+ def ==(other)
148
+ result = (other.x == x && other.y == y && other.z == z)
149
+ # puts "(#{other.x} == #{x} && #{other.y} == #{y} && #{other.z} == #{z}) = #{result.inspect}"
150
+ result
151
+ end
152
+
153
+ # Display this vector as a String, either in <x, y> or <x, y, z> notation.
154
+ def to_s
155
+ if z
156
+ "<#{x ? x : 'nil'}, #{y ? y : 'nil'}, #{z}>"
157
+ else
158
+ "<#{x ? x : 'nil'}, #{y ? y : 'nil'}>"
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,55 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rquad}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Roman Scherer"]
12
+ s.date = %q{2010-11-02}
13
+ s.description = %q{Ruby Quadtree Library}
14
+ s.email = %q{roman.scherer@nugg.ad}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "CHANGES",
22
+ "LICENSE",
23
+ "README",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/rquad.rb",
27
+ "lib/rquad/quadtree.rb",
28
+ "lib/rquad/vector.rb",
29
+ "rquad.gemspec",
30
+ "test/helper.rb",
31
+ "test/rquad/test_quadtree.rb",
32
+ "test/rquad/test_vector.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/r0man/rquad}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.7}
38
+ s.summary = %q{Ruby Quadtree Library}
39
+ s.test_files = [
40
+ "test/rquad/test_quadtree.rb",
41
+ "test/rquad/test_vector.rb",
42
+ "test/helper.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ else
51
+ end
52
+ else
53
+ end
54
+ end
55
+
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ require 'rquad'
7
+
8
+ class Test::Unit::TestCase
9
+ end
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env ruby
2
+ # SOFTWARE INFO
3
+ #
4
+ # This file is part of the quadtree.rb Ruby quadtree library, distributed
5
+ # subject to the 'MIT License' below. This software is available for
6
+ # download at http://iterationlabs.com/free_software/quadtree.
7
+ #
8
+ # If you make modifications to this software and would be willing to
9
+ # contribute them back to the community, please send them to us for
10
+ # possible inclusion in future releases!
11
+ #
12
+ # LICENSE
13
+ #
14
+ # Copyright (c) 2008, Iteration Labs, LLC, http://iterationlabs.com
15
+ #
16
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
17
+ # of this software and associated documentation files (the "Software"), to deal
18
+ # in the Software without restriction, including without limitation the rights
19
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
+ # copies of the Software, and to permit persons to whom the Software is
21
+ # furnished to do so, subject to the following conditions:
22
+ #
23
+ # The above copyright notice and this permission notice shall be included in
24
+ # all copies or substantial portions of the Software.
25
+ #
26
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
+ # THE SOFTWARE.
33
+ #
34
+
35
+ require 'test/unit'
36
+ require 'fileutils'
37
+ require "rquad/quadtree"
38
+ require "rquad/vector"
39
+
40
+ module RQuad
41
+
42
+ class TestQuadTree < Test::Unit::TestCase
43
+ def standard_quad
44
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
45
+ q.add(QuadTreePayload.new(Vector.new(10, 10), :a))
46
+ q.add(QuadTreePayload.new(Vector.new(75, 75), :b))
47
+ q.add(QuadTreePayload.new(Vector.new(5, 99), :c))
48
+ q.add(QuadTreePayload.new(Vector.new(99, 5), :d))
49
+ q.add(QuadTreePayload.new(Vector.new(99, 4), :e))
50
+ q
51
+ end
52
+
53
+ def test_new_quadtree
54
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
55
+ assert_equal 0, q.size
56
+ end
57
+
58
+ def test_adding_element
59
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
60
+ q.add(QuadTreePayload.new(Vector.new(10, 10), 'hello'))
61
+ assert_equal 1, q.size
62
+ assert_equal 'hello', q.payload.first.data
63
+ end
64
+
65
+ def test_adding_a_few_elements
66
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
67
+ q.add(QuadTreePayload.new(Vector.new(10, 10), :a))
68
+ q.add(QuadTreePayload.new(Vector.new(75, 75), :b))
69
+ q.add(QuadTreePayload.new(Vector.new(5, 99), :c))
70
+ q.add(QuadTreePayload.new(Vector.new(99, 5), :d))
71
+ assert_equal 4, q.size
72
+ assert_equal nil, q.payload
73
+ assert_equal 1, q.tlq.size
74
+ assert_equal 1, q.trq.size
75
+ assert_equal 1, q.blq.size
76
+ assert_equal 1, q.brq.size
77
+ assert_equal :c, q.tlq.payload.first.data
78
+ assert_equal :b, q.trq.payload.first.data
79
+ assert_equal :a, q.blq.payload.first.data
80
+ assert_equal :d, q.brq.payload.first.data
81
+ end
82
+
83
+ def test_greedy_adding_of_elements_on_boundaries
84
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
85
+ q.add(QuadTreePayload.new(Vector.new(50, 50), :a))
86
+ assert_equal 1, q.size
87
+ assert_equal :a, q.payload.first.data
88
+ q.add(QuadTreePayload.new(Vector.new(0, 50), :b))
89
+ assert_equal :a, q.tlq.brq.payload.first.data
90
+ assert_equal :b, q.tlq.blq.payload.first.data
91
+ end
92
+
93
+ def test_adding_two_identical_elements
94
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
95
+ q.add(QuadTreePayload.new(Vector.new(10, 10), 'hello'))
96
+ assert_equal 1, q.size
97
+ assert_equal 'hello', q.payload.first.data
98
+ q.add(QuadTreePayload.new(Vector.new(10, 10), 'hi!'))
99
+ assert_equal 2, q.size
100
+ assert_equal 2, q.payload.length
101
+ assert_equal 'hello', q.payload.first.data
102
+ assert_equal 'hi!', q.payload.last.data
103
+ end
104
+
105
+ def test_approx_near
106
+ q = standard_quad
107
+ assert_equal 5, q.approx_near(Vector.new(50, 50), 5).length
108
+ assert_equal 5, q.approx_near(Vector.new(50, 50), 10).length
109
+ assert_equal true, q.approx_near(Vector.new(99, 1), 3).any? {|i| i.vector == Vector.new(99, 4)}
110
+ assert_equal true, q.approx_near(Vector.new(99, 1), 3).any? {|i| i.vector == Vector.new(99, 5)}
111
+ assert_equal false, q.approx_near(Vector.new(99, 1), 3).any? {|i| i.vector == Vector.new(10, 10)}
112
+ end
113
+
114
+ def test_payloads_in_region_in_small_region
115
+ q = standard_quad
116
+ assert_equal 2, q.payloads_in_region(Vector.new(98, 10), Vector.new(100, 0)).length
117
+ assert_equal 1, q.payloads_in_region(Vector.new(98, 10), Vector.new(100, 0), 1).length
118
+ assert_equal true, q.payloads_in_region(Vector.new(98, 10), Vector.new(100, 0)).any? {|i| i.vector == Vector.new(99, 4)}
119
+ assert_equal true, q.payloads_in_region(Vector.new(98, 10), Vector.new(100, 0)).any? {|i| i.vector == Vector.new(99, 5)}
120
+ assert_equal false, q.payloads_in_region(Vector.new(98, 10), Vector.new(100, 0)).any? {|i| i.vector == Vector.new(10, 10)}
121
+ end
122
+
123
+ def test_payloads_in_region_in_large_region
124
+ q = standard_quad
125
+ assert_equal 5, q.payloads_in_region(Vector.new(0, 100), Vector.new(100, 0)).length
126
+ end
127
+
128
+ def test_adding_a_third_element_to_two_identical_elements
129
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
130
+ q.add(QuadTreePayload.new(Vector.new(10, 10), 'hello'))
131
+ assert_equal 1, q.size
132
+ assert_equal 'hello', q.payload.first.data
133
+ q.add(QuadTreePayload.new(Vector.new(10, 10), 'hi!'))
134
+ assert_equal 2, q.size
135
+ assert_equal 2, q.payload.length
136
+ assert_equal 'hello', q.payload.first.data
137
+ assert_equal 'hi!', q.payload.last.data
138
+
139
+ q.add(QuadTreePayload.new(Vector.new(20,20), 'third wheel'))
140
+ assert_equal 3, q.size
141
+ assert_equal nil, q.payload
142
+ assert_equal 2, q.blq.blq.blq.payload.length
143
+ assert_equal 1, q.blq.blq.trq.payload.length
144
+ assert_equal 'third wheel', q.blq.blq.trq.payload.first.data
145
+
146
+ # And test get_contained_payloads while we're at it.
147
+ assert_equal 3, q.get_contained_payloads.length
148
+ assert_equal 3, q.blq.blq.get_contained_payloads.length
149
+ assert_equal 1, q.blq.blq.trq.get_contained_payloads.length
150
+ assert_equal 2, q.blq.blq.blq.get_contained_payloads.length
151
+ assert_equal 0, q.blq.blq.brq.get_contained_payloads.length
152
+ end
153
+
154
+ def test_get_contained_payloads_with_number_limit
155
+ q = standard_quad
156
+ assert_equal 1, q.get_contained_payloads(:max_count => 1).length
157
+ assert_equal 4, q.get_contained_payloads(:max_count => 4).length
158
+ assert_equal 5, q.get_contained_payloads(:max_count => 20).length
159
+ assert_equal 5, q.get_contained_payloads.length
160
+
161
+ assert_equal true, q.get_contained_payloads(:max_count => 4).any? {|i| i.vector == Vector.new(10, 10)}
162
+ assert_equal true, q.get_contained_payloads(:max_count => 4).any? {|i| i.vector == Vector.new(75, 75)}
163
+ assert_equal true, q.get_contained_payloads(:max_count => 4).any? {|i| i.vector == Vector.new(5, 99)}
164
+ assert_equal true, q.get_contained_payloads(:max_count => 4).any? {|i| i.vector == Vector.new(99, 5)}
165
+ assert_equal false, q.get_contained_payloads(:max_count => 4).any? {|i| i.vector == Vector.new(11, 10)} # because it's lower and quads go clockwise
166
+ end
167
+
168
+ def test_center_of_mass
169
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
170
+ q.add(QuadTreePayload.new(Vector.new(30, 55), :a))
171
+ q.add(QuadTreePayload.new(Vector.new(70, 55), :b))
172
+ assert_equal Vector.new(50,55), q.center_of_mass
173
+ assert_equal Vector.new(30,55), q.tlq.center_of_mass
174
+ assert_equal Vector.new(70,55), q.trq.center_of_mass
175
+ end
176
+
177
+ def test_depth
178
+ q = standard_quad
179
+ assert_equal 1, q.depth
180
+ assert_equal 2, q.tlq.depth
181
+ assert_equal 2, q.trq.depth
182
+ assert_equal 2, q.blq.depth
183
+ assert_equal 2, q.brq.depth
184
+ assert_equal 3, q.brq.brq.depth
185
+ end
186
+
187
+ def test_leaves_each
188
+ q = standard_quad
189
+ leaves = []
190
+ q.leaves_each(100) do |leaf|
191
+ leaves << leaf
192
+ end
193
+ assert_equal 5, leaves.length
194
+
195
+ leaves = []
196
+ q.leaves_each(3) do |leaf|
197
+ leaves << leaf
198
+ end
199
+ assert_equal 4, leaves.length
200
+ end
201
+
202
+ def test_clip_vector
203
+ q = QuadTree.new(Vector.new(0,100), Vector.new(100,0))
204
+ assert_equal Vector.new(0, 100), q.clip_vector(Vector.new(-1, 100))
205
+ assert_equal Vector.new(100, 100), q.clip_vector(Vector.new(200, 200))
206
+ assert_equal Vector.new(0, 0), q.clip_vector(Vector.new(-200, -200))
207
+ assert_equal Vector.new(100, 0), q.clip_vector(Vector.new(200, -200))
208
+ end
209
+
210
+ def test_child_of_and_parent_of
211
+ q = standard_quad
212
+ assert_equal true, q.blq.child_of?(q)
213
+ assert_equal true, q.trq.child_of?(q)
214
+ assert_equal true, q.brq.tlq.child_of?(q.brq)
215
+ assert_equal true, q.brq.parent_of?(q.brq.brq)
216
+ end
217
+
218
+ def test_payloads_and_centers_in_region
219
+ q = standard_quad
220
+ assert_equal 1, q.payloads_and_centers_in_region(Vector.new(0,100), Vector.new(100, 0), 1)[:details].length
221
+ assert_equal 2, q.payloads_and_centers_in_region(Vector.new(0,100), Vector.new(100, 0), 1)[:details].first.last
222
+ assert_equal 3, q.payloads_and_centers_in_region(Vector.new(0,100), Vector.new(100, 0), 1)[:payloads].length
223
+ end
224
+
225
+ def test_parent
226
+ q = standard_quad
227
+ assert_equal q.brq, q.brq.brq.parent
228
+ assert_equal q, q.brq.parent
229
+ assert_equal nil, q.parent
230
+ end
231
+
232
+ def test_quadtreepayload_node
233
+ q = standard_quad
234
+ assert_equal q.blq, q.get_contained_payloads(:max_count => 5).find {|i| i.vector == Vector.new(10, 10)}.node
235
+ end
236
+
237
+ def test_family_size_at_width
238
+ q = standard_quad
239
+ tl = Vector.new(0, 49)
240
+ br = Vector.new(49, 0)
241
+ assert_equal 5, q.family_size_at_width(tl, br)
242
+ assert_equal 5, q.brq.brq.family_size_at_width(tl, br)
243
+ assert_equal 1, q.blq.family_size_at_width(tl, br)
244
+ end
245
+ end
246
+
247
+ end
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+ # SOFTWARE INFO
3
+ #
4
+ # This file is part of the quadtree.rb Ruby quadtree library, distributed
5
+ # subject to the 'MIT License' below. This software is available for
6
+ # download at http://iterationlabs.com/free_software/quadtree.
7
+ #
8
+ # If you make modifications to this software and would be willing to
9
+ # contribute them back to the community, please send them to us for
10
+ # possible inclusion in future releases!
11
+ #
12
+ # LICENSE
13
+ #
14
+ # Copyright (c) 2008, Iteration Labs, LLC, http://iterationlabs.com
15
+ #
16
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
17
+ # of this software and associated documentation files (the "Software"), to deal
18
+ # in the Software without restriction, including without limitation the rights
19
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
+ # copies of the Software, and to permit persons to whom the Software is
21
+ # furnished to do so, subject to the following conditions:
22
+ #
23
+ # The above copyright notice and this permission notice shall be included in
24
+ # all copies or substantial portions of the Software.
25
+ #
26
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
+ # THE SOFTWARE.
33
+ #
34
+
35
+ require 'test/unit'
36
+ require 'fileutils'
37
+ require "rquad/vector"
38
+
39
+ module RQuad
40
+
41
+ class TestVector < Test::Unit::TestCase
42
+ def test_new_vector
43
+ assert_equal nil, Vector.new.x
44
+ assert_equal nil, Vector.new.y
45
+ assert_equal nil, Vector.new.z
46
+
47
+ v = Vector.new(1, 2, 3)
48
+ v2 = Vector.new(v)
49
+ assert_equal 1, v2.x
50
+ assert_equal 2, v2.y
51
+ assert_equal 3, v2.z
52
+ assert_equal v, v2
53
+
54
+ v3 = Vector.new([1, 2, 3])
55
+ assert_equal v, v3
56
+ end
57
+
58
+ def test_multiply
59
+ assert_equal Vector.new(4, 6), Vector.new(2, 3) * 2
60
+ assert_equal Vector.new(0, -10), Vector.new(0, 1) * -10
61
+ assert_equal Vector.new(2, -10, 100), Vector.new(-0.2, 1, -10) * -10
62
+ end
63
+
64
+ def test_add
65
+ assert_equal Vector.new(2, 3), Vector.new(1, 1) + Vector.new(1, 2)
66
+ assert_equal Vector.new(2, 3), Vector.new(-1, 10) + Vector.new(3, -7.0)
67
+ assert_equal Vector.new(2, 3, -1),
68
+ Vector.new(-1, 10, 2) + Vector.new(3, -7.0, -3)
69
+ end
70
+
71
+ def test_subtract
72
+ assert_equal Vector.new(2, 3), Vector.new(4, 4) - Vector.new(2, 1)
73
+ assert_equal Vector.new(5, -1), Vector.new(-1, 10) - Vector.new(-6, 11)
74
+ assert_equal Vector.new(5, -1, 10),
75
+ Vector.new(-1, 10, 12) - Vector.new(-6, 11, 2)
76
+ end
77
+
78
+ def test_length
79
+ assert_equal 5, Vector.new(5, 0).length
80
+ assert_equal 5.0, Vector.new(0, 5, 0).length
81
+ assert_equal 5, Vector.new(3, 4, 0).length
82
+ assert_equal 5, Vector.new(0, 3, 4).length
83
+ end
84
+
85
+ def test_equality
86
+ assert_equal Vector.new(5, 0), Vector.new(5, 0)
87
+ assert_equal Vector.new(-1, -2), Vector.new(-1, -2)
88
+ assert_equal Vector.new(-1, -2, -4), Vector.new(-1, -2, -4)
89
+ assert_not_equal Vector.new(-1, -2, 5), Vector.new(-1, -2, 4)
90
+ assert_not_equal Vector.new(-1, -2), Vector.new(-1, -2, 4)
91
+ assert_not_equal Vector.new(-2, -2), Vector.new(-1, -2)
92
+ end
93
+ end
94
+
95
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rquad
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Roman Scherer
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-02 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Ruby Quadtree Library
23
+ email: roman.scherer@nugg.ad
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - LICENSE
30
+ - README
31
+ files:
32
+ - .gitignore
33
+ - CHANGES
34
+ - LICENSE
35
+ - README
36
+ - Rakefile
37
+ - VERSION
38
+ - lib/rquad.rb
39
+ - lib/rquad/quadtree.rb
40
+ - lib/rquad/vector.rb
41
+ - rquad.gemspec
42
+ - test/helper.rb
43
+ - test/rquad/test_quadtree.rb
44
+ - test/rquad/test_vector.rb
45
+ has_rdoc: true
46
+ homepage: http://github.com/r0man/rquad
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --charset=UTF-8
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.7
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Ruby Quadtree Library
79
+ test_files:
80
+ - test/rquad/test_quadtree.rb
81
+ - test/rquad/test_vector.rb
82
+ - test/helper.rb