rgeo 2.3.1 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -0
  3. data/README.md +23 -14
  4. data/ext/geos_c_impl/analysis.c +30 -25
  5. data/ext/geos_c_impl/analysis.h +8 -7
  6. data/ext/geos_c_impl/coordinates.c +27 -21
  7. data/ext/geos_c_impl/coordinates.h +5 -2
  8. data/ext/geos_c_impl/errors.c +19 -10
  9. data/ext/geos_c_impl/errors.h +11 -4
  10. data/ext/geos_c_impl/extconf.rb +42 -28
  11. data/ext/geos_c_impl/factory.c +540 -451
  12. data/ext/geos_c_impl/factory.h +105 -95
  13. data/ext/geos_c_impl/geometry.c +593 -387
  14. data/ext/geos_c_impl/geometry.h +10 -5
  15. data/ext/geos_c_impl/geometry_collection.c +306 -339
  16. data/ext/geos_c_impl/geometry_collection.h +6 -20
  17. data/ext/geos_c_impl/globals.c +169 -0
  18. data/ext/geos_c_impl/globals.h +46 -0
  19. data/ext/geos_c_impl/line_string.c +271 -231
  20. data/ext/geos_c_impl/line_string.h +5 -8
  21. data/ext/geos_c_impl/main.c +16 -16
  22. data/ext/geos_c_impl/point.c +65 -67
  23. data/ext/geos_c_impl/point.h +4 -7
  24. data/ext/geos_c_impl/polygon.c +137 -135
  25. data/ext/geos_c_impl/polygon.h +11 -11
  26. data/ext/geos_c_impl/preface.h +16 -10
  27. data/ext/geos_c_impl/ruby_more.c +67 -0
  28. data/ext/geos_c_impl/ruby_more.h +25 -0
  29. data/lib/rgeo/cartesian/analysis.rb +5 -3
  30. data/lib/rgeo/cartesian/bounding_box.rb +74 -79
  31. data/lib/rgeo/cartesian/calculations.rb +64 -33
  32. data/lib/rgeo/cartesian/factory.rb +57 -102
  33. data/lib/rgeo/cartesian/feature_classes.rb +68 -46
  34. data/lib/rgeo/cartesian/feature_methods.rb +67 -25
  35. data/lib/rgeo/cartesian/interface.rb +6 -41
  36. data/lib/rgeo/cartesian/planar_graph.rb +373 -0
  37. data/lib/rgeo/cartesian/sweepline_intersector.rb +147 -0
  38. data/lib/rgeo/cartesian/valid_op.rb +69 -0
  39. data/lib/rgeo/cartesian.rb +3 -0
  40. data/lib/rgeo/coord_sys/cs/entities.rb +303 -99
  41. data/lib/rgeo/coord_sys/cs/factories.rb +0 -2
  42. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +90 -42
  43. data/lib/rgeo/coord_sys.rb +1 -20
  44. data/lib/rgeo/error.rb +15 -0
  45. data/lib/rgeo/feature/curve.rb +0 -11
  46. data/lib/rgeo/feature/factory.rb +26 -36
  47. data/lib/rgeo/feature/factory_generator.rb +6 -14
  48. data/lib/rgeo/feature/geometry.rb +146 -66
  49. data/lib/rgeo/feature/geometry_collection.rb +16 -9
  50. data/lib/rgeo/feature/line_string.rb +4 -5
  51. data/lib/rgeo/feature/linear_ring.rb +0 -1
  52. data/lib/rgeo/feature/multi_curve.rb +0 -6
  53. data/lib/rgeo/feature/multi_surface.rb +3 -4
  54. data/lib/rgeo/feature/point.rb +4 -5
  55. data/lib/rgeo/feature/polygon.rb +1 -2
  56. data/lib/rgeo/feature/surface.rb +3 -4
  57. data/lib/rgeo/feature/types.rb +69 -85
  58. data/lib/rgeo/geographic/factory.rb +98 -125
  59. data/lib/rgeo/geographic/interface.rb +69 -166
  60. data/lib/rgeo/geographic/projected_feature_classes.rb +21 -9
  61. data/lib/rgeo/geographic/projected_feature_methods.rb +67 -42
  62. data/lib/rgeo/geographic/projected_window.rb +36 -22
  63. data/lib/rgeo/geographic/{proj4_projector.rb → projector.rb} +3 -5
  64. data/lib/rgeo/geographic/simple_mercator_projector.rb +26 -25
  65. data/lib/rgeo/geographic/spherical_feature_classes.rb +29 -9
  66. data/lib/rgeo/geographic/spherical_feature_methods.rb +86 -9
  67. data/lib/rgeo/geographic/spherical_math.rb +17 -20
  68. data/lib/rgeo/geographic.rb +1 -1
  69. data/lib/rgeo/geos/capi_factory.rb +87 -158
  70. data/lib/rgeo/geos/capi_feature_classes.rb +50 -36
  71. data/lib/rgeo/geos/ffi_factory.rb +105 -173
  72. data/lib/rgeo/geos/ffi_feature_classes.rb +34 -10
  73. data/lib/rgeo/geos/ffi_feature_methods.rb +105 -127
  74. data/lib/rgeo/geos/interface.rb +20 -59
  75. data/lib/rgeo/geos/utils.rb +5 -5
  76. data/lib/rgeo/geos/zm_factory.rb +53 -95
  77. data/lib/rgeo/geos/zm_feature_methods.rb +30 -33
  78. data/lib/rgeo/geos.rb +8 -8
  79. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +9 -22
  80. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -2
  81. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +28 -56
  82. data/lib/rgeo/impl_helper/basic_point_methods.rb +2 -14
  83. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +17 -26
  84. data/lib/rgeo/impl_helper/utils.rb +21 -0
  85. data/lib/rgeo/impl_helper/valid_op.rb +350 -0
  86. data/lib/rgeo/impl_helper/validity_check.rb +139 -0
  87. data/lib/rgeo/impl_helper.rb +1 -0
  88. data/lib/rgeo/version.rb +1 -1
  89. data/lib/rgeo/wkrep/wkb_generator.rb +73 -63
  90. data/lib/rgeo/wkrep/wkb_parser.rb +33 -31
  91. data/lib/rgeo/wkrep/wkt_generator.rb +52 -45
  92. data/lib/rgeo/wkrep/wkt_parser.rb +48 -35
  93. data/lib/rgeo.rb +1 -3
  94. metadata +50 -13
  95. data/lib/rgeo/coord_sys/srs_database/entry.rb +0 -107
  96. data/lib/rgeo/coord_sys/srs_database/sr_org.rb +0 -64
  97. data/lib/rgeo/coord_sys/srs_database/url_reader.rb +0 -65
