2010-04-14 30 views
41

Harita üzerinde bir daire çizmek için, bir GLatLng (A) merkezi ve metre cinsinden bir yarıçap (r) var.Bir noktanın enlemi nasıl hesaplanır?

  ----------- 
     --/   \-- 
     -/     \- 
    /     \ 
    /      \ 
/     r  \ 
    |   *-------------* 
    \    A   /B 
    \      /
    \     /
     -\     /- 
     --\   /-- 
      ----------- 

Nasıl pozisyon B GLatLng hesaplamak için: Burada

bir diyagram var? R'nin ekvator ile paralel olduğunu varsayarsak.

A ve B verildiğinde yarıçapı almak GLatLng.distanceFrom() yöntemini kullanarak önemsizdir, ancak bunu yapmanın başka bir yolu yoktur. Daha ağır bir matematik yapmam gerekiyor gibi görünüyor.

+0

@Rene : Cevabımı GMaps API v2'ye uyarlamanın basit olması gerekir. Ben sadece google.maps.LatLng'nın GLatLng ile değiştirilmesi meselesi olduğuna inanıyorum. Herhangi bir zorluk bulursan bana haber ver. –

+0

Teşekkürler, burada zorluk yok :) –

cevap

85

Biz bir rulman ve kaynak noktasından mesafeyi verildiğinde hedef noktasını döndüren bir yöntem gerekir. Neyse ki, Chris Veness tarafından Calculate distance, bearing and more between Latitude/Longitude points numaralı telefondan çok iyi bir JavaScript uygulaması var.

şu google.maps.LatLng sınıfla çalışmak üzere uyarlanmıştır:

<!DOCTYPE html> 
<html> 
<head> 
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
    <title>Google Maps Geometry</title> 
    <script src="http://maps.google.com/maps/api/js?sensor=false" 
      type="text/javascript"></script> 
</head> 
<body> 
    <div id="map" style="width: 400px; height: 300px"></div> 

    <script type="text/javascript"> 
     Number.prototype.toRad = function() { 
     return this * Math.PI/180; 
     } 

     Number.prototype.toDeg = function() { 
     return this * 180/Math.PI; 
     } 

     google.maps.LatLng.prototype.destinationPoint = function(brng, dist) { 
     dist = dist/6371; 
     brng = brng.toRad(); 

     var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); 

     var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) + 
           Math.cos(lat1) * Math.sin(dist) * Math.cos(brng)); 

     var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) * 
             Math.cos(lat1), 
             Math.cos(dist) - Math.sin(lat1) * 
             Math.sin(lat2)); 

     if (isNaN(lat2) || isNaN(lon2)) return null; 

     return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg()); 
     } 

     var pointA = new google.maps.LatLng(40.70, -74.00); // Circle center 
     var radius = 10;          // 10km 

     var mapOpt = { 
     mapTypeId: google.maps.MapTypeId.TERRAIN, 
     center: pointA, 
     zoom: 10 
     }; 

     var map = new google.maps.Map(document.getElementById("map"), mapOpt); 

     // Draw the circle 
     new google.maps.Circle({ 
     center: pointA, 
     radius: radius * 1000,  // Convert to meters 
     fillColor: '#FF0000', 
     fillOpacity: 0.2, 
     map: map 
     }); 

     // Show marker at circle center 
     new google.maps.Marker({ 
     position: pointA, 
     map: map 
     }); 

     // Show marker at destination point 
     new google.maps.Marker({ 
     position: pointA.destinationPoint(90, radius), 
     map: map 
     }); 
    </script> 
</body> 
</html> 
: Burada
var pointA = new google.maps.LatLng(25.48, -71.26); 
var radiusInKm = 10; 

var pointB = pointA.destinationPoint(90, radiusInKm); 

Google Maps API v3 kullanarak tam bir örnektir: aşağıdaki gibi

Number.prototype.toRad = function() { 
    return this * Math.PI/180; 
} 

Number.prototype.toDeg = function() { 
    return this * 180/Math.PI; 
} 

