rgeo 3.0.0.pre.rc.3 → 3.0.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -0
  3. data/ext/geos_c_impl/factory.c +41 -5
  4. data/ext/geos_c_impl/factory.h +13 -2
  5. data/ext/geos_c_impl/geometry.c +151 -122
  6. data/ext/geos_c_impl/geometry_collection.c +17 -19
  7. data/ext/geos_c_impl/line_string.c +46 -36
  8. data/ext/geos_c_impl/point.c +0 -2
  9. data/ext/geos_c_impl/polygon.c +10 -11
  10. data/ext/geos_c_impl/polygon.h +1 -1
  11. data/ext/geos_c_impl/ruby_more.c +7 -0
  12. data/ext/geos_c_impl/ruby_more.h +8 -0
  13. data/lib/rgeo/cartesian/analysis.rb +5 -3
  14. data/lib/rgeo/cartesian/bounding_box.rb +74 -79
  15. data/lib/rgeo/cartesian/calculations.rb +20 -26
  16. data/lib/rgeo/cartesian/factory.rb +47 -49
  17. data/lib/rgeo/cartesian/planar_graph.rb +10 -16
  18. data/lib/rgeo/cartesian/sweepline_intersector.rb +1 -3
  19. data/lib/rgeo/cartesian/valid_op.rb +1 -3
  20. data/lib/rgeo/coord_sys/cs/entities.rb +87 -101
  21. data/lib/rgeo/coord_sys/cs/factories.rb +0 -2
  22. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +70 -29
  23. data/lib/rgeo/feature/curve.rb +0 -1
  24. data/lib/rgeo/feature/factory.rb +25 -27
  25. data/lib/rgeo/feature/factory_generator.rb +3 -4
  26. data/lib/rgeo/feature/geometry.rb +41 -30
  27. data/lib/rgeo/feature/geometry_collection.rb +3 -4
  28. data/lib/rgeo/feature/line_string.rb +1 -2
  29. data/lib/rgeo/feature/linear_ring.rb +0 -1
  30. data/lib/rgeo/feature/multi_curve.rb +0 -1
  31. data/lib/rgeo/feature/multi_surface.rb +0 -1
  32. data/lib/rgeo/feature/point.rb +0 -1
  33. data/lib/rgeo/feature/polygon.rb +1 -2
  34. data/lib/rgeo/feature/surface.rb +0 -1
  35. data/lib/rgeo/feature/types.rb +73 -83
  36. data/lib/rgeo/geographic/factory.rb +87 -80
  37. data/lib/rgeo/geographic/interface.rb +40 -23
  38. data/lib/rgeo/geographic/projected_feature_methods.rb +2 -6
  39. data/lib/rgeo/geographic/projected_window.rb +35 -21
  40. data/lib/rgeo/geographic/simple_mercator_projector.rb +25 -13
  41. data/lib/rgeo/geographic/spherical_feature_methods.rb +8 -3
  42. data/lib/rgeo/geographic/spherical_math.rb +17 -20
  43. data/lib/rgeo/geos/capi_factory.rb +50 -50
  44. data/lib/rgeo/geos/ffi_factory.rb +41 -42
  45. data/lib/rgeo/geos/ffi_feature_methods.rb +72 -97
  46. data/lib/rgeo/geos/interface.rb +16 -16
  47. data/lib/rgeo/geos/utils.rb +3 -3
  48. data/lib/rgeo/geos/zm_factory.rb +50 -42
  49. data/lib/rgeo/geos/zm_feature_methods.rb +15 -8
  50. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +4 -4
  51. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -2
  52. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +18 -24
  53. data/lib/rgeo/impl_helper/basic_point_methods.rb +1 -3
  54. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +15 -16
  55. data/lib/rgeo/impl_helper/utils.rb +3 -9
  56. data/lib/rgeo/impl_helper/valid_op.rb +12 -16
  57. data/lib/rgeo/version.rb +1 -1
  58. data/lib/rgeo/wkrep/wkb_generator.rb +42 -47
  59. data/lib/rgeo/wkrep/wkb_parser.rb +17 -18
  60. data/lib/rgeo/wkrep/wkt_generator.rb +23 -16
  61. data/lib/rgeo/wkrep/wkt_parser.rb +23 -13
  62. metadata +5 -5