@@ -6,19 +6,30 @@
6
6
  #
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ require_relative "../impl_helper/validity_check"
10
+
9
11
  module RGeo
10
12
  module Geos
11
- module CAPIGeometryMethods # :nodoc:
13
+ module CAPIGeometryMethods
12
14
  include Feature::Instance
13
15
 
14
- def is_empty? # rubocop:disable Naming/PredicateName
15
- warn "The is_empty? method is deprecated, please use the empty? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
16
- empty?
16
+ def coordinate_dimension
17
+ dim = 2
18
+ dim += 1 if factory.supports_z?
19
+ dim += 1 if factory.supports_m?
20
+ dim
21
+ end
22
+
23
+ def spatial_dimension
24
+ factory.supports_z? ? 3 : 2
17
25
  end
18
26
 
19
- def is_simple? # rubocop:disable Naming/PredicateName
20
- warn "The is_simple? method is deprecated, please use the simple? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
21
- simple?
27
+ def is_3d?
28
+ factory.supports_z?
29
+ end
30
+
31
+ def measured?
32
+ factory.supports_m?
22
33
  end
23
34
 
24
35
  def inspect
@@ -60,44 +71,33 @@ module RGeo
60
71
  alias to_s as_text
61
72
  end
62
73
 
63
- module CAPIMultiLineStringMethods # :nodoc:
64
- def is_closed? # rubocop:disable Naming/PredicateName
65
- warn "The is_closed? method is deprecated, please use the closed? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
66
- closed?
67
- end
68
- end
69
-
70
- module CAPILineStringMethods # :nodoc:
71
- def is_closed? # rubocop:disable Naming/PredicateName
72
- warn "The is_closed? method is deprecated, please use the closed? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
73
- closed?
74
- end
75
-
76
- def is_ring? # rubocop:disable Naming/PredicateName
77
- warn "The is_ring? method is deprecated, please use the ring? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
78
- ring?
79
- end
80
- end
81
-
82
74
  module CAPIGeometryCollectionMethods # :nodoc:
