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,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