ffi-geos 1.2.2 → 2.3.0

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +49 -0
  3. data/.rubocop.yml +5117 -4
  4. data/FUNDING.yml +2 -0
  5. data/Gemfile +9 -16
  6. data/Guardfile +3 -4
  7. data/MIT-LICENSE +1 -1
  8. data/README.rdoc +2 -20
  9. data/Rakefile +3 -2
  10. data/ffi-geos.gemspec +7 -2
  11. data/lib/ffi-geos/buffer_params.rb +1 -1
  12. data/lib/ffi-geos/coordinate_sequence.rb +179 -177
  13. data/lib/ffi-geos/geometry.rb +118 -31
  14. data/lib/ffi-geos/geometry_collection.rb +26 -12
  15. data/lib/ffi-geos/interrupt.rb +11 -14
  16. data/lib/ffi-geos/line_string.rb +64 -49
  17. data/lib/ffi-geos/multi_line_string.rb +1 -1
  18. data/lib/ffi-geos/point.rb +18 -18
  19. data/lib/ffi-geos/polygon.rb +44 -30
  20. data/lib/ffi-geos/prepared_geometry.rb +1 -1
  21. data/lib/ffi-geos/strtree.rb +28 -30
  22. data/lib/ffi-geos/tools.rb +1 -1
  23. data/lib/ffi-geos/utils.rb +16 -23
  24. data/lib/ffi-geos/version.rb +1 -1
  25. data/lib/ffi-geos/wkb_reader.rb +1 -1
  26. data/lib/ffi-geos/wkb_writer.rb +4 -5
  27. data/lib/ffi-geos/wkt_reader.rb +1 -1
  28. data/lib/ffi-geos/wkt_writer.rb +7 -13
  29. data/lib/ffi-geos.rb +134 -48
  30. data/sonar-project.properties +16 -0
  31. data/test/coordinate_sequence_tests.rb +148 -126
  32. data/test/geometry_collection_tests.rb +41 -67
  33. data/test/geometry_tests.rb +341 -40
  34. data/test/interrupt_tests.rb +7 -7
  35. data/test/line_string_tests.rb +23 -15
  36. data/test/point_tests.rb +5 -5
  37. data/test/polygon_tests.rb +6 -7
  38. data/test/prepared_geometry_tests.rb +8 -8
  39. data/test/strtree_tests.rb +13 -12
  40. data/test/test_helper.rb +74 -56
  41. data/test/utils_tests.rb +69 -59
  42. data/test/wkb_reader_tests.rb +9 -9
  43. data/test/wkb_writer_tests.rb +14 -12
  44. data/test/wkt_reader_tests.rb +0 -1
  45. data/test/wkt_writer_tests.rb +2 -5
  46. metadata +12 -10
  47. data/.travis.yml +0 -21
@@ -34,7 +34,7 @@ module Geos
34
34
  end
35
35
 
36
36
  def dump_points(cur_path = [])
37
- points = [ exterior_ring.dump_points ]
37
+ points = [exterior_ring.dump_points]
38
38
 
39
39
  interior_rings.each do |ring|
40
40
  points.push(ring.dump_points)
@@ -44,25 +44,25 @@ module Geos
44
44
  end
45
45
 
46
46
  def snap_to_grid!(*args)
47
- if !self.empty?
47
+ unless empty?
48
48
  exterior_ring = self.exterior_ring.coord_seq.snap_to_grid!(*args)
49
49
 
50
- if exterior_ring.length == 0
51
- @ptr = Geos.create_empty_polygon(:srid => self.srid).ptr
50
+ if exterior_ring.empty?
51
+ @ptr = Geos.create_empty_polygon(srid: srid).ptr
52
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")
53
+ raise Geos::InvalidGeometryError, "snap_to_grid! produced an invalid number of points in exterior ring - found #{exterior_ring.length} - must be 0 or >= 4"
54
54
  else