83
75
  include Enumerable
84
76
  end
85
77
 
86
- class CAPIGeometryImpl # :nodoc:
78
+ class CAPIGeometryImpl
79
+ include Feature::Geometry
80
+ include ImplHelper::ValidityCheck
87
81
  include CAPIGeometryMethods
88
82
  end
89
83
 
90
- class CAPIPointImpl # :nodoc:
84
+ class CAPIPointImpl
85
+ include Feature::Point
86
+ include ImplHelper::ValidityCheck
91
87
  include CAPIGeometryMethods
92
88
  include CAPIPointMethods
93
89
  end
94
90
 
95
- class CAPILineStringImpl # :nodoc:
91
+ class CAPILineStringImpl
92
+ include Feature::LineString
93
+ include ImplHelper::ValidityCheck
96
94
  include CAPIGeometryMethods
97
95
  include CAPILineStringMethods
98
96
  end
99
97
 
100
- class CAPILinearRingImpl # :nodoc:
98
+ class CAPILinearRingImpl
99
+ include Feature::LinearRing
100
+ include ImplHelper::ValidityCheck
101
101
  include CAPIGeometryMethods
102
102
  include CAPILineStringMethods
103
103
  include CAPILinearRingMethods
@@ -107,38 +107,52 @@ module RGeo
107
107
  end
108
108
  end
109
109
 
110
- class CAPILineImpl # :nodoc:
110
+ class CAPILineImpl
111
+ include Feature::Line
112
+ include ImplHelper::ValidityCheck
111
113
  include CAPIGeometryMethods
112
114
  include CAPILineStringMethods
113
115
  include CAPILineMethods
114
116
  end
115
117
 
116
- class CAPIPolygonImpl # :nodoc:
118
+ class CAPIPolygonImpl
119
+ include Feature::Polygon
120
+ include ImplHelper::ValidityCheck
117
121
  include CAPIGeometryMethods
118
122
  include CAPIPolygonMethods
119
123
  end
120
124
 
121
- class CAPIGeometryCollectionImpl # :nodoc:
125
+ class CAPIGeometryCollectionImpl
126
+ include Feature::GeometryCollection
127
+ include ImplHelper::ValidityCheck
122
128
  include CAPIGeometryMethods
123
129
  include CAPIGeometryCollectionMethods
124
130
  end
125
131
 
126
- class CAPIMultiPointImpl # :nodoc:
132
+ class CAPIMultiPointImpl
133
+ include Feature::MultiPoint
134
+ include ImplHelper::ValidityCheck
127
135
  include CAPIGeometryMethods
128
136
  include CAPIGeometryCollectionMethods
129
137
  include CAPIMultiPointMethods
130
138
  end
131
139
 
132
- class CAPIMultiLineStringImpl # :nodoc:
140
+ class CAPIMultiLineStringImpl
141
+ include Feature::MultiLineString
142
+ include ImplHelper::ValidityCheck
133
143
  include CAPIGeometryMethods
134
144
  include CAPIGeometryCollectionMethods
135
145
  include CAPIMultiLineStringMethods
136
146
  end
137
147
 
138
- class CAPIMultiPolygonImpl # :nodoc:
148
+ class CAPIMultiPolygonImpl
149
+ include Feature::MultiPolygon
150
+ include ImplHelper::ValidityCheck
139
151
  include CAPIGeometryMethods
140
152
  include CAPIGeometryCollectionMethods
141
153
  include CAPIMultiPolygonMethods
142
154
  end
155
+
156
+ ImplHelper::ValidityCheck.override_classes
143
157
  end
144
158
  end
@@ -9,104 +9,91 @@
9
9
  module RGeo
10
10
  module Geos
11
11
  # This the FFI-GEOS implementation of RGeo::Feature::Factory.
12
-
13
12
  class FFIFactory
14
13
  include Feature::Factory::Instance
15
14
  include ImplHelper::Utils
16
15
 
16
+ attr_reader :coordinate_dimension, :spatial_dimension, :_has_3d, :_auto_prepare
17
+
18
+ # Returns the SRID of geometries created by this factory.
19
+ attr_reader :srid
20
+
21
+ # Returns the resolution used by buffer calculations on geometries
22
+ # created by this factory
23
+ attr_reader :buffer_resolution
24
+
25
+ # See RGeo::Feature::Factory#coord_sys
26
+ attr_reader :coord_sys
27
+
17
28
  # Create a new factory. Returns nil if the FFI-GEOS implementation
