ffi-geos 1.2.2 → 2.3.0

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