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,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -8,34 +7,83 @@ module Geos
8
7
  # Yields each Geometry in the GeometryCollection.
9
8
  def each
10
9
  if block_given?
11
- self.num_geometries.times do |n|
12
- yield self.get_geometry_n(n)
10
+ num_geometries.times do |n|
11
+ yield get_geometry_n(n)
13
12
  end
14
13
  self
15
14
  else
16
- self.num_geometries.times.collect { |n|
17
- self.get_geometry_n(n)
15
+ num_geometries.times.collect { |n|
16
+ get_geometry_n(n)
18
17
  }.to_enum
19
18
  end
20
19
  end
21
20
 
22
21
  def get_geometry_n(n)
23
- if n < 0 || n >= self.num_geometries
22
+ if n.negative? || n >= num_geometries
24
23
  nil
25
24
  else
26
- cast_geometry_ptr(FFIGeos.GEOSGetGeometryN_r(Geos.current_handle_pointer, self.ptr, n), :auto_free => false)
25
+ cast_geometry_ptr(FFIGeos.GEOSGetGeometryN_r(Geos.current_handle_pointer, ptr, n), auto_free: false)
27
26
  end
28
27
  end
29
- alias_method :geometry_n, :get_geometry_n
28
+ alias geometry_n get_geometry_n
30
29
 
31
30
  def [](*args)
32
31
  if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
33
- self.get_geometry_n(args.first)
32
+ get_geometry_n(args.first)
34
33
  else
35
- self.to_a[*args]
34
+ to_a[*args]
36
35
  end
37
36
  end
38
- alias_method :slice, :[]
39
- alias_method :at, :[]
37
+ alias slice []
38
+ alias at []
39
+
40
+ def dump_points(cur_path = [])
41
+ each do |geom|
42
+ cur_path << geom.dump_points
43
+ end
44
+ cur_path
45
+ end
46
+
47
+ %w{ x y z }.each do |dimension|
48
+ %w{ max min }.each do |op|
49
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
50
+ def #{dimension}_#{op}
51
+ unless self.empty?
52
+ self.collect(&:#{dimension}_#{op}).#{op}
53
+ end
54
+ end
55
+ EOF
56
+ end
57
+ end
58
+
59
+ %w{
60
+ affine
61
+ rotate
62
+ rotate_x
63
+ rotate_y
64
+ rotate_z
65
+ scale
66
+ snap_to_grid
67
+ trans_scale
68
+ translate
69
+ }.each do |m|
70
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
71
+ def #{m}!(*args)
72
+ unless self.empty?
73
+ self.num_geometries.times do |i|
74
+ self[i].#{m}!(*args)
75
+ end
76
+ end
77
+
78
+ self
79
+ end
80
+
81
+ def #{m}(*args)
82
+ ret = self.dup.#{m}!(*args)
83
+ ret.srid = pick_srid_according_to_policy(self.srid)
84
+ ret
85
+ end
86
+ EOF
87
+ end
40
88
  end
41
89
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -27,9 +26,9 @@ module Geos
27
26
  # up in unexpected ways while interrupts are firing.
28
27
  def register(method_or_block = nil, &block)
29
28
  if method_or_block.nil? && !block_given?
30
- raise ArgumentError.new("Expected either a method or a block for Geos::Interrupt.register")
29
+ raise ArgumentError, 'Expected either a method or a block for Geos::Interrupt.register'
31
30
  elsif !method_or_block.nil? && block_given?
32
- raise ArgumentError.new("Cannot use both a method and a block for Geos::Interrupt.register")
31
+ raise ArgumentError, 'Cannot use both a method and a block for Geos::Interrupt.register'
33
32
  else
34
33
  retval = @current_interrupt_callback
35
34
 
@@ -72,4 +71,3 @@ module Geos
72
71
  end
73
72
  end
74
73
  end
75
-
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -7,82 +6,192 @@ module Geos
7
6
 
8
7
  def each
9
8
  if block_given?
10
- self.num_points.times do |n|
11
- yield self.point_n(n)
9
+ num_points.times do |n|
10
+ yield point_n(n)
12
11
  end
13
12
  self
14
13
  else
15
- self.num_points.times.collect { |n|
16
- self.point_n(n)
14
+ num_points.times.collect { |n|
15
+ point_n(n)
17
16
  }.to_enum
18
17
  end
19
18
  end
20
19
 
21
20
  if FFIGeos.respond_to?(:GEOSGeomGetNumPoints_r)
22
21
  def num_points
23
- FFIGeos.GEOSGeomGetNumPoints_r(Geos.current_handle_pointer, self.ptr)
22
+ FFIGeos.GEOSGeomGetNumPoints_r(Geos.current_handle_pointer, ptr)
24
23
  end
25
24
  else
26
25
  def num_points
27
- self.coord_seq.length
26
+ coord_seq.length
28
27
  end
29
28
  end
30
29
 
31
30
  def point_n(n)
32
- if n < 0 || n >= self.num_points
33
- raise Geos::IndexBoundsError.new
34
- else
35
- cast_geometry_ptr(
36
- FFIGeos.GEOSGeomGetPointN_r(Geos.current_handle_pointer, self.ptr, n), {
37
- :srid_copy => self.srid
38
- }
39
- )
40
- end
31
+ raise Geos::IndexBoundsError if n < 0 || n >= num_points
32
+
33
+ cast_geometry_ptr(FFIGeos.GEOSGeomGetPointN_r(Geos.current_handle_pointer, ptr, n), srid_copy: srid)
41
34
  end
42
35
 
43
36
  def [](*args)
44
37
  if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
45
- self.point_n(args.first)
38
+ point_n(args.first)
46
39
  else
47
- self.to_a[*args]
40
+ to_a[*args]
48
41
  end
49
42
  end
50
- alias_method :slice, :[]
43
+ alias slice []
51
44
 
52
45
  def offset_curve(width, options = {})
53
46
  options = Constants::BUFFER_PARAM_DEFAULTS.merge(options)
54
47
 
55
48
  cast_geometry_ptr(FFIGeos.GEOSOffsetCurve_r(
56
- Geos.current_handle_pointer,
57
- self.ptr,
58
- width,
59
- options[:quad_segs],
60
- options[:join],
61
- options[:mitre_limit]
62
- ), {
63
- :srid_copy => self.srid
64
- })
49
+ Geos.current_handle_pointer,
50
+ ptr,
51
+ width,
52
+ options[:quad_segs],
53
+ options[:join],
54
+ options[:mitre_limit]
55
+ ), srid_copy: srid)
65
56
  end
66
57
 
67
58
  if FFIGeos.respond_to?(:GEOSisClosed_r)
68
59
  def closed?
69
- bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer, self.ptr))
60
+ bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer, ptr))
70
61
  end
