Enlem / Boylam X noktadan hesaplanıyor?


46

Rulman, mesafe ve başlangıç ​​enlem ve boylamı verilen bir enlem ve boylam noktası bulmak istiyorum.

Bu, bu sorunun tam tersi gibi görünüyor (en / uzun noktalar arasındaki mesafe ).

Halen formül formuna daha önce baktım ve dünyaya yaklaşmanın yeterince yakın olduğunu düşünüyorum.

Bilinmeyen Lat / Long'um için haversine formülünü çözmem gerektiğini düşünüyorum, bu doğru mu? Bu tür şeylerden bahseden iyi bir web sitesi var mı? Yaygın olacak gibi gözüküyor, ama benim Google'ım sadece yukarıdaki soruya benzer sorular ortaya koydu.

Gerçekten aradığım şey bunun için bir formül. Bir başlangıç ​​/ lng, bir rulman ve bir mesafeyi (mil veya kilometre) vermek istiyorum ve ondan bir yere varacaklarını gösteren bir lat / lng çifti almak istiyorum. bu yol.


Bunu yapan bir araç mı arıyorsunuz (Esri's pe.dll gibi) veya formül mü?
Kirk Kuykendall,

Özür dilerim, özür dilerim ... Bir formül arıyorum. Daha spesifik olmak için sorumu güncelleyeceğim.
Jason Whitehorn,

Çalışılan matematik örneklerinin birçoğu burada bulunuyor. "Hedef" çözümünü içeren <a href=" movable-type.co.uk/scripts/latlong.html"> Enlem / Boylam noktaları arasındaki mesafeyi, yükü ve daha fazlasını hesaplayın </a> başlangıç ​​noktasından uzaklık ve yatak verilen nokta ".
Stephen Quan


Burada sayfa bağlantısı enlem için / uzun hesaplamalar [Lat / uzun hesaplamalar] (işte movable-type.co.uk/scripts/latlong.html ) da bu sayfayı Lat / uzun hesaplamalar bir kod + hesaplayıcı bulunur
Abo gaseem

Yanıtlar:


21

Bu formülden elde edilen sonuçların Esri'nin pe.dll ile karşılaştırmasını merak ediyorum .

( alıntı )

Bir nokta {lat, lon}, tc üzerinde 1 noktasından radyal olarak çıkan bir mesafedir.

 lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
 IF (cos(lat)=0)
    lon=lon1      // endpoint a pole
 ELSE
    lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
 ENDIF

Bu algoritma, dlon <pi / 2, yani dünyanın çevresinin dörtte birinden daha uzun boylu boyunca uzananlar gibi mesafelerle sınırlıdır. Daha büyük mesafelere izin veriliyorsa, tamamen genel fakat daha karmaşık bir algoritma gerekir:

 lat =asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
 dlon=atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(lat))
 lon=mod( lon1-dlon +pi,2*pi )-pi

İşte test için bir html sayfası .


Çabuk geri dönüşünüz için teşekkür ederim. Bu bilgilerin bir kısmını özetlememe izin ver, ben de seninle geri döneceğim. Yüzeyde olsa da, bu nokta görünüyor.
Jason Whitehorn

