public static string EncodePolygon(GeoLinearRing linearRing) { Argument.AssertNotNull(linearRing, nameof(linearRing)); StringBuilder odata = new("geography'POLYGON(("); bool first = true; foreach (GeoPosition position in linearRing.Coordinates) { if (!first) { odata.Append(','); } else { first = false; } odata.Append(JsonSerialization.Double(position.Longitude, CultureInfo.InvariantCulture)) .Append(' ') .Append(JsonSerialization.Double(position.Latitude, CultureInfo.InvariantCulture)); } return(odata .Append("))'") .ToString()); }
/// <summary> /// Encodes the longitude and latitude of points or positions for use in OData filters. /// </summary> /// <param name="longitude">The longitude to encode, which may also be known as Y.</param> /// <param name="latitude">The latitude to encode, which may also be known as X.</param> /// <returns>The OData filter-encoded POINT string.</returns> public static string EncodePoint(double longitude, double latitude) { const int maxLength = 19 + // "geography'POINT( )'".Length 2 * // Lat and Long each have: (15 + // Maximum precision for a double (without G17) 1 + // Optional decimal point 1); // Optional negative sign return(new StringBuilder(maxLength) .Append("geography'POINT(") .Append(JsonSerialization.Double(longitude, CultureInfo.InvariantCulture)) .Append(" ") .Append(JsonSerialization.Double(latitude, CultureInfo.InvariantCulture)) .Append(")'") .ToString()); }
/// <summary> /// Convert a <see cref="GeometryPosition"/> to an OData value. /// </summary> /// <param name="position">The position.</param> /// <returns>The OData representation of the position.</returns> private static string EncodeGeometry(GeometryPosition position) { const int maxLength = 19 + // "geography'POINT( )'".Length 2 * // Lat and Long each have: (15 + // Maximum precision for a double (without G17) 1 + // Optional decimal point 1); // Optional negative sign StringBuilder odata = new StringBuilder(maxLength); odata.Append("geography'POINT("); odata.Append(JsonSerialization.Double(position.Longitude, CultureInfo.InvariantCulture)); odata.Append(" "); odata.Append(JsonSerialization.Double(position.Latitude, CultureInfo.InvariantCulture)); odata.Append(")'"); return(odata.ToString()); }
/// <summary> /// Encodes a polygon for use in OData filters. /// </summary> /// <param name="line">The <see cref="GeographyLineStringProxy"/> to encode.</param> /// <returns>The OData filter-encoded POLYGON string.</returns> /// <exception cref="ArgumentException">The <paramref name="line"/> has fewer than 4 points, or the first and last points do not match.</exception> /// <exception cref="ArgumentNullException"><paramref name="line"/> or <see cref="GeographyLineStringProxy.Points"/> is null.</exception> public static string EncodePolygon(GeographyLineStringProxy line) { Argument.AssertNotNull(line, nameof(line)); Argument.AssertNotNull(line.Points, $"{nameof(line)}.{nameof(line.Points)}"); if (line.Points.Count < 4) { #pragma warning disable CA2208 // Instantiate argument exceptions correctly throw new ArgumentException( $"A GeographyLineString must have at least four Points to form a searchable polygon.", $"{nameof(line)}.{nameof(line.Points)}"); #pragma warning restore CA2208 // Instantiate argument exceptions correctly } else if (line.Points[0] != line.Points[line.Points.Count - 1]) { #pragma warning disable CA2208 // Instantiate argument exceptions correctly throw new ArgumentException( $"A GeographyLineString must have matching first and last Points to form a searchable polygon.", $"{nameof(line)}.{nameof(line.Points)}"); #pragma warning restore CA2208 // Instantiate argument exceptions correctly } StringBuilder odata = new StringBuilder("geography'POLYGON(("); bool first = true; foreach (GeographyPointProxy position in line.Points) { if (!first) { odata.Append(','); } else { first = false; } odata.Append(JsonSerialization.Double(position.Longitude, CultureInfo.InvariantCulture)) .Append(' ') .Append(JsonSerialization.Double(position.Latitude, CultureInfo.InvariantCulture)); } return(odata .Append("))'") .ToString()); }
// Support for both Azure.Core.GeoJson and Microsoft.Spatial encoding are duplicated // below to avoid extraneous allocations for adapters and to consolidate them to a single // source file for easier maintenance. #if EXPERIMENTAL_SPATIAL /// <summary> /// Encodes a polygon for use in OData filters. /// </summary> /// <param name="line">The <see cref="GeoLine"/> to encode.</param> /// <returns>The OData filter-encoded POLYGON string.</returns> /// <exception cref="ArgumentException">The <paramref name="line"/> has fewer than 4 points, or the first and last points do not match.</exception> /// <exception cref="ArgumentNullException"><paramref name="line"/> or <see cref="GeoLine.Positions"/> is null.</exception> public static string EncodePolygon(GeoLine line) { Argument.AssertNotNull(line, nameof(line)); Argument.AssertNotNull(line.Positions, $"{nameof(line)}.{nameof(line.Positions)}"); if (line.Positions.Count < 4) { throw new ArgumentException( $"A {nameof(GeoLine)} must have at least four {nameof(GeoLine.Positions)} to form a searchable polygon.", $"{nameof(line)}.{nameof(line.Positions)}"); } else if (line.Positions[0] != line.Positions[line.Positions.Count - 1]) { throw new ArgumentException( $"A {nameof(GeoLine)} must have matching first and last {nameof(GeoLine.Positions)} to form a searchable polygon.", $"{nameof(line)}.{nameof(line.Positions)}"); } StringBuilder odata = new StringBuilder("geography'POLYGON(("); bool first = true; foreach (GeoPosition position in line.Positions) { if (!first) { odata.Append(","); } else { first = false; } odata.Append(JsonSerialization.Double(position.Longitude, CultureInfo.InvariantCulture)) .Append(" ") .Append(JsonSerialization.Double(position.Latitude, CultureInfo.InvariantCulture)); } return(odata .Append("))'") .ToString()); }
/// <summary> /// Convert a <see cref="LineGeometry"/> forming a polygon to an OData /// value. A LineGeometry must have at least four /// <see cref="LineGeometry.Positions"/> and the first and last must /// match to form a searchable polygon. /// </summary> /// <param name="line">The line forming a polygon.</param> /// <returns>The OData representation of the line.</returns> private static string EncodeGeometry(LineGeometry line) { Argument.AssertNotNull(line, nameof(line)); Argument.AssertNotNull(line.Positions, $"{nameof(line)}.{nameof(line.Positions)}"); if (line.Positions.Count < 4) { throw new ArgumentException( $"A {nameof(LineGeometry)} must have at least four {nameof(LineGeometry.Positions)} to form a searchable polygon.", $"{nameof(line)}.{nameof(line.Positions)}"); } else if (line.Positions[0] != line.Positions[line.Positions.Count - 1]) { throw new ArgumentException( $"A {nameof(LineGeometry)} must have matching first and last {nameof(LineGeometry.Positions)} to form a searchable polygon.", $"{nameof(line)}.{nameof(line.Positions)}"); } Argument.AssertInRange(line.Positions?.Count ?? 0, 4, int.MaxValue, $"{nameof(line)}.{nameof(line.Positions)}"); StringBuilder odata = new StringBuilder(); odata.Append("geography'POLYGON(("); bool first = true; foreach (GeometryPosition position in line.Positions) { if (!first) { odata.Append(","); } first = false; odata.Append(JsonSerialization.Double(position.Longitude, CultureInfo.InvariantCulture)); odata.Append(" "); odata.Append(JsonSerialization.Double(position.Latitude, CultureInfo.InvariantCulture)); } odata.Append("))'"); return(odata.ToString()); }
/// <summary> /// Create an OData filter expression from an interpolated string. The /// interpolated values will be quoted and escaped as necessary. /// </summary> /// <param name="filter">An interpolated filter string.</param> /// <param name="formatProvider"> /// Format provider used to convert values to strings. /// <see cref="CultureInfo.InvariantCulture"/> is used as a default. /// </param> /// <returns>A valid OData filter expression.</returns> public static string Create(FormattableString filter, IFormatProvider formatProvider) { if (filter == null) { return(null); } formatProvider ??= CultureInfo.InvariantCulture; string[] args = new string[filter.ArgumentCount]; for (int i = 0; i < filter.ArgumentCount; i++) { args[i] = filter.GetArgument(i) switch { // Null null => "null", // Boolean bool x => x.ToString(formatProvider).ToLowerInvariant(), // Numeric sbyte x => x.ToString(formatProvider), byte x => x.ToString(formatProvider), short x => x.ToString(formatProvider), ushort x => x.ToString(formatProvider), int x => x.ToString(formatProvider), uint x => x.ToString(formatProvider), long x => x.ToString(formatProvider), ulong x => x.ToString(formatProvider), decimal x => x.ToString(formatProvider), // Floating point float x => JsonSerialization.Float(x, formatProvider), double x => JsonSerialization.Double(x, formatProvider), // Dates as 8601 with a time zone DateTimeOffset x => JsonSerialization.Date(x, formatProvider), DateTime x => JsonSerialization.Date(x, formatProvider), #if EXPERIMENTAL_SPATIAL // Points GeometryPosition x => EncodeGeometry(x), PointGeometry x => EncodeGeometry(x), // Polygons LineGeometry x => EncodeGeometry(x), PolygonGeometry x => EncodeGeometry(x), #endif // Text string x => Quote(x), char x => Quote(x.ToString(formatProvider)), StringBuilder x => Quote(x.ToString()), // Everything else object x => throw new ArgumentException( $"Unable to convert argument {i} from type {x.GetType()} to an OData literal.") }; } string text = string.Format(formatProvider, filter.Format, args); return(text); }