@@ -6,8 +6,10 @@ module GeoJSON
6
6
# the RGeo::Feature::Factory and the RGeo::GeoJSON::EntityFactory to
7
7
# be used) so that you can encode and decode without specifying those
8
8
# settings every time.
9
-
10
9
class Coder
10
+ class Error < RGeo ::GeoJSON ::Error
11
+ end
12
+
11
13
# Create a new coder settings object. The geo factory is passed as
12
14
# a required argument.
13
15
#
@@ -23,11 +25,37 @@ class Coder
23
25
# RGeo::GeoJSON::Feature or RGeo::GeoJSON::FeatureCollection.
24
26
# See RGeo::GeoJSON::EntityFactory for more information.
25
27
def initialize ( opts = { } )
26
- @geo_factory = opts [ :geo_factory ] || RGeo ::Cartesian . preferred_factory
27
- @entity_factory = opts [ :entity_factory ] || EntityFactory . instance
28
+ @geo_factory = opts . fetch (
29
+ :geo_factory ,
30
+ RGeo ::Cartesian . preferred_factory ( uses_lenient_assertions : true )
31
+ )
32
+ @entity_factory = opts . fetch ( :entity_factory , EntityFactory . instance )
33
+ if @geo_factory . property ( :has_m_coordinate )
34
+ # If a GeoJSON has more than 2 elements, the first one should be
35
+ # longitude and the second one latitude. M is not part of GeoJSON
36
+ # specifications and only kept here for backward compatibilities.
37
+ #
38
+ # Quote from https://tools.ietf.org/html/rfc7946#section-3.1.1:
39
+ #
40
+ # > A position is an array of numbers. There MUST be two or more
41
+ # > elements. The first two elements are longitude and latitude, or
42
+ # > easting and northing, precisely in that order and using decimal
43
+ # > numbers. Altitude or elevation MAY be included as an optional third
44
+ # > element.
45
+ # >
46
+ # > Implementations SHOULD NOT extend positions beyond three elements
47
+ # > because the semantics of extra elements are unspecified and
48
+ # > ambiguous. Historically, some implementations have used a fourth
49
+ # > element to carry a linear referencing measure (sometimes denoted as
50
+ # > "M") or a numerical timestamp, but in most situations a parser will
51
+ # > not be able to properly interpret these values. The interpretation
52
+ # > and meaning of additional elements is beyond the scope of this
53
+ # > specification, and additional elements MAY be ignored by parsers.
54
+ raise Error , "GeoJSON format cannot handle m coordinate."
55
+ end
56
+
28
57
@num_coordinates = 2
29
58
@num_coordinates += 1 if @geo_factory . property ( :has_z_coordinate )
30
- @num_coordinates += 1 if @geo_factory . property ( :has_m_coordinate )
31
59
end
32
60
33
61
# Encode the given object as GeoJSON. The object may be one of the
@@ -41,17 +69,16 @@ def initialize(opts = {})
41
69
# appropriate JSON library installed.
42
70
#
43
71
# Returns nil if nil is passed in as the object.
44
-
45
72
def encode ( object )
73
+ return nil if object . nil?
74
+
46
75
if @entity_factory . is_feature_collection? ( object )
47
76
{
48
77
"type" => "FeatureCollection" ,
49
78
"features" => @entity_factory . map_feature_collection ( object ) { |f | encode_feature ( f ) } ,
50
79
}
51
80
elsif @entity_factory . is_feature? ( object )
52
81
encode_feature ( object )
53
- elsif object . nil?
54
- nil
55
82
else
56
83
encode_geometry ( object )
57
84
end
@@ -111,35 +138,20 @@ def encode_feature(object)
111
138
end
112
139
113
140
def encode_geometry ( object )
141
+ return nil if object . nil?
142
+ if object . factory . property ( :has_m_coordinate )
143
+ raise Error , "GeoJSON format cannot handle m coordinate."
144
+ end
145
+
114
146
case object
115
- when RGeo ::Feature ::Point
116
- {
117
- "type" => "Point" ,
118
- "coordinates" => object . coordinates
119
- }
120
- when RGeo ::Feature ::LineString
147
+ when RGeo ::Feature ::Point ,
148
+ RGeo :: Feature :: LineString ,
149
+ RGeo :: Feature :: Polygon ,
150
+ RGeo :: Feature :: MultiPoint ,
151
+ RGeo :: Feature :: MultiLineString ,
152
+ RGeo ::Feature ::MultiPolygon
121
153
{
122
- "type" => "LineString" ,
123
- "coordinates" => object . coordinates
124
- }
125
- when RGeo ::Feature ::Polygon
126
- {
127
- "type" => "Polygon" ,
128
- "coordinates" => object . coordinates
129
- }
130
- when RGeo ::Feature ::MultiPoint
131
- {
132
- "type" => "MultiPoint" ,
133
- "coordinates" => object . coordinates
134
- }
135
- when RGeo ::Feature ::MultiLineString
136
- {
137
- "type" => "MultiLineString" ,
138
- "coordinates" => object . coordinates
139
- }
140
- when RGeo ::Feature ::MultiPolygon
141
- {
142
- "type" => "MultiPolygon" ,
154
+ "type" => object . geometry_type . type_name ,
143
155
"coordinates" => object . coordinates
144
156
}
145
157
when RGeo ::Feature ::GeometryCollection
@@ -178,7 +190,7 @@ def decode_geometry(input)
178
190
when "MultiPolygon"
179
191
decode_multi_polygon_coords ( input [ "coordinates" ] )
180
192
else
181
- nil
193
+ raise Error , "' #{ input [ 'type' ] } ' type is not part of GeoJSON spec."
182
194
end
183
195
end
184
196
0 commit comments