18
29
  # is not supported.
19
30
  #
20
31
  # See RGeo::Geos.factory for a list of supported options.
21
32
 
22
33
  def initialize(opts = {})
23
- # Main flags
24
- @uses_lenient_multi_polygon_assertions = opts[:uses_lenient_assertions] ||
25
- opts[:lenient_multi_polygon_assertions] || opts[:uses_lenient_multi_polygon_assertions]
26
34
  @has_z = opts[:has_z_coordinate] ? true : false
27
35
  @has_m = opts[:has_m_coordinate] ? true : false
36
+
28
37
  if @has_z && @has_m
29
38
  raise Error::UnsupportedOperation, "GEOS cannot support both Z and M coordinates at the same time."
30
39
  end
40
+
41
+ @coordinate_dimension = 2
42
+ @coordinate_dimension += 1 if @has_z
43
+ @coordinate_dimension += 1 if @has_m
44
+ @spatial_dimension = @has_z ? 3 : 2
45
+
31
46
  @_has_3d = @has_z || @has_m
32
47
  @buffer_resolution = opts[:buffer_resolution].to_i
33
48
  @buffer_resolution = 1 if @buffer_resolution < 1
34
- @_auto_prepare = opts[:auto_prepare] == :disabled ? false : true
49
+ @_auto_prepare = opts[:auto_prepare] != :disabled
35
50
 
36
51
  # Interpret the generator options
37
- wkt_generator_ = opts[:wkt_generator]
38
- case wkt_generator_
39
- when :geos
40
- @wkt_writer = ::Geos::WktWriter.new
41
- @wkt_generator = nil
52
+ wkt_generator = opts[:wkt_generator]
53
+ case wkt_generator
42
54
  when Hash
43
- @wkt_generator = WKRep::WKTGenerator.new(wkt_generator_)
55
+ @wkt_generator = WKRep::WKTGenerator.new(wkt_generator)
44
56
  @wkt_writer = nil
45
57
  else
46
- @wkt_generator = WKRep::WKTGenerator.new(convert_case: :upper)
47
- @wkt_writer = nil
58
+ @wkt_writer = ::Geos::WktWriter.new
59
+ @wkt_writer.output_dimensions = 2
60
+ @wkt_writer.trim = true
61
+ @wkt_generator = nil
48
62
  end
49
- wkb_generator_ = opts[:wkb_generator]
50
- case wkb_generator_
51
- when :geos
52
- @wkb_writer = ::Geos::WkbWriter.new
53
- @wkb_generator = nil
63
+ wkb_generator = opts[:wkb_generator]
64
+ case wkb_generator
54
65
  when Hash
55
- @wkb_generator = WKRep::WKBGenerator.new(wkb_generator_)
66
+ @wkb_generator = WKRep::WKBGenerator.new(wkb_generator)
56
67
  @wkb_writer = nil
57
68
  else
58
- @wkb_generator = WKRep::WKBGenerator.new
59
- @wkb_writer = nil
69
+ @wkb_writer = ::Geos::WkbWriter.new
70
+ @wkb_writer.output_dimensions = 2
71
+ @wkb_generator = nil
60
72
  end
61
73
 
62
- # Coordinate system (srid, proj4, and coord_sys)
63
- @srid = opts[:srid]
64
- @proj4 = opts[:proj4]
65
- if @proj4 && CoordSys.check!(:proj4)
66
- if @proj4.is_a?(String) || @proj4.is_a?(Hash)
67
- @proj4 = CoordSys::Proj4.create(@proj4)
68
- end
69
- else
70
- @proj4 = nil
71
- end
72
- @coord_sys = opts[:coord_sys]
73
- if @coord_sys.is_a?(String)
74
- @coord_sys = CoordSys::CS.create_from_wkt(@coord_sys)
75
- end
76
- if (!@proj4 || !@coord_sys) && @srid && (db = opts[:srs_database])
77
- entry = db.get(@srid.to_i)
78
- if entry
79
- @proj4 ||= entry.proj4
80
- @coord_sys ||= entry.coord_sys
81
- end
82
- end
83
- @srid ||= @coord_sys.authority_code if @coord_sys
84
- @srid = @srid.to_i
74
+ # Coordinate system (srid and coord_sys)
75
+ coord_sys_info = ImplHelper::Utils.setup_coord_sys(opts[:srid], opts[:coord_sys], opts[:coord_sys_class])
76
+ @srid = coord_sys_info[:srid]
77
+ @coord_sys = coord_sys_info[:coord_sys]
85
78
 
