/*******************************************************************************
* Copyright 2014 Geoscience Australia
*
* Licensed 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.
******************************************************************************/
package au.gov.ga.earthsci.worldwind.common.layers;
import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Sector;
/**
* Basic implementation of {@link Bounds}.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class Bounds
{
public final Position minimum;
public final Position maximum;
public final Position center;
public final Angle deltaLatitude;
public final Angle deltaLongitude;
public final double deltaElevation;
public static Bounds fromSector(Sector sector)
{
return fromSector(sector, 0, 0);
}
public static Bounds fromSector(Sector sector, double minimumElevation, double maximumElevation)
{
Position minimum = new Position(sector.getMinLatitude(), sector.getMinLongitude(), minimumElevation);
Position maximum = new Position(sector.getMaxLatitude(), sector.getMaxLongitude(), maximumElevation);
return new Bounds(minimum, maximum);
}
public static Bounds union(Bounds bounds1, Bounds bounds2)
{
if (bounds1 == null)
{
return bounds2;
}
if (bounds2 == null)
{
return bounds1;
}
Position minimum1 = bounds1.getMinimum();
Position minimum2 = bounds2.getMinimum();
Position maximum1 = bounds1.getMaximum();
Position maximum2 = bounds2.getMaximum();
Position minimum = Position.fromDegrees(
Math.min(minimum1.latitude.degrees, minimum2.latitude.degrees),
Math.min(minimum1.longitude.degrees, minimum2.longitude.degrees),
Math.min(minimum1.elevation, minimum2.elevation));
Position maximum = Position.fromDegrees(
Math.max(maximum1.latitude.degrees, maximum2.latitude.degrees),
Math.max(maximum1.longitude.degrees, maximum2.longitude.degrees),
Math.max(maximum1.elevation, maximum2.elevation));
return new Bounds(minimum, maximum);
}
public static Bounds union(Bounds bounds, Position position)
{
if (position == null)
{
return bounds;
}
if (bounds == null)
{
return new Bounds(position);
}
Position bminimum = bounds.getMinimum();
Position bmaximum = bounds.getMaximum();
Position minimum = Position.fromDegrees(
Math.min(bminimum.latitude.degrees, position.latitude.degrees),
Math.min(bminimum.longitude.degrees, position.longitude.degrees),
Math.min(bminimum.elevation, position.elevation));
Position maximum = Position.fromDegrees(
Math.max(bmaximum.latitude.degrees, position.latitude.degrees),
Math.max(bmaximum.longitude.degrees, position.longitude.degrees),
Math.max(bmaximum.elevation, position.elevation));
return new Bounds(minimum, maximum);
}
public Bounds(Position position)
{
this(position, position);
}
public Bounds(Position minimum, Position maximum)
{
this.minimum = minimum;
this.maximum = maximum;
this.center = Position.interpolate(0.5, minimum, maximum);
this.deltaLatitude = maximum.latitude.subtract(minimum.latitude);
this.deltaLongitude = maximum.longitude.subtract(minimum.longitude);
this.deltaElevation = maximum.elevation - minimum.elevation;
}
/**
* @return Minimum corner position of the bounding box
*/
public Position getMinimum()
{
return minimum;
}
/**
* @return Maximum corner position of the bounding box
*/
public Position getMaximum()
{
return maximum;
}
/**
* @return Center of the bounding box, sitting halfway on the line between
* the minimum and maximum corners
*/
public Position getCenter()
{
return center;
}
public Sector toSector()
{
return new Sector(minimum.latitude, maximum.latitude, minimum.longitude, maximum.longitude);
}
/**
* Calculate the union between these bounds and the given bounds.
*
* @param bounds
* @return Union between this and <code>bounds</code>
*/
public Bounds union(Bounds bounds)
{
return Bounds.union(this, bounds);
}
/**
* Calculate the union between these bounds and the given position.
*
* @param position
* @return Union between this and <code>position</code>
*/
public Bounds union(Position position)
{
return Bounds.union(this, position);
}
/**
* Do these bounds contain the given position, inclusive?
*
* @param position
* @return True if the bounds contain <code>position</code>
*/
public boolean contains(Position position)
{
return contains(position, true);
}
/**
* Do these bounds contain the given position?
*
* @param position
* @param inclusive
* If true, includes positions that lie on the boundary of the
* bounds
* @return True if the bounds contain <code>position</code>
*/
public boolean contains(Position position, boolean inclusive)
{
return lessThan(minimum.latitude.degrees, position.latitude.degrees, inclusive) &&
lessThan(position.latitude.degrees, maximum.latitude.degrees, inclusive) &&
lessThan(minimum.longitude.degrees, position.longitude.degrees, inclusive) &&
lessThan(position.longitude.degrees, maximum.longitude.degrees, inclusive) &&
lessThan(minimum.elevation, position.elevation, inclusive) &&
lessThan(position.elevation, maximum.elevation, inclusive);
}
private static boolean lessThan(double d1, double d2, boolean orEqualTo)
{
return orEqualTo ? d1 <= d2 : d1 < d2;
}
}