/* Copyright 2011 Austin Wagner * * This file is part of Mobile Shuttle Tracker. * * Mobile Shuttle Tracker is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Mobile Shuttle Tracker is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Mobile Shuttle Tracker. If not, see <http://www.gnu.org/licenses/>. */ package com.abstractedsheep.shuttletrackerworld; public class Coordinate { private final int latitudeE6; private final int longitudeE6; private final double latitude; private final double longitude; public int getLatitudeE6() { return this.latitudeE6; } public int getLongitudeE6() { return this.longitudeE6; } public Coordinate(int latitudeE6, int longitudeE6) { this.latitudeE6 = latitudeE6; this.latitude = latitudeE6 / 1E6; this.longitudeE6 = longitudeE6; this.longitude = longitudeE6 / 1E6; } public double distanceTo(Coordinate c) { double earthRadius = 3956; // Miles double dlong = degToRad(c.longitude - this.longitude); double dlat = degToRad(c.latitude - this.latitude); double lat1 = degToRad(this.latitude); double lat2 = degToRad(c.latitude); double a = Math.pow(Math.sin(dlat / 2.0), 2) + Math.pow(Math.sin(dlong / 2.0), 2) * Math.cos(lat1) * Math.cos(lat2); double b = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a)); return earthRadius * b; } public double bearingTowards(Coordinate c) { double dlong = this.longitude - c.longitude; double y = Math.sin(dlong) * Math.cos(c.latitude); double x = Math.cos(this.latitude) * Math.sin(c.latitude) - Math.sin(this.latitude) * Math.cos(c.latitude) * Math.cos(dlong); return radToDeg(Math.atan2(x, y)); } public Coordinate closestPoint(Coordinate endpoint1, Coordinate endpoint2) { double R = 3956; Point3D ep1cart = new Point3D( R * Math.cos(degToRad(endpoint1.latitude)) * Math.cos(degToRad(endpoint1.longitude)), R * Math.cos(degToRad(endpoint1.latitude)) * Math.sin(degToRad(endpoint1.longitude)), R * Math.sin(degToRad(endpoint1.latitude))); Point3D ep2cart = new Point3D( R * Math.cos(degToRad(endpoint2.latitude)) * Math.cos(degToRad(endpoint2.longitude)), R * Math.cos(degToRad(endpoint2.latitude)) * Math.sin(degToRad(endpoint2.longitude)), R * Math.sin(degToRad(endpoint2.latitude))); Point3D ptcart = new Point3D( R * Math.cos(degToRad(this.latitude)) * Math.cos(degToRad(this.longitude)), R * Math.cos(degToRad(this.latitude)) * Math.sin(degToRad(this.longitude)), R * Math.sin(degToRad(this.latitude))); Point3D origin = new Point3D(0, 0, 0); double d = ptcart.subtract(ep1cart).crossProduct(ptcart.subtract(ep2cart)).magnitude() / ep2cart.subtract(ep1cart).magnitude(); double hypotenuse = ptcart.distanceTo(ep1cart); double theta = Math.asin(d / hypotenuse); double adjacent = d / Math.tan(theta); Point3D closestcart = ep1cart.moveTowards(ep2cart, adjacent); Point3D surfacecart = origin.moveTowards(closestcart, R); return new Coordinate( (int)(radToDeg(Math.asin(surfacecart.getZ() / R)) * 1E6), (int)(radToDeg(Math.atan2(surfacecart.getY(), surfacecart.getX())) * 1E6)); } private double degToRad(double degrees) { return degrees / 180.0 * Math.PI; } private double radToDeg(double rad) { return rad * 180.0 / Math.PI; } @Override public String toString() { return "(" + (this.latitudeE6 / 1E6) + ", " + (this.longitudeE6 / 1E6) + ")"; } @Override public boolean equals(Object obj) { if (obj == null) return false; try { Coordinate c = (Coordinate) obj; return this.latitudeE6 == c.latitudeE6 && this.longitudeE6 == c.longitudeE6; } catch (ClassCastException e) { return false; } } @Override public int hashCode() { return this.latitudeE6 ^ this.longitudeE6; } }