55
55
  interior_rings = []
56
56
 
57
- self.num_interior_rings.times { |i|
58
- interior_ring = self.interior_ring_n(i).coord_seq.snap_to_grid!(*args)
57
+ num_interior_rings.times do |i|
58
+ interior_ring = interior_ring_n(i).coord_seq.snap_to_grid!(*args)
59
59
 
60
60
  interior_rings << interior_ring unless interior_ring.length < 4
61
- }
61
+ end
62
62
 
63
63
  interior_rings.compact!
64
64
 
65
- polygon = Geos.create_polygon(exterior_ring, interior_rings, :srid => self.srid)
65
+ polygon = Geos.create_polygon(exterior_ring, interior_rings, srid: srid)
66
66
  @ptr = polygon.ptr
67
67
  end
68
68
  end
@@ -71,33 +71,47 @@ module Geos
71
71
  end
72
72
 
73
73
  def snap_to_grid(*args)
74
- ret = self.dup.snap_to_grid!(*args)
75
- ret.srid = pick_srid_according_to_policy(self.srid)
74
+ ret = dup.snap_to_grid!(*args)
75
+ ret.srid = pick_srid_according_to_policy(srid)
76
76
  ret
77
77
  end
78
78
 
79
79
  %w{ max min }.each do |op|
80
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}
81
+ native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..-1]}_r"
82
+
83
+ if FFIGeos.respond_to?(native_method)
84
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
85
+ def #{dimension}_#{op}
86
+ return if empty?
87
+
88
+ double_ptr = FFI::MemoryPointer.new(:double)
89
+ FFIGeos.#{native_method}(Geos.current_handle_pointer, ptr, double_ptr)
90
+ double_ptr.read_double
85
91
  end
86
- end
87
- EOF
92
+ RUBY
93
+ else
94
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
95
+ def #{dimension}_#{op}
96
+ unless empty?
97
+ envelope.exterior_ring.#{dimension}_#{op}
98
+ end
99
+ end
100
+ RUBY
101
+ end
88
102
  end
89
103
 
90
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
104
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
91
105
  def z_#{op}
92
- unless self.empty?
93
- if self.has_z?
94
- self.exterior_ring.z_#{op}
106
+ unless empty?
107
+ if has_z?
108
+ exterior_ring.z_#{op}
95
109
  else
96
110
  0
97
111
  end
98
112
  end
99
113
  end
100
- EOF
114
+ RUBY
101
115
  end
102
116
 
103
117
  %w{
@@ -110,21 +124,21 @@ module Geos
110
124
  trans_scale
111
125
  translate
112
126
  }.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|
127
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
128
+ def #{m}!(*args, **kwargs)
129
+ exterior_ring.coord_seq.#{m}!(*args, **kwargs)
130
+ interior_rings.each do |ring|
117
131
  ring.coord_seq.#{m}!(*args)
118
132
  end
119
133
  self
120
134
  end
121
135
 
122
- def #{m}(*args)
123
- ret = self.dup.#{m}!(*args)
124
- ret.srid = pick_srid_according_to_policy(self.srid)
136
+ def #{m}(*args, **kwargs)
137
+ ret = dup.#{m}!(*args, **kwargs)
138
+ ret.srid = pick_srid_according_to_policy(srid)
125
139
  ret
126
140
  end
127
- EOF
141
+ RUBY
128
142
  end
129
143
  end
130
144
  end
@@ -24,7 +24,7 @@ module Geos
24
24
  @ptr.autorelease = !!options[:auto_free]
25
25
  end
26
26
 
27
- def self.release(ptr) #:nodoc:
27
+ def self.release(ptr) # :nodoc:
28
28
  FFIGeos.GEOSPreparedGeom_destroy_r(Geos.current_handle_pointer, ptr)
29
29
  end
30
30
 
@@ -23,23 +23,22 @@ module Geos
23
23
  geoms_and_objects = nil # forward declaration
