/* * Copyright 2013 Google Inc. * * 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 com.google.maps.android; import com.google.android.gms.maps.model.LatLng; import java.util.List; import static com.google.maps.android.MathUtil.arcHav; import static com.google.maps.android.MathUtil.havDistance; import static java.lang.Math.PI; import static java.lang.Math.abs; import static java.lang.Math.atan2; import static java.lang.Math.cos; import static java.lang.Math.sin; import static java.lang.Math.tan; import static java.lang.Math.toRadians; public class SphericalUtil { private final static double EARTH_RADIUS = 6371000; private SphericalUtil() { } /** * Returns distance on the unit sphere; the arguments are in radians. */ private static double distanceRadians(double lat1, double lng1, double lat2, double lng2) { return arcHav(havDistance(lat1, lat2, lng1 - lng2)); } /** * Returns the angle between two LatLngs, in radians. This is the same as the distance * on the unit sphere. */ private static double computeAngleBetween(LatLng from, LatLng to) { return distanceRadians(toRadians(from.latitude), toRadians(from.longitude), toRadians(to.latitude), toRadians(to.longitude)); } /** * Returns the distance between two LatLngs, in meters. */ public static double computeDistanceBetween(LatLng from, LatLng to) { return computeAngleBetween(from, to) * EARTH_RADIUS; } /** * Returns the area of a closed path on Earth. * * @param path A closed path. * @return The path's area in square meters. */ public static double computeArea(List<LatLng> path) { return abs(computeSignedArea(path)); } /** * Returns the signed area of a closed path on a sphere of given radius. * The computed area uses the same units as the radius squared. * Used by SphericalUtilTest. */ private static double computeSignedArea(List<LatLng> path) { int size = path.size(); if (size < 3) { return 0; } double total = 0; LatLng prev = path.get(size - 1); double prevTanLat = tan((PI / 2 - toRadians(prev.latitude)) / 2); double prevLng = toRadians(prev.longitude); // For each edge, accumulate the signed area of the triangle formed by the North Pole // and that edge ("polar triangle"). for (LatLng point : path) { double tanLat = tan((PI / 2 - toRadians(point.latitude)) / 2); double lng = toRadians(point.longitude); total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng); prevTanLat = tanLat; prevLng = lng; } return total * (EARTH_RADIUS * EARTH_RADIUS); } /** * Returns the signed area of a triangle which has North Pole as a vertex. * Formula derived from "Area of a spherical triangle given two edges and the included angle" * as per "Spherical Trigonometry" by Todhunter, page 71, section 103, point 2. * See http://books.google.com/books?id=3uBHAAAAIAAJ&pg=PA71 * The arguments named "tan" are tan((pi/2 - latitude)/2). */ private static double polarTriangleArea(double tan1, double lng1, double tan2, double lng2) { double deltaLng = lng1 - lng2; double t = tan1 * tan2; return 2 * atan2(t * sin(deltaLng), 1 + t * cos(deltaLng)); } }