rgeo-geojson 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +5 -0
- data/README.rdoc +104 -0
- data/Version +1 -0
- data/lib/rgeo/geo_json.rb +62 -0
- data/lib/rgeo/geo_json/coder.rb +401 -0
- data/lib/rgeo/geo_json/entities.rb +301 -0
- data/lib/rgeo/geo_json/interface.rb +129 -0
- data/test/tc_basic.rb +281 -0
- metadata +88 -0
data/History.rdoc
ADDED
data/README.rdoc
ADDED
@@ -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
|