24
24
  capacity = 10
25
25
 
26
- if args.first.is_a?(Integer)
27
- capacity = args.first
28
- elsif args.first.is_a?(Array)
29
- geoms_and_objects = if args.first.first.is_a?(Array)
30
- args.first
31
- else
32
- args
33
- end
26
+ case args.first
27
+ when Integer
28
+ capacity = args.first
29
+ when Array
30
+ geoms_and_objects = if args.first.first.is_a?(Array)
31
+ args.first
32
+ else
33
+ args
34
+ end
34
35
 
35
- geoms_and_objects.each do |geom, _obj|
36
- check_geometry(geom)
37
- end
36
+ geoms_and_objects.each do |geom, _obj|
37
+ check_geometry(geom)
38
+ end
38
39
  end
39
40
 
40
- if capacity <= 0
41
- raise ArgumentError, 'STRtree capacity must be greater than 0'
42
- end
41
+ raise ArgumentError, 'STRtree capacity must be greater than 0' if capacity <= 0
43
42
 
44
43
  ptr = FFIGeos.GEOSSTRtree_create_r(Geos.current_handle_pointer, capacity)
45
44
 
@@ -61,7 +60,7 @@ module Geos
61
60
  end
62
61
  end
63
62
 
64
- def self.release(ptr) #:nodoc:
63
+ def self.release(ptr) # :nodoc:
65
64
  FFIGeos.GEOSSTRtree_destroy_r(Geos.current_handle_pointer, ptr)
66
65
  end
67
66
 
@@ -99,7 +98,7 @@ module Geos
99
98
  def remove(geom, item)
100
99
  check_geometry(geom)
101
100
 
102
- key = if storage = @storage.detect { |k, v| v[:item] == item }
101
+ key = if (storage = @storage.detect { |_k, v| v[:item] == item })
103
102
  storage[0]
104
103
  end
105
104
 
@@ -139,16 +138,17 @@ module Geos
139
138
 
140
139
  def query(geom, ret = :item)