86
79
  # Interpret parser options
87
80
  wkt_parser = opts[:wkt_parser]
88
81
  case wkt_parser
89
- when :geos
90
- @wkt_reader = ::Geos::WktReader.new
91
- @wkt_parser = nil
92
82
  when Hash
93
83
  @wkt_parser = WKRep::WKTParser.new(self, wkt_parser)
94
84
  @wkt_reader = nil
95
85
  else
96
- @wkt_parser = WKRep::WKTParser.new(self)
97
- @wkt_reader = nil
86
+ @wkt_reader = ::Geos::WktReader.new
87
+ @wkt_parser = nil
98
88
  end
99
89
  wkb_parser = opts[:wkb_parser]
100
90
  case wkb_parser
101
- when :geos
102
- @wkb_reader = ::Geos::WkbReader.new
103
- @wkb_parser = nil
104
91
  when Hash
105
92
  @wkb_parser = WKRep::WKBParser.new(self, wkb_parser)
106
93
  @wkb_reader = nil
107
94
  else
108
- @wkb_parser = WKRep::WKBParser.new(self)
109
- @wkb_reader = nil
95
+ @wkb_reader = ::Geos::WkbReader.new
96
+ @wkb_parser = nil
110
97
  end
111
98
  end
112
99
 
@@ -118,19 +105,19 @@ module RGeo
118
105
 
119
106
  # Factory equivalence test.
120
107
 
121
- def eql?(rhs)
122
- rhs.is_a?(self.class) && @srid == rhs.srid &&
123
- @has_z == rhs.property(:has_z_coordinate) &&
124
- @has_m == rhs.property(:has_m_coordinate) &&
125
- @buffer_resolution == rhs.property(:buffer_resolution) &&
126
- @proj4.eql?(rhs.proj4)
108
+ def eql?(other)
109
+ other.is_a?(self.class) && @srid == other.srid &&
110
+ @has_z == other.property(:has_z_coordinate) &&
111
+ @has_m == other.property(:has_m_coordinate) &&
112
+ @buffer_resolution == other.property(:buffer_resolution) &&
113
+ @coord_sys.eql?(other.coord_sys)
127
114
  end
128
115
  alias == eql?
129
116
 
130
117
  # Standard hash code
131
118
 
132
119
  def hash
133
- @hash ||= [@srid, @has_z, @has_m, @buffer_resolution, @proj4].hash
120
+ @hash ||= [@srid, @has_z, @has_m, @buffer_resolution, @coord_sys].hash
134
121
  end
135
122
 
136
123
  # Marshal support
@@ -141,42 +128,30 @@ module RGeo
141
128
  "hasm" => @has_m,
142
129
  "srid" => @srid,
143
130
  "bufr" => @buffer_resolution,
144
- "wktg" => @wkt_generator.properties,
145
- "wkbg" => @wkb_generator.properties,
146
- "wktp" => @wkt_parser.properties,
147
- "wkbp" => @wkb_parser.properties,
148
- "lmpa" => @uses_lenient_multi_polygon_assertions,
131
+ "wktg" => @wkt_generator&.properties,
132
+ "wkbg" => @wkb_generator&.properties,
133
+ "wktp" => @wkt_parser&.properties,
134
+ "wkbp" => @wkb_parser&.properties,
149
135
  "apre" => @_auto_prepare
150
136
  }
151
- hash["proj4"] = @proj4.marshal_dump if @proj4
152
137
  hash["cs"] = @coord_sys.to_wkt if @coord_sys
153
138
  hash
154
139
  end
155
140
 
156
141
  def marshal_load(data) # :nodoc:
