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