rgeo-geojson 0.2.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.
@@ -0,0 +1,5 @@
1
+ === 0.2.0 / 2010-12-07
2
+
3
+ * Initial public alpha release. Spun rgeo-geojson off from the core rgeo gem.
4
+
5
+ For earlier history, see the History file for the rgeo gem.
@@ -0,0 +1,104 @@
1
+ == RGeo::GeoJSON
2
+
3
+ RGeo::GeoJSON is an optional module for {RGeo}[http://github.com/dazuma/rgeo]
4
+ that provides GeoJSON encoding and decoding services.
5
+
6
+ === Summary
7
+
8
+ \RGeo is a key component for writing location-aware applications in the
9
+ Ruby programming language. At its core is an implementation of the
10
+ industry standard OGC Simple Features Specification, which provides data
11
+ representations of geometric objects such as points, lines, and polygons,
12
+ along with a set of geometric analysis operations. See the README for the
13
+ "rgeo" gem for more information.
14
+
15
+ RGeo::GeoJSON is an optional \RGeo add-on module that provides GeoJSON
16
+ encoding and decoding services. GeoJSON is an emerging standard format
17
+ used by many web services that need to communicate geospatial data. See
18
+ http://www.geojson.com for more information.
19
+
20
+ Example:
21
+
22
+ require 'rgeo/geo_json'
23
+
24
+ str1 = '{"type":"Point","coordinates":[1,2]}'
25
+ geom = RGeo::GeoJSON.decode(str1, :json_parser => :json)
26
+ geom.as_text # => "POINT(1.0 2.0)"
27
+
28
+ str2 = '{"type":"Feature","geometry":{"type":"Point","coordinates":[2.5,4.0]},"properties":{"color":"red"}}'
29
+ feature = RGeo::GeoJSON.decode(str2, :json_parser => :json)
30
+ feature['color'] # => 'red'
31
+ feature.geometry.as_text # => "POINT(2.5 4.0)"
32
+
33
+ hash = RGeo::GeoJSON.encode(feature)
34
+ hash.to_json == str2 # => true
35
+
36
+ === Installation
37
+
38
+ RGeo::GeoJSON has the following requirements:
39
+
40
+ * Ruby 1.8.7 or later. Ruby 1.9.2 or later preferred.
41
+ * \RGeo 0.2.0 or later.
42
+ * If you are using Ruby 1.8, you should install the "json" gem to support
43
+ parsing JSON strings. Ruby 1.9 has JSON support in its standard library
44
+ and does not require the gem.
45
+
46
+ Install RGeo::GeoJSON as a gem:
47
+
48
+ gem install rgeo
49
+ gem install rgeo-geojson
50
+
51
+ See the README for the "rgeo" gem, a required dependency, for further
52
+ installation information.
53
+
54
+ === To-do list
55
+
56
+ * Add support for the "bbox" and "crs" elements.
57
+
58
+ === Development and support
59
+
60
+ Documentation is available at http://virtuoso.rubyforge.org/rgeo-geojson/README_rdoc.html
61
+
62
+ Source code is hosted on Github at http://github.com/dazuma/rgeo-geojson
63
+
64
+ Contributions are welcome. Fork the project on Github.
65
+
66
+ Report bugs on Github issues at http://github.org/dazuma/rgeo-geojson/issues
67
+
68
+ Contact the author at dazuma at gmail dot com.
69
+
70
+ === Acknowledgments
71
+
72
+ \RGeo is written by Daniel Azuma (http://www.daniel-azuma.com).
73
+
74
+ Development of \RGeo is sponsored by GeoPage, Inc. (http://www.geopage.com).
75
+
76
+ === License
77
+
78
+ Copyright 2010 Daniel Azuma
79
+
80
+ All rights reserved.
81
+
82
+ Redistribution and use in source and binary forms, with or without
83
+ modification, are permitted provided that the following conditions are met:
84
+
85
+ * Redistributions of source code must retain the above copyright notice,
86
+ this list of conditions and the following disclaimer.
87
+ * Redistributions in binary form must reproduce the above copyright notice,
88
+ this list of conditions and the following disclaimer in the documentation
89
+ and/or other materials provided with the distribution.
90
+ * Neither the name of the copyright holder, nor the names of any other
91
+ contributors to this software, may be used to endorse or promote products
92
+ derived from this software without specific prior written permission.
93
+
94
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
95
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
96
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
97
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
98
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
99
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
100
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
101
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
102
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
103
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
104
+ POSSIBILITY OF SUCH DAMAGE.
data/Version ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,62 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # GeoJSON implementation for RGeo
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ # Dependencies
38
+ require 'rgeo'
39
+
40
+
41
+ # RGeo is a spatial data library for Ruby, provided by the "rgeo" gem.
42
+ #
43
+ # The optional RGeo::GeoJSON module provides a set of tools for GeoJSON
44
+ # encoding and decoding.
45
+
46
+ module RGeo
47
+
48
+
49
+ # This is a namespace for a set of tools that provide GeoJSON encoding.
50
+ # See http://geojson.org/ for more information about this specification.
51
+
52
+ module GeoJSON
53
+ end
54
+
55
+
56
+ end
57
+
58
+
59
+ # Implementation files
60
+ require 'rgeo/geo_json/entities'
61
+ require 'rgeo/geo_json/coder'
62
+ require 'rgeo/geo_json/interface'
@@ -0,0 +1,401 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # GeoJSON encoder object
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module RGeo
38
+
39
+ module GeoJSON
40
+
41
+
42
+ # This object encapsulates encoding and decoding settings (principally
43
+ # the RGeo::Feature::Factory and the RGeo::GeoJSON::EntityFactory to
44
+ # be used) so that you can encode and decode without specifying those
45
+ # settings every time.
46
+
47
+ class Coder
48
+
49
+
50
+ @@json_available = nil
51
+ @@yajl_available = nil
52
+ @@activesupport_available = nil
53
+
54
+
55
+ # Create a new coder settings object. The geo factory is passed as
56
+ # a required argument.
57
+ #
58
+ # Options include:
59
+ #
60
+ # <tt>:geo_factory</tt>::
61
+ # Specifies the geo factory to use to create geometry objects.
62
+ # Defaults to the preferred cartesian factory.
63
+ # <tt>:entity_factory</tt>::
64
+ # Specifies an entity factory, which lets you override the types
65
+ # of GeoJSON entities that are created. It defaults to the default
66
+ # RGeo::GeoJSON::EntityFactory, which generates objects of type
67
+ # RGeo::GeoJSON::Feature or RGeo::GeoJSON::FeatureCollection.
68
+ # See RGeo::GeoJSON::EntityFactory for more information.
69
+ # <tt>:json_parser</tt>::
70
+ # Specifies a JSON parser to use when decoding a String or IO
71
+ # object. The value may be a Proc object taking the string as the
72
+ # sole argument and returning the JSON hash, or it may be one of
73
+ # the special values <tt>:json</tt>, <tt>:yajl</tt>, or
74
+ # <tt>:active_support</tt>. Setting one of those special values
75
+ # will require the corresponding library to be available. Note
76
+ # that the <tt>:json</tt> library is present in the standard
77
+ # library in Ruby 1.9, but requires the "json" gem in Ruby 1.8.
78
+ # If a parser is not specified, then the decode method will not
79
+ # accept a String or IO object; it will require a Hash.
80
+
81
+ def initialize(opts_={})
82
+ @geo_factory = opts_[:geo_factory] || ::RGeo::Cartesian.preferred_factory
83
+ @entity_factory = opts_[:entity_factory] || EntityFactory.instance
84
+ @json_parser = opts_[:json_parser]
85
+ case @json_parser
86
+ when :json
87
+ if @@json_available.nil?
88
+ begin
89
+ require 'json'
90
+ @@json_available = true
91
+ rescue ::LoadError
92
+ @@json_available = false
93
+ end
94
+ end
95
+ if @@json_available
96
+ @json_parser = ::Proc.new{ |str_| ::JSON.parse(str_) }
97
+ else
98
+ raise Error::RGeoError, "JSON library is not available. You may need to install the 'json' gem."
99
+ end
100
+ when :yajl
101
+ if @@yajl_available.nil?
102
+ begin
103
+ require 'yajl'
104
+ @@yajl_available = true
105
+ rescue ::LoadError
106
+ @@yajl_available = false
107
+ end
108
+ end
109
+ if @@yajl_available
110
+ @json_parser = ::Proc.new{ |str_| ::Yajl::Parser.new.parse(str_) }
111
+ else
112
+ raise Error::RGeoError, "Yajl library is not available. You may need to install the 'yajl' gem."
113
+ end
114
+ when :active_support
115
+ if @@activesupport_available.nil?
116
+ begin
117
+ require 'active_support/json'
118
+ @@activesupport_available = true
119
+ rescue ::LoadError
120
+ @@activesupport_available = false
121
+ end
122
+ end
123
+ if @@activesupport_available
124
+ @json_parser = ::Proc.new{ |str_| ::ActiveSupport::JSON.decode(str_) }
125
+ else
126
+ raise Error::RGeoError, "ActiveSupport::JSON library is not available. You may need to install the 'activesupport' gem."
127
+ end
128
+ when ::Proc, nil
129
+ # Leave as is
130
+ else
131
+ raise ::ArgumentError, "Unrecognzied json_parser: #{@json_parser.inspect}"
132
+ end
133
+ @num_coordinates = 2
134
+ @num_coordinates += 1 if @geo_factory.property(:has_z_coordinate)
135
+ @num_coordinates += 1 if @geo_factory.property(:has_m_coordinate)
136
+ end
137
+
138
+
139
+ # Encode the given object as GeoJSON. The object may be one of the
140
+ # geometry objects specified in RGeo::Feature, or an appropriate
141
+ # GeoJSON wrapper entity supported by this coder's entity factory.
142
+ #
143
+ # This method returns a JSON object (i.e. a hash). In order to
144
+ # generate a string suitable for transmitting to a service, you
145
+ # will need to JSON-encode it. This is usually accomplished by
146
+ # calling <tt>to_json</tt> on the hash object, if you have the
147
+ # appropriate JSON library installed.
148
+
149
+ def encode(object_)
150
+ if @entity_factory.is_feature_collection?(object_)
151
+ {
152
+ 'type' => 'FeatureCollection',
153
+ 'features' => @entity_factory.map_feature_collection(object_){ |f_| _encode_feature(f_) },
154
+ }
155
+ elsif @entity_factory.is_feature?(object_)
156
+ _encode_feature(object_)
157
+ else
158
+ _encode_geometry(object_)
159
+ end
160
+ end
161
+
162
+
163
+ # Decode an object from GeoJSON. The input may be a JSON hash, a
164
+ # String, or an IO object from which to read the JSON string.
165
+ # If an error occurs, nil is returned.
166
+
167
+ def decode(input_)
168
+ if input_.kind_of?(::IO)
169
+ input_ = input_.read rescue nil
170
+ end
171
+ if input_.kind_of?(::String)
172
+ input_ = @json_parser.call(input_) rescue nil
173
+ end
174
+ unless input_.kind_of?(::Hash)
175
+ return nil
176
+ end
177
+ case input_['type']
178
+ when 'FeatureCollection'
179
+ features_ = input_['features']
180
+ features_ = [] unless features_.kind_of?(::Array)
181
+ decoded_features_ = []
182
+ features_.each do |f_|
183
+ if f_['type'] == 'Feature'
184
+ decoded_features_ << _decode_feature(f_)
185
+ end
186
+ end
187
+ @entity_factory.feature_collection(decoded_features_)
188
+ when 'Feature'
189
+ _decode_feature(input_)
190
+ else
191
+ _decode_geometry(input_)
192
+ end
193
+ end
194
+
195
+
196
+ # Returns the RGeo::Feature::Factory used to generate geometry objects.
197
+
198
+ def geo_factory
199
+ @geo_factory
200
+ end
201
+
202
+
203
+ # Returns the RGeo::GeoJSON::EntityFactory used to generate GeoJSON
204
+ # wrapper entities.
205
+
206
+ def entity_factory
207
+ @entity_factory
208
+ end
209
+
210
+
211
+ def _encode_feature(object_) # :nodoc:
212
+ json_ = {
213
+ 'type' => 'Feature',
214
+ 'geometry' => _encode_geometry(@entity_factory.get_feature_geometry(object_)),
215
+ 'properties' => @entity_factory.get_feature_properties(object_).dup,
216
+ }
217
+ id_ = @entity_factory.get_feature_id(object_)
218
+ json_['id'] = id_ if id_
219
+ json_
220
+ end
221
+
222
+
223
+ def _encode_geometry(object_, point_encoder_=nil) # :nodoc:
224
+ unless point_encoder_
225
+ if object_.factory.property(:has_z_coordinate)
226
+ if object_.factory.property(:has_m_coordinate)
227
+ point_encoder_ = ::Proc.new{ |p_| [p_.x, p_.y, p_.z, p_.m] }
228
+ else
229
+ point_encoder_ = ::Proc.new{ |p_| [p_.x, p_.y, p_.z] }
230
+ end
231
+ else
232
+ if object_.factory.property(:has_m_coordinate)
233
+ point_encoder_ = ::Proc.new{ |p_| [p_.x, p_.y, p_.m] }
234
+ else
235
+ point_encoder_ = ::Proc.new{ |p_| [p_.x, p_.y] }
236
+ end
237
+ end
238
+ end
239
+ case object_
240
+ when ::RGeo::Feature::Point
241
+ {
242
+ 'type' => 'Point',
243
+ 'coordinates' => point_encoder_.call(object_),
244
+ }
245
+ when ::RGeo::Feature::LineString
246
+ {
247
+ 'type' => 'LineString',
248
+ 'coordinates' => object_.points.map(&point_encoder_),
249
+ }
250
+ when ::RGeo::Feature::Polygon
251
+ {
252
+ 'type' => 'Polygon',
253
+ 'coordinates' => [object_.exterior_ring.points.map(&point_encoder_)] + object_.interior_rings.map{ |r_| r_.points.map(&point_encoder_) }
254
+ }
255
+ when ::RGeo::Feature::MultiPoint
256
+ {
257
+ 'type' => 'MultiPoint',
258
+ 'coordinates' => object_.map(&point_encoder_),
259
+ }
260
+ when ::RGeo::Feature::MultiLineString
261
+ {
262
+ 'type' => 'MultiLineString',
263
+ 'coordinates' => object_.map{ |ls_| ls_.points.map(&point_encoder_) },
264
+ }
265
+ when ::RGeo::Feature::MultiPolygon
266
+ {
267
+ 'type' => 'MultiPolygon',
268
+ 'coordinates' => object_.map{ |poly_| [poly_.exterior_ring.points.map(&point_encoder_)] + poly_.interior_rings.map{ |r_| r_.points.map(&point_encoder_) } },
269
+ }
270
+ when ::RGeo::Feature::GeometryCollection
271
+ {
272
+ 'type' => 'GeometryCollection',
273
+ 'geometries' => object_.map{ |geom_| _encode_geometry(geom_, point_encoder_) },
274
+ }
275
+ else
276
+ nil
277
+ end
278
+ end
279
+
280
+
281
+ def _decode_feature(input_) # :nodoc:
282
+ geometry_ = input_['geometry']
283
+ if geometry_
284
+ geometry_ = _decode_geometry(geometry_)
285
+ return nil unless geometry_
286
+ end
287
+ @entity_factory.feature(geometry_, input_['id'], input_['properties'])
288
+ end
289
+
290
+
291
+ def _decode_geometry(input_) # :nodoc:
292
+ case input_['type']
293
+ when 'GeometryCollection'
294
+ _decode_geometry_collection(input_)
295
+ when 'Point'
296
+ _decode_point_coords(input_['coordinates'])
297
+ when 'LineString'
298
+ _decode_line_string_coords(input_['coordinates'])
299
+ when 'Polygon'
300
+ _decode_polygon_coords(input_['coordinates'])
301
+ when 'MultiPoint'
302
+ _decode_multi_point_coords(input_['coordinates'])
303
+ when 'MultiLineString'
304
+ _decode_multi_line_string_coords(input_['coordinates'])
305
+ when 'MultiPolygon'
306
+ _decode_multi_polygon_coords(input_['coordinates'])
307
+ else
308
+ nil
309
+ end
310
+ end
311
+
312
+
313
+ def _decode_geometry_collection(input_) # :nodoc:
314
+ geometries_ = input_['geometries']
315
+ geometries_ = [] unless geometries_.kind_of?(::Array)
316
+ decoded_geometries_ = []
317
+ geometries_.each do |g_|
318
+ g_ = _decode_geometry(g_)
319
+ decoded_geometries_ << g_ if g_
320
+ end
321
+ @geo_factory.collection(decoded_geometries_)
322
+ end
323
+
324
+
325
+ def _decode_point_coords(point_coords_) # :nodoc:
326
+ return nil unless point_coords_.kind_of?(::Array)
327
+ @geo_factory.point(*(point_coords_[0...@num_coordinates].map{ |c_| c_.to_f })) rescue nil
328
+ end
329
+
330
+
331
+ def _decode_line_string_coords(line_coords_) # :nodoc:
332
+ return nil unless line_coords_.kind_of?(::Array)
333
+ points_ = []
334
+ line_coords_.each do |point_coords_|
335
+ point_ = _decode_point_coords(point_coords_)
336
+ points_ << point_ if point_
337
+ end
338
+ @geo_factory.line_string(points_)
339
+ end
340
+
341
+
342
+ def _decode_polygon_coords(poly_coords_) # :nodoc:
343
+ return nil unless poly_coords_.kind_of?(::Array)
344
+ rings_ = []
345
+ poly_coords_.each do |ring_coords_|
346
+ return nil unless ring_coords_.kind_of?(::Array)
347
+ points_ = []
348
+ ring_coords_.each do |point_coords_|
349
+ point_ = _decode_point_coords(point_coords_)
350
+ points_ << point_ if point_
351
+ end
352
+ ring_ = @geo_factory.linear_ring(points_)
353
+ rings_ << ring_ if ring_
354
+ end
355
+ if rings_.size == 0
356
+ nil
357
+ else
358
+ @geo_factory.polygon(rings_[0], rings_[1..-1])
359
+ end
360
+ end
361
+
362
+
363
+ def _decode_multi_point_coords(multi_point_coords_) # :nodoc:
364
+ return nil unless multi_point_coords_.kind_of?(::Array)
365
+ points_ = []
366
+ multi_point_coords_.each do |point_coords_|
367
+ point_ = _decode_point_coords(point_coords_)
368
+ points_ << point_ if point_
369
+ end
370
+ @geo_factory.multi_point(points_)
371
+ end
372
+
373
+
374
+ def _decode_multi_line_string_coords(multi_line_coords_) # :nodoc:
375
+ return nil unless multi_line_coords_.kind_of?(::Array)
376
+ lines_ = []
377
+ multi_line_coords_.each do |line_coords_|
378
+ line_ = _decode_line_string_coords(line_coords_)
379
+ lines_ << line_ if line_
380
+ end
381
+ @geo_factory.multi_line_string(lines_)
382
+ end
383
+
384
+
385
+ def _decode_multi_polygon_coords(multi_polygon_coords_) # :nodoc:
386
+ return nil unless multi_polygon_coords_.kind_of?(::Array)
387
+ polygons_ = []
388
+ multi_polygon_coords_.each do |poly_coords_|
389
+ poly_ = _decode_polygon_coords(poly_coords_)
390
+ polygons_ << poly_ if poly_
391
+ end
392
+ @geo_factory.multi_polygon(polygons_)
393
+ end
394
+
395
+
396
+ end
397
+
398
+
399
+ end
400
+
401
+ end