@@ -24,8 +24,32 @@ public interface IGeoShape
2424 bool ? IgnoreUnmapped { get ; set ; }
2525 }
2626
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+ public const string BoundingBox = "BBOX" ;
47+ }
48+
2749 public abstract class GeoShapeBase : IGeoShape
2850 {
51+ internal GeoShapeFormat Format { get ; set ; }
52+
2953 protected GeoShapeBase ( string type ) => this . Type = type ;
3054
3155 /// <inheritdoc />
@@ -38,52 +62,121 @@ public abstract class GeoShapeBase : IGeoShape
3862
3963 internal class GeoShapeConverter : JsonConverter
4064 {
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+ }
4272
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+ // Fixed in 7.x
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+ }
45135
46136 public override object ReadJson ( JsonReader reader , Type objectType , object existingValue , JsonSerializer serializer )
47137 {
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+ }
53148 }
54149
55150 internal static object ReadJToken ( JToken shape , JsonSerializer serializer )
56151 {
57- var type = shape [ "type" ] ;
58- var typeName = type ? . Value < string > ( ) ;
152+ var typeName = shape [ "type" ] ? . Value < string > ( ) . ToUpperInvariant ( ) ;
59153 switch ( typeName )
60154 {
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 :
65158 return ParseEnvelopeGeoShape ( shape , serializer ) ;
66- case "linestring" :
159+ case GeoShapeType . LineString :
67160 return ParseLineStringGeoShape ( shape , serializer ) ;
68- case "multilinestring" :
161+ case GeoShapeType . MultiLineString :
69162 return ParseMultiLineStringGeoShape ( shape , serializer ) ;
70- case "point" :
163+ case GeoShapeType . Point :
71164 return ParsePointGeoShape ( shape , serializer ) ;
72- case "multipoint" :
165+ case GeoShapeType . MultiPoint :
73166 return ParseMultiPointGeoShape ( shape , serializer ) ;
74- case "polygon" :
167+ case GeoShapeType . Polygon :
75168 return ParsePolygonGeoShape ( shape , serializer ) ;
76- case "multipolygon" :
169+ case GeoShapeType . MultiPolygon :
77170 return ParseMultiPolygonGeoShape ( shape , serializer ) ;
78- case "geometrycollection" :
171+ case GeoShapeType . GeometryCollection :
79172 return ParseGeometryCollection ( shape , serializer ) ;
80173 default :
81174 return null ;
82175 }
83176 }
84177
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 ) ;
87180
88181 private static GeometryCollection ParseGeometryCollection ( JToken shape , JsonSerializer serializer )
89182 {
@@ -128,11 +221,11 @@ private static LineStringGeoShape ParseLineStringGeoShape(JToken shape, JsonSeri
128221 private static EnvelopeGeoShape ParseEnvelopeGeoShape ( JToken shape , JsonSerializer serializer ) =>
129222 new EnvelopeGeoShape { Coordinates = GetCoordinates < IEnumerable < GeoCoordinate > > ( shape , serializer ) } ;
130223
131- private static CircleGeoShape ParseCircleGeoShape ( JToken shape , JsonSerializer serializer , JToken radius ) =>
224+ private static CircleGeoShape ParseCircleGeoShape ( JToken shape , JsonSerializer serializer ) =>
132225 new CircleGeoShape
133226 {
134227 Coordinates = GetCoordinates < GeoCoordinate > ( shape , serializer ) ,
135- Radius = radius ? . Value < string > ( )
228+ Radius = shape [ " radius" ] ? . Value < string > ( )
136229 } ;
137230
138231 private static T GetCoordinates < T > ( JToken shape , JsonSerializer serializer )
0 commit comments