1
32N, 117W ile 40N, 82W arasındaki html sayfasından mesafeyi ve ileri azimutu aldıktan sonra pe.dll (aslında solaris'te libpe.so) kullanarak doğrudan davayı denedim. 32N, 117W, d = 3255.056515890041, azi = 64.24498012065699 kullanılarak 40N, 82W (aslında 82.00000000064) kullandım.
mkennedy

3
Müthiş! Ed Williams'ın Havacılık Formülerliği makalesine bağlantı için çok teşekkür ederim, bunu daha önce görmedim ancak bugüne kadar okuduğumuzu kanıtladı. Gelecekte buna bakan herkes için bir not, bu formülün giriş ve çıkışları TÜM radyanlar, hatta mesafelerdir.
Jason Whitehorn

1
Bu formüldeki uzaklık birimi nedir?
Karthik Murugan

1
@KarthikMurugan Ed'in intro mesafe birimlerinin büyük bir daire boyunca radyan olduğunu söylüyor
Kirk Kuykendall

18

Eğer bir düzlemdeyseniz, kuzeyden doğuya doğru bir dereceye kadar r metre uzakta olan nokta kuzey yönünde r * cos (a) ve doğu yönünde r * günah (a) ile değiştirilir. (Bu ifadeler az ya da çok sinüsü ve kosinüsü tanımlar .)

Bir düzlemde olmamanıza rağmen - Dünya yüzeyini modelleyen eğri bir elipsoidin yüzeyinde çalışıyorsunuz - birkaç yüz kilometreden daha kısa herhangi bir mesafe, yüzeyin o kadar küçük bir bölümünü kaplar ki en pratik amaçlar için düz olarak kabul edilmek. Kalan tek komplikasyon, bir boylam derecesinin enlem derecesi ile aynı mesafeyi kaplamamasıdır. Küresel bir Dünya modelinde, bir derece boylam sadece enlem derecesi kadar cos (enlem) 'dir. (Bir elipsoidal modelde, bu hala yaklaşık 2.5 önemli rakam için iyi, mükemmel bir yaklaşımdır.)

Son olarak, bir enlem derecesi yaklaşık olarak 10 ^ 7/90 = 111.111 metredir. Artık sayaçları derecelere dönüştürmek için gereken tüm bilgilere sahibiz:

Kuzeye doğru yer değiştirme r * cos (a) / 111111 derece;

Doğuya doğru yer değiştirme r * sin (a) / cos (enlem) / 111111 derecedir.

Örneğin, -0.31399 derece enleminde ve kuzeyin = 30 derecelik doğusunda, hesaplayabiliriz.

cos(a) = cos(30 degrees) = cos(pi/6 radians) = Sqrt(3)/2 = 0.866025.
sin(a) = sin(30 degrees) = sin(pi/6 radians) = 1/2 = 0.5.
cos(latitude) = cos(-0.31399 degrees) = cos(-0.00548016 radian) = 0.999984984.
r = 100 meters.
east displacement = 100 * 0.5 / 0.999984984 / 111111 = 0.000450007 degree.
north displacement = 100 * 0.866025 / 111111 = 0.000779423 degree.

Bu nedenle, (-78.4437, -0.31399) 'dan başlayan yeni konum (-78.4437 + 0.00045, -0.31399 + 0.0007794) = (-78.4432, -0.313211).

Modern ITRF00 referans sisteminde daha doğru bir cevap (-78.4433, -0.313207): bu, yaklaşık cevabın% 0,43 olduğunu belirterek, yaklaşık cevabın 0,43 metre uzağındadır. Daha yüksek bir doğruluk elde etmek için ya elipsoidal mesafe formüllerini (çok daha karmaşık olan) ya da sıfır sapmalı (yatak doğru olacak şekilde) yüksek kalitede bir uyumlu projeksiyon kullanmalısınız.


2
Matematiksel bağlamı doğru bir şekilde anlamak için +1 (yani, yerel düzlemi)
Frank Conry 10:14

4

Bir JavaScript çözümüne ihtiyacınız varsa, bu functionsve şu kemanı düşünün :

var gis = {
  /**
  * All coordinates expected EPSG:4326
  * @param {Array} start Expected [lon, lat]
  * @param {Array} end Expected [lon, lat]
  * @return {number} Distance - meter.
  */
  calculateDistance: function(start, end) {
    var lat1 = parseFloat(start[1]),
        lon1 = parseFloat(start[0]),
        lat2 = parseFloat(end[1]),
        lon2 = parseFloat(end[0]);

    return gis.sphericalCosinus(lat1, lon1, lat2, lon2);
  },

  /**
  * All coordinates expected EPSG:4326
  * @param {number} lat1 Start Latitude
  * @param {number} lon1 Start Longitude
  * @param {number} lat2 End Latitude
  * @param {number} lon2 End Longitude
  * @return {number} Distance - meters.
  */
  sphericalCosinus: function(lat1, lon1, lat2, lon2) {
    var radius = 6371e3; // meters
    var dLon = gis.toRad(lon2 - lon1),
        lat1 = gis.toRad(lat1),
        lat2 = gis.toRad(lat2),
        distance = Math.acos(Math.sin(lat1) * Math.sin(lat2) +
            Math.cos(lat1) * Math.cos(lat2) * Math.cos(dLon)) * radius;

    return distance;
  },

  /**
  * @param {Array} coord Expected [lon, lat] EPSG:4326
  * @param {number} bearing Bearing in degrees
  * @param {number} distance Distance in meters
  * @return {Array} Lon-lat coordinate.
  */
  createCoord: function(coord, bearing, distance) {
    /** http://www.movable-type.co.uk/scripts/latlong.html
    * φ is latitude, λ is longitude, 
    * θ is the bearing (clockwise from north), 
    * δ is the angular distance d/R; 
    * d being the distance travelled, R the earth’s radius*
    **/
    var 
      radius = 6371e3, // meters
      δ = Number(distance) / radius, // angular distance in radians
      θ = gis.toRad(Number(bearing));
      φ1 = gis.toRad(coord[1]),
      λ1 = gis.toRad(coord[0]);

    var φ2 = Math.asin(Math.sin(φ1)*Math.cos(δ) + 
      Math.cos(φ1)*Math.sin(δ)*Math.cos(θ));

    var λ2 = λ1 + Math.atan2(Math.sin(θ) * Math.sin(δ)*Math.cos(φ1),
      Math.cos(δ)-Math.sin(φ1)*Math.sin(φ2));
    // normalise to -180..+180°
    λ2 = (λ2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI; 

    return [gis.toDeg(λ2), gis.toDeg(φ2)];
  },
  /**
   * All coordinates expected EPSG:4326
   * @param {Array} start Expected [lon, lat]
   * @param {Array} end Expected [lon, lat]
   * @return {number} Bearing in degrees.
   */
  getBearing: function(start, end){
    var
      startLat = gis.toRad(start[1]),
      startLong = gis.toRad(start[0]),
      endLat = gis.toRad(end[1]),
      endLong = gis.toRad(end[0]),
      dLong = endLong - startLong;

    var dPhi = Math.log(Math.tan(endLat/2.0 + Math.PI/4.0) / 
      Math.tan(startLat/2.0 + Math.PI/4.0));

    if (Math.abs(dLong) > Math.PI) {
      dLong = (dLong > 0.0) ? -(2.0 * Math.PI - dLong) : (2.0 * Math.PI + dLong);
    }

    return (gis.toDeg(Math.atan2(dLong, dPhi)) + 360.0) % 360.0;
  },
  toDeg: function(n) { return n * 180 / Math.PI; },
  toRad: function(n) { return n * Math.PI / 180; }
};

Eğer yeni bir koordinat hesaplamak istiyorsanız, şöyle olabilir:

var start = [15, 38.70250];
var end = [21.54967, 38.70250];
var total_distance = gis.calculateDistance(start, end); // meters
var percent = 10;
// this can be also meters
var distance = (percent / 100) * total_distance;
var bearing = gis.getBearing(start, end);
var new_coord = gis.createCoord(icon_coord, bearing, distance);

2

Bunu ObjectiveC'de çalıştım. Burada anahtar radyanlarda lat / lng noktalarına ihtiyacınız olduğunu ve denklemi uyguladıktan sonra tekrar lat / lng'ye dönüştürmeniz gerektiğini bilmektir. Ayrıca, mesafenin ve tc'nin radyan olduğuna dikkat edin.

İşte orijinal denklem:

 lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
 IF (cos(lat)=0)
    lon=lon1      // endpoint a pole
 ELSE
    lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
 ENDIF

Burada, radyanin N'den saat yönünün tersine ölçülen bir radyan olduğu (örneğin, PI / 2'nin W, PI'nin S, 2 PI / 3'ün E olduğu) ve mesafenin kilometre olduğu ObjC'de uygulanmaktadır.

+ (CLLocationCoordinate2D)displaceLatLng:(CLLocationCoordinate2D)coordinate2D withRadian:(double)radian
                            withDistance:(CGFloat)distance {
  double lat1Radians = coordinate2D.latitude * (M_PI / 180);
  double lon1Radians = coordinate2D.longitude * (M_PI / 180);
  double distanceRadians = distance / 6371;
  double lat = asin(sin(lat1Radians)*cos(distanceRadians)+cos(lat1Radians)*sin(distanceRadians)
      *cos(radian));
  double lon;
  if (cos(lat) == 0) {
    lon = lon1Radians;
  } else {
    lon = fmodf((float) (lon1Radians - asin(sin(radian) * sin(distanceRadians) / cos(lat)) + M_PI),
        (float) (2 * M_PI)) - M_PI;
  }
  double newLat = lat * (180 / M_PI);
  double newLon = lon * (180 / M_PI);
  return CLLocationCoordinate2DMake(newLat, newLon);
}

50 mil kuzeyde, 50 mil batıda, 50 mil doğuda vb. Durduğum noktadan 4 lat almak istediğim bir çözüm arıyorum. bu ?
Rahul Vyas

1

Daha iyi doğrulukla ilgileniyorsanız, Vincenty var . (Bağlantı tam olarak neyin peşindeyseniz 'doğrudan' biçimindedir.

Kuralların peşindeyseniz, epeyce mevcut uygulamalar vardır.

Ayrıca bir soru: Gezginin tüm seyahat boyunca aynı kaliteyi koruduğunu varsaymıyorsunuz, değil mi? Eğer öyleyse, o zaman bu yöntemler doğru soruyu cevaplamıyor. (Merkator'a projeksiyon yapmaktan, düz bir çizgi çizdikten ve sonucu çıkarıp bırakmadan daha iyi olursunuz.)


Çok güzel bir soru, sorumun bir gezgin için bir varış yeri hesapladığımı belirten ifadesine rağmen, değilim. Yine de iyi nokta. Bu esas olarak sınırlayıcı bir alanı hesaplayabilmemdi (küçük bir siparişte, 50 mil).
Jason Whitehorn

gis.stackexchange.com/questions/3264/… aynı soruyu soruyordu (bir noktadan ve mesafeden sınırlayıcı alanlar inşa etmek)
Dan S.

0

İşte bir Python çözümü:

    def displace(self, theta, distance):
    """
    Displace a LatLng theta degrees counterclockwise and some
    meters in that direction.
    Notes:
        http://www.movable-type.co.uk/scripts/latlong.html
        0 DEGREES IS THE VERTICAL Y AXIS! IMPORTANT!
    Args:
        theta:    A number in degrees.
        distance: A number in meters.
    Returns:
        A new LatLng.
    """
    theta = np.float32(theta)

    delta = np.divide(np.float32(distance), np.float32(E_RADIUS))

    def to_radians(theta):
        return np.divide(np.dot(theta, np.pi), np.float32(180.0))

    def to_degrees(theta):
        return np.divide(np.dot(theta, np.float32(180.0)), np.pi)

    theta = to_radians(theta)
    lat1 = to_radians(self.lat)
    lng1 = to_radians(self.lng)

    lat2 = np.arcsin( np.sin(lat1) * np.cos(delta) +
                      np.cos(lat1) * np.sin(delta) * np.cos(theta) )

    lng2 = lng1 + np.arctan2( np.sin(theta) * np.sin(delta) * np.cos(lat1),
                              np.cos(delta) - np.sin(lat1) * np.sin(lat2))

    lng2 = (lng2 + 3 * np.pi) % (2 * np.pi) - np.pi

    return LatLng(to_degrees(lat2), to_degrees(lng2))

-2

Aşağıda açıklanan yaklaşımı, önceki koordinattan yön ve mesafeye verilen bir sonraki koordinatı belirlemek için kullanıyorum. İnternetten okuduğum diğer yaklaşımlarla ilgili doğruluk konusunda sorun yaşıyorum.

Bunu bir çokgen olan kara alanını belirlemek için kullanıyorum ve bu çokgeni google dünyadaki arsa. Bir Arazi Başlığı, bu şekilde yazılmış yatakları ve mesafeleri vardır: "NorthOrSouth x derece y dakika, EastOrWest, z metreleri n;

Bu nedenle, referans noktasının verilen koordinatlarından başlayarak, önce bir derece enlem ve bir derece boylam başına mesafeyi hesapladım, çünkü bu, bölgeye bağlı olarak değişir. Sonra bir sonraki koordinatı trigonometri sinüs ve kosinüs formülünden belirlerim.

Javascript aşağıdadır:

var mapCenter = new google.maps.LatLng(referencePointLatitude, referencePointLongitude); //the ref point lat and lon must be given, usually a land mark (BLLM)
var latDiv = latDiv(mapCenter); //distance per one degree latitude in this location
var lngDiv = lngDiv(mapCenter); //distance per one degree longitude in this location
var LatLng2 = NextCoord(PrevCoord,NorthOrSouth,x,y,EastOrWest,z); //next coordinate given the bearing and distance from previous coordinate
var Lat2 = LatLng2.lat(); //next coord latitude in degrees
var Lng2 = LatLng2.lng(); //next coord longitude in degrees
var polygon=[p1,p2,...,pn-1,pn,p1]; //p1,p2,etc. are the coordinates of points of the polygon, i.e. the land Title. Be sure to close the polygon to the point of beginning p1
var area = Area(polygon); //area of the polygon in sq.m.
function NextCoord(PrevCoord,NorthOrSouth,x,y,EastOrWest,z) {
  var angle = ( x + ( y / 60 ) ) * Math.PI / 180;
  var a = 1;
  var b = 1;
  if (NorthOrSouth == 'South') { a = -1; }
  if (EastOrWest == 'West') { b = -1; }
  var nextLat = PrevCoord.lat() +  ( a * z * Math.cos(angle) / latDiv );
  var nextLng = PrevCoord.lng() +  ( b * z * Math.sin(angle) / lngDiv );
  var nextCoord = new google.maps.LatLng(nextLat, nextLng);
  return nextCoord;
}
function latDiv(mapCenter) {
  var p1 = new google.maps.LatLng(mapCenter.lat()-0.5, mapCenter.lng());
  var p2 = new google.maps.LatLng(mapCenter.lat()+0.5, mapCenter.lng());
  return dist(p1,p2);
}
function lngDiv(mapCenter) {
  var p3 = new google.maps.LatLng(mapCenter.lat(), mapCenter.lng()-0.5);
  var p4 = new google.maps.LatLng(mapCenter.lat(), mapCenter.lng()+0.5);
  return dist(p3,p4);
}
function dist(pt1, pt2) {
    var dLat  = ( pt2.lat() - pt1.lat() ) * Math.PI / 180;
    var dLng = ( pt2.lng() - pt1.lng() ) * Math.PI / 180;
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +                 
            Math.cos(rad(pt1.lat())) * Math.cos(rad(pt2.lat())) *
            Math.sin(dLng/2) * Math.sin(dLng/2);
    var R = 6372800; //earth's radius
    var distance = R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    return distance;
}
function Area(polygon) {
  var xPts=[];
  for (i=1; i&lt;polygon.length; i++) {
    xPts[i-1] = ( polygon[i].lat() - polygon[0].lat() ) * latDiv;
  }
  var yPts=[];
  for (i=1; i&lt;polygon.length; i++) {
    yPts[i-1] = ( polygon[i].lng() - polygon[0].lng() ) * lngDiv;
  }
  var area = 0;
  j = polygon.length-2;
  for (i=0; i&lt;polygon.length-1; i++) {
    area = area +  ( xPts[j] + xPts[i] ) * ( yPts[j] - yPts[i] );
    j = i;
  }
  area = Math.abs(area/2);
  return area;
}

1
Burada uygulamaya çalıştığınız çokgen alanın Kartezyen formülü, eğri bir yüzeyde hesaplanan uzaklıklara ve açılara uygulanamaz (örneğin bir sferoid). Bu formül Kartezyen koordinatlarmış gibi enlem ve boylamları kullanarak ek bir hata yapar. Kullanımının göz önüne alınabileceği tek koşul, tam olarak (haversine formülünün zaten gereksiz olduğu durumlarda (çok küçük poligonlar için) olacaktır. Genel olarak görünen o ki, bu kod kazanç elde etmek için çok fazla çalışıyor.
whuber
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.