google.maps.LatLng.prototype.destinationPoint = function(brng, dist) { 
    dist = dist/6371; 
    brng = brng.toRad(); 

    var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); 

    var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) + 
         Math.cos(lat1) * Math.sin(dist) * Math.cos(brng)); 

    var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) * 
           Math.cos(lat1), 
           Math.cos(dist) - Math.sin(lat1) * 
           Math.sin(lat2)); 

    if (isNaN(lat2) || isNaN(lon2)) return null; 

    return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg()); 
} 

Sadece bunu kullanmak istiyorsunuz

Ekran Görüntüsü:

Google Maps Geometry

GÜNCELLEME: cevapta

aşağıdaki yorum Paul's için, bu çember etrafında kutuplara biri sarar olan bu işte.

var pointA = new google.maps.LatLng(85, 0); // Close to north pole 
    var radius = 1000;       // 1000km 

Ekran pointA.destinationPoint(90, radius) için: 1,000km yarıçapında, kuzey kutbuna yakın pointA basılıyor

size 2 enlem/Ing noktaları arasındaki mesafenin sonra ise

Close to north pole

+1

Bu, her zaman doğudaki hedef noktayı veriyor mu? – Nirmal

+4

@Nirmal: Hayır, destinationPoint() 'e ilettiğiniz ilk paramater'e bağlı. 90 Doğu, ancak 0 = Kuzey'den başlayarak, saat yönünde hareket eden herhangi bir yatak kullanabilirsiniz. –

+0

Teşekkürler, bu mükemmel. –

3

Bu sorunun cevabı ve daha burada bulunabilir: http://www.edwilliams.org/avform.htm

+0

Bu sayfada çok fazla acos, günah, bronzluk, vb görüyorum. Ama ben Daniel'in cevabına bağlı kalacağım. Yardım için teşekkürler. –

+0

@Paul, çok güzel bir bağlantı için teşekkürler ... – aProgrammer

+0

Bağlantıya şu andan itibaren bozuldu. –

3

Dünya yüzeyinin karşısındaki javascript'i burada bulabilirsiniz:

http://www.movable-type.co.uk/scripts/latlong-vincenty.html

Bu Kolayca java javascript kodu dönüştürebilir android.location.Location::distanceTo

de android API kullanılan aynı formüldür.

public class LatLngUtils { 

    /** 
    * @param lat1 
    *   Initial latitude 
    * @param lon1 
    *   Initial longitude 
    * @param lat2 
    *   destination latitude 
    * @param lon2 
    *   destination longitude 
    * @param results 
    *   To be populated with the distance, initial bearing and final 
    *   bearing 
    */ 

