@@ -24,8 +24,32 @@ public interface IGeoShape
24
24
bool ? IgnoreUnmapped { get ; set ; }
25
25
}
26
26
27
+ internal enum GeoShapeFormat
28
+ {
29
+ GeoJson ,
30
+ WellKnownText
31
+ }
32
+
33
+ internal static class GeoShapeType
34
+ {
35
+ public const string Point = "POINT" ;
36
+ public const string MultiPoint = "MULTIPOINT" ;
37
+ public const string LineString = "LINESTRING" ;
38
+ public const string MultiLineString = "MULTILINESTRING" ;
39
+ public const string Polygon = "POLYGON" ;
40
+ public const string MultiPolygon = "MULTIPOLYGON" ;
41
+ public const string Circle = "CIRCLE" ;
42
+ public const string Envelope = "ENVELOPE" ;
43
+ public const string GeometryCollection = "GEOMETRYCOLLECTION" ;
44
+
45
+ // WKT uses BBOX for envelope geo shape
46
+ internal const string BoundingBox = "BBOX" ;
47
+ }
48
+
27
49
public abstract class GeoShapeBase : IGeoShape
28
50
{
51
+ internal GeoShapeFormat Format { get ; set ; }
52
+
29
53
protected GeoShapeBase ( string type ) => this . Type = type ;
30
54
31
55
/// <inheritdoc />
@@ -38,52 +62,121 @@ public abstract class GeoShapeBase : IGeoShape
38
62
39
63
internal class GeoShapeConverter : JsonConverter
40
64
{
41
- public override bool CanWrite => false ;
65
+ public override void WriteJson ( JsonWriter writer , object value , JsonSerializer serializer )
66
+ {
67
+ if ( value == null )
68
+ {
69
+ writer . WriteNull ( ) ;
70
+ return ;
71
+ }
42
72
43
- public override void WriteJson ( JsonWriter writer , object value , JsonSerializer serializer ) =>
44
- throw new NotSupportedException ( ) ;
73
+ // IGeometryCollection needs to be handled separately because it does not
74
+ // implement IGeoShape, and can't because it would be a binary breaking change.
75
+ // This is fixed in next major release.
76
+ if ( value is IGeometryCollection collection )
77
+ {
78
+ if ( collection is GeometryCollection geometryCollection && geometryCollection . Format == GeoShapeFormat . WellKnownText )
79
+ {
80
+ writer . WriteValue ( GeoWKTWriter . Write ( collection ) ) ;
81
+ return ;
82
+ }
83
+
84
+ writer . WriteStartObject ( ) ;
85
+ writer . WritePropertyName ( "type" ) ;
86
+ writer . WriteValue ( collection . Type ) ;
87
+ writer . WritePropertyName ( "geometries" ) ;
88
+ serializer . Serialize ( writer , collection . Geometries ) ;
89
+ writer . WriteEndObject ( ) ;
90
+ }
91
+ else if ( value is IGeoShape shape )
92
+ {
93
+ if ( value is GeoShapeBase shapeBase && shapeBase . Format == GeoShapeFormat . WellKnownText )
94
+ {
95
+ writer . WriteValue ( GeoWKTWriter . Write ( shapeBase ) ) ;
96
+ return ;
97
+ }
98
+
99
+ writer . WriteStartObject ( ) ;
100
+ writer . WritePropertyName ( "type" ) ;
101
+ writer . WriteValue ( shape . Type ) ;
102
+ writer . WritePropertyName ( "coordinates" ) ;
103
+ switch ( shape )
104
+ {
105
+ case IPointGeoShape point :
106
+ serializer . Serialize ( writer , point . Coordinates ) ;
107
+ break ;
108
+ case IMultiPointGeoShape multiPoint :
109
+ serializer . Serialize ( writer , multiPoint . Coordinates ) ;
110
+ break ;
111
+ case ILineStringGeoShape lineString :
112
+ serializer . Serialize ( writer , lineString . Coordinates ) ;
113
+ break ;
114
+ case IMultiLineStringGeoShape multiLineString :
115
+ serializer . Serialize ( writer , multiLineString . Coordinates ) ;
116
+ break ;
117
+ case IPolygonGeoShape polygon :
118
+ serializer . Serialize ( writer , polygon . Coordinates ) ;
119
+ break ;
120
+ case IMultiPolygonGeoShape multiPolyon :
121
+ serializer . Serialize ( writer , multiPolyon . Coordinates ) ;
122
+ break ;
123
+ case IEnvelopeGeoShape envelope :
124
+ serializer . Serialize ( writer , envelope . Coordinates ) ;
125
+ break ;
126
+ case ICircleGeoShape circle :
127
+ serializer . Serialize ( writer , circle . Coordinates ) ;
128
+ writer . WritePropertyName ( "radius" ) ;
129
+ writer . WriteValue ( circle . Radius ) ;
130
+ break ;
131
+ }
132
+ writer . WriteEndObject ( ) ;
133
+ }
134
+ }
45
135
46
136
public override object ReadJson ( JsonReader reader , Type objectType , object existingValue , JsonSerializer serializer )
47
137
{
48
- if ( reader . TokenType == JsonToken . Null )
49
- return null ;
50
-
51
- var shape = JObject . Load ( reader ) ;
52
- return ReadJToken ( shape , serializer ) ;
138
+ switch ( reader . TokenType )
139
+ {
140
+ case JsonToken . Null :
141
+ return null ;
142
+ case JsonToken . String :
143
+ return GeoWKTReader . Read ( ( string ) reader . Value ) ;
144
+ default :
145
+ var shape = JObject . Load ( reader ) ;
146
+ return ReadJToken ( shape , serializer ) ;
147
+ }
53
148
}
54
149
55
150
internal static object ReadJToken ( JToken shape , JsonSerializer serializer )
56
151
{
57
- var type = shape [ "type" ] ;
58
- var typeName = type ? . Value < string > ( ) ;
152
+ var typeName = shape [ "type" ] ? . Value < string > ( ) . ToUpperInvariant ( ) ;
59
153
switch ( typeName )
60
154
{
61
- case "circle" :
62
- var radius = shape [ "radius" ] ;
63
- return ParseCircleGeoShape ( shape , serializer , radius ) ;
64
- case "envelope" :
155
+ case GeoShapeType . Circle :
156
+ return ParseCircleGeoShape ( shape , serializer ) ;
157
+ case GeoShapeType . Envelope :
65
158
return ParseEnvelopeGeoShape ( shape , serializer ) ;
66
- case "linestring" :
159
+ case GeoShapeType . LineString :
67
160
return ParseLineStringGeoShape ( shape , serializer ) ;
68
- case "multilinestring" :
161
+ case GeoShapeType . MultiLineString :
69
162
return ParseMultiLineStringGeoShape ( shape , serializer ) ;
70
- case "point" :
163
+ case GeoShapeType . Point :
71
164
return ParsePointGeoShape ( shape , serializer ) ;
72
- case "multipoint" :
165
+ case GeoShapeType . MultiPoint :
73
166
return ParseMultiPointGeoShape ( shape , serializer ) ;
74
- case "polygon" :
167
+ case GeoShapeType . Polygon :
75
168
return ParsePolygonGeoShape ( shape , serializer ) ;
76
- case "multipolygon" :
169
+ case GeoShapeType . MultiPolygon :
77
170
return ParseMultiPolygonGeoShape ( shape , serializer ) ;
78
- case "geometrycollection" :
171
+ case GeoShapeType . GeometryCollection :
79
172
return ParseGeometryCollection ( shape , serializer ) ;
80
173
default :
81
174
return null ;
82
175
}
83
176
}
84
177
85
- public override bool CanConvert ( Type objectType ) => typeof ( IGeoShape ) . IsAssignableFrom ( objectType ) ||
86
- typeof ( IGeometryCollection ) . IsAssignableFrom ( objectType ) ;
178
+ public override bool CanConvert ( Type objectType ) =>
179
+ typeof ( IGeoShape ) . IsAssignableFrom ( objectType ) || typeof ( IGeometryCollection ) . IsAssignableFrom ( objectType ) ;
87
180
88
181
private static GeometryCollection ParseGeometryCollection ( JToken shape , JsonSerializer serializer )
89
182
{
@@ -128,11 +221,11 @@ private static LineStringGeoShape ParseLineStringGeoShape(JToken shape, JsonSeri
128
221
private static EnvelopeGeoShape ParseEnvelopeGeoShape ( JToken shape , JsonSerializer serializer ) =>
129
222
new EnvelopeGeoShape { Coordinates = GetCoordinates < IEnumerable < GeoCoordinate > > ( shape , serializer ) } ;
130
223
131
- private static CircleGeoShape ParseCircleGeoShape ( JToken shape , JsonSerializer serializer , JToken radius ) =>
224
+ private static CircleGeoShape ParseCircleGeoShape ( JToken shape , JsonSerializer serializer ) =>
132
225
new CircleGeoShape
133
226
{
134
227
Coordinates = GetCoordinates < GeoCoordinate > ( shape , serializer ) ,
135
- Radius = radius ? . Value < string > ( )
228
+ Radius = shape [ " radius" ] ? . Value < string > ( )
136
229
} ;
137
230
138
231
private static T GetCoordinates < T > ( JToken shape , JsonSerializer serializer )
0 commit comments