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