@@ -19,9 +19,7 @@ module RGeo
19
19
  # LineStrings in general need to check that there's not one point
20
20
  # GEOS doesn't allow instantiation of single point LineStrings so
21
21
  # we should handle it.
22
- if @points.size == 1
23
- raise Error::InvalidGeometry, "LineString Cannot Have 1 Point"
24
- end
22
+ raise Error::InvalidGeometry, "LineString Cannot Have 1 Point" if @points.size == 1
25
23
  init_geometry
26
24
  end
27
25
 
@@ -29,8 +27,8 @@ module RGeo
29
27
  @points.size
30
28
  end
31
29
 
32
- def point_n(n)
33
- n < 0 ? nil : @points[n]
30
+ def point_n(idx)
31
+ idx < 0 ? nil : @points[idx]
34
32
  end
35
33
 
36
34
  def points
@@ -64,10 +62,9 @@ module RGeo
64
62
  end
65
63
 
66
64
  def closed?
67
- unless defined?(@closed)
68
- @closed = @points.size > 2 && @points.first == @points.last
69
- end
70
- @closed
65
+ return @closed if defined?(@closed)
66
+
67
+ @closed = @points.size > 2 && @points.first == @points.last
71
68
  end
72
69
 
73
70
  def ring?
@@ -111,15 +108,15 @@ module RGeo
111
108
  def point_intersect_segment?(point, start_point, end_point)
112
109
  return false unless point_collinear?(point, start_point, end_point)
113
110
 
114
- if start_point.x != end_point.x
115
- between_coordinate?(point.x, start_point.x, end_point.x)
116
- else
111
+ if start_point.x == end_point.x
117
112
  between_coordinate?(point.y, start_point.y, end_point.y)
113
+ else
114
+ between_coordinate?(point.x, start_point.x, end_point.x)
118
115
  end
119
116
  end
120
117
 
121
- def point_collinear?(a, b, c)
122
- (b.x - a.x) * (c.y - a.y) == (c.x - a.x) * (b.y - a.y)
118
+ def point_collinear?(pt1, pt2, pt3)
119
+ (pt2.x - pt1.x) * (pt3.y - pt1.y) == (pt3.x - pt1.x) * (pt2.y - pt1.y)
123
120
  end
124
121
 
125
122
  def between_coordinate?(coord, start_coord, end_coord)
@@ -137,9 +134,7 @@ module RGeo
137
134
  def initialize(factory, start, stop)
138
135
  self.factory = factory
139
136
  cstart = Feature.cast(start, factory, Feature::Point)
140
- unless cstart
141
- raise Error::InvalidGeometry, "Could not cast start: #{start}"
142
- end
137
+ raise Error::InvalidGeometry, "Could not cast start: #{start}" unless cstart
143
138
  cstop = Feature.cast(stop, factory, Feature::Point)
144
139
  raise Error::InvalidGeometry, "Could not cast end: #{stop}" unless cstop
145
140
  @points = [cstart, cstop]
@@ -158,9 +153,7 @@ module RGeo
158
153
  module BasicLinearRingMethods # :nodoc:
159
154
  def initialize(factory, points)
160
155
  super
161
- unless @points.size >= 4 || @points.size == 0
162
- raise Error::InvalidGeometry, "LinearRings must have 0 or >= 4 points"
163
- end
156
+ raise Error::InvalidGeometry, "LinearRings must have 0 or >= 4 points" if @points.size.between?(1, 3)
164
157
  end
165
158
 
166
159
  def geometry_type
@@ -176,10 +169,11 @@ module RGeo
176
169
  # Close ring if necessary.
177
170
  def init_geometry
