quadtree 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/LICENSE.txt +1 -1
- data/README.md +9 -7
- data/Rakefile +18 -10
- data/VERSION +1 -1
- data/lib/quadtree/axis_aligned_bounding_box.rb +155 -108
- data/lib/quadtree/point.rb +161 -107
- data/lib/quadtree/quadtree.rb +222 -148
- data/lib/quadtree/unknown_type_error.rb +8 -7
- data/lib/quadtree/version.rb +7 -5
- data/lib/quadtree.rb +16 -14
- data/quadtree.gemspec +25 -32
- metadata +36 -26
- data/.editorconfig +0 -12
- data/.gitignore +0 -208
- data/.rspec +0 -3
data/lib/quadtree/quadtree.rb
CHANGED
@@ -1,148 +1,222 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
#
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
# @return [
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quadtree
|
4
|
+
# A Quadtree.
|
5
|
+
class Quadtree
|
6
|
+
# Arbitrary constant to indicate how many elements can be stored in this
|
7
|
+
# quad tree node.
|
8
|
+
# @return [Integer] number of {Point}s this {Quadtree} can hold.
|
9
|
+
NODE_CAPACITY = 4
|
10
|
+
|
11
|
+
# Axis-aligned bounding box stored as a center with half-dimensions to
|
12
|
+
# represent the boundaries of this quad tree.
|
13
|
+
# @return [AxisAlignedBoundingBox]
|
14
|
+
attr_accessor :boundary
|
15
|
+
|
16
|
+
# Points in this quad tree node.
|
17
|
+
# @return [Array<Point>]
|
18
|
+
attr_accessor :points
|
19
|
+
|
20
|
+
# Children
|
21
|
+
|
22
|
+
# North west corner of this quad.
|
23
|
+
# @return [Quadtree]
|
24
|
+
attr_accessor :north_west
|
25
|
+
|
26
|
+
# North east corner of this quad.
|
27
|
+
# @return [Quadtree]
|
28
|
+
attr_accessor :north_east
|
29
|
+
|
30
|
+
# South west corner of this quad.
|
31
|
+
# @return [Quadtree]
|
32
|
+
attr_accessor :south_west
|
33
|
+
|
34
|
+
# South east corner of this quad.
|
35
|
+
# @return [Quadtree]
|
36
|
+
attr_accessor :south_east
|
37
|
+
|
38
|
+
#
|
39
|
+
# Create a new {Quadtree}.
|
40
|
+
#
|
41
|
+
# @param [AxisAlignedBoundingBox] boundary the boundary for this {Quadtree}.
|
42
|
+
# @param [Array<Point>] points any initial {Point}s.
|
43
|
+
# @param [Quadtree] north_west northwestern child {Quadtree}
|
44
|
+
# @param [Quadtree] north_east northeastern child {Quadtree}
|
45
|
+
# @param [Quadtree] south_west southwestern child {Quadtree}
|
46
|
+
# @param [Quadtree] south_east southestern child {Quadtree}
|
47
|
+
#
|
48
|
+
def initialize(boundary, points = [], north_west = nil, north_east = nil, south_west = nil, south_east = nil)
|
49
|
+
self.boundary = boundary
|
50
|
+
self.points = points
|
51
|
+
self.north_west = north_west
|
52
|
+
self.north_east = north_east
|
53
|
+
self.south_west = south_west
|
54
|
+
self.south_east = south_east
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Create a Hash from this {Quadtree}.
|
59
|
+
#
|
60
|
+
# @return [Hash] Hash representation.
|
61
|
+
#
|
62
|
+
def to_h
|
63
|
+
{
|
64
|
+
'boundary': boundary.to_h,
|
65
|
+
'points': points.map(&:to_h),
|
66
|
+
'north_west': north_west.nil? ? nil : north_west.to_h,
|
67
|
+
'north_east': north_east.nil? ? nil : north_east.to_h,
|
68
|
+
'south_west': south_west.nil? ? nil : south_west.to_h,
|
69
|
+
'south_east': south_east.nil? ? nil : south_east.to_h
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Create a Hash from this {Quadtree}.
|
75
|
+
#
|
76
|
+
# @return [Hash] Hash representation of this {Quadtree}.
|
77
|
+
#
|
78
|
+
def to_hash
|
79
|
+
to_h
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Create a JSON String representation of this {Quadtree}.
|
84
|
+
#
|
85
|
+
# @return [String] JSON String of this {Quadtree}.
|
86
|
+
#
|
87
|
+
def to_json(*_args)
|
88
|
+
require 'json'
|
89
|
+
to_h.to_json
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Create a String for this {Quadtree}.
|
94
|
+
#
|
95
|
+
# @return [String] String representation of this {Quadtree}.
|
96
|
+
#
|
97
|
+
def to_s
|
98
|
+
to_h.to_s
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Construct a Quadtree from a JSON String.
|
103
|
+
#
|
104
|
+
# @param [String] json_data input JSON String.
|
105
|
+
#
|
106
|
+
# @return [Quadtree] the {Quadtree} contained in the JSON String.
|
107
|
+
#
|
108
|
+
def self.from_json(json_data)
|
109
|
+
new(
|
110
|
+
AxisAlignedBoundingBox.from_json(json_data['boundary']),
|
111
|
+
json_data['points'].map { |point_data| Point.from_json(point_data) },
|
112
|
+
json_data['north_west'].nil? ? nil : Quadtree.from_json(json_data['north_west']),
|
113
|
+
json_data['north_east'].nil? ? nil : Quadtree.from_json(json_data['north_east']),
|
114
|
+
json_data['south_west'].nil? ? nil : Quadtree.from_json(json_data['south_west']),
|
115
|
+
json_data['south_east'].nil? ? nil : Quadtree.from_json(json_data['south_east'])
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Insert a {Point} in this {Quadtree}.
|
120
|
+
#
|
121
|
+
# @param point [Point] the point to insert.
|
122
|
+
# @return [Boolean] +true+ on success, +false+ otherwise.
|
123
|
+
def insert!(point)
|
124
|
+
return false unless boundary.contains_point?(point)
|
125
|
+
|
126
|
+
if points.size < NODE_CAPACITY
|
127
|
+
points << point
|
128
|
+
return true
|
129
|
+
end
|
130
|
+
|
131
|
+
subdivide! if north_west.nil?
|
132
|
+
return true if north_west.insert!(point)
|
133
|
+
return true if north_east.insert!(point)
|
134
|
+
return true if south_west.insert!(point)
|
135
|
+
return true if south_east.insert!(point)
|
136
|
+
|
137
|
+
false
|
138
|
+
end
|
139
|
+
|
140
|
+
# Return the size of this instance, the number of {Point}s stored in this
|
141
|
+
# {Quadtree}.
|
142
|
+
#
|
143
|
+
# @return [Integer] the size of this instance.
|
144
|
+
def size
|
145
|
+
count = 0
|
146
|
+
count += points.size
|
147
|
+
unless north_west.nil?
|
148
|
+
count += north_west.size
|
149
|
+
count += north_east.size
|
150
|
+
count += south_west.size
|
151
|
+
count += south_east.size
|
152
|
+
end
|
153
|
+
count
|
154
|
+
end
|
155
|
+
|
156
|
+
# Finds all points contained within a range.
|
157
|
+
#
|
158
|
+
# @param range [AxisAlignedBoundingBox] the range to search within.
|
159
|
+
# @return [Array<Point>] all {Point}s in given range.
|
160
|
+
def query_range(range)
|
161
|
+
# Prepare an array of results
|
162
|
+
points_in_range = []
|
163
|
+
|
164
|
+
# Automatically abort if the range does not intersect this quad
|
165
|
+
return points_in_range unless boundary.intersects?(range)
|
166
|
+
|
167
|
+
# Check objects at this quad level
|
168
|
+
points.each do |point|
|
169
|
+
points_in_range << point if range.contains_point?(point)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Terminate here, if there are no children
|
173
|
+
return points_in_range if north_west.nil?
|
174
|
+
|
175
|
+
# Otherwise, add the points from the children
|
176
|
+
points_in_range += north_west.query_range(range)
|
177
|
+
points_in_range += north_east.query_range(range)
|
178
|
+
points_in_range += south_west.query_range(range)
|
179
|
+
points_in_range += south_east.query_range(range)
|
180
|
+
|
181
|
+
points_in_range
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
# @return [Boolean] +true+ on success, +false+ otherwise.
|
187
|
+
def subdivide!
|
188
|
+
left_edge = boundary.left
|
189
|
+
right_edge = boundary.right
|
190
|
+
top_edge = boundary.top
|
191
|
+
bottom_edge = boundary.bottom
|
192
|
+
quad_half_dimension = boundary.half_dimension / 2
|
193
|
+
|
194
|
+
north_west_center = Point.new(left_edge + quad_half_dimension,
|
195
|
+
top_edge - quad_half_dimension)
|
196
|
+
north_east_center = Point.new(right_edge - quad_half_dimension,
|
197
|
+
top_edge - quad_half_dimension)
|
198
|
+
south_east_center = Point.new(left_edge + quad_half_dimension,
|
199
|
+
bottom_edge + quad_half_dimension)
|
200
|
+
south_west_center = Point.new(right_edge - quad_half_dimension,
|
201
|
+
bottom_edge + quad_half_dimension)
|
202
|
+
|
203
|
+
north_west_boundary = AxisAlignedBoundingBox.new(north_west_center,
|
204
|
+
quad_half_dimension)
|
205
|
+
north_east_boundary = AxisAlignedBoundingBox.new(north_east_center,
|
206
|
+
quad_half_dimension)
|
207
|
+
south_west_boundary = AxisAlignedBoundingBox.new(south_west_center,
|
208
|
+
quad_half_dimension)
|
209
|
+
south_east_boundary = AxisAlignedBoundingBox.new(south_east_center,
|
210
|
+
quad_half_dimension)
|
211
|
+
|
212
|
+
self.north_west = Quadtree.new north_west_boundary
|
213
|
+
self.north_east = Quadtree.new north_east_boundary
|
214
|
+
self.south_west = Quadtree.new south_west_boundary
|
215
|
+
self.south_east = Quadtree.new south_east_boundary
|
216
|
+
|
217
|
+
true
|
218
|
+
rescue StandardError
|
219
|
+
false
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quadtree
|
4
|
+
# An error for unknown types.
|
5
|
+
# @since 1.0.5
|
6
|
+
class UnknownTypeError < StandardError
|
7
|
+
end
|
8
|
+
end
|
data/lib/quadtree/version.rb
CHANGED
data/lib/quadtree.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require
|
5
|
-
|
6
|
-
require
|
7
|
-
|
8
|
-
require
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'version'
|
4
|
+
require 'quadtree/version'
|
5
|
+
|
6
|
+
require 'quadtree/unknown_type_error'
|
7
|
+
|
8
|
+
require 'quadtree/point'
|
9
|
+
require 'quadtree/axis_aligned_bounding_box'
|
10
|
+
require 'quadtree/quadtree'
|
11
|
+
|
12
|
+
# Quadtrees.
|
13
|
+
#
|
14
|
+
# @author Jan Lindblom <janlindblom@fastmail.fm>
|
15
|
+
module Quadtree
|
16
|
+
end
|
data/quadtree.gemspec
CHANGED
@@ -1,53 +1,46 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: quadtree 1.0.
|
2
|
+
# stub: quadtree 1.0.9 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "quadtree".freeze
|
6
|
-
s.version = "1.0.
|
6
|
+
s.version = "1.0.9"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1".freeze) if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib".freeze]
|
10
10
|
s.authors = ["Jan Lindblom".freeze]
|
11
11
|
s.bindir = "exe".freeze
|
12
|
-
s.date = "
|
12
|
+
s.date = "2022-11-29"
|
13
13
|
s.email = ["janlindblom@fastmail.fm".freeze]
|
14
|
-
s.files = ["
|
15
|
-
s.homepage = "https://
|
14
|
+
s.files = ["CODE_OF_CONDUCT.md".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "lib/quadtree.rb".freeze, "lib/quadtree/axis_aligned_bounding_box.rb".freeze, "lib/quadtree/point.rb".freeze, "lib/quadtree/quadtree.rb".freeze, "lib/quadtree/unknown_type_error.rb".freeze, "lib/quadtree/version.rb".freeze, "quadtree.gemspec".freeze]
|
15
|
+
s.homepage = "https://github.com/janlindblom/ruby-quadtree".freeze
|
16
16
|
s.licenses = ["MIT".freeze]
|
17
17
|
s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze)
|
18
|
-
s.rubygems_version = "
|
18
|
+
s.rubygems_version = "3.3.26".freeze
|
19
19
|
s.summary = "Quadtrees in Ruby.".freeze
|
20
20
|
|
21
21
|
if s.respond_to? :specification_version then
|
22
22
|
s.specification_version = 4
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
s.add_dependency(%q<bundler>.freeze, ["~> 1.14"])
|
35
|
-
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
36
|
-
s.add_dependency(%q<rspec>.freeze, ["~> 3.0"])
|
37
|
-
s.add_dependency(%q<pry>.freeze, ["~> 0.11"])
|
38
|
-
s.add_dependency(%q<yard>.freeze, ["~> 0.9"])
|
39
|
-
s.add_dependency(%q<simplecov>.freeze, ["~> 0.16"])
|
40
|
-
s.add_dependency(%q<rubocop>.freeze, ["~> 0.54"])
|
41
|
-
s.add_dependency(%q<version>.freeze, ["~> 1.1"])
|
42
|
-
end
|
25
|
+
if s.respond_to? :add_runtime_dependency then
|
26
|
+
s.add_development_dependency(%q<bundler>.freeze, ["~> 2"])
|
27
|
+
s.add_development_dependency(%q<rake>.freeze, ["~> 13"])
|
28
|
+
s.add_development_dependency(%q<rspec>.freeze, ["~> 3"])
|
29
|
+
s.add_development_dependency(%q<pry>.freeze, ["~> 0.14"])
|
30
|
+
s.add_development_dependency(%q<yard>.freeze, ["~> 0.9"])
|
31
|
+
s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.21"])
|
32
|
+
s.add_development_dependency(%q<rspec_junit_formatter>.freeze, ["~> 0.6"])
|
33
|
+
s.add_development_dependency(%q<rubocop>.freeze, ["~> 1"])
|
34
|
+
s.add_runtime_dependency(%q<version>.freeze, ["~> 1"])
|
43
35
|
else
|
44
|
-
s.add_dependency(%q<bundler>.freeze, ["~>
|
45
|
-
s.add_dependency(%q<rake>.freeze, ["~>
|
46
|
-
s.add_dependency(%q<rspec>.freeze, ["~> 3
|
47
|
-
s.add_dependency(%q<pry>.freeze, ["~> 0.
|
36
|
+
s.add_dependency(%q<bundler>.freeze, ["~> 2"])
|
37
|
+
s.add_dependency(%q<rake>.freeze, ["~> 13"])
|
38
|
+
s.add_dependency(%q<rspec>.freeze, ["~> 3"])
|
39
|
+
s.add_dependency(%q<pry>.freeze, ["~> 0.14"])
|
48
40
|
s.add_dependency(%q<yard>.freeze, ["~> 0.9"])
|
49
|
-
s.add_dependency(%q<simplecov>.freeze, ["~> 0.
|
50
|
-
s.add_dependency(%q<
|
51
|
-
s.add_dependency(%q<
|
41
|
+
s.add_dependency(%q<simplecov>.freeze, ["~> 0.21"])
|
42
|
+
s.add_dependency(%q<rspec_junit_formatter>.freeze, ["~> 0.6"])
|
43
|
+
s.add_dependency(%q<rubocop>.freeze, ["~> 1"])
|
44
|
+
s.add_dependency(%q<version>.freeze, ["~> 1"])
|
52
45
|
end
|
53
46
|
end
|