/******************************************************************************* * Copyright (c) 2015 Voyager Search and MITRE * All rights reserved. This program and the accompanying materials * are made available under the terms of the Apache License, Version 2.0 which * accompanies this distribution and is available at * http://www.apache.org/licenses/LICENSE-2.0.txt ******************************************************************************/ package org.locationtech.spatial4j.distance; import org.locationtech.spatial4j.context.SpatialContext; import org.locationtech.spatial4j.shape.Circle; import org.locationtech.spatial4j.shape.Point; import org.locationtech.spatial4j.shape.Rectangle; import static org.locationtech.spatial4j.distance.DistanceUtils.toDegrees; import static org.locationtech.spatial4j.distance.DistanceUtils.toRadians; /** * A base class for a Distance Calculator that assumes a spherical earth model. */ public abstract class GeodesicSphereDistCalc extends AbstractDistanceCalculator { private static final double radiusDEG = DistanceUtils.toDegrees(1);//in degrees @Override public Point pointOnBearing(Point from, double distDEG, double bearingDEG, SpatialContext ctx, Point reuse) { if (distDEG == 0) { if (reuse == null) return from; reuse.reset(from.getX(), from.getY()); return reuse; } Point result = DistanceUtils.pointOnBearingRAD( toRadians(from.getY()), toRadians(from.getX()), toRadians(distDEG), toRadians(bearingDEG), ctx, reuse);//output result is in radians result.reset(toDegrees(result.getX()), toDegrees(result.getY())); return result; } @Override public Rectangle calcBoxByDistFromPt(Point from, double distDEG, SpatialContext ctx, Rectangle reuse) { return DistanceUtils.calcBoxByDistFromPtDEG(from.getY(), from.getX(), distDEG, ctx, reuse); } @Override public double calcBoxByDistFromPt_yHorizAxisDEG(Point from, double distDEG, SpatialContext ctx) { return DistanceUtils.calcBoxByDistFromPt_latHorizAxisDEG(from.getY(), from.getX(), distDEG); } @Override public double area(Rectangle rect) { //From http://mathforum.org/library/drmath/view/63767.html double lat1 = toRadians(rect.getMinY()); double lat2 = toRadians(rect.getMaxY()); return Math.PI / 180 * radiusDEG * radiusDEG * Math.abs(Math.sin(lat1) - Math.sin(lat2)) * rect.getWidth(); } @Override public double area(Circle circle) { //formula is a simplified case of area(rect). double lat = toRadians(90 - circle.getRadius()); return 2 * Math.PI * radiusDEG * radiusDEG * (1 - Math.sin(lat)); } @Override public boolean equals(Object obj) { if (obj == null) return false; return getClass().equals(obj.getClass()); } @Override public int hashCode() { return getClass().hashCode(); } @Override public final double distance(Point from, double toX, double toY) { return toDegrees(distanceLatLonRAD(toRadians(from.getY()), toRadians(from.getX()), toRadians(toY), toRadians(toX))); } protected abstract double distanceLatLonRAD(double lat1, double lon1, double lat2, double lon2); public static class Haversine extends GeodesicSphereDistCalc { @Override protected double distanceLatLonRAD(double lat1, double lon1, double lat2, double lon2) { return DistanceUtils.distHaversineRAD(lat1,lon1,lat2,lon2); } } public static class LawOfCosines extends GeodesicSphereDistCalc { @Override protected double distanceLatLonRAD(double lat1, double lon1, double lat2, double lon2) { return DistanceUtils.distLawOfCosinesRAD(lat1, lon1, lat2, lon2); } } public static class Vincenty extends GeodesicSphereDistCalc { @Override protected double distanceLatLonRAD(double lat1, double lon1, double lat2, double lon2) { return DistanceUtils.distVincentyRAD(lat1, lon1, lat2, lon2); } } }