rgeo-geojson 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,301 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # GeoJSON standard entities
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 is a GeoJSON wrapper entity that corresponds to the GeoJSON
43
+ # "Feature" type. It is an immutable type.
44
+ #
45
+ # This is the default implementation that is generated by
46
+ # RGeo::GeoJSON::EntityFactory. You may replace this implementation
47
+ # by writing your own entity factory. Note that an alternate Feature
48
+ # implementation need not subclass or even duck-type this class.
49
+ # the entity factory mediates all interaction between the GeoJSON
50
+ # engine and features.
51
+
52
+ class Feature
53
+
54
+
55
+ # Create a feature wrapping the given geometry, with the given ID
56
+ # and properties.
57
+
58
+ def initialize(geometry_, id_=nil, properties_={})
59
+ @geometry = geometry_
60
+ @id = id_
61
+ @properties = properties_.dup
62
+ end
63
+
64
+
65
+ def inspect # :nodoc:
66
+ "#<#{self.class}:0x#{object_id.to_s(16)} id=#{@id.inspect} geom=#{@geometry ? @geometry.as_text.inspect : 'nil'}>"
67
+ end
68
+
69
+ def to_s # :nodoc:
70
+ inspect
71
+ end
72
+
73
+ def hash # :nodoc:
74
+ @geometry.hash + @id.hash + @properties.hash
75
+ end
76
+
77
+
78
+ # Two features are equal if their geometries, IDs, and properties
79
+ # are all equal.
80
+ # This method uses the eql? method to test geometry equality, which
81
+ # may behave differently than the == operator.
82
+
83
+ def eql?(rhs_)
84
+ rhs_.kind_of?(Feature) && @geometry.eql?(rhs_.geometry) && @id.eql?(rhs_.feature_id) && @properties.eql?(rhs_.instance_variable_get(:@properties))
85
+ end
86
+
87
+
88
+ # Two features are equal if their geometries, IDs, and properties
89
+ # are all equal.
90
+ # This method uses the == operator to test geometry equality, which
91
+ # may behave differently than the eql? method.
92
+
93
+ def ==(rhs_)
94
+ rhs_.kind_of?(Feature) && @geometry == rhs_.geometry && @id == rhs_.feature_id && @properties == rhs_.instance_variable_get(:@properties)
95
+ end
96
+
97
+
98
+ # Returns the geometry contained in this feature, which may be nil.
99
+
100
+ def geometry
101
+ @geometry
102
+ end
103
+
104
+
105
+ # Returns the ID for this feature, which may be nil.
106
+
107
+ def feature_id
108
+ @id
109
+ end
110
+
111
+
112
+ # Returns a copy of the properties for this feature.
113
+
114
+ def properties
115
+ @properties.dup
116
+ end
117
+
118
+
119
+ # Gets the value of the given named property.
120
+ # Returns nil if the given property is not found.
121
+
122
+ def property(key_)
123
+ @properties[key_.to_s]
124
+ end
125
+ alias_method :[], :property
126
+
127
+
128
+ # Gets an array of the known property keys in this feature.
129
+
130
+ def keys
131
+ @properties.keys
132
+ end
133
+
134
+
135
+ end
136
+
137
+
138
+ # This is a GeoJSON wrapper entity that corresponds to the GeoJSON
139
+ # "FeatureCollection" type. It is an immutable type.
140
+ #
141
+ # This is the default implementation that is generated by
142
+ # RGeo::GeoJSON::EntityFactory. You may replace this implementation
143
+ # by writing your own entity factory. Note that an alternate
144
+ # FeatureCollection implementation need not subclass or even
145
+ # duck-type this class. The entity factory mediates all interaction
146
+ # between the GeoJSON engine and feature collections.
147
+
148
+ class FeatureCollection
149
+
150
+ include ::Enumerable
151
+
152
+
153
+ # Create a new FeatureCollection with the given features, which must
154
+ # be provided as an Enumerable.
155
+
156
+ def initialize(features_=[])
157
+ @features = []
158
+ features_.each{ |f_| @features << f_ if f_.kind_of?(Feature) }
159
+ end
160
+
161
+
162
+ def inspect # :nodoc:
163
+ "#<#{self.class}:0x#{object_id.to_s(16)}>"
164
+ end
165
+
166
+ def to_s # :nodoc:
167
+ inspect
168
+ end
169
+
170
+ def hash # :nodoc:
171
+ @features.hash
172
+ end
173
+
174
+
175
+ # Two feature collections are equal if they contain the same
176
+ # features in the same order.
177
+ # This methods uses the eql? method to test geometry equality, which
178
+ # may behave differently than the == operator.
179
+
180
+ def eql?(rhs_)
181
+ rhs_.kind_of?(FeatureCollection) && @features.eql?(rhs_.instance_variable_get(:@features))
182
+ end
183
+
184
+
185
+ # Two feature collections are equal if they contain the same
186
+ # features in the same order.
187
+ # This methods uses the == operator to test geometry equality, which
188
+ # may behave differently than the eql? method.
189
+
190
+ def ==(rhs_)
191
+ rhs_.kind_of?(FeatureCollection) && @features == rhs_.instance_variable_get(:@features)
192
+ end
193
+
194
+
195
+ # Iterates or returns an iterator for the features.
196
+
197
+ def each(&block_)
198
+ @features.each(&block_)
199
+ end
200
+
201
+
202
+ # Returns the number of features contained in this collection.
203
+
204
+ def size
205
+ @features.size
206
+ end
207
+
208
+
209
+ # Access a feature by index.
210
+
211
+ def [](index_)
212
+ @features[index_]
213
+ end
214
+
215
+
216
+ end
217
+
218
+
219
+ # This is the default entity factory. It creates objects of type
220
+ # RGeo::GeoJSON::Feature and RGeo::GeoJSON::FeatureCollection.
221
+ # You may create your own entity factory by duck-typing this class.
222
+
223
+ class EntityFactory
224
+
225
+
226
+ # Create and return a new feature, given geometry, ID, and
227
+ # properties hash. Note that, per the GeoJSON spec, geometry and/or
228
+ # properties may be nil.
229
+
230
+ def feature(geometry_, id_=nil, properties_=nil)
231
+ Feature.new(geometry_, id_, properties_ || {})
232
+ end
233
+
234
+
235
+ # Create and return a new feature collection, given an enumerable
236
+ # of feature objects.
237
+
238
+ def feature_collection(features_=[])
239
+ FeatureCollection.new(features_)
240
+ end
241
+
242
+
243
+ # Returns true if the given object is a feature created by this
244
+ # entity factory.
245
+
246
+ def is_feature?(object_)
247
+ object_.kind_of?(Feature)
248
+ end
249
+
250
+
251
+ # Returns true if the given object is a feature collection created
252
+ # by this entity factory.
253
+
254
+ def is_feature_collection?(object_)
255
+ object_.kind_of?(FeatureCollection)
256
+ end
257
+
258
+
259
+ # Run Enumerable#map on the features contained in the given feature
260
+ # collection.
261
+
262
+ def map_feature_collection(object_, &block_)
263
+ object_.map(&block_)
264
+ end
265
+
266
+
267
+ # Returns the geometry associated with the given feature.
268
+
269
+ def get_feature_geometry(object_)
270
+ object_.geometry
271
+ end
272
+
273
+
274
+ # Returns the ID of the given feature, or nil for no ID.
275
+
276
+ def get_feature_id(object_)
277
+ object_.feature_id
278
+ end
279
+
280
+
281
+ # Returns the properties of the given feature as a hash. Editing
282
+ # this hash does not change the state of the feature.
283
+
284
+ def get_feature_properties(object_)
285
+ object_.properties
286
+ end
287
+
288
+
289
+ # Return the singleton instance of EntityFactory.
290
+
291
+ def self.instance
292
+ @instance ||= self.new
293
+ end
294
+
295
+
296
+ end
297
+
298
+
299
+ end
300
+
301
+ end
@@ -0,0 +1,129 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # GeoJSON toplevel interface
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
+ class << self
42
+
43
+
44
+ # High-level convenience routine for encoding an object as GeoJSON.
45
+ # Pass the object, which may one of the geometry objects specified
46
+ # in RGeo::Feature, or an appropriate GeoJSON wrapper entity such
47
+ # as RGeo::GeoJSON::Feature or RGeo::GeoJSON::FeatureCollection.
48
+ #
49
+ # The only option supported is <tt>:entity_factory</tt>, which lets
50
+ # you override the types of GeoJSON entities supported. See
51
+ # RGeo::GeoJSON::EntityFactory for more information. By default,
52
+ # encode supports objects of type RGeo::GeoJSON::Feature and
53
+ # RGeo::GeoJSON::FeatureCollection.
54
+
55
+ def encode(object_, opts_={})
56
+ Coder.new(opts_).encode(object_)
57
+ end
58
+
59
+
60
+ # High-level convenience routine for decoding an object from GeoJSON.
61
+ # The input may be a JSON hash, a String, or an IO object from which
62
+ # to read the JSON string.
63
+ #
64
+ # Options include:
65
+ #
66
+ # <tt>:geo_factory</tt>::
67
+ # Specifies the geo factory to use to create geometry objects.
68
+ # Defaults to the preferred cartesian factory.
69
+ # <tt>:entity_factory</tt>::
70
+ # Specifies an entity factory, which lets you override the types
71
+ # of GeoJSON entities that are created. It defaults to the default
72
+ # RGeo::GeoJSON::EntityFactory, which generates objects of type
73
+ # RGeo::GeoJSON::Feature or RGeo::GeoJSON::FeatureCollection.
74
+ # See RGeo::GeoJSON::EntityFactory for more information.
75
+ # <tt>:json_parser</tt>::
76
+ # Specifies a JSON parser to use when decoding a String or IO
77
+ # object. The value may be a Proc object taking the string as the
78
+ # sole argument and returning the JSON hash, or it may be one of
79
+ # the special values <tt>:json</tt>, <tt>:yajl</tt>, or
80
+ # <tt>:active_support</tt>. Setting one of those special values
81
+ # will require the corresponding library to be available. Note
82
+ # that the <tt>:json</tt> library is present in the standard
83
+ # library in Ruby 1.9, but requires the "json" gem in Ruby 1.8.
84
+ # If a parser is not specified, then the decode method will not
85
+ # accept a String or IO object; it will require a Hash.
86
+
87
+ def decode(input_, opts_={})
88
+ Coder.new(opts_).decode(input_)
89
+ end
90
+
91
+
92
+ # Creates and returns a coder object of type RGeo::GeoJSON::Coder
93
+ # that encapsulates encoding and decoding settings (principally the
94
+ # RGeo::Feature::Factory and the RGeo::GeoJSON::EntityFactory to be
95
+ # used).
96
+ #
97
+ # The geo factory is a required argument. Other options include:
98
+ #
99
+ # <tt>:geo_factory</tt>::
100
+ # Specifies the geo factory to use to create geometry objects.
101
+ # Defaults to the preferred cartesian factory.
102
+ # <tt>:entity_factory</tt>::
103
+ # Specifies an entity factory, which lets you override the types
104
+ # of GeoJSON entities that are created. It defaults to the default
105
+ # RGeo::GeoJSON::EntityFactory, which generates objects of type
106
+ # RGeo::GeoJSON::Feature or RGeo::GeoJSON::FeatureCollection.
107
+ # See RGeo::GeoJSON::EntityFactory for more information.
108
+ # <tt>:json_parser</tt>::
109
+ # Specifies a JSON parser to use when decoding a String or IO
110
+ # object. The value may be a Proc object taking the string as the
111
+ # sole argument and returning the JSON hash, or it may be one of
112
+ # the special values <tt>:json</tt>, <tt>:yajl</tt>, or
113
+ # <tt>:active_support</tt>. Setting one of those special values
114
+ # will require the corresponding library to be available. Note
115
+ # that the <tt>:json</tt> library is present in the standard
116
+ # library in Ruby 1.9, but requires the "json" gem in Ruby 1.8.
117
+ # If a parser is not specified, then the decode method will not
118
+ # accept a String or IO object; it will require a Hash.
119
+
120
+ def coder(opts_={})
121
+ Coder.new(opts_)
122
+ end
123
+
124
+
125
+ end
126
+
127
+ end
128
+
129
+ end
@@ -0,0 +1,281 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Tests for basic GeoJSON usage
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
+ require 'test/unit'
38
+ require 'rgeo/geo_json'
39
+
40
+
41
+ module RGeo
42
+ module GeoJSON
43
+ module Tests # :nodoc:
44
+
45
+ class TestGeoJSON < ::Test::Unit::TestCase # :nodoc:
46
+
47
+
48
+ def setup
49
+ @geo_factory = ::RGeo::Cartesian.simple_factory(:srid => 4326)
50
+ @geo_factory_z = ::RGeo::Cartesian.simple_factory(:srid => 4326, :has_z_coordinate => true)
51
+ @geo_factory_m = ::RGeo::Cartesian.simple_factory(:srid => 4326, :has_m_coordinate => true)
52
+ @geo_factory_zm = ::RGeo::Cartesian.simple_factory(:srid => 4326, :has_z_coordinate => true, :has_m_coordinate => true)
53
+ @entity_factory = ::RGeo::GeoJSON::EntityFactory.instance
54
+ end
55
+
56
+
57
+ def test_point
58
+ object_ = @geo_factory.point(10, 20)
59
+ json_ = {
60
+ 'type' => 'Point',
61
+ 'coordinates' => [10.0, 20.0],
62
+ }
63
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
64
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
65
+ end
66
+
67
+
68
+ def test_point_z
69
+ object_ = @geo_factory_z.point(10, 20, -1)
70
+ json_ = {
71
+ 'type' => 'Point',
72
+ 'coordinates' => [10.0, 20.0, -1.0],
73
+ }
74
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
75
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory_z).eql?(object_))
76
+ end
77
+
78
+
79
+ def test_point_m
80
+ object_ = @geo_factory_m.point(10, 20, -1)
81
+ json_ = {
82
+ 'type' => 'Point',
83
+ 'coordinates' => [10.0, 20.0, -1.0],
84
+ }
85
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
86
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory_m).eql?(object_))
87
+ end
88
+
89
+
90
+ def test_point_zm
91
+ object_ = @geo_factory_zm.point(10, 20, -1, -2)
92
+ json_ = {
93
+ 'type' => 'Point',
94
+ 'coordinates' => [10.0, 20.0, -1.0, -2.0],
95
+ }
96
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
97
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory_zm).eql?(object_))
98
+ end
99
+
100
+
101
+ def test_line_string
102
+ object_ = @geo_factory.line_string([@geo_factory.point(10, 20), @geo_factory.point(12, 22), @geo_factory.point(-3, 24)])
103
+ json_ = {
104
+ 'type' => 'LineString',
105
+ 'coordinates' => [[10.0, 20.0], [12.0, 22.0], [-3.0, 24.0]],
106
+ }
107
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
108
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
109
+ end
110
+
111
+
112
+ def test_polygon
113
+ object_ = @geo_factory.polygon(@geo_factory.linear_ring([@geo_factory.point(10, 20), @geo_factory.point(12, 22), @geo_factory.point(-3, 24), @geo_factory.point(10, 20)]))
114
+ json_ = {
115
+ 'type' => 'Polygon',
116
+ 'coordinates' => [[[10.0, 20.0], [12.0, 22.0], [-3.0, 24.0], [10.0, 20.0]]],
117
+ }
118
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
119
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
120
+ end
121
+
122
+
123
+ def test_polygon_complex
124
+ object_ = @geo_factory.polygon(@geo_factory.linear_ring([@geo_factory.point(0, 0), @geo_factory.point(10, 0), @geo_factory.point(10, 10), @geo_factory.point(0, 10), @geo_factory.point(0, 0)]), [@geo_factory.linear_ring([@geo_factory.point(4, 4), @geo_factory.point(6, 5), @geo_factory.point(4, 6), @geo_factory.point(4, 4)])])
125
+ json_ = {
126
+ 'type' => 'Polygon',
127
+ 'coordinates' => [[[0.0, 0.0], [10.0, 0.0], [10.0, 10.0], [0.0, 10.0], [0.0, 0.0]], [[4.0, 4.0], [6.0, 5.0], [4.0, 6.0], [4.0, 4.0]]],
128
+ }
129
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
130
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
131
+ end
132
+
133
+
134
+ def test_multi_point
135
+ object_ = @geo_factory.multi_point([@geo_factory.point(10, 20), @geo_factory.point(12, 22), @geo_factory.point(-3, 24)])
136
+ json_ = {
137
+ 'type' => 'MultiPoint',
138
+ 'coordinates' => [[10.0, 20.0], [12.0, 22.0], [-3.0, 24.0]],
139
+ }
140
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
141
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
142
+ end
143
+
144
+
145
+ def test_multi_line_string
146
+ object_ = @geo_factory.multi_line_string([@geo_factory.line_string([@geo_factory.point(10, 20), @geo_factory.point(12, 22), @geo_factory.point(-3, 24)]), @geo_factory.line_string([@geo_factory.point(1, 2), @geo_factory.point(3, 4)])])
147
+ json_ = {
148
+ 'type' => 'MultiLineString',
149
+ 'coordinates' => [[[10.0, 20.0], [12.0, 22.0], [-3.0, 24.0]], [[1.0, 2.0], [3.0, 4.0]]],
150
+ }
151
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
152
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
153
+ end
154
+
155
+
156
+ def test_multi_polygon
157
+ object_ = @geo_factory.multi_polygon([@geo_factory.polygon(@geo_factory.linear_ring([@geo_factory.point(0, 0), @geo_factory.point(10, 0), @geo_factory.point(10, 10), @geo_factory.point(0, 10), @geo_factory.point(0, 0)]), [@geo_factory.linear_ring([@geo_factory.point(4, 4), @geo_factory.point(6, 5), @geo_factory.point(4, 6), @geo_factory.point(4, 4)])]), @geo_factory.polygon(@geo_factory.linear_ring([@geo_factory.point(-10,-10), @geo_factory.point(-15, -10), @geo_factory.point(-10, -15), @geo_factory.point(-10, -10)]))])
158
+ json_ = {
159
+ 'type' => 'MultiPolygon',
160
+ 'coordinates' => [[[[0.0, 0.0], [10.0, 0.0], [10.0, 10.0], [0.0, 10.0], [0.0, 0.0]], [[4.0, 4.0], [6.0, 5.0], [4.0, 6.0], [4.0, 4.0]]], [[[-10.0, -10.0], [-15.0, -10.0], [-10.0, -15.0], [-10.0, -10.0]]]]
161
+ }
162
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
163
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
164
+ end
165
+
166
+
167
+ def test_geometry_collection
168
+ object_ = @geo_factory.collection([@geo_factory.point(10, 20), @geo_factory.collection([@geo_factory.point(12, 22), @geo_factory.point(-3, 24)])])
169
+ json_ = {
170
+ 'type' => 'GeometryCollection',
171
+ 'geometries' => [
172
+ {
173
+ 'type' => 'Point',
174
+ 'coordinates' => [10.0, 20.0],
175
+ },
176
+ {
177
+ 'type' => 'GeometryCollection',
178
+ 'geometries' => [
179
+ {
180
+ 'type' => 'Point',
181
+ 'coordinates' => [12.0, 22.0],
182
+ },
183
+ {
184
+ 'type' => 'Point',
185
+ 'coordinates' => [-3.0, 24.0],
186
+ },
187
+ ],
188
+ },
189
+ ],
190
+ }
191
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
192
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
193
+ end
194
+
195
+
196
+ def test_feature
197
+ object_ = @entity_factory.feature(@geo_factory.point(10, 20))
198
+ json_ = {
199
+ 'type' => 'Feature',
200
+ 'geometry' => {
201
+ 'type' => 'Point',
202
+ 'coordinates' => [10.0, 20.0],
203
+ },
204
+ 'properties' => {},
205
+ }
206
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
207
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
208
+ end
209
+
210
+
211
+ def test_feature_nulls
212
+ json_ = {
213
+ 'type' => 'Feature',
214
+ 'geometry' => nil,
215
+ 'properties' => nil,
216
+ }
217
+ obj_ = ::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory)
218
+ assert_not_nil(obj_)
219
+ assert_nil(obj_.geometry)
220
+ assert_equal({}, obj_.properties)
221
+ end
222
+
223
+
224
+ def test_feature_complex
225
+ object_ = @entity_factory.feature(@geo_factory.point(10, 20), 2, {'prop1' => 'foo', 'prop2' => 'bar'})
226
+ json_ = {
227
+ 'type' => 'Feature',
228
+ 'geometry' => {
229
+ 'type' => 'Point',
230
+ 'coordinates' => [10.0, 20.0],
231
+ },
232
+ 'id' => 2,
233
+ 'properties' => {'prop1' => 'foo', 'prop2' => 'bar'},
234
+ }
235
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
236
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
237
+ end
238
+
239
+
240
+ def test_feature_collection
241
+ object_ = @entity_factory.feature_collection([@entity_factory.feature(@geo_factory.point(10, 20)), @entity_factory.feature(@geo_factory.point(11, 22)), @entity_factory.feature(@geo_factory.point(10, 20), 8)])
242
+ json_ = {
243
+ 'type' => 'FeatureCollection',
244
+ 'features' => [
245
+ {
246
+ 'type' => 'Feature',
247
+ 'geometry' => {
248
+ 'type' => 'Point',
249
+ 'coordinates' => [10.0, 20.0],
250
+ },
251
+ 'properties' => {},
252
+ },
253
+ {
254
+ 'type' => 'Feature',
255
+ 'geometry' => {
256
+ 'type' => 'Point',
257
+ 'coordinates' => [11.0, 22.0],
258
+ },
259
+ 'properties' => {},
260
+ },
261
+ {
262
+ 'type' => 'Feature',
263
+ 'geometry' => {
264
+ 'type' => 'Point',
265
+ 'coordinates' => [10.0, 20.0],
266
+ },
267
+ 'id' => 8,
268
+ 'properties' => {},
269
+ },
270
+ ]
271
+ }
272
+ assert_equal(json_, ::RGeo::GeoJSON.encode(object_))
273
+ assert(::RGeo::GeoJSON.decode(json_, :geo_factory => @geo_factory).eql?(object_))
274
+ end
275
+
276
+
277
+ end
278
+
279
+ end
280
+ end
281
+ end