/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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 Lucene.Net.Spatial.Utils; namespace Lucene.Net.Spatial.Geometry { public abstract class LatLng { public abstract bool IsNormalized(); public abstract bool IsFixedPoint(); public abstract LatLng Normalize(); public abstract int GetFixedLat(); public abstract int GetFixedLng(); public abstract double GetLat(); public abstract double GetLng(); public abstract LatLng Copy(); public abstract FixedLatLng ToFixed(); public abstract FloatLatLng ToFloat(); /// /// Convert the lat/lng into the cartesian coordinate plane such that all /// world coordinates are represented in the first quadrant. /// The x dimension corresponds to latitude and y corresponds to longitude. /// The translation starts with the normalized latlng and adds 180 to the latitude and /// 90 to the longitude (subject to fixed point scaling). /// public CartesianPoint ToCartesian() { LatLng ll = Normalize(); int lat = ll.GetFixedLat(); int lng = ll.GetFixedLng(); return new CartesianPoint( lng + 180 * FixedLatLng.ScaleFactorInt, lat + 90 * FixedLatLng.ScaleFactorInt ); } /// ///The inverse of ToCartesian(). Always returns a FixedLatLng. /// public static LatLng FromCartesian(CartesianPoint pt) { int lat = pt.Y - 90 * FixedLatLng.ScaleFactorInt; int lng = pt.X - 180 * FixedLatLng.ScaleFactorInt; return new FixedLatLng(lat, lng); } /// /// Calculates the distance between two lat/lng's in miles. /// /// The lat lng. /// Returns the distance in miles public double ArcDistance(LatLng ll2) { return ArcDistance(ll2, DistanceUnits.MILES); } /// ///Calculates the distance between two lat/lng's in miles or meters. /// /// Second lat,lng position to calculate distance to. /// Units to calculate distance, defaults to miles /// Returns the distance in meters or miles public double ArcDistance(LatLng ll2, DistanceUnits lUnits) { LatLng ll1 = Normalize(); ll2 = ll2.Normalize(); double lat1 = ll1.GetLat(), lng1 = ll1.GetLng(); double lat2 = ll2.GetLat(), lng2 = ll2.GetLng(); // Check for same position if (lat1 == lat2 && lng1 == lng2) return 0.0; // Get the m_dLongitude difference. Don't need to worry about // crossing 180 since cos(x) = cos(-x) double dLon = lng2 - lng1; double a = Radians(90.0 - lat1); double c = Radians(90.0 - lat2); double cosB = (Math.Cos(a) * Math.Cos(c)) + (Math.Sin(a) * Math.Sin(c) * Math.Cos(Radians(dLon))); double radius = (lUnits == DistanceUnits.MILES) ? 3963.205 /* MILERADIUSOFEARTH */ : 6378.160187 /* KMRADIUSOFEARTH */; // Find angle subtended (with some bounds checking) in radians and // multiply by earth radius to find the arc distance if (cosB < -1.0) return MathHelper.PI * radius; if (cosB >= 1.0) return 0; return Math.Acos(cosB) * radius; } private static double Radians(double a) { return a * 0.01745329251994; } public override string ToString() { return string.Format("[{0},{1}]", GetLat(), GetLng()); } /// /// Calculate the midpoint between this point an another. Respects fixed vs floating point /// /// The other. /// public abstract LatLng CalculateMidpoint(LatLng other); public abstract int GetHashCode(); public abstract bool Equals(Object obj); } }