ffi-geos 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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)