178
171
  super
179
- if @points.size > 0
180
- @points << @points.first if @points.first != @points.last
181
- @points = @points.chunk { |x| x }.map(&:first)
182
- end
172
+
173
+ return if @points.empty?
174
+
175
+ @points << @points.first if @points.first != @points.last
176
+ @points = @points.chunk { |x| x }.map(&:first)
183
177
  end
184
178
  end
185
179
  end
@@ -15,9 +15,7 @@ module RGeo
15
15
  @y = y.to_f
16
16
  @z = factory.property(:has_z_coordinate) ? extra.shift.to_f : nil
17
17
  @m = factory.property(:has_m_coordinate) ? extra.shift.to_f : nil
18
- if extra.size > 0
19
- raise ArgumentError, "Too many arguments for point initializer"
20
- end
18
+ raise ArgumentError, "Too many arguments for point initializer" unless extra.empty?
21
19
  init_geometry
22
20
  end
23
21
 
@@ -12,14 +12,10 @@ module RGeo
12
12
  def initialize(factory, exterior_ring, interior_rings)
13
13
  self.factory = factory
14
14
  @exterior_ring = Feature.cast(exterior_ring, factory, Feature::LinearRing)
15
- unless @exterior_ring
16
- raise Error::InvalidGeometry, "Failed to cast exterior ring #{exterior_ring}"
17
- end
15
+ raise Error::InvalidGeometry, "Failed to cast exterior ring #{exterior_ring}" unless @exterior_ring
18
16
  @interior_rings = (interior_rings || []).map do |elem|
19
17
  elem = Feature.cast(elem, factory, Feature::LinearRing)
20
- unless elem
21
- raise Error::InvalidGeometry, "Could not cast interior ring #{elem}"
22
- end
18
+ raise Error::InvalidGeometry, "Could not cast interior ring #{elem}" unless elem
23
19
  elem
24
20
  end
25
21
  init_geometry
@@ -33,8 +29,8 @@ module RGeo
33
29
  @interior_rings.size
34
30
  end
35
31
 
36
- def interior_ring_n(n)
37
- n < 0 ? nil : @interior_rings[n]
32
+ def interior_ring_n(idx)
33
+ idx < 0 ? nil : @interior_rings[idx]
38
34
  end
39
35
 
40
36
  def interior_rings
@@ -61,11 +57,14 @@ module RGeo
61
57
  end
62
58
 
63
59
  def rep_equals?(rhs)
64
- if rhs.is_a?(self.class) && rhs.factory.eql?(@factory) && @exterior_ring.rep_equals?(rhs.exterior_ring) && @interior_rings.size == rhs.num_interior_rings
65
- rhs.interior_rings.each_with_index { |r, i| return false unless @interior_rings[i].rep_equals?(r) }
66
- else
67
- false
68
- end
60
+ proper_match = rhs.is_a?(self.class) &&
61
+ rhs.factory.eql?(@factory) &&
62
+ @exterior_ring.rep_equals?(rhs.exterior_ring) &&
63
+ @interior_rings.size == rhs.num_interior_rings
64
+
65
+ return false unless proper_match
66
+
67
+ rhs.interior_rings.each_with_index { |r, i| return false unless @interior_rings[i].rep_equals?(r) }
69
68
  end
70
69
 
71
70
  def hash
@@ -80,7 +79,8 @@ module RGeo
80
79
  if Feature::Point === rhs
81
80
  contains_point?(rhs)
82
81
  else