71
62
  end
72
63
 
73
64
  def to_linear_ring
74
- if self.closed?
75
- Geos.create_linear_ring(self.coord_seq, :srid => pick_srid_according_to_policy(self.srid))
76
- else
77
- self_cs = self.coord_seq.to_a
78
- self_cs.push(self_cs[0])
65
+ return Geos.create_linear_ring(coord_seq, srid: pick_srid_according_to_policy(srid)) if closed?
79
66
 
80
- Geos.create_linear_ring(self_cs, :srid => pick_srid_according_to_policy(self.srid))
81
- end
67
+ self_cs = coord_seq.to_a
68
+ self_cs.push(self_cs[0])
69
+
70
+ Geos.create_linear_ring(self_cs, srid: pick_srid_according_to_policy(srid))
82
71
  end
83
72
 
84
73
  def to_polygon
85
- self.to_linear_ring.to_polygon
74
+ to_linear_ring.to_polygon
75
+ end
76
+
77
+ def dump_points(cur_path = [])
78
+ cur_path.concat(to_a)
79
+ end
80
+
81
+ def snap_to_grid!(*args)
82
+ if !self.empty?
83
+ cs = self.coord_seq.snap_to_grid!(*args)
84
+
85
+ if cs.length == 0
86
+ @ptr = Geos.create_empty_line_string(:srid => self.srid).ptr
87
+ elsif cs.length <= 1
88
+ raise Geos::InvalidGeometryError.new("snap_to_grid! produced an invalid number of points in for a LineString - found #{cs.length} - must be 0 or > 1")
89
+ else
90
+ @ptr = Geos.create_line_string(cs).ptr
91
+ end
92
+ end
93
+
94
+ self
95
+ end
96
+
97
+ def snap_to_grid(*args)
98
+ ret = self.dup.snap_to_grid!(*args)
99
+ ret.srid = pick_srid_according_to_policy(self.srid)
100
+ ret
101
+ end
102
+
103
+ def line_interpolate_point(fraction)
104
+ if !fraction.between?(0, 1)
105
+ raise ArgumentError.new("fraction must be between 0 and 1")
106
+ end
107
+
108
+ case fraction
109
+ when 0
110
+ self.start_point
111
+ when 1
112
+ self.end_point
113
+ else
114
+ length = self.length
115
+ total_length = 0
116
+ segs = self.num_points - 1
117
+
118
+ segs.times do |i|
119
+ p1 = self[i]
120
+ p2 = self[i + 1]
121
+
122
+ seg_length = p1.distance(p2) / length
123
+
124
+ if fraction < total_length + seg_length
125
+ dseg = (fraction - total_length) / seg_length;
126
+
127
+ args = []
128
+ args << p1.x + ((p2.x - p1.x) * dseg)
129
+ args << p1.y + ((p2.y - p1.y) * dseg)
130
+ args << p1.z + ((p2.z - p1.z) * dseg) if self.has_z?
131
+
132
+ args << { :srid => pick_srid_according_to_policy(self.srid) } unless self.srid == 0
133
+
134
+ return Geos.create_point(*args)
135
+ end
136
+
137
+ total_length += seg_length
138
+ end
139
+
140
+ # if all else fails...
141
+ self.end_point
142
+ end
143
+ end
144
+ alias_method :interpolate_point, :line_interpolate_point
145
+
146
+ %w{ max min }.each do |op|
147
+ %w{ x y }.each do |dimension|
148
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
149
+ def #{dimension}_#{op}
150
+ unless self.empty?
151
+ self.coord_seq.#{dimension}_#{op}
152
+ end
153
+ end
154
+ EOF
155
+ end
156
+
157
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
158
+ def z_#{op}
159
+ unless self.empty?
160
+ if self.has_z?
161
+ self.coord_seq.z_#{op}
162
+ else
163
+ 0
164
+ end
165
+ end
166
+ end
167
+ EOF
168
+ end
169
+
170
+ %w{
171
+ affine
172
+ rotate
173
+ rotate_x
174
+ rotate_y
175
+ rotate_z
176
+ scale
177
+ trans_scale
178
+ translate
179
+ }.each do |m|
180
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
181
+ def #{m}!(*args)
182
+ unless self.empty?
183
+ self.coord_seq.#{m}!(*args)
184
+ end
185
+
186
+ self
187
+ end
188
+
189
+ def #{m}(*args)
190
+ ret = self.dup.#{m}!(*args)
191
+ ret.srid = pick_srid_according_to_policy(self.srid)
192
+ ret
193
+ end
194
+ EOF
86
195
  end
