ffi-geos 1.2.1 → 1.2.2

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.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +20 -0
  3. data/.travis.yml +7 -3
  4. data/Gemfile +1 -1
  5. data/Guardfile +4 -5
  6. data/ffi-geos.gemspec +1 -1
  7. data/lib/ffi-geos.rb +212 -196
  8. data/lib/ffi-geos/buffer_params.rb +9 -20
  9. data/lib/ffi-geos/coordinate_sequence.rb +342 -58
  10. data/lib/ffi-geos/geometry.rb +167 -178
  11. data/lib/ffi-geos/geometry_collection.rb +60 -12
  12. data/lib/ffi-geos/interrupt.rb +2 -4
  13. data/lib/ffi-geos/line_string.rb +146 -37
  14. data/lib/ffi-geos/linear_ring.rb +2 -3
  15. data/lib/ffi-geos/multi_line_string.rb +1 -2
  16. data/lib/ffi-geos/multi_point.rb +0 -1
  17. data/lib/ffi-geos/multi_polygon.rb +0 -1
  18. data/lib/ffi-geos/point.rb +69 -14
  19. data/lib/ffi-geos/polygon.rb +110 -21
  20. data/lib/ffi-geos/prepared_geometry.rb +11 -12
  21. data/lib/ffi-geos/strtree.rb +41 -52
  22. data/lib/ffi-geos/tools.rb +15 -18
  23. data/lib/ffi-geos/utils.rb +27 -44
  24. data/lib/ffi-geos/version.rb +1 -3
  25. data/lib/ffi-geos/wkb_reader.rb +4 -9
  26. data/lib/ffi-geos/wkb_writer.rb +14 -18
  27. data/lib/ffi-geos/wkt_reader.rb +2 -5
  28. data/lib/ffi-geos/wkt_writer.rb +17 -22
  29. data/test/.rubocop.yml +36 -0
  30. data/test/coordinate_sequence_tests.rb +263 -14
  31. data/test/geometry_collection_tests.rb +412 -1
  32. data/test/geometry_tests.rb +156 -86
  33. data/test/interrupt_tests.rb +2 -4
  34. data/test/line_string_tests.rb +212 -23
  35. data/test/linear_ring_tests.rb +1 -2
  36. data/test/misc_tests.rb +28 -29
  37. data/test/multi_line_string_tests.rb +0 -1
  38. data/test/point_tests.rb +158 -1
  39. data/test/polygon_tests.rb +284 -1
  40. data/test/prepared_geometry_tests.rb +1 -3
  41. data/test/strtree_tests.rb +9 -10
  42. data/test/test_helper.rb +49 -18
  43. data/test/tools_tests.rb +1 -3
  44. data/test/utils_tests.rb +22 -22
  45. data/test/wkb_reader_tests.rb +10 -9
  46. data/test/wkb_writer_tests.rb +5 -13
  47. data/test/wkt_reader_tests.rb +1 -2
  48. data/test/wkt_writer_tests.rb +9 -14
  49. metadata +6 -3
@@ -1,41 +1,130 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
5
4
  class Polygon < Geometry
6
5
  def num_interior_rings
7
- FFIGeos.GEOSGetNumInteriorRings_r(Geos.current_handle_pointer, self.ptr)
6
+ FFIGeos.GEOSGetNumInteriorRings_r(Geos.current_handle_pointer, ptr)
8
7
  end
9
8
 
10
9
  def interior_ring_n(n)
11
- if n < 0 || n >= self.num_interior_rings
12
- raise Geos::IndexBoundsError.new
13
- else
14
- cast_geometry_ptr(
15
- FFIGeos.GEOSGetInteriorRingN_r(Geos.current_handle_pointer, self.ptr, n), {
16
- :auto_free => false,
17
- :srid_copy => self.srid,
18
- :parent => self
19
- }
20
- )
21
- end
10
+ raise Geos::IndexBoundsError if n.negative? || n >= num_interior_rings
11
+
12
+ cast_geometry_ptr(
13
+ FFIGeos.GEOSGetInteriorRingN_r(Geos.current_handle_pointer, ptr, n),
14
+ auto_free: false,
15
+ srid_copy: srid,
16
+ parent: self
17
+ )
22
18
  end
23
- alias_method :interior_ring, :interior_ring_n
19
+ alias interior_ring interior_ring_n
24
20
 
