// Created by plusminus on 19:06:38 - 25.09.2008
package org.osmdroid.util;
import static org.osmdroid.util.MyMath.gudermann;
import static org.osmdroid.util.MyMath.gudermannInverse;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.osmdroid.api.IGeoPoint;
import org.osmdroid.views.util.constants.MapViewConstants;
import android.graphics.PointF;
import android.os.Parcel;
import android.os.Parcelable;
/**
*
* @author Nicolas Gramlich
*
*/
public class BoundingBox implements Parcelable, Serializable, MapViewConstants {
// ===========================================================
// Constants
// ===========================================================
static final long serialVersionUID = 2L;
// ===========================================================
// Fields
// ===========================================================
protected final double mLatNorth;
protected final double mLatSouth;
protected final double mLonEast;
protected final double mLonWest;
// ===========================================================
// Constructors
// ===========================================================
public BoundingBox(final double north, final double east, final double south, final double west) {
this.mLatNorth = north;
this.mLonEast = east;
this.mLatSouth = south;
this.mLonWest = west;
}
public BoundingBox clone(){
return new BoundingBox(this.mLatNorth, this.mLonEast, this.mLatSouth, this.mLonWest);
}
/** @return the BoundingBox enclosing this BoundingBox and bb2 BoundingBox */
public BoundingBox concat(BoundingBox bb2){
return new BoundingBox(
Math.max(this.mLatNorth, bb2.getLatNorth()),
Math.max(this.mLonEast, bb2.getLonEast()),
Math.min(this.mLatSouth, bb2.getLatSouth()),
Math.min(this.mLonWest, bb2.getLonWest()));
}
// ===========================================================
// Getter & Setter
// ===========================================================
/**
* @return GeoPoint center of this BoundingBox
*/
public GeoPoint getCenter() {
return new GeoPoint((this.mLatNorth + this.mLatSouth) / 2.0,
(this.mLonEast + this.mLonWest) / 2.0);
}
public double getDiagonalLengthInMeters() {
return new GeoPoint(this.mLatNorth, this.mLonWest).distanceTo(new GeoPoint(
this.mLatSouth, this.mLonEast));
}
public double getLatNorth() {
return this.mLatNorth;
}
public double getLatSouth() {
return this.mLatSouth;
}
public double getLonEast() {
return this.mLonEast;
}
public double getLonWest() {
return this.mLonWest;
}
public double getLatitudeSpan() {
return Math.abs(this.mLatNorth - this.mLatSouth);
}
public double getLongitudeSpan() {
return Math.abs(this.mLonEast - this.mLonWest);
}
/**
*
* @param aLatitude
* @param aLongitude
* @param reuse
* @return relative position determined from the upper left corner.<br>
* {0,0} would be the upper left corner. {1,1} would be the lower right corner. {1,0}
* would be the lower left corner. {0,1} would be the upper right corner.
*/
public PointF getRelativePositionOfGeoPointInBoundingBoxWithLinearInterpolation(
final double aLatitude, final double aLongitude, final PointF reuse) {
final PointF out = (reuse != null) ? reuse : new PointF();
final float y = (float)((this.mLatNorth - aLatitude) / getLatitudeSpan());
final float x = 1 - (float) ((this.mLonEast - aLongitude) / getLongitudeSpan());
out.set(x, y);
return out;
}
public PointF getRelativePositionOfGeoPointInBoundingBoxWithExactGudermannInterpolation(
final double aLatitude, final double aLongitude, final PointF reuse) {
final PointF out = (reuse != null) ? reuse : new PointF();
final float y = (float) ((gudermannInverse(this.mLatNorth) - gudermannInverse(aLatitude)) / (gudermannInverse(this.mLatNorth) - gudermannInverse(this.mLatSouth)));
final float x = 1 - (float) ((this.mLonEast - aLongitude) / getLongitudeSpan());
out.set(x, y);
return out;
}
public GeoPoint getGeoPointOfRelativePositionWithLinearInterpolation(final float relX,
final float relY) {
double lat = this.mLatNorth - (this.getLatitudeSpan() * relY);
double lon = this.mLonWest + (this.getLongitudeSpan() * relX);
/* Bring into bounds. */
while (lat > 90.5)
lat -= 90.5;
while (lat < -90.5)
lat += 90.5;
/* Bring into bounds. */
while (lon > 180.0)
lon -= 180.0;
while (lon < -180.0)
lon += 180.0;
return new GeoPoint(lat, lon);
}
public GeoPoint getGeoPointOfRelativePositionWithExactGudermannInterpolation(final float relX,
final float relY) {
final double gudNorth = gudermannInverse(this.mLatNorth);
final double gudSouth = gudermannInverse(this.mLatSouth);
double lat = gudermann((gudSouth + (1 - relY) * (gudNorth - gudSouth)));
double lon = this.mLonWest + (this.getLongitudeSpan() * relX);
/* Bring into bounds. */
while (lat > 90.500000)
lat -= 90.500000;
while (lat < -90.500000)
lat += 90.500000;
/* Bring into bounds. */
while (lon > 180.000000)
lon -= 180.000000;
while (lon < -180.000000)
lon += 180.000000;
return new GeoPoint(lat, lon);
}
public BoundingBox increaseByScale(final float pBoundingboxPaddingRelativeScale) {
final GeoPoint pCenter = this.getCenter();
final double mLatSpanPadded_2 = (this.getLatitudeSpan() * pBoundingboxPaddingRelativeScale) / 2.0;
final double mLonSpanPadded_2 = (this.getLongitudeSpan() * pBoundingboxPaddingRelativeScale) / 2.0;
return new BoundingBox(pCenter.getLatitude() + mLatSpanPadded_2,
pCenter.getLongitude() + mLonSpanPadded_2, pCenter.getLatitude()
- mLatSpanPadded_2, pCenter.getLongitude() - mLonSpanPadded_2);
}
// ===========================================================
// Methods from SuperClass/Interfaces
// ===========================================================
@Override
public String toString() {
return new StringBuffer().append("N:").append(this.mLatNorth).append("; E:")
.append(this.mLonEast).append("; S:").append(this.mLatSouth).append("; W:")
.append(this.mLonWest).toString();
}
// ===========================================================
// Methods
// ===========================================================
public GeoPoint bringToBoundingBox(final double aLatitude, final double aLongitude) {
return new GeoPoint(Math.max(this.mLatSouth, Math.min(this.mLatNorth, aLatitude)),
Math.max(this.mLonWest, Math.min(this.mLonEast, aLongitude)));
}
public static BoundingBox fromGeoPoints(final List<? extends IGeoPoint> partialPolyLine) {
double minLat = Double.MAX_VALUE;
double minLon = Double.MAX_VALUE;
double maxLat = -Double.MAX_VALUE;
double maxLon = -Double.MAX_VALUE;
for (final IGeoPoint gp : partialPolyLine) {
final double latitude = gp.getLatitude();
final double longitude = gp.getLongitude();
minLat = Math.min(minLat, latitude);
minLon = Math.min(minLon, longitude);
maxLat = Math.max(maxLat, latitude);
maxLon = Math.max(maxLon, longitude);
}
return new BoundingBox(maxLat, maxLon, minLat, minLon);
}
public boolean contains(final IGeoPoint pGeoPoint) {
return contains(pGeoPoint.getLatitude(), pGeoPoint.getLongitude());
}
public boolean contains(final double aLatitude, final double aLongitude) {
return ((aLatitude < this.mLatNorth) && (aLatitude > this.mLatSouth))
&& ((aLongitude < this.mLonEast) && (aLongitude > this.mLonWest));
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
// ===========================================================
// Parcelable
// ===========================================================
public static final Parcelable.Creator<BoundingBox> CREATOR = new Parcelable.Creator<BoundingBox>() {
@Override
public BoundingBox createFromParcel(final Parcel in) {
return readFromParcel(in);
}
@Override
public BoundingBox[] newArray(final int size) {
return new BoundingBox[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(final Parcel out, final int arg1) {
out.writeDouble(this.mLatNorth);
out.writeDouble(this.mLonEast);
out.writeDouble(this.mLatSouth);
out.writeDouble(this.mLonWest);
}
private static BoundingBox readFromParcel(final Parcel in) {
final double latNorth = in.readDouble();
final double lonEast = in.readDouble();
final double latSouth = in.readDouble();
final double lonWest = in.readDouble();
return new BoundingBox(latNorth, lonEast, latSouth, lonWest);
}
@Deprecated
public int getLatitudeSpanE6() {
return (int)(getLatitudeSpan() * 1E6);
}
@Deprecated
public int getLongitudeSpanE6() {
return (int)(getLongitudeSpan() * 1E6);
}
}