157
- if (proj4_data = data["proj4"]) && CoordSys.check!(:proj4)
158
- proj4 = CoordSys::Proj4.allocate
159
- proj4.marshal_load(proj4_data)
160
- else
161
- proj4 = nil
162
- end
163
- if (coord_sys_data = data["cs"])
164
- coord_sys = CoordSys::CS.create_from_wkt(coord_sys_data)
165
- else
166
- coord_sys = nil
167
- end
142
+ cs_class = CoordSys::CONFIG.default_coord_sys_class
143
+ coord_sys = data["cs"]&.then { |cs| cs_class.create_from_wkt(cs) }
144
+
168
145
  initialize(
169
146
  has_z_coordinate: data["hasz"],
170
147
  has_m_coordinate: data["hasm"],
171
148
  srid: data["srid"],
172
149
  buffer_resolution: data["bufr"],
173
- wkt_generator: symbolize_hash(data["wktg"]),
174
- wkb_generator: symbolize_hash(data["wkbg"]),
175
- wkt_parser: symbolize_hash(data["wktp"]),
176
- wkb_parser: symbolize_hash(data["wkbp"]),
177
- uses_lenient_multi_polygon_assertions: data["lmpa"],
150
+ wkt_generator: data["wktg"] && symbolize_hash(data["wktg"]),
151
+ wkb_generator: data["wkbg"] && symbolize_hash(data["wkbg"]),
152
+ wkt_parser: data["wktp"] && symbolize_hash(data["wktp"]),
153
+ wkb_parser: data["wkbp"] && symbolize_hash(data["wkbp"]),
178
154
  auto_prepare: (data["apre"] ? :simple : :disabled),
179
- proj4: proj4,
180
155
  coord_sys: coord_sys
181
156
  )
182
157
  end
@@ -188,68 +163,33 @@ module RGeo
188
163
  coder["has_m_coordinate"] = @has_m
189
164
  coder["srid"] = @srid
190
165
  coder["buffer_resolution"] = @buffer_resolution
191
- coder["lenient_multi_polygon_assertions"] = @uses_lenient_multi_polygon_assertions
192
- coder["wkt_generator"] = @wkt_generator.properties
193
- coder["wkb_generator"] = @wkb_generator.properties
194
- coder["wkt_parser"] = @wkt_parser.properties
195
- coder["wkb_parser"] = @wkb_parser.properties
166
+ coder["wkt_generator"] = @wkt_generator&.properties
167
+ coder["wkb_generator"] = @wkb_generator&.properties
168
+ coder["wkt_parser"] = @wkt_parser&.properties
169
+ coder["wkb_parser"] = @wkb_parser&.properties
196
170
  coder["auto_prepare"] = @_auto_prepare ? "simple" : "disabled"
197
- if @proj4
198
- str = @proj4.original_str || @proj4.canonical_str
199
- coder["proj4"] = @proj4.radians? ? { "proj4" => str, "radians" => true } : str
200
- end
201
171
  coder["coord_sys"] = @coord_sys.to_wkt if @coord_sys
202
172
  end
203
173
 
204
174
  def init_with(coder) # :nodoc:
205
- if (proj4_data = coder["proj4"])
206
- CoordSys.check!(:proj4)
207
- if proj4_data.is_a?(Hash)
208
- proj4 = CoordSys::Proj4.create(proj4_data["proj4"], radians: proj4_data["radians"])
209
- else
210
- proj4 = CoordSys::Proj4.create(proj4_data.to_s)
211
- end
212
- else
213
- proj4 = nil
214
- end
215
- if (coord_sys_data = coder["cs"])
216
- coord_sys = CoordSys::CS.create_from_wkt(coord_sys_data.to_s)
217
- else
218
- coord_sys = nil
219
- end
175
+ cs_class = CoordSys::CONFIG.default_coord_sys_class
176
+ coord_sys = coder["cs"]&.then { |cs| cs_class.create_from_wkt(cs) }
177
+
220
178
  initialize(
221
179
  has_z_coordinate: coder["has_z_coordinate"],
222
180
  has_m_coordinate: coder["has_m_coordinate"],
223
181
  srid: coder["srid"],
224
182
  buffer_resolution: coder["buffer_resolution"],
225
- wkt_generator: symbolize_hash(coder["wkt_generator"]),
226
- wkb_generator: symbolize_hash(coder["wkb_generator"]),
227
- wkt_parser: symbolize_hash(coder["wkt_parser"]),
228
- wkb_parser: symbolize_hash(coder["wkb_parser"]),
183
+ wkt_generator: coder["wkt_generator"] && symbolize_hash(coder["wkt_generator"]),
184
+ wkb_generator: coder["wkb_generator"] && symbolize_hash(coder["wkb_generator"]),
185
+ wkt_parser: coder["wkt_parser"] && symbolize_hash(coder["wkt_parser"]),
186
+ wkb_parser: coder["wkb_parser"] && symbolize_hash(coder["wkb_parser"]),
229
187
  auto_prepare: coder["auto_prepare"] == "disabled" ? :disabled : :simple,
230
- uses_lenient_multi_polygon_assertions: coder["lenient_multi_polygon_assertions"],
231
- proj4: proj4,
232
188
  coord_sys: coord_sys
233
189
  )