25
21
  def exterior_ring
26
22
  cast_geometry_ptr(
27
- FFIGeos.GEOSGetExteriorRing_r(Geos.current_handle_pointer, self.ptr), {
28
- :auto_free => false,
29
- :srid_copy => self.srid,
30
- :parent => self
31
- }
23
+ FFIGeos.GEOSGetExteriorRing_r(Geos.current_handle_pointer, ptr),
24
+ auto_free: false,
25
+ srid_copy: srid,
26
+ parent: self
32
27
  )
33
28
  end
34
29
 
35
30
  def interior_rings
36
- self.num_interior_rings.times.collect do |n|
37
- self.interior_ring_n(n)
31
+ num_interior_rings.times.collect do |n|
32
+ interior_ring_n(n)
38
33
  end
39
34
  end
35
+
36
+ def dump_points(cur_path = [])
37
+ points = [ exterior_ring.dump_points ]
38
+
39
+ interior_rings.each do |ring|
40
+ points.push(ring.dump_points)
41
+ end
42
+
43
+ cur_path.concat(points)
44
+ end
45
+
46
+ def snap_to_grid!(*args)
47
+ if !self.empty?
48
+ exterior_ring = self.exterior_ring.coord_seq.snap_to_grid!(*args)
49
+
50
+ if exterior_ring.length == 0
51
+ @ptr = Geos.create_empty_polygon(:srid => self.srid).ptr
52
+ elsif exterior_ring.length < 4
53
+ raise Geos::InvalidGeometryError.new("snap_to_grid! produced an invalid number of points in exterior ring - found #{exterior_ring.length} - must be 0 or >= 4")
54
+ else
55
+ interior_rings = []
56
+
57
+ self.num_interior_rings.times { |i|
58
+ interior_ring = self.interior_ring_n(i).coord_seq.snap_to_grid!(*args)
59
+
60
+ interior_rings << interior_ring unless interior_ring.length < 4
61
+ }
62
+
63
+ interior_rings.compact!
64
+
65
+ polygon = Geos.create_polygon(exterior_ring, interior_rings, :srid => self.srid)
66
+ @ptr = polygon.ptr
67
+ end
68
+ end
69
+
70
+ self
71
+ end
72
+
73
+ def snap_to_grid(*args)
74
+ ret = self.dup.snap_to_grid!(*args)
75
+ ret.srid = pick_srid_according_to_policy(self.srid)
76
+ ret
77
+ end
78
+
79
+ %w{ max min }.each do |op|
80
+ %w{ x y }.each do |dimension|
81
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
82
+ def #{dimension}_#{op}
83
+ unless self.empty?
84
+ self.envelope.exterior_ring.#{dimension}_#{op}
85
+ end
86
+ end
87
+ EOF
88
+ end
89
+
90
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
91
+ def z_#{op}
92
+ unless self.empty?
93
+ if self.has_z?
94
+ self.exterior_ring.z_#{op}
95
+ else
96
+ 0
97
+ end
98
+ end
99
+ end
100
+ EOF
101
+ end
102
+
103
+ %w{
104
+ affine
105
+ rotate
106
+ rotate_x
107
+ rotate_y
108
+ rotate_z
109
+ scale
110
+ trans_scale
111
+ translate
112
+ }.each do |m|
113
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
114
+ def #{m}!(*args)
115
+ self.exterior_ring.coord_seq.#{m}!(*args)
116
+ self.interior_rings.each do |ring|
117
+ ring.coord_seq.#{m}!(*args)
118
+ end
119
+ self
120
+ end
121
+
122
+ def #{m}(*args)
123
+ ret = self.dup.#{m}!(*args)
124
+ ret.srid = pick_srid_according_to_policy(self.srid)
125
+ ret
126
+ end
127
+ EOF
128
+ end
40
129
  end
41
130
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -13,7 +12,7 @@ module Geos
13
12
  check_geometry(geom)
14
13
 
15
14
  options = {
16
- :auto_free => true
15
+ auto_free: true
17
16
  }.merge(options)
18
17
 