83
- raise(Error::UnsupportedOperation,
82
+ raise(
83
+ Error::UnsupportedOperation,
84
84
  "Method Polygon#contains? is only defined for Point"
85
85
  )
86
86
  end
@@ -90,7 +90,7 @@ module RGeo
90
90
 
91
91
  def contains_point?(point)
92
92
  ring_encloses_point?(@exterior_ring, point) &&
93
- !@interior_rings.any? do |exclusion|
93
+ @interior_rings.none? do |exclusion|
94
94
  ring_encloses_point?(exclusion, point, on_border_return: true)
95
95
  end
96
96
  end
@@ -114,7 +114,6 @@ module RGeo
114
114
  encloses_point
115
115
  end
116
116
 
117
-
118
117
  def copy_state_from(obj)
119
118
  super
120
119
  @exterior_ring = obj.exterior_ring
@@ -18,20 +18,14 @@ module RGeo
18
18
  # multiple times with different values and others pass the data
19
19
  # to a CAPI or FFI.
20
20
  def self.setup_coord_sys(srid, coord_sys, coord_sys_class)
21
- unless coord_sys_class.is_a?(Class)
22
- coord_sys_class = CoordSys::CONFIG.default_coord_sys_class
23
- end
21
+ coord_sys_class = CoordSys::CONFIG.default_coord_sys_class unless coord_sys_class.is_a?(Class)
24
22
 
25
- if coord_sys.is_a?(String)
26
- coord_sys = coord_sys_class.create_from_wkt(coord_sys)
27
- end
23
+ coord_sys = coord_sys_class.create_from_wkt(coord_sys) if coord_sys.is_a?(String)
28
24
 
29
25
  srid ||= coord_sys.authority_code if coord_sys
30
26
  srid = srid.to_i
31
27
  # Create a coord sys based on the SRID if one was not given
32
- if coord_sys.nil? && srid != 0
33
- coord_sys = coord_sys_class.create(srid)
34
- end
28
+ coord_sys = coord_sys_class.create(srid) if coord_sys.nil? && srid != 0
35
29
 
36
30
  { coord_sys: coord_sys, srid: srid }
37
31
  end
@@ -181,12 +181,12 @@ module RGeo
181
181
 
182
182
  # Checks that the given point has valid coordinates.
183
183
  #
184
- # @param pt [RGeo::Feature::Point]
184
+ # @param point [RGeo::Feature::Point]
185
185
  #
186
186
  # @return [String] invalid_reason
187
- def check_invalid_coordinate(pt)
188
- x = pt.x
189
- y = pt.y
187
+ def check_invalid_coordinate(point)
188
+ x = point.x
189
+ y = point.y
190
190
  return if x.finite? && y.finite? && x.real? && y.real?
191
191
 
192
192
  Error::INVALID_COORDINATE
@@ -265,9 +265,7 @@ module RGeo
265
265
 
266
266
  poly.interior_rings.each do |interior|
267
267
  test_pt = interior.start_point
268
- unless shell.contains?(test_pt) || poly.exterior_ring.contains?(test_pt)
269
- return Error::HOLE_OUTSIDE_SHELL
270
- end
268
+ return Error::HOLE_OUTSIDE_SHELL unless shell.contains?(test_pt) || poly.exterior_ring.contains?(test_pt)
271
269
  end
272
270
 
273
271
  nil
@@ -322,27 +320,25 @@ module RGeo
322
320
 
323
321
  # Checks that polygons do not intersect in a multipolygon.
324
322
  #
325
- # @param mp [RGeo::Feature::MultiPolygon]
323
+ # @param mpoly [RGeo::Feature::MultiPolygon]
326
324
  #
327
325
  # @return [String] invalid_reason
328
- def check_consistent_area_mp(mp)
329
- mp.geometries.combination(2) do |p1, p2|
330
- if p1.exterior_ring.crosses?(p2.exterior_ring)
331
- return Error::SELF_INTERSECTION
332
- end
326
+ def check_consistent_area_mp(mpoly)
327
+ mpoly.geometries.combination(2) do |p1, p2|
328
+ return Error::SELF_INTERSECTION if p1.exterior_ring.crosses?(p2.exterior_ring)
333
329
  end
334
330
  nil
335
331
  end
336
332
 
337
333
  # Checks that individual polygons within a multipolygon are not nested.
338
334
  #
339
- # @param mp [RGeo::Feature::MultiPolygon]
335
+ # @param mpoly [RGeo::Feature::MultiPolygon]
340
336
  #
341
337
  # @return [String] invalid_reason
342
- def check_shells_not_nested(mp)
338
+ def check_shells_not_nested(mpoly)
343
339
  # Since we've passed the consistent area test, we can just check
344
340
  # that one point lies in the other.
345
- mp.geometries.combination(2) do |p1, p2|
341
+ mpoly.geometries.combination(2) do |p1, p2|
346
342
  if p1.contains?(p2.exterior_ring.start_point) || p2.contains?(p1.exterior_ring.start_point)
347
343
  return Error::NESTED_SHELLS
348
344
  end
data/lib/rgeo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RGeo
4
- VERSION = "3.0.0-rc.3"
4
+ VERSION = "3.0.0"
5
5
  end
@@ -39,7 +39,6 @@ module RGeo
39
39
  # [<tt>:little_endian</tt>]
40
40
  # If true, output little endian (NDR) byte order. If false, output
41
41
  # big endian (XDR), or network byte order. Default is false.
42
-
43
42
  class WKBGenerator
44
43
  # :stopdoc:
45
44
  TYPE_CODES = {
@@ -107,7 +106,7 @@ module RGeo
107
106
  has_m = false
108
107
  end
109
108
  result = Result.new(has_z, has_m)
110
- generate_feature(obj, result, true)
109
+ generate_feature(obj, result, toplevel: true)
111
110
  result.emit(@hex_format)
112
111
  end
113
112
 
@@ -126,7 +125,7 @@ module RGeo
126
125
 
127
126
  def emit(hex_format)
128
127
  str = @buffer.join
129
- hex_format ? str.unpack("H*")[0] : str
128
+ hex_format ? str.unpack1("H*") : str
130
129
  end
131
130
 
132
131
  def z?
@@ -139,79 +138,75 @@ module RGeo
139
138
  end
140
139
  private_constant :Result
141
140
 
142
- def emit_byte(value, rv)
143
- rv << [value].pack("C")
141
+ def emit_byte(value, rval)
142
+ rval << [value].pack("C")
144
143
  end
145
144
 
146
- def emit_integer(value, rv)
147
- rv << [value].pack(@little_endian ? "V" : "N")
145
+ def emit_integer(value, rval)
146
+ rval << [value].pack(@little_endian ? "V" : "N")
148
147
  end
149
148
 
150
- def emit_doubles(array, rv)
151
- rv << array.pack(@little_endian ? "E*" : "G*")
149
+ def emit_doubles(array, rval)
150
+ rval << array.pack(@little_endian ? "E*" : "G*")
152
151
  end
153
152
 
154
- def emit_line_string_coords(obj, rv)
153
+ def emit_line_string_coords(obj, rval)
155
154
  array = []
156
- obj.points.each { |pt| point_coords(pt, rv, array) }
157
- emit_integer(obj.num_points, rv)
158
- emit_doubles(array, rv)
155
+ obj.points.each { |pt| point_coords(pt, rval, array) }
156
+ emit_integer(obj.num_points, rval)
157
+ emit_doubles(array, rval)
159
158
  end
160
159
 
161
- def point_coords(obj, rv, array = [])
160
+ def point_coords(obj, rval, array = [])
162
161
  array << obj.x
163
162
  array << obj.y
164
- array << obj.z if rv.z?
165
- array << obj.m if rv.m?
163
+ array << obj.z if rval.z?
164
+ array << obj.m if rval.m?
166
165
  array
167
166
  end
168
167
 
169
- def generate_feature(obj, rv, toplevel = false)
170
- emit_byte(@little_endian ? 1 : 0, rv)
168
+ def generate_feature(obj, rval, toplevel: false)
169
+ emit_byte(@little_endian ? 1 : 0, rval)
171
170
  type = obj.geometry_type
172
171
  type_code = TYPE_CODES[type]
173
- unless type_code
174
- raise Error::ParseError, "Unrecognized Geometry Type: #{type}"
175
- end
172
+ raise Error::ParseError, "Unrecognized Geometry Type: #{type}" unless type_code
176
173
  emit_srid = false
177
- if @type_format == :ewkb
178
- type_code |= 0x80000000 if rv.z?
179
- type_code |= 0x40000000 if rv.m?
174
+ case @type_format
175
+ when :ewkb
176
+ type_code |= 0x80000000 if rval.z?
177
+ type_code |= 0x40000000 if rval.m?
180
178
  if @emit_ewkb_srid && toplevel
181
179
  type_code |= 0x20000000
182
180
  emit_srid = true
183
181
  end
184
- elsif @type_format == :wkb12
185
- type_code += 1000 if rv.z?
186
- type_code += 2000 if rv.m?
182
+ when :wkb12
183
+ type_code += 1000 if rval.z?
184
+ type_code += 2000 if rval.m?
187
185
  end
188
- emit_integer(type_code, rv)
189
- emit_integer(obj.srid, rv) if emit_srid
186
+ emit_integer(type_code, rval)
187
+ emit_integer(obj.srid, rval) if emit_srid
188
+ type_is_collection = [
189
+ Feature::GeometryCollection,
190
+ Feature::MultiPoint,
191
+ Feature::MultiLineString,
192
+ Feature::MultiPolygon
193
+ ].include?(type)
190
194
  if type == Feature::Point
191
- emit_doubles(point_coords(obj, rv), rv)
195
+ emit_doubles(point_coords(obj, rval), rval)
192
196
  elsif type.subtype_of?(Feature::LineString)
193
- emit_line_string_coords(obj, rv)
197
+ emit_line_string_coords(obj, rval)
194
198
  elsif type == Feature::Polygon
195
199
  exterior_ring = obj.exterior_ring
196
200
  if exterior_ring.empty?
197
- emit_integer(0, rv)
201
+ emit_integer(0, rval)
198
202
  else
199
- emit_integer(1 + obj.num_interior_rings, rv)
200
- emit_line_string_coords(exterior_ring, rv)
201
- obj.interior_rings.each { |r| emit_line_string_coords(r, rv) }
203
+ emit_integer(1 + obj.num_interior_rings, rval)
204
+ emit_line_string_coords(exterior_ring, rval)
205
+ obj.interior_rings.each { |r| emit_line_string_coords(r, rval) }
202
206
  end
203
- elsif type == Feature::GeometryCollection
204
- emit_integer(obj.num_geometries, rv)
205
- obj.each { |g| generate_feature(g, rv) }
206
- elsif type == Feature::MultiPoint
207
- emit_integer(obj.num_geometries, rv)
208
- obj.each { |g| generate_feature(g, rv) }
209
- elsif type == Feature::MultiLineString
210
- emit_integer(obj.num_geometries, rv)
211
- obj.each { |g| generate_feature(g, rv) }
212
- elsif type == Feature::MultiPolygon
213
- emit_integer(obj.num_geometries, rv)
214
- obj.each { |g| generate_feature(g, rv) }
207
+ elsif type_is_collection
208
+ emit_integer(obj.num_geometries, rval)
209
+ obj.each { |g| generate_feature(g, rval) }
215
210
  end
216
211
  end
217
212
  end
@@ -42,7 +42,6 @@ module RGeo
42
42
  # [<tt>:default_srid</tt>]
43
43
  # A SRID to pass to the factory generator if no SRID is present in
44
44
  # the input. Defaults to nil (i.e. don't specify a SRID).
45
-
46
45
  class WKBParser
47
46
  # Create and configure a WKB parser. See the WKBParser
48
47
  # documentation for the options that can be passed.
@@ -118,9 +117,7 @@ module RGeo
118
117
  obj = parse_object(false)
119
118
  unless @ignore_extra_bytes
120
119
  bytes = bytes_remaining
121
- if bytes > 0
122
- raise Error::ParseError, "Found #{bytes} extra bytes at the end of the stream."
123
- end
120
+ raise Error::ParseError, "Found #{bytes} extra bytes at the end of the stream." if bytes > 0
124
121
  end
125
122
  ensure
126
123
  @data = nil
@@ -133,7 +130,7 @@ module RGeo
133
130
  private
134
131
 
135
132
  def parse_object(contained)
136
- endian_value = get_byte
133
+ endian_value = byte
137
134
  case endian_value
138
135
  when 0
139
136
  little_endian = false
@@ -161,14 +158,20 @@ module RGeo
161
158
  if contained != true && contained != type_code
162
159
  raise Error::ParseError, "Enclosed type=#{type_code} is different from container constraint #{contained}"
163
160
  end
161
+
164
162
  if has_z != @cur_has_z
165
163
  raise Error::ParseError, "Enclosed hasZ=#{has_z} is different from toplevel hasZ=#{@cur_has_z}"
166
164
  end
165
+
167
166
  if has_m != @cur_has_m
168
167
  raise Error::ParseError, "Enclosed hasM=#{has_m} is different from toplevel hasM=#{@cur_has_m}"
169
168
  end
169
+
170
170
  if srid && srid != @cur_srid
171
- raise Error::ParseError, "Enclosed SRID #{srid} is different from toplevel srid #{@cur_srid || '(unspecified)'}"
171
+ raise(
172
+ Error::ParseError,
173
+ "Enclosed SRID #{srid} is different from toplevel srid #{@cur_srid || '(unspecified)'}"
174
+ )
172
175
  end
173
176
  else
174
177
  @cur_has_z = has_z
@@ -176,9 +179,11 @@ module RGeo
176
179
  @cur_dims = 2 + (@cur_has_z ? 1 : 0) + (@cur_has_m ? 1 : 0)
177
180
  @cur_srid = srid
178
181
  @cur_factory = @factory_generator.call(srid: @cur_srid, has_z_coordinate: has_z, has_m_coordinate: has_m)
182
+
179
183
  if @cur_has_z && !@cur_factory.property(:has_z_coordinate)
180
184
  raise Error::ParseError, "Data has Z coordinates but the factory doesn't have Z coordinates"
181
185
  end
186
+
182
187
  if @cur_has_m && !@cur_factory.property(:has_m_coordinate)
183
188
  raise Error::ParseError, "Data has M coordinates but the factory doesn't have M coordinates"
184
189
  end
@@ -222,29 +227,23 @@ module RGeo
222
227
  @len - @pos
223
228
  end
224
229
 
225
- def get_byte
226
- if @pos + 1 > @len
227
- raise Error::ParseError, "Not enough bytes left to fulfill 1 byte"
228
- end
230
+ def byte
231
+ raise Error::ParseError, "Not enough bytes left to fulfill 1 byte" if @pos + 1 > @len
229
232
  str = @data[@pos, 1]
230
233
  @pos += 1
231
- str.unpack("C").first
234
+ str.unpack1("C")
232
235
  end
233
236
 
234
237
  def get_integer(little_endian)
235
- if @pos + 4 > @len
236
- raise Error::ParseError, "Not enough bytes left to fulfill 1 integer"
237
- end
238
+ raise Error::ParseError, "Not enough bytes left to fulfill 1 integer" if @pos + 4 > @len
238
239
  str = @data[@pos, 4]
239
240
  @pos += 4
240
- str.unpack(little_endian ? "V" : "N").first
241
+ str.unpack1(little_endian ? "V" : "N")
241
242
  end
242
243
 
243
244
  def get_doubles(little_endian, count)
244
245
  len = 8 * count
245
- if @pos + len > @len
246
- raise Error::ParseError, "Not enough bytes left to fulfill #{count} doubles"
247
- end
246
+ raise Error::ParseError, "Not enough bytes left to fulfill #{count} doubles" if @pos + len > @len
248
247
  str = @data[@pos, len]
249
248
  @pos += len
250
249
  str.unpack("#{little_endian ? 'E' : 'G'}*")
@@ -45,15 +45,16 @@ module RGeo
45
45
  # letters to lower case; or nil, indicating no case changes from
46
46
  # the default (which is not specified exactly, but is chosen by the
47
47
  # generator to emphasize readability.) Default is nil.
48
-
49
48
  class WKTGenerator
50
49
  # Create and configure a WKT generator. See the WKTGenerator
51
50
  # documentation for the options that can be passed.
52
51
 
53
52
  def initialize(opts = {})
54
53
  @tag_format = opts[:tag_format] || opts[:type_format] || :wkt11
55
- @emit_ewkt_srid = @tag_format == :ewkt ?
56
- (opts[:emit_ewkt_srid] ? true : false) : nil
54
+ @emit_ewkt_srid =
55
+ if @tag_format == :ewkt
56
+ (opts[:emit_ewkt_srid] ? true : false)
57
+ end
57
58
  @square_brackets = opts[:square_brackets] ? true : false
58
59
  @convert_case = opts[:convert_case]
59
60
  end
@@ -99,10 +100,11 @@ module RGeo
99
100
  support_z = factory.property(:has_z_coordinate)
100
101
  support_m = factory.property(:has_m_coordinate)
101
102
  end
102
- str = generate_feature(obj, support_z, support_m, true)
103
- if @convert_case == :upper
103
+ str = generate_feature(obj, support_z, support_m, toplevel: true)
104
+ case @convert_case
105
+ when :upper
104
106
  str.upcase
105
- elsif @convert_case == :lower
107
+ when :lower
106
108
  str.downcase
107
109
  else
108
110
  str
@@ -111,20 +113,22 @@ module RGeo
111
113
 
112
114
  private
113
115
 
114
- def generate_feature(obj, support_z, support_m, toplevel = false)
116
+ def generate_feature(obj, support_z, support_m, toplevel: false)
115
117
  type = obj.geometry_type
116
118
  type = Feature::LineString if type.subtype_of?(Feature::LineString)
117
119
  tag = type.type_name.dup
118
- if @tag_format == :ewkt
120
+ case @tag_format
121
+ when :ewkt
119
122
  tag << "M" if support_m && !support_z
120
123
  tag = "SRID=#{obj.srid};#{tag}" if toplevel && @emit_ewkt_srid
121
- elsif @tag_format == :wkt12
124
+ when :wkt12
122
125
  if support_z
123
- if support_m
124
- tag << " ZM"
125
- else
126
- tag << " Z"
127
- end
126
+ tag <<
127
+ if support_m
128
+ " ZM"
129
+ else
130
+ " Z"
131
+ end
128
132
  elsif support_m
129
133
  tag << " M"
130
134
  end
@@ -163,7 +167,8 @@ module RGeo
163
167
  if obj.empty?
164
168
  "EMPTY"
165
169
  else
166
- "#{@begin_bracket}#{obj.points.map { |p| generate_coords(p, support_z, support_m) }.join(', ')}#{@end_bracket}"
170
+ points = obj.points.map { |p| generate_coords(p, support_z, support_m) }
171
+ "#{@begin_bracket}#{points.join(', ')}#{@end_bracket}"
167
172
  end
168
173
  end
169
174
 
@@ -171,7 +176,9 @@ module RGeo
171
176
  if obj.empty?
172
177
  "EMPTY"
173
178
  else
174
- "#{@begin_bracket}#{([generate_line_string(obj.exterior_ring, support_z, support_m)] + obj.interior_rings.map { |r| generate_line_string(r, support_z, support_m) }).join(', ')}#{@end_bracket}"
179
+ lines = [generate_line_string(obj.exterior_ring, support_z, support_m)]
180
+ lines += obj.interior_rings.map { |r| generate_line_string(r, support_z, support_m) }
181
+ "#{@begin_bracket}#{lines.join(', ')}#{@end_bracket}"
175
182
  end
176
183
  end
177
184