234
190
  end
235
191
 
236
- # Returns the SRID of geometries created by this factory.
237
-
238
- attr_reader :srid
239
-
240
- # Returns the resolution used by buffer calculations on geometries
241
- # created by this factory
242
-
243
- attr_reader :buffer_resolution
244
-
245
- # Returns true if this factory is lenient with MultiPolygon assertions
246
-
247
- def lenient_multi_polygon_assertions?
248
- @uses_lenient_multi_polygon_assertions
249
- end
250
-
251
192
  # See RGeo::Feature::Factory#property
252
-
253
193
  def property(name_)
254
194
  case name_
255
195
  when :has_z_coordinate
@@ -260,18 +200,19 @@ module RGeo
260
200
  true
261
201
  when :buffer_resolution
262
202
  @buffer_resolution
263
- when :uses_lenient_multi_polygon_assertions
264
- @uses_lenient_multi_polygon_assertions
265
203
  when :auto_prepare
266
204
  @_auto_prepare ? :simple : :disabled
267
205
  end
268
206
  end
269
207
 
270
208
  # See RGeo::Feature::Factory#parse_wkt
271
-
272
209
  def parse_wkt(str)
273
210
  if @wkt_reader
274
- wrap_fg_geom(@wkt_reader.read(str), nil)
211
+ begin
212
+ wrap_fg_geom(@wkt_reader.read(str), nil)
213
+ rescue ::Geos::WktReader::ParseError => e
214
+ raise RGeo::Error::ParseError, e.message.partition(":").last
215
+ end
275
216
  else
276
217
  @wkt_parser.parse(str)
277
218
  end
@@ -281,7 +222,12 @@ module RGeo
281
222
 
282
223
  def parse_wkb(str)
283
224
  if @wkb_reader
284
- wrap_fg_geom(@wkb_reader.read(str), nil)
225
+ begin
226
+ meth = str[0].match?(/[0-9a-fA-F]/) ? :read_hex : :read
227
+ wrap_fg_geom(@wkb_reader.public_send(meth, str), nil)
228
+ rescue ::Geos::WkbReader::ParseError => e
229
+ raise RGeo::Error::ParseError, e.message.partition(":").last
230
+ end
285
231
  else
286
232
  @wkb_parser.parse(str)
287
233
  end
@@ -351,10 +297,8 @@ module RGeo
351
297
  inner_rings = inner_rings.to_a unless inner_rings.is_a?(Array)
352
298
  return unless RGeo::Feature::LineString.check_type(outer_ring)
353
299
  outer_ring = create_fg_linear_ring(outer_ring.points)
354
- inner_rings = inner_rings.map do |r|
355
- return unless RGeo::Feature::LineString.check_type(r)
356
- create_fg_linear_ring(r.points)
357
- end
300
+ return unless inner_rings.all? { |r| RGeo::Feature::LineString.check_type(r) }
301
+ inner_rings = inner_rings.map { |r| create_fg_linear_ring(r.points) }
358
302
  inner_rings.compact!
359
303
  fg_geom = ::Geos::Utils.create_polygon(outer_ring, *inner_rings)
360
304
  FFIPolygonImpl.new(self, fg_geom, nil)
@@ -383,11 +327,16 @@ module RGeo
383
327
  def multi_point(elems)
384
328
  elems = elems.to_a unless elems.is_a?(Array)
385
329
  elems = elems.map do |elem|
386
- elem = RGeo::Feature.cast(elem, self, RGeo::Feature::Point,
387
- :force_new, :keep_subtype)
388
- return unless elem
389
- elem.detach_fg_geom
390
- end
330
+ RGeo::Feature.cast(
331
+ elem,
332
+ self,
333
+ RGeo::Feature::Point,
334
+ :force_new,
335
+ :keep_subtype
336
+ )
337
+ end
338
+ return unless elems.all?
339
+ elems = elems.map(&:detach_fg_geom)
391
340
  klasses = Array.new(elems.size, FFIPointImpl)