19
18
  @ptr = FFI::AutoPointer.new(
@@ -31,52 +30,52 @@ module Geos
31
30
 
32
31
  def contains?(geom)
33
32
  check_geometry(geom)
34
- bool_result(FFIGeos.GEOSPreparedContains_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
33
+ bool_result(FFIGeos.GEOSPreparedContains_r(Geos.current_handle_pointer, ptr, geom.ptr))
35
34
  end
36
35
 
37
36
  def contains_properly?(geom)
38
37
  check_geometry(geom)
39
- bool_result(FFIGeos.GEOSPreparedContainsProperly_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
38
+ bool_result(FFIGeos.GEOSPreparedContainsProperly_r(Geos.current_handle_pointer, ptr, geom.ptr))
40
39
  end
41
40
 
42
41
  def covered_by?(geom)
43
42
  check_geometry(geom)
44
- bool_result(FFIGeos.GEOSPreparedCoveredBy_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
43
+ bool_result(FFIGeos.GEOSPreparedCoveredBy_r(Geos.current_handle_pointer, ptr, geom.ptr))
45
44
  end
46
45
 
47
46
  def covers?(geom)
48
47
  check_geometry(geom)
49
- bool_result(FFIGeos.GEOSPreparedCovers_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
48
+ bool_result(FFIGeos.GEOSPreparedCovers_r(Geos.current_handle_pointer, ptr, geom.ptr))
50
49
  end
51
50
 
52
51
  def crosses?(geom)
53
52
  check_geometry(geom)
54
- bool_result(FFIGeos.GEOSPreparedCrosses_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
53
+ bool_result(FFIGeos.GEOSPreparedCrosses_r(Geos.current_handle_pointer, ptr, geom.ptr))
55
54
  end
56
55
 
57
56
  def disjoint?(geom)
58
57
  check_geometry(geom)
59
- bool_result(FFIGeos.GEOSPreparedDisjoint_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
58
+ bool_result(FFIGeos.GEOSPreparedDisjoint_r(Geos.current_handle_pointer, ptr, geom.ptr))
60
59
  end
61
60
 
62
61
  def intersects?(geom)
63
62
  check_geometry(geom)
64
- bool_result(FFIGeos.GEOSPreparedIntersects_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
63
+ bool_result(FFIGeos.GEOSPreparedIntersects_r(Geos.current_handle_pointer, ptr, geom.ptr))
65
64
  end
66
65
 
67
66
  def overlaps?(geom)
68
67
  check_geometry(geom)
69
- bool_result(FFIGeos.GEOSPreparedOverlaps_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
68
+ bool_result(FFIGeos.GEOSPreparedOverlaps_r(Geos.current_handle_pointer, ptr, geom.ptr))
70
69
  end
71
70
 
72
71
  def touches?(geom)
73
72
  check_geometry(geom)
74
- bool_result(FFIGeos.GEOSPreparedTouches_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
73
+ bool_result(FFIGeos.GEOSPreparedTouches_r(Geos.current_handle_pointer, ptr, geom.ptr))
75
74
  end
76
75
 
77
76
  def within?(geom)
78
77
  check_geometry(geom)
79
- bool_result(FFIGeos.GEOSPreparedWithin_r(Geos.current_handle_pointer, self.ptr, geom.ptr))
78
+ bool_result(FFIGeos.GEOSPreparedWithin_r(Geos.current_handle_pointer, ptr, geom.ptr))
80
79
  end
81
80
  end
82
81
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -12,7 +11,7 @@ module Geos
12
11
 
13
12
  class AlreadyBuiltError < Geos::Error
14
13
  def initialize(*)
15
- super("STRtree has already been built")
14
+ super('STRtree has already been built')
16
15
  end
17
16
  end
18
17
 
@@ -33,13 +32,13 @@ module Geos
33
32
  args
34
33
  end
35
34
 
36
- geoms_and_objects.each do |geom, obj|
35
+ geoms_and_objects.each do |geom, _obj|
37
36
  check_geometry(geom)
38
37
  end
39
38
  end
40
39
 
41
40
  if capacity <= 0
42
- raise ArgumentError.new("STRtree capacity must be greater than 0")
41
+ raise ArgumentError, 'STRtree capacity must be greater than 0'
43
42
  end
44
43
 
45
44
  ptr = FFIGeos.GEOSSTRtree_create_r(Geos.current_handle_pointer, capacity)
@@ -55,10 +54,10 @@ module Geos
55
54
  @storage_key = 0
56
55
  @built = false
57
56
 
58
- if geoms_and_objects
59
- geoms_and_objects.each do |geom, obj|
60
- self.insert(geom, obj)
61
- end
57
+ return unless geoms_and_objects
58
+
59
+ geoms_and_objects.each do |geom, obj|
60
+ insert(geom, obj)
62
61
  end
63
62
  end
64
63
 
@@ -80,23 +79,21 @@ module Geos
80
79
  private :next_key
81
80
 
82
81
  def insert(geom, item = nil)
83
- if self.built?
84
- raise AlreadyBuiltError.new
85
- else
86
- check_geometry(geom)
82
+ raise AlreadyBuiltError if built?
87
83
 
88
- key = next_key
89
- key_ptr = FFI::MemoryPointer.new(:pointer)
90
- key_ptr.write_int(key)
84
+ check_geometry(geom)
91
85
 
92
- @storage[key] = {
93
- :item => item,
94
- :geometry => geom
95
- }
96
- @ptrs[key] = key_ptr
86
+ key = next_key
87
+ key_ptr = FFI::MemoryPointer.new(:pointer)
88
+ key_ptr.write_int(key)
97
89
 
98
- FFIGeos.GEOSSTRtree_insert_r(Geos.current_handle_pointer, self.ptr, geom.ptr, key_ptr)
99
- end
90
+ @storage[key] = {
91
+ item: item,
92
+ geometry: geom
93
+ }
94
+ @ptrs[key] = key_ptr
95
+
96
+ FFIGeos.GEOSSTRtree_insert_r(Geos.current_handle_pointer, ptr, geom.ptr, key_ptr)
100
97
  end
101
98
 
102
99
  def remove(geom, item)
@@ -106,15 +103,13 @@ module Geos
106
103
  storage[0]
107
104
  end
108
105
 
109
- if key
110
- key_ptr = @ptrs[key]
111
- result = FFIGeos.GEOSSTRtree_remove_r(Geos.current_handle_pointer, self.ptr, geom.ptr, key_ptr)
112
- built!
106
+ return unless key
113
107
 
114
- if result == 1
115
- @storage.delete(key)
116
- end
117
- end
108
+ key_ptr = @ptrs[key]
109
+ result = FFIGeos.GEOSSTRtree_remove_r(Geos.current_handle_pointer, ptr, geom.ptr, key_ptr)
110
+ built!
111
+
112
+ @storage.delete(key) if result == 1
118
113
  end
119
114
 
120
115
  def query_all(geom)
@@ -128,14 +123,12 @@ module Geos
128
123
  storage = @storage[key]
129
124
  retval << storage
130
125
 
131
- if block_given?
132
- yield(storage)
133
- end
126
+ yield(storage) if block_given?
134
127
  }
135
128
 
136
129
  FFIGeos.GEOSSTRtree_query_r(
137
130
  Geos.current_handle_pointer,
138
- self.ptr,
131
+ ptr,
139
132
  geom.ptr,
140
133
  callback,
141
134
  nil
@@ -145,12 +138,12 @@ module Geos
145
138
  end
146
139
 
147
140
  def query(geom, ret = :item)
148
- self.query_all(geom).collect { |storage|
141
+ query_all(geom).collect { |storage|
149
142
  item = if ret.is_a?(Array)
150
143
  storage.inject({}) do |memo, k|
151
- memo.tap {
144
+ memo.tap do
152
145
  memo[k] = storage[k]
153
- }
146
+ end
154
147
  end
155
148
  elsif ret == :all
156
149
  storage
@@ -158,27 +151,23 @@ module Geos
158
151
  storage[ret]
159
152
  end
160
153
 
161
- item.tap {
162
- if block_given?
163
- yield(item)
164
- end
165
- }
154
+ item.tap do
155
+ yield(item) if block_given?
156
+ end
166
157
  }.compact
167
158
  end
168
159
 
169
160
  def query_geometries(geom)
170
- self.query_all(geom).collect { |storage|
171
- storage[:geometry].tap { |val|
172
- if block_given?
173
- yield(val)
174
- end
175
- }
161
+ query_all(geom).collect { |storage|
162
+ storage[:geometry].tap do |val|
163
+ yield(val) if block_given?
164
+ end
176
165
  }.compact
177
166
  end
178
- alias_method :query_geoms, :query_geometries
167
+ alias query_geoms query_geometries
179
168
 
180
169
  def iterate
181
- @storage.values.each do |v|
170
+ @storage.each_value do |v|
182
171
  yield(v)
183
172
  end
184
173
  end
@@ -205,7 +194,7 @@ module Geos
205
194
 
206
195
  key_ptr = FFIGeos.GEOSSTRtree_nearest_generic_r(
207
196
  Geos.current_handle_pointer,
208
- self.ptr,
197
+ ptr,
209
198
  geom.ptr,
210
199
  geom.envelope.ptr,
211
200
  callback,
@@ -219,7 +208,7 @@ module Geos
219
208
  item = nearest_generic(geom)
220
209
  item[:geometry] if item
221
210
  end
222
- alias_method :nearest_geometry, :nearest
211
+ alias nearest_geometry nearest
223
212
 
224
213
  def nearest_item(geom)
225
214
  item = nearest_generic(geom)
@@ -1,16 +1,15 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
5
4
  class NullPointerError < Geos::Error
6
5
  def initialize(*)
7
- super("Tried to create a Geometry from a NULL pointer!")
6
+ super('Tried to create a Geometry from a NULL pointer!')
8
7
  end
9
8
  end
10
9
 
11
10
  class InvalidGeometryTypeError < Geos::Error
12
11
  def initialize(*)
13
- super("Invalid geometry type")
12
+ super('Invalid geometry type')
14
13
  end
15
14
  end
16
15
 
@@ -25,12 +24,10 @@ module Geos
25
24
 
26
25
  def cast_geometry_ptr(geom_ptr, options = {})
27
26
  options = {
28
- :auto_free => true
27
+ auto_free: true
29
28
  }.merge(options)
30
29
 
31
- if geom_ptr.null?
32
- raise Geos::NullPointerError.new
33
- end
30
+ raise Geos::NullPointerError if geom_ptr.null?
34
31
 
35
32
  klass = case FFIGeos.GEOSGeomTypeId_r(Geos.current_handle_pointer, geom_ptr)
36
33
  when GEOS_POINT
@@ -53,7 +50,7 @@ module Geos
53
50
  raise Geos::InvalidGeometryTypeError.new
54
51
  end
55
52
 
56
- klass.new(geom_ptr, options).tap { |ret|
53
+ klass.new(geom_ptr, options).tap do |ret|
57
54
  if options[:srid]
58
55
  ret.srid = options[:srid] || 0
59
56
  elsif options[:srid_copy]
@@ -63,11 +60,11 @@ module Geos
63
60
  options[:srid_copy] || 0
64
61
  end
65
62
  end
66
- }
63
+ end
67
64
  end
68
65
 
69
66
  def check_geometry(geom)
70
- raise TypeError.new("Expected Geos::Geometry") unless geom.is_a?(Geos::Geometry)
67
+ raise TypeError, 'Expected Geos::Geometry' unless geom.is_a?(Geos::Geometry)
71
68
  end
72
69
 
73
70
  def pick_srid_from_geoms(srid_a, srid_b, policy = Geos.srid_copy_policy)
@@ -81,7 +78,7 @@ module Geos
81
78
  when :strict
82
79
  raise Geos::MixedSRIDsError.new(srid_a, srid_b)
83
80
  else
84
- raise ArgumentError.new("Unexpected policy value: #{policy}")
81
+ raise ArgumentError, "Unexpected policy value: #{policy}"
85
82
  end
86
83
  end
87
84
 
@@ -97,12 +94,12 @@ module Geos
97
94
 
98
95
  def bool_result(result)
99
96
  case result
100
- when 1
101
- true
102
- when 0
103
- false
104
- else
105
- raise Geos::UnexpectedBooleanResultError.new(result)
97
+ when 1
98
+ true
99
+ when 0
100
+ false
101
+ else
102
+ raise Geos::UnexpectedBooleanResultError, result
106
103
  end
107
104
  end
108
105
 
@@ -116,7 +113,7 @@ module Geos
116
113
 
117
114
  def check_enum_value(enum, value)
118
115
  enum[value] or
119
- raise TypeError.new("Couldn't find valid #{enum.tag} value: #{value}")
116
+ raise TypeError, "Couldn't find valid #{enum.tag} value: #{value}"
120
117
  end
121
118
 
122
119
  def symbol_for_enum(enum, value)