87
196
  end
88
197
  end
@@ -1,14 +1,13 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
5
4
  class LinearRing < LineString
6
5
  def to_polygon
7
- Geos.create_polygon(self, :srid => pick_srid_according_to_policy(self.srid))
6
+ Geos.create_polygon(self, srid: pick_srid_according_to_policy(srid))
8
7
  end
9
8
 
10
9
  def to_line_string
11
- Geos.create_line_string(self.coord_seq, :srid => pick_srid_according_to_policy(self.srid))
10
+ Geos.create_line_string(coord_seq, srid: pick_srid_according_to_policy(srid))
12
11
  end
13
12
  end
14
13
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -6,7 +5,7 @@ module Geos
6
5
  if FFIGeos.respond_to?(:GEOSisClosed_r) && Geos::GEOS_VERSION >= '3.5.0'
7
6
  # Available in GEOS 3.5.0+.
8
7
  def closed?
9
- bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer, self.ptr))
8
+ bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer, ptr))
10
9
  end
11
10
  end
12
11
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Geos
@@ -6,41 +5,41 @@ module Geos
6
5
  if FFIGeos.respond_to?(:GEOSGeomGetX_r)
7
6
  def get_x
8
7
  double_ptr = FFI::MemoryPointer.new(:double)
9
- FFIGeos.GEOSGeomGetX_r(Geos.current_handle_pointer, self.ptr, double_ptr)
8
+ FFIGeos.GEOSGeomGetX_r(Geos.current_handle_pointer, ptr, double_ptr)
10
9
  double_ptr.read_double
