package au.gov.amsa.geo.model; import java.io.Serializable; import au.gov.amsa.risky.format.HasPosition; import com.google.common.base.Optional; /** * A latitude longitude rectangle bordered by rhumb lines east-west and * north-south. The rectangle is equal in degrees in width and height (but in * terms of distance this can of course vary depending on the location of the * cell on the earth). */ public class Cell implements Serializable { private static final long serialVersionUID = 5489135874617545438L; private static final double radiusEarthKm = 6371.01; private static final double KM_PER_NM = 1.852; private final long latIndex; private final long lonIndex; private final int hashCode; /** * Constructor. * * @param latIndex * @param lonIndex */ Cell(long latIndex, long lonIndex) { this.latIndex = latIndex; this.lonIndex = lonIndex; hashCode = calculateHashCode(); } public static Optional<Cell> cellAt(HasPosition p, Options options) { return cellAt(p.lat(), p.lon(), options); } public static Optional<Cell> cellAt(double lat, double lon, Options options) { return options.getGrid().cellAt(lat, lon); } public double leftEdgeLongitude(Options options) { return options.getGrid().leftEdgeLongitude(this); } public double rightEdgeLongitude(Options options) { return options.getGrid().rightEdgeLongitude(this); } public double topEdgeLatitude(Options options) { return options.getGrid().topEdgeLatitude(this); } public double bottomEdgeLatitude(Options options) { return options.getGrid().bottomEdgeLatitude(this); } public long getLatIndex() { return latIndex; } public long getLonIndex() { return lonIndex; } public double getCentreLon(Options options) { return options.getGrid().centreLon(lonIndex); } public double getCentreLat(Options options) { return options.getGrid().centreLat(latIndex); } /** * From http://mathforum.org/library/drmath/view/63767.html * * @param options * @return */ public double areaNauticalMiles(Options options) { double topLatRads = Math.toRadians(topEdgeLatitude(options)); double bottomLatRads = Math.toRadians(bottomEdgeLatitude(options)); return Math.PI / 180 * radiusEarthKm * radiusEarthKm * Math.abs(Math.sin(topLatRads) - Math.sin(bottomLatRads)) * options.getCellSizeDegreesAsDouble() / (KM_PER_NM * KM_PER_NM); } @Override public int hashCode() { return hashCode; } private int calculateHashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (latIndex ^ (latIndex >>> 32)); result = prime * result + (int) (lonIndex ^ (lonIndex >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Cell other = (Cell) obj; if (latIndex != other.latIndex) return false; if (lonIndex != other.lonIndex) return false; return true; } @Override public String toString() { return "Cell [latIndex=" + latIndex + ", lonIndex=" + lonIndex + "]"; } }