141
140
  query_all(geom).collect { |storage|
142
- item = if ret.is_a?(Array)
143
- storage.inject({}) do |memo, k|
144
- memo.tap do
145
- memo[k] = storage[k]
141
+ item = case ret
142
+ when Array
143
+ storage.inject({}) do |memo, k|
144
+ memo.tap do
145
+ memo[k] = storage[k]
146
+ end
146
147
  end
147
- end
148
- elsif ret == :all
149
- storage
150
- else
151
- storage[ret]
148
+ when :all
149
+ storage
150
+ else
151
+ storage[ret]
152
152
  end
153
153
 
154
154
  item.tap do
@@ -166,10 +166,8 @@ module Geos
166
166
  end
167
167
  alias query_geoms query_geometries
168
168
 
169
- def iterate
170
- @storage.each_value do |v|
171
- yield(v)
172
- end
169
+ def iterate(&block)
170
+ @storage.each_value(&block)
173
171
  end
174
172
 
175
173
  if FFIGeos.respond_to?(:GEOSSTRtree_nearest_generic_r)
@@ -180,7 +178,7 @@ module Geos
180
178
 
181
179
  return nil if @storage.empty?
182
180
 
183
- callback = proc { |item, _item2, distance_ptr|
181
+ callback = proc { |item, _item_2, distance_ptr|
184
182
  key = item.read_int
185
183
  geom_from_storage = @storage[key][:geometry]
186
184
 
@@ -47,7 +47,7 @@ module Geos
47
47
  when GEOS_GEOMETRYCOLLECTION
48
48
  GeometryCollection
49
49
  else
50
- raise Geos::InvalidGeometryTypeError.new
50
+ raise Geos::InvalidGeometryTypeError
51
51
  end
52
52
 
53
53
  klass.new(geom_ptr, options).tap do |ret|
@@ -30,22 +30,21 @@ module Geos
30
30
  def create_point(*args)
31
31
  options = extract_options!(args)
32
32
 
33
- if args.length == 1
34
- cs = args.first
35
- elsif args.length == 2
36
- cs = CoordinateSequence.new(1, 2)
37
- cs.x[0] = args[0].to_f
38
- cs.y[0] = args[1].to_f
39
- elsif args.length == 3
40
- cs = CoordinateSequence.new(1, 3)
41
- cs.x[0], cs.y[0], cs.z[0] = args.map(&:to_f)
42
- else
43
- raise ArgumentError, "Wrong number of arguments (#{args.length} for 1-3)"
33
+ case args.length
34
+ when 1
35
+ cs = args.first
36
+ when 2
37
+ cs = CoordinateSequence.new(1, 2)
38
+ cs.x[0] = args[0].to_f
39
+ cs.y[0] = args[1].to_f
40
+ when 3
41
+ cs = CoordinateSequence.new(1, 3)
42
+ cs.x[0], cs.y[0], cs.z[0] = args.map(&:to_f)
43
+ else
44
+ raise ArgumentError, "Wrong number of arguments (#{args.length} for 1-3)"
44
45
  end
45
46
 
46
- if cs.length != 1
47
- raise ArgumentError, 'IllegalArgumentException: Point coordinate list must contain a single element'
48
- end
47
+ raise ArgumentError, 'IllegalArgumentException: Point coordinate list must contain a single element' if cs.length != 1
49
48
 
50
49
  cs_dup = cs.dup
51
50
  cs_dup.ptr.autorelease = false
@@ -56,9 +55,7 @@ module Geos
56
55
  def create_line_string(cs, options = {})
57
56
  cs = cs_from_cs_or_geom(cs)
58
57
 
59
- if cs.length <= 1 && cs.length != 0
60
- raise ArgumentError, 'IllegalArgumentException: point array must contain 0 or >1 elements'
61
- end
58
+ raise ArgumentError, 'IllegalArgumentException: point array must contain 0 or >1 elements' if cs.length <= 1 && !cs.empty?
62
59
 
63
60
  cs_dup = cs.dup
64
61
  cs_dup.ptr.autorelease = false
@@ -69,9 +66,7 @@ module Geos
69
66
  def create_linear_ring(cs, options = {})
70
67
  cs = cs_from_cs_or_geom(cs)
71
68
 
72
- if cs.length <= 1 && cs.length != 0
73
- raise ArgumentError, 'IllegalArgumentException: point array must contain 0 or >1 elements'
74
- end
69
+ raise ArgumentError, 'IllegalArgumentException: point array must contain 0 or >1 elements' if cs.length <= 1 && !cs.empty?
75
70
 
76
71
  cs.ptr.autorelease = false
77
72
 
@@ -154,9 +149,7 @@ module Geos
154
149
  options = extract_options!(args)
155
150
 
156
151
  geoms = Array(args).flatten.tap do |i|
157
- if i.detect { |g| !g.is_a?(klass) }
158
- raise TypeError, "Expected geoms Array to contain #{klass} objects"
159
- end
152
+ raise TypeError, "Expected geoms Array to contain #{klass} objects" if i.detect { |g| !g.is_a?(klass) }
160
153
  end
161
154
 
162
155
  geoms_dups = geoms.map(&:dup)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geos
4
- VERSION = '1.2.2'.freeze
4
+ VERSION = '2.3.0'
5
5
  end
@@ -34,7 +34,7 @@ module Geos
34
34
  raise ParseError, e
35
35
  end
36
36
 
37
- def self.release(ptr) #:nodoc:
37
+ def self.release(ptr) # :nodoc:
38
38
  FFIGeos.GEOSWKBReader_destroy_r(Geos.current_handle_pointer, ptr)
39
39
  end
40
40
  end
@@ -20,7 +20,7 @@ module Geos
20
20
  set_options(options)
21
21
  end
22
22
 
23
- def self.release(ptr) #:nodoc:
23
+ def self.release(ptr) # :nodoc:
24
24
  FFIGeos.GEOSWKBWriter_destroy_r(Geos.current_handle_pointer, ptr)
25
25
  end
26
26
 
@@ -57,9 +57,8 @@ module Geos
57
57
  end
58
58
 
59
59
  def output_dimensions=(dim)
60
- if dim < 2 || dim > 3
61
- raise ArgumentError, 'Output dimensions must be either 2 or 3'
62
- end
60
+ raise ArgumentError, 'Output dimensions must be either 2 or 3' if dim < 2 || dim > 3
61
+
63
62
  FFIGeos.GEOSWKBWriter_setOutputDimension_r(Geos.current_handle_pointer, ptr, dim)
64
63
  end
65
64
 
@@ -86,7 +85,7 @@ module Geos
86
85
 
87
86
  private
88
87
 
89
- def set_options(options) #:nodoc:
88
+ def set_options(options) # :nodoc:
90
89
  self.include_srid = options[:include_srid] if options.key?(:include_srid)
91
90
  end
92
91
  end
@@ -28,7 +28,7 @@ module Geos
28
28
  raise ParseError, e
29
29
  end
30
30
 
31
- def self.release(ptr) #:nodoc:
31
+ def self.release(ptr) # :nodoc:
32
32
  FFIGeos.GEOSWKTReader_destroy_r(Geos.current_handle_pointer, ptr)
33
33
  end
34
34
  end
@@ -2,10 +2,7 @@
2
2
 
3
3
  module Geos
4
4
  class WktWriter
5
- attr_reader :ptr
6
- attr_reader :old_3d
7
- attr_reader :rounding_precision
8
- attr_reader :trim
5
+ attr_reader :ptr, :old_3d, :rounding_precision, :trim
9
6
 
10
7
  def initialize(options = {})
11
8
  options = {
@@ -24,12 +21,12 @@ module Geos
24
21
  set_options(options)
25
22
  end
26
23
 
27
- def self.release(ptr) #:nodoc:
24
+ def self.release(ptr) # :nodoc:
28
25
  FFIGeos.GEOSWKTWriter_destroy_r(Geos.current_handle_pointer, ptr)
29
26
  end
30
27
 
31
- def set_options(options) #:nodoc:
32
- [ :trim, :old_3d, :rounding_precision, :output_dimensions ].each do |k|
28
+ def set_options(options) # :nodoc:
29
+ [:trim, :old_3d, :rounding_precision, :output_dimensions].each do |k|
33
30
  send("#{k}=", options[k]) if respond_to?("#{k}=") && options.key?(k)
34
31
  end
35
32
  end
@@ -67,9 +64,7 @@ module Geos
67
64
  # Available in GEOS 3.3+.
68
65
  def rounding_precision=(r)
69
66
  r = r.to_i
70
- if r > 255
71
- raise ArgumentError, 'Rounding precision cannot be greater than 255'
72
- end
67
+ raise ArgumentError, 'Rounding precision cannot be greater than 255' if r > 255
73
68
 
74
69
  @rounding_precision = r
75
70
  FFIGeos.GEOSWKTWriter_setRoundingPrecision_r(Geos.current_handle_pointer, ptr, @rounding_precision)
@@ -88,9 +83,8 @@ module Geos
88
83
  # Available in GEOS 3.3+.
89
84
  def output_dimensions=(dim)
90
85
  dim = dim.to_i
91
- if dim < 2 || dim > 3
92
- raise ArgumentError, 'Output dimensions must be either 2 or 3'
93
- end
86
+ raise ArgumentError, 'Output dimensions must be either 2 or 3' if dim < 2 || dim > 3
87
+
94
88
  FFIGeos.GEOSWKTWriter_setOutputDimension_r(Geos.current_handle_pointer, ptr, dim)
95
89
  end
96
90
  end