392
341
  fg_geom = ::Geos::Utils.create_collection(::Geos::GeomTypes::GEOS_MULTIPOINT, elems)
393
342
  FFIMultiPointImpl.new(self, fg_geom, klasses)
@@ -417,33 +366,14 @@ module RGeo
417
366
  raise(RGeo::Error::InvalidGeometry, "Could not cast to polygon: #{elem}") unless elem
418
367
  elem.detach_fg_geom
419
368
  end
420
- unless @uses_lenient_multi_polygon_assertions
421
- (1...elems.size).each do |i|
422
- (0...i).each do |j|
423
- igeom = elems[i]
424
- jgeom = elems[j]
425
- if igeom.relate_pattern(jgeom, "2********") || igeom.relate_pattern(jgeom, "****1****")
426
- raise(RGeo::Error::InvalidGeometry, "Invalid relate pattern: #{jgeom}")
427
- end
428
- end
429
- end
430
- end
431
369
  klasses = Array.new(elems.size, FFIPolygonImpl)
432
370
  fg_geom = ::Geos::Utils.create_collection(::Geos::GeomTypes::GEOS_MULTIPOLYGON, elems)
433
371
  FFIMultiPolygonImpl.new(self, fg_geom, klasses)
434
372
  end
435
373
 
436
- # See RGeo::Feature::Factory#proj4
437
-
438
- attr_reader :proj4
439
-
440
- # See RGeo::Feature::Factory#coord_sys
441
-
442
- attr_reader :coord_sys
443
-
444
374
  # See RGeo::Feature::Factory#override_cast
445
375
 
446
- def override_cast(original, ntype, flags)
376
+ def override_cast(_original, _ntype, _flags)
447
377
  false
448
378
  # TODO
449
379
  end
@@ -491,14 +421,13 @@ module RGeo
491
421
  klass.new(self, fg_geom, klasses)
492
422
  end
493
423
 
494
- attr_reader :_has_3d # :nodoc:
495
- attr_reader :_auto_prepare # :nodoc:
496
-
497
424
  def convert_to_fg_geometry(obj, type = nil)
498
- if type && obj.factory != self
499
- obj = Feature.cast(obj, self, type)
500
- end
501
- obj&.fg_geom
425
+ obj = Feature.cast(obj, self, type) if type && obj.factory != self
426
+
427
+ geom = obj&.fg_geom
428
+ raise RGeo::Error::InvalidGeometry, "Unable to cast the geometry to the FFI Factory" if geom.nil?
429
+
430
+ geom
502
431
  end
503
432
 
504
433
  def generate_wkt(geom)
@@ -520,6 +449,7 @@ module RGeo
520
449
  def write_for_marshal(geom)
521
450
  if Utils.ffi_supports_set_output_dimension || !@_has_3d
522
451
  wkb_writer = ::Geos::WkbWriter.new
452
+ wkb_writer.output_dimensions = 2
523
453
  wkb_writer.output_dimensions = 3 if @_has_3d
524
454
  wkb_writer.write(geom.fg_geom)
525
455
  else
@@ -534,6 +464,8 @@ module RGeo
534
464
  def write_for_psych(geom)
535
465
  if Utils.ffi_supports_set_output_dimension || !@_has_3d
536
466
  wkt_writer = ::Geos::WktWriter.new
467
+ wkt_writer.output_dimensions = 2
468
+ wkt_writer.trim = true
537
469
  wkt_writer.output_dimensions = 3 if @_has_3d
538
470
  wkt_writer.write(geom.fg_geom)
539
471
  else
@@ -549,14 +481,14 @@ module RGeo
549
481
 
550
482
  def create_fg_linear_ring(points)
551
483
  size = points.size
552
- return if size == 1 || size == 2
484
+ return if size.between?(1, 2)
553
485
  if size > 0 && points.first != points.last
554
486
  points += [points.first]
555
487
  size += 1
556
488
  end
557
489
  cs = ::Geos::CoordinateSequence.new(size, 3)
490
+ return unless points.all? { |p| RGeo::Feature::Point.check_type(p) }
558
491
  points.each_with_index do |p, i|
559
- return unless RGeo::Feature::Point.check_type(p)
560
492
  cs.set_x(i, p.x)
561
493
  cs.set_y(i, p.y)
562
494
  if @has_z