public static CartesianPoint FromWellKnownText(string wkt)
        {
            using var tokenizer = new WellKnownTextTokenizer(new StringReader(wkt));
            var token = tokenizer.NextToken();

            if (token != TokenType.Word)
            {
                throw new GeoWKTException(
                          $"Expected word but found {tokenizer.TokenString()}", tokenizer.LineNumber, tokenizer.Position);
            }

            var type = tokenizer.TokenValue.ToUpperInvariant();

            if (type != GeoShapeType.Point)
            {
                throw new GeoWKTException(
                          $"Expected {GeoShapeType.Point} but found {type}", tokenizer.LineNumber, tokenizer.Position);
            }

            if (GeoWKTReader.NextEmptyOrOpen(tokenizer) == TokenType.Word)
            {
                return(null);
            }

            var x = Convert.ToSingle(GeoWKTReader.NextNumber(tokenizer));
            var y = Convert.ToSingle(GeoWKTReader.NextNumber(tokenizer));

            // ignore any z value for now
            if (GeoWKTReader.IsNumberNext(tokenizer))
            {
                GeoWKTReader.NextNumber(tokenizer);
            }

            var point = new CartesianPoint(x, y)
            {
                Format = ShapeFormat.WellKnownText
            };

            GeoWKTReader.NextCloser(tokenizer);

            return(point);
        }
        public GeoLocation Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
        {
            switch (reader.GetCurrentJsonToken())
            {
            case JsonToken.Null:
                reader.ReadNext();
                return(null);

            case JsonToken.String:
                var wkt = reader.ReadString();
                using (var tokenizer = new WellKnownTextTokenizer(new StringReader(wkt)))
                {
                    var token = tokenizer.NextToken();
                    if (token != TokenType.Word)
                    {
                        throw new GeoWKTException(
                                  $"Expected word but found {tokenizer.TokenString()}", tokenizer.LineNumber, tokenizer.Position);
                    }

                    var type = tokenizer.TokenValue.ToUpperInvariant();
                    if (type != GeoShapeType.Point)
                    {
                        throw new GeoWKTException(
                                  $"Expected {GeoShapeType.Point} but found {type}", tokenizer.LineNumber, tokenizer.Position);
                    }

                    if (GeoWKTReader.NextEmptyOrOpen(tokenizer) == TokenType.Word)
                    {
                        return(null);
                    }

                    var lon = GeoWKTReader.NextNumber(tokenizer);
                    var lat = GeoWKTReader.NextNumber(tokenizer);
                    return(new GeoLocation(lat, lon)
                    {
                        Format = GeoFormat.WellKnownText
                    });
                }

            default:
            {
                var    count = 0;
                double lat   = 0;
                double lon   = 0;
                while (reader.ReadIsInObject(ref count))
                {
                    var propertyName = reader.ReadPropertyNameSegmentRaw();
                    if (Fields.TryGetValue(propertyName, out var value))
                    {
                        switch (value)
                        {
                        case 0:
                            lat = reader.ReadDouble();
                            break;

                        case 1:
                            lon = reader.ReadDouble();
                            break;
                        }
                    }
                    else
                    {
                        reader.ReadNextBlock();
                    }
                }

                return(new GeoLocation(lat, lon)
                    {
                        Format = GeoFormat.GeoJson
                    });
            }
            }
        }