11
10
  end
12
11
  else
13
12
  def get_x
14
- self.coord_seq.get_x(0)
13
+ coord_seq.get_x(0)
15
14
  end
16
15
  end
17
- alias_method :x, :get_x
16
+ alias x get_x
18
17
 
19
18
  if FFIGeos.respond_to?(:GEOSGeomGetY_r)
20
19
  def get_y
21
20
  double_ptr = FFI::MemoryPointer.new(:double)
22
- FFIGeos.GEOSGeomGetY_r(Geos.current_handle_pointer, self.ptr, double_ptr)
21
+ FFIGeos.GEOSGeomGetY_r(Geos.current_handle_pointer, ptr, double_ptr)
23
22
  double_ptr.read_double
24
23
  end
25
24
  else
26
25
  def get_y
27
- self.coord_seq.get_y(0)
26
+ coord_seq.get_y(0)
28
27
  end
29
28
  end
30
- alias_method :y, :get_y
29
+ alias y get_y
31
30
 
32
31
  if FFIGeos.respond_to?(:GEOSGeomGetZ_r)
33
32
  def get_z
34
33
  double_ptr = FFI::MemoryPointer.new(:double)
35
- FFIGeos.GEOSGeomGetZ_r(Geos.current_handle_pointer, self.ptr, double_ptr)
34
+ FFIGeos.GEOSGeomGetZ_r(Geos.current_handle_pointer, ptr, double_ptr)
36
35
  double_ptr.read_double
37
36
  end
38
37
  else
39
38
  def get_z
40
- self.coord_seq.get_z(0)
39
+ coord_seq.get_z(0)
41
40
  end
42
41
  end
43
- alias_method :z, :get_z
42
+ alias z get_z
44
43
 
45
44
  def area
46
45
  0
@@ -61,7 +60,7 @@ module Geos
61
60
  def normalize!
62
61
  self
63
62
  end
64
- alias_method :normalize, :normalize!
63
+ alias normalize normalize!
65
64
 
66
65
  %w{
67
66
  convex_hull
@@ -70,11 +69,67 @@ module Geos
70
69
  envelope
71
70
  topology_preserve_simplify
72
71
  }.each do |method|
73
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
72
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
74
73
  def #{method}(*args)
75
- self.dup.tap { |ret|
74
+ dup.tap do |ret|
76
75
  ret.srid = pick_srid_according_to_policy(ret.srid)
77
- }
76
+ end
77
+ end
78
+ RUBY
79
+ end
80
+
81
+ def dump_points(cur_path = [])
82
+ cur_path.push(self.dup)
83
+ end
84
+
85
+ %w{ max min }.each do |op|
86
+ %w{ x y }.each do |dimension|
87
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
88
+ def #{dimension}_#{op}
89
+ unless self.empty?
90
+ self.#{dimension}
91
+ end
92
+ end
93
+ EOF
94
+ end
95
+
96
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
97
+ def z_#{op}
98
+ unless self.empty?
99
+ if self.has_z?
100
+ self.z
101
+ else
102
+ 0
103
+ end
104
+ end
105
+ end
106
+ EOF
107
+ end
108
+
109
+ %w{
110
+ affine
111
+ rotate
112
+ rotate_x
113
+ rotate_y
114
+ rotate_z
115
+ scale
116
+ snap_to_grid
117
+ trans_scale
118
+ translate
119
+ }.each do |m|
120
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
121
+ def #{m}!(*args)
122
+ unless self.empty?
123
+ self.coord_seq.#{m}!(*args)
124
+ end
125
+
126
+ self
127
+ end
128
+
129
+ def #{m}(*args)
130
+ ret = self.dup.#{m}!(*args)
131
+ ret.srid = pick_srid_according_to_policy(self.srid)
132
+ ret
78
133
  end
79
134
  EOF
80
135
  end