/* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
using System;
using System.Globalization;
using System.Runtime.Serialization;
using OpenSearch.Net.Utf8Json;
/*
* Taken from SolrNet https://github.com/mausch/SolrNet/blob/master/SolrNet/Location.cs
*/
namespace OpenSearch.Client
{
///
/// Represents a Latitude/Longitude as a 2 dimensional point that gets serialized as { lat, lon }
///
[JsonFormatter(typeof(GeoLocationFormatter))]
public class GeoLocation : IEquatable, IFormattable
{
///
/// Represents a Latitude/Longitude as a 2 dimensional point.
///
public GeoLocation(double latitude, double longitude)
{
Latitude = latitude;
Longitude = longitude;
}
///
/// Latitude
///
[DataMember(Name = "lat")]
public double Latitude { get; }
///
/// Longitude
///
[DataMember(Name = "lon")]
public double Longitude { get; }
[IgnoreDataMember]
internal GeoFormat Format { get; set; }
public bool Equals(GeoLocation other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return Latitude.Equals(other.Latitude) && Longitude.Equals(other.Longitude);
}
public string ToString(string format, IFormatProvider formatProvider) => ToString();
///
/// Checks if is a valid latitude between -90 and 90, inclusive.
///
///
///
public static bool IsValidLatitude(double latitude) => latitude >= -90 && latitude <= 90;
///
/// Checks if is a valid longitude between -180 and 180, inclusive.
///
///
///
public static bool IsValidLongitude(double longitude) => longitude >= -180 && longitude <= 180;
///
/// Try to create a .
///
///
///
///
public static GeoLocation TryCreate(double latitude, double longitude) => new GeoLocation(latitude, longitude);
public override string ToString() =>
Latitude.ToString("#0.0#######", CultureInfo.InvariantCulture) + "," +
Longitude.ToString("#0.0#######", CultureInfo.InvariantCulture);
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
if (obj.GetType() != GetType())
return false;
return Equals((GeoLocation)obj);
}
public override int GetHashCode() =>
unchecked((Latitude.GetHashCode() * 397) ^ Longitude.GetHashCode());
public static implicit operator GeoLocation(string latLon)
{
if (string.IsNullOrEmpty(latLon))
throw new ArgumentNullException(nameof(latLon));
var parts = latLon.Split(',');
if (parts.Length != 2) throw new ArgumentException("Invalid format: string must be in the form of lat,lon");
if (!double.TryParse(parts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out var lat))
throw new ArgumentException("Invalid latitude value");
if (!double.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var lon))
throw new ArgumentException("Invalid longitude value");
return new GeoLocation(lat, lon);
}
public static implicit operator GeoLocation(double[] lonLat) => lonLat.Length != 2
? null
: new GeoLocation(lonLat[1], lonLat[0]);
}
///
/// Represents a Latitude/Longitude and optional Z value as a 2 or 3 dimensional point
/// that gets serialized as new [] { lon, lat, [z] }
///
[JsonFormatter(typeof(GeoCoordinateFormatter))]
public class GeoCoordinate : GeoLocation
{
///
/// Creates a new instance of
///
public GeoCoordinate(double latitude, double longitude) : base(latitude, longitude) { }
///
/// Creates a new instance of
///
public GeoCoordinate(double latitude, double longitude, double z) : base(latitude, longitude) =>
Z = z;
///
/// Gets or sets the Z value
///
public double? Z { get; set; }
///
/// Creates a new instance of from an array
/// of 2 or 3 doubles, in the order Latitude, Longitude, and optional Z value.
/// Returns null if coordinates are null
/// If the array does not contain 2 or 3 values
///
public static implicit operator GeoCoordinate(double[] coordinates)
{
if (coordinates == null) return null;
switch (coordinates.Length)
{
case 2:
return new GeoCoordinate(coordinates[0], coordinates[1]);
case 3:
return new GeoCoordinate(coordinates[0], coordinates[1], coordinates[2]);
default:
throw new ArgumentOutOfRangeException(
nameof(coordinates),
$"Cannot create a {nameof(GeoCoordinate)} from an array that does not contain 2 or 3 values");
}
}
}
}