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.
@@ -1,148 +1,222 @@
1
- module Quadtree
2
- # A Quadtree.
3
- class Quadtree
4
- # Arbitrary constant to indicate how many elements can be stored in this
5
- # quad tree node.
6
- # @return [Integer] number of {Point}s this {Quadtree} can hold.
7
- NODE_CAPACITY = 4
8
-
9
- # Axis-aligned bounding box stored as a center with half-dimensions to
10
- # represent the boundaries of this quad tree.
11
- # @return [AxisAlignedBoundingBox]
12
- attr_accessor :boundary
13
-
14
- # Points in this quad tree node.
15
- # @return [Array<Point>]
16
- attr_accessor :points
17
-
18
- # Children
19
-
20
- # North west corner of this quad.
21
- # @return [Quadtree]
22
- attr_accessor :north_west
23
-
24
- # North east corner of this quad.
25
- # @return [Quadtree]
26
- attr_accessor :north_east
27
-
28
- # South west corner of this quad.
29
- # @return [Quadtree]
30
- attr_accessor :south_west
31
-
32
- # South east corner of this quad.
33
- # @return [Quadtree]
34
- attr_accessor :south_east
35
-
36
- # @param boundary [AxisAlignedBoundingBox] the boundary for this {Quadtree}.
37
- def initialize(boundary)
38
- self.boundary = boundary
39
- self.points = []
40
- self.north_west = nil
41
- self.north_east = nil
42
- self.south_west = nil
43
- self.south_east = nil
44
- end
45
-
46
- # Insert a {Point} in this {Quadtree}.
47
- #
48
- # @param point [Point] the point to insert.
49
- # @return [Boolean] +true+ on success, +false+ otherwise.
50
- def insert!(point)
51
- return false unless boundary.contains_point?(point)
52
-
53
- if points.size < NODE_CAPACITY
54
- points << point
55
- return true
56
- end
57
-
58
- subdivide! if north_west.nil?
59
- return true if north_west.insert!(point)
60
- return true if north_east.insert!(point)
61
- return true if south_west.insert!(point)
62
- return true if south_east.insert!(point)
63
-
64
- false
65
- end
66
-
67
- # Return the size of this instance, the number of {Point}s stored in this
68
- # {Quadtree}.
69
- # @return [Integer] the size of this instance.
70
- def size
71
- count = 0
72
- count += points.size
73
- unless north_west.nil?
74
- count += north_west.size
75
- count += north_east.size
76
- count += south_west.size
77
- count += south_east.size
78
- end
79
- count
80
- end
81
-
82
- # Finds all points contained within a range.
83
- #
84
- # @param range [AxisAlignedBoundingBox] the range to search within.
85
- # @return [Array<Point>] all {Point}s in given range.
86
- def query_range(range)
87
- # Prepare an array of results
88
- points_in_range = []
89
-
90
- # Automatically abort if the range does not intersect this quad
91
- return points_in_range unless boundary.intersects?(range)
92
-
93
- # Check objects at this quad level
94
- points.each do |point|
95
- points_in_range << point if range.contains_point?(point)
96
- end
97
-
98
- # Terminate here, if there are no children
99
- return points_in_range if north_west.nil?
100
-
101
- # Otherwise, add the points from the children
102
- points_in_range += north_west.query_range(range)
103
- points_in_range += north_east.query_range(range)
104
- points_in_range += south_west.query_range(range)
105
- points_in_range += south_east.query_range(range)
106
-
107
- points_in_range
108
- end
109
-
110
- private
111
-
112
- # @return [Boolean] +true+ on success, +false+ otherwise.
113
- def subdivide!
114
- left_edge = boundary.left
115
- right_edge = boundary.right
116
- top_edge = boundary.top
117
- bottom_edge = boundary.bottom
118
- quad_half_dimension = boundary.half_dimension / 2
119
-
120
- north_west_center = Point.new(left_edge + quad_half_dimension,
121
- top_edge - quad_half_dimension)
122
- north_east_center = Point.new(right_edge - quad_half_dimension,
123
- top_edge - quad_half_dimension)
124
- south_east_center = Point.new(left_edge + quad_half_dimension,
125
- bottom_edge + quad_half_dimension)
126
- south_west_center = Point.new(right_edge - quad_half_dimension,
127
- bottom_edge + quad_half_dimension)
128
-
129
- north_west_boundary = AxisAlignedBoundingBox.new(north_west_center,
130
- quad_half_dimension)
131
- north_east_boundary = AxisAlignedBoundingBox.new(north_east_center,
132
- quad_half_dimension)
133
- south_west_boundary = AxisAlignedBoundingBox.new(south_west_center,
134
- quad_half_dimension)
135
- south_east_boundary = AxisAlignedBoundingBox.new(south_east_center,
136
- quad_half_dimension)
137
-
138
- self.north_west = Quadtree.new north_west_boundary
139
- self.north_east = Quadtree.new north_east_boundary
140
- self.south_west = Quadtree.new south_west_boundary
141
- self.south_east = Quadtree.new south_east_boundary
142
-
143
- true
144
- rescue StandardError
145
- false
146
- end
147
- end
148
- end
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
- module Quadtree
2
- # An error for unknown types.
3
- # @since 1.0.5
4
- class UnknownTypeError < StandardError
5
-
6
- end
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
@@ -1,5 +1,7 @@
1
- require "version"
2
-
3
- module Quadtree
4
- is_versioned
5
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'version'
4
+
5
+ module Quadtree
6
+ is_versioned
7
+ end
data/lib/quadtree.rb CHANGED
@@ -1,14 +1,16 @@
1
- require "version"
2
- require "quadtree/version"
3
-
4
- require "quadtree/unknown_type_error"
5
-
6
- require "quadtree/point"
7
- require "quadtree/axis_aligned_bounding_box"
8
- require "quadtree/quadtree"
9
-
10
- # Quadtrees.
11
- #
12
- # @author Jan Lindblom <janlindblom@fastmail.fm>
13
- module Quadtree
14
- end
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.7 ruby lib
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.7"
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 = "2018-04-04"
12
+ s.date = "2022-11-29"
13
13
  s.email = ["janlindblom@fastmail.fm".freeze]
14
- s.files = [".editorconfig".freeze, ".gitignore".freeze, ".rspec".freeze, "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://bitbucket.org/janlindblom/ruby-quadtree".freeze
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 = "2.6.13".freeze
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
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
- s.add_development_dependency(%q<bundler>.freeze, ["~> 1.14"])
26
- s.add_development_dependency(%q<rake>.freeze, ["~> 10.0"])
27
- s.add_development_dependency(%q<rspec>.freeze, ["~> 3.0"])
28
- s.add_development_dependency(%q<pry>.freeze, ["~> 0.11"])
29
- s.add_development_dependency(%q<yard>.freeze, ["~> 0.9"])
30
- s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16"])
31
- s.add_development_dependency(%q<rubocop>.freeze, ["~> 0.54"])
32
- s.add_runtime_dependency(%q<version>.freeze, ["~> 1.1"])
33
- else
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, ["~> 1.14"])
45
- s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
46
- s.add_dependency(%q<rspec>.freeze, ["~> 3.0"])
47
- s.add_dependency(%q<pry>.freeze, ["~> 0.11"])
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.16"])
50
- s.add_dependency(%q<rubocop>.freeze, ["~> 0.54"])
51
- s.add_dependency(%q<version>.freeze, ["~> 1.1"])
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