/* * 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.Shape { /// /// Lat-long rect. Instances are mutable. /// public class LLRect { private LatLng _ll; private LatLng _ur; public LLRect(LatLng ll, LatLng ur) { _ll = ll; _ur = ur; } public LLRect(LLRect other) { _ll = other._ll; _ur = other._ur; } /// /// Return the area in units of lat-lng squared. This is a contrived unit /// that only has value when comparing to something else. /// public double Area() { return Math.Abs((_ll.GetLat() - _ur.GetLat()) * (_ll.GetLng() - _ur.GetLng())); } public LatLng GetLowerLeft() { return _ll; } public LatLng GetUpperRight() { return _ur; } public LatLng GetMidpoint() { return _ll.CalculateMidpoint(_ur); } /// /// Approximates a box centered at the given point with the given width and height in miles. /// /// The center. /// The width mi. /// The height mi. /// public static LLRect CreateBox(LatLng center, double widthMi, double heightMi) { double d = widthMi; LatLng ur = BoxCorners(center, d, 45.0); // assume right angles LatLng ll = BoxCorners(center, d, 225.0); return new LLRect(ll, ur); } private static LatLng BoxCorners(LatLng center, double d, double brngdeg) { double a = center.GetLat(); double b = center.GetLng(); double R = 3963.0; // radius of earth in miles double brng = (MathHelper.PI * brngdeg / 180); double lat1 = (MathHelper.PI * a / 180); double lon1 = (MathHelper.PI * b / 180); // Haversine formula double lat2 = Math.Asin(Math.Sin(lat1) * Math.Cos(d / R) + Math.Cos(lat1) * Math.Sin(d / R) * Math.Cos(brng)); double lon2 = lon1 + Math.Atan2(Math.Sin(brng) * Math.Sin(d / R) * Math.Cos(lat1), Math.Cos(d / R) - Math.Sin(lat1) * Math.Sin(lat2)); lat2 = (lat2 * 180) / MathHelper.PI; lon2 = (lon2 * 180) / MathHelper.PI; // normalize long first LatLng ll = NormLng(lat2, lon2); // normalize lat - could flip poles ll = NormLat(ll.GetLat(), ll.GetLng()); return ll; } /// /// Returns a normalized Lng rectangle shape for the bounding box /// private static LatLng NormLng(double lat, double lng) { if (lng > 180.0) { lng = -1.0 * (180.0 - (lng - 180.0)); } else if (lng < -180.0) { lng = (lng + 180.0) + 180.0; } LatLng ll = new FloatLatLng(lat, lng); return ll; } /// /// Returns a normalized Lat rectangle shape for the bounding box /// If you go over the poles, you need to flip the lng value too /// private static LatLng NormLat(double lat, double lng) { if (lat > 90.0) { lat = 90.0 - (lat - 90.0); if (lng < 0) { lng = lng + 180; } else { lng = lng - 180; } } else if (lat < -90.0) { lat = -90.0 - (lat + 90.0); if (lng < 0) { lng = lng + 180; } else { lng = lng - 180; } } LatLng ll = new FloatLatLng(lat, lng); return ll; } public Rectangle ToRectangle() { return new Rectangle(_ll.GetLng(), _ll.GetLat(), _ur.GetLng(), _ur.GetLat()); } public override string ToString() { return "{" + _ll +", " + _ur +"}"; } public override int GetHashCode() { const int prime = 31; int result = 1; result = prime * result + ((_ll == null) ? 0 : _ll.GetHashCode()); result = prime * result + ((_ur == null) ? 0 : _ur.GetHashCode()); return result; } public override bool Equals(object obj) { if (this == obj) return true; if (obj == null) return false; if (GetType() != obj.GetType()) return false; var other = (LLRect)obj; if (_ll == null) { if (other._ll != null) return false; } else if (!_ll.Equals(other._ll)) return false; if (_ur == null) { if (other._ur != null) return false; } else if (!_ur.Equals(other._ur)) return false; return true; } } }