    public static void computeDistanceAndBearing(double lat1, double lon1, 
     double lat2, double lon2, double results[]) { 
    // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf 
    // using the "Inverse Formula" (section 4) 

    int MAXITERS = 20; 
    // Convert lat/long to radians 
    lat1 *= Math.PI/180.0; 
    lat2 *= Math.PI/180.0; 
    lon1 *= Math.PI/180.0; 
    lon2 *= Math.PI/180.0; 

    double a = 6378137.0; // WGS84 major axis 
    double b = 6356752.3142; // WGS84 semi-major axis 
    double f = (a - b)/a; 
    double aSqMinusBSqOverBSq = (a * a - b * b)/(b * b); 

    double L = lon2 - lon1; 
    double A = 0.0; 
    double U1 = Math.atan((1.0 - f) * Math.tan(lat1)); 
    double U2 = Math.atan((1.0 - f) * Math.tan(lat2)); 

    double cosU1 = Math.cos(U1); 
    double cosU2 = Math.cos(U2); 
    double sinU1 = Math.sin(U1); 
    double sinU2 = Math.sin(U2); 
    double cosU1cosU2 = cosU1 * cosU2; 
    double sinU1sinU2 = sinU1 * sinU2; 

    double sigma = 0.0; 
    double deltaSigma = 0.0; 
    double cosSqAlpha = 0.0; 
    double cos2SM = 0.0; 
    double cosSigma = 0.0; 
    double sinSigma = 0.0; 
    double cosLambda = 0.0; 
    double sinLambda = 0.0; 

    double lambda = L; // initial guess 
    for (int iter = 0; iter < MAXITERS; iter++) { 
     double lambdaOrig = lambda; 
     cosLambda = Math.cos(lambda); 
     sinLambda = Math.sin(lambda); 
     double t1 = cosU2 * sinLambda; 
     double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda; 
     double sinSqSigma = t1 * t1 + t2 * t2; // (14) 
     sinSigma = Math.sqrt(sinSqSigma); 
     cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15) 
     sigma = Math.atan2(sinSigma, cosSigma); // (16) 
     double sinAlpha = (sinSigma == 0) ? 0.0 : cosU1cosU2 * sinLambda 
     /sinSigma; // (17) 
     cosSqAlpha = 1.0 - sinAlpha * sinAlpha; 
     cos2SM = (cosSqAlpha == 0) ? 0.0 : cosSigma - 2.0 * sinU1sinU2 
     /cosSqAlpha; // (18) 

     double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn 
     A = 1 + (uSquared/16384.0) * // (3) 
      (4096.0 + uSquared * (-768 + uSquared * (320.0 - 175.0 * uSquared))); 
     double B = (uSquared/1024.0) * // (4) 
      (256.0 + uSquared * (-128.0 + uSquared * (74.0 - 47.0 * uSquared))); 
     double C = (f/16.0) * cosSqAlpha * (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10) 
     double cos2SMSq = cos2SM * cos2SM; 
     deltaSigma = B 
      * sinSigma 
      * // (6) 
      (cos2SM + (B/4.0) 
       * (cosSigma * (-1.0 + 2.0 * cos2SMSq) - (B/6.0) * cos2SM 
        * (-3.0 + 4.0 * sinSigma * sinSigma) 
        * (-3.0 + 4.0 * cos2SMSq))); 

     lambda = L 
      + (1.0 - C) 
      * f 
      * sinAlpha 
      * (sigma + C * sinSigma 
       * (cos2SM + C * cosSigma * (-1.0 + 2.0 * cos2SM * cos2SM))); // (11) 

     double delta = (lambda - lambdaOrig)/lambda; 
     if (Math.abs(delta) < 1.0e-12) { 
     break; 
     } 
    } 

    double distance = (b * A * (sigma - deltaSigma)); 
    results[0] = distance; 
    if (results.length > 1) { 
     double initialBearing = Math.atan2(cosU2 * sinLambda, cosU1 * sinU2 
      - sinU1 * cosU2 * cosLambda); 
     initialBearing *= 180.0/Math.PI; 
     results[1] = initialBearing; 
     if (results.length > 2) { 
     double finalBearing = Math.atan2(cosU1 * sinLambda, -sinU1 * cosU2 
      + cosU1 * sinU2 * cosLambda); 
     finalBearing *= 180.0/Math.PI; 
     results[2] = finalBearing; 
     } 
    } 
    } 

    /* 
    * Vincenty Direct Solution of Geodesics on the Ellipsoid (c) Chris Veness 
    * 2005-2012 
    * 
    * from: Vincenty direct formula - T Vincenty, "Direct and Inverse Solutions 
    * of Geodesics on the Ellipsoid with application of nested equations", Survey 
    * Review, vol XXII no 176, 1975 http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf 
    */ 

    /** 
    * Calculates destination point and final bearing given given start point, 
    * bearing & distance, using Vincenty inverse formula for ellipsoids 
    * 
    * @param lat1 
    *   start point latitude 
    * @param lon1 
    *   start point longitude 
    * @param brng 
    *   initial bearing in decimal degrees 
    * @param dist 
    *   distance along bearing in metres 
    * @returns an array of the desination point coordinates and the final bearing 
    */ 

    public static void computeDestinationAndBearing(double lat1, double lon1, 
     double brng, double dist, double results[]) { 
    double a = 6378137, b = 6356752.3142, f = 1/298.257223563; // WGS-84 
                   // ellipsiod 
    double s = dist; 
    double alpha1 = toRad(brng); 
    double sinAlpha1 = Math.sin(alpha1); 
    double cosAlpha1 = Math.cos(alpha1); 

    double tanU1 = (1 - f) * Math.tan(toRad(lat1)); 
    double cosU1 = 1/Math.sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1; 
    double sigma1 = Math.atan2(tanU1, cosAlpha1); 
    double sinAlpha = cosU1 * sinAlpha1; 
    double cosSqAlpha = 1 - sinAlpha * sinAlpha; 
    double uSq = cosSqAlpha * (a * a - b * b)/(b * b); 
    double A = 1 + uSq/16384 
     * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); 
    double B = uSq/1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); 
    double sinSigma = 0, cosSigma = 0, deltaSigma = 0, cos2SigmaM = 0; 
    double sigma = s/(b * A), sigmaP = 2 * Math.PI; 

    while (Math.abs(sigma - sigmaP) > 1e-12) { 
     cos2SigmaM = Math.cos(2 * sigma1 + sigma); 
     sinSigma = Math.sin(sigma); 
     cosSigma = Math.cos(sigma); 
     deltaSigma = B 
      * sinSigma 
      * (cos2SigmaM + B 
      /4 
       * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B/6 
        * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) 
        * (-3 + 4 * cos2SigmaM * cos2SigmaM))); 
     sigmaP = sigma; 
     sigma = s/(b * A) + deltaSigma; 
    } 

    double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1; 
    double lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1, 
     (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp)); 
    double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 
     * sinSigma * cosAlpha1); 
    double C = f/16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); 
    double L = lambda 
     - (1 - C) 
     * f 
     * sinAlpha 
     * (sigma + C * sinSigma 
      * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); 
    double lon2 = (toRad(lon1) + L + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // normalise 
                      // to 
                      // -180...+180 

    double revAz = Math.atan2(sinAlpha, -tmp); // final bearing, if required 

    results[0] = toDegrees(lat2); 
    results[1] = toDegrees(lon2); 
    results[2] = toDegrees(revAz); 

    } 

    private static double toRad(double angle) { 
    return angle * Math.PI/180; 
    } 

    private static double toDegrees(double radians) { 
    return radians * 180/Math.PI; 
    } 

} 
+0

Not: Vincenty’nin formülü, kullanılan elipsoid üzerinde 0,5 mm veya 0,000015 ″ (!) Aralığındadır. (Çok daha basit) Haversine gibi küresel bir modele dayanan hesaplamalar yaklaşık% 0.3'e kadar doğrudur. Yani önceki javascript çözümü, muhtemelen çoğu insanın ihtiyacı. –

2
: Burada http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html

java formüller şunlardır: Eğer yönünü ve mesafesini, başlangıç ​​noktası verilen hedef noktasını hesaplamak istiyorsanız

o zaman bu yöntemi gerek Birçok jeodezik hesaplamalar için

Javascript (doğrudan & ters problemler, alan hesaplamaları, vb).

http://geographiclib.sourceforge.net/scripts/geod-calc.html

google haritalar için bir arayüz de gösterilmiştir

http://geographiclib.sourceforge.net/scripts/geographiclib.js

Örnek kullanımda, mevcut olan

Bu jeodezik çizilmesi içerir

http://geographiclib.sourceforge.net/scripts/geod-google.html

(mavi sağlanır), jeodezik daire (yeşil) ve jeodezik zarf (kırmızı).

sample geodesic starting in New Zealand and wrapping 1.5 times round the world

0

JavaScript uygulaması size google's kullanabilirsiniz diğerinden belirli bir yatak ve bir mesafede bir lat, uzun noktayı hesaplamak için:

var pointA = new google.maps.LatLng(25.48, -71.26); 
var distance = 10; // 10 metres 
var bearing 90; // 90 degrees 
var pointB = google.maps.geometry.spherical.computeOffset(pointA, distance, bearing); 

dokümantasyon için https://developers.google.com/maps/documentation/javascript/reference#spherical Bkz

İlgili konular