rgeo 2.3.1 → 3.0.1

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