คำนวณไมล์ / ลองจิจูด X จากจุดหรือไม่


46

ฉันต้องการค้นหาละติจูดและลองจิจูดโดยให้ระยะทางและละติจูดและลองจิจูดเริ่มต้น

สิ่งนี้ดูเหมือนจะตรงกันข้ามกับคำถามนี้ ( ระยะห่างระหว่างจุดละติจูด / ลองจิจูด )

ฉันได้ตรวจสอบสูตรแฮเวอรีนแล้วและคิดว่ามันใกล้เคียงกับโลกมากพอสมควร

ฉันสมมติว่าฉันต้องแก้สูตรแฮเวอรีนสำหรับ lat / long ที่ไม่รู้จักของฉันถูกต้องหรือไม่ มีเว็บไซต์ที่ดีที่พูดถึงเรื่องแบบนี้บ้างไหม? ดูเหมือนว่าจะเป็นเรื่องปกติ แต่ googling ของฉันมีคำถามที่คล้ายกับคำถามข้างต้นเท่านั้น

สิ่งที่ฉันกำลังมองหาจริงๆเป็นเพียงสูตรสำหรับสิ่งนี้ ฉันต้องการให้ lat / lng เริ่มต้นการแบกและระยะทาง (ไมล์หรือกิโลเมตร) และฉันต้องการออกจากมันเป็นคู่ lat / lng ที่แสดงถึงสถานที่ที่พวกเขาจะเดินทางไปด้วยกัน เส้นทางนั้น


คุณกำลังมองหาเครื่องมือที่ทำสิ่งนี้ (เช่น pe.dll ของ Esri) หรือสูตรหรือไม่?
Kirk Kuykendall

ขออภัยฉันไม่เจาะจง ... ฉันกำลังมองหาสูตร ฉันจะอัปเดตคำถามของฉันให้เจาะจงยิ่งขึ้น
Jason Whitehorn

กลุ่มตัวอย่างคณิตศาสตร์ที่ทำงานอยู่ที่นี่ <a href=" movable-type.co.uk/scripts/latlong.html"> คำนวณระยะทางแบริ่งและอื่น ๆ ระหว่างจุดละติจูด / ลองจิจูด </a> ซึ่งรวมถึงวิธีแก้ปัญหา "ปลายทาง จุดที่กำหนดระยะทางและแบริ่งจากจุดเริ่มต้น ".
Stephen Quan

1
ที่เกี่ยวข้องอย่างใกล้ชิดgis.stackexchange.com/questions/2951/...
whuber

นี่คือหน้าที่เชื่อมโยงไปยังการคำนวณ lat / long [การคำนวณ lat / long] ( movable-type.co.uk/scripts/latlong.html ) และหน้านี้การคำนวณ Lat / long การคำนวณ Lat / longมีรหัส + เครื่องคิดเลข
Abo gaseem

คำตอบ:


21

ฉันจะอยากรู้ว่าผลที่ได้จากสูตรนี้เปรียบเทียบกับpe.dll ของ Esri

( การอ้างอิง )

จุด {lat, lon} คือระยะทาง d บนรัศมี tc จากจุด 1 ถ้า:

 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

อัลกอริทึมนี้ถูก จำกัด ระยะทางเช่น dlon <pi / 2 นั่นคือระยะทางที่น้อยกว่าหนึ่งในสี่ของเส้นรอบวงโลกในลองจิจูด โดยทั่วไปสมบูรณ์ แต่อัลกอริทึมที่ซับซ้อนมากขึ้นเป็นสิ่งจำเป็นหากอนุญาตระยะทางมากขึ้น:

 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

นี่คือเพจ HTML สำหรับการทดสอบ


ขอบคุณสำหรับการตอบกลับอย่างรวดเร็ว ให้ฉันแยกย่อยข้อมูลนี้และฉันจะกลับไปหาคุณ บนพื้นผิวมันดูเป็นจุด ๆ
Jason Whitehorn

1
ฉันลองใช้กรณีโดยตรงโดยใช้ pe.dll (จริง ๆ แล้ว libpe.so บน Solaris) หลังจากดึงระยะทางและ azimuth ไปข้างหน้าจากหน้า html สำหรับ 32N, 117W ถึง 40N, 82W ใช้ 32N, 117W, d = 3255.056515890041, azi = 64.24498012065699, ฉันได้ 40N, 82W (จริง ๆ 82.0000000006464)
mkennedy

3
! น่ากลัว ขอบคุณมากสำหรับลิงก์ไปยังบทความเกี่ยวกับสูตรการบินโดยเอ็ดวิลเลียมส์ฉันไม่เคยเห็นมาก่อน แต่มันได้พิสูจน์แล้วว่าเป็นสิ่งที่อ่านได้อย่างยอดเยี่ยม เพียงแค่บันทึกสำหรับทุกคนที่ดูสิ่งนี้ในอนาคตอินพุตและเอาต์พุตของสูตรนี้จะเป็นเรเดียนแม้แต่ระยะทาง
Jason Whitehorn

1
หน่วยของระยะทางในสูตรนี้คืออะไร?
Karthik Murugan

1
@ คำนำของ @KarthikMurugan Ed บอกว่าระยะทางอยู่ในหน่วยเรเดียนตามวงกลมใหญ่
Kirk Kuykendall

18

ถ้าคุณอยู่ในเครื่องบินแล้วจุดที่เป็นRห่างเมตรที่แบริ่งขององศาตะวันออกของภาคเหนือจะถูกแทนที่ด้วย R * cos (ก) ในทิศทางเหนือและ R บาป * (ก) ในทิศทางตะวันออก (ข้อความเหล่านี้มากหรือน้อยกว่ากำหนดไซน์และโคไซน์)

แม้ว่าคุณจะไม่ได้อยู่ในระนาบ - คุณกำลังทำงานอยู่บนพื้นผิวของทรงรีทรงรีที่จำลองพื้นผิวโลก - ระยะทางน้อยกว่าสองสามร้อยกิโลเมตรนั้นครอบคลุมส่วนเล็ก ๆ ของพื้นผิวที่สามารถใช้งานได้จริง ถือว่าแบน ภาวะแทรกซ้อนที่เหลืออยู่เพียงอย่างเดียวคือลองจิจูดระดับหนึ่งไม่ครอบคลุมระยะทางเดียวกันกับระดับละติจูด ในโมเดล Earth ทรงกลมลองจิจูดหนึ่งองศาจะเท่ากับ cos (ละติจูด) ตราบใดที่องศาละติจูด (ในรูปแบบวงรีรูปไข่นี่ยังคงเป็นค่าประมาณที่ดีเยี่ยมถึงประมาณ 2.5 ตัวเลขที่มีนัยสำคัญ)

ในที่สุดละติจูดหนึ่งองศาจะอยู่ที่ประมาณ 10 ^ 7/90 = 111,111 เมตร ขณะนี้เรามีข้อมูลทั้งหมดที่จำเป็นสำหรับการแปลงเมตรเป็นองศา:

การกระจัดไปทางทิศเหนือคือ r * cos (a) / 111111 องศา;

การกระจัดไปทางทิศตะวันออกคือ r * sin (a) / cos (ละติจูด) / 111111 องศา

ตัวอย่างเช่นที่ละติจูด -0.31399 องศาและการแบก = 30 องศาทางตะวันออกของภาคเหนือเราสามารถคำนวณ

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.

ดังนั้นเริ่มต้นที่ (-78.4437, -0.31399) ตำแหน่งใหม่อยู่ที่ (-78.4437 + 0.00045, -0.31399 + 0.0007794) = (-78.4432, -0.313211)

คำตอบที่ถูกต้องมากขึ้นในระบบอ้างอิง ITRF00 ที่ทันสมัยคือ (-78.4433, -0.313207): นี่คือ 0.43 เมตรห่างจากคำตอบโดยประมาณซึ่งบ่งชี้ถึงการประมาณ errs 0.43% ในกรณีนี้ เพื่อให้ได้ความแม่นยำที่สูงขึ้นคุณจะต้องใช้สูตรระยะทางรูปวงรี (ซึ่งมีความซับซ้อนมากกว่า) หรือการฉายภาพที่มีความเที่ยงตรงสูงด้วยการเบี่ยงเบนศูนย์ (เพื่อให้ตลับลูกปืนมีความถูกต้อง)


2
+1 สำหรับการทำความเข้าใจอย่างถูกต้องบริบททางคณิตศาสตร์ (เช่นเครื่องบินในประเทศของมัน)
แฟรงก์ Conry

4

หากคุณต้องการโซลูชัน JavaScript ให้พิจารณาสิ่งเหล่านี้functionsและซอนี้ :

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; }
};

ดังนั้นหากคุณต้องการคำนวณพิกัดใหม่อาจเป็นเช่นนั้น:

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

ฉันได้ทำงานใน ObjectiveC นี้ กุญแจสำคัญในที่นี้คือรู้ว่าคุณต้องการจุด lat / lng เป็นเรเดียนและคุณต้องแปลงกลับเป็น lat / lng หลังจากใช้สมการ นอกจากนี้รู้ระยะทางและ tc เป็นเรเดียน

นี่คือสมการดั้งเดิม:

 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

ที่นี่มีการใช้งานใน ObjC โดยที่เรเดียนเป็นตัวนับเรเดียนที่วัดตามเข็มนาฬิกาจาก N (เช่น PI / 2 คือ W, PI คือ S, 2 PI / 3 เป็น E) และระยะทางอยู่ในกิโลเมตร

+ (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);
}

ฉันกำลังมองหาวิธีแก้ปัญหาที่ฉันอยากได้ละติจูด 4 เส้นจากจุดที่ฉันยืนได้ถึง 50 ไมล์ทางทิศเหนือทิศตะวันตก 50 ไมล์ทิศตะวันออก 50 ไมล์เป็นต้น ... ในคำตอบข้างต้นคุณสามารถอธิบายได้อย่างไรว่าฉันจะประสบความสำเร็จได้อย่างไร นี้ ?
Rahul Vyas

1

หากคุณสนใจในความถูกต้องดีกว่าไม่Vincenty (ลิงก์คือรูปแบบ 'โดยตรง' ซึ่งเป็นสิ่งที่คุณต้องการอย่างแน่นอน)

มีการใช้งานที่มีอยู่ไม่กี่ถ้าคุณหลังจากรหัส

นอกจากนี้คำถาม: คุณไม่ได้สมมติว่านักเดินทางยังคงมีผลเช่นเดียวกันตลอดการเดินทางใช่ไหม? ถ้าเป็นเช่นนั้นวิธีการเหล่านี้จะไม่ตอบคำถามที่ถูกต้อง (คุณน่าจะดีกว่าที่จะฉายไปที่ mercator วาดเส้นตรงแล้วยกเลิกการคาดการณ์ผลลัพธ์)


คำถามที่ดีมากแม้จะมีถ้อยคำในคำถามของฉันที่อาจระบุว่าฉันกำลังคำนวณจุดหมายปลายทางสำหรับนักเดินทาง แต่ฉันก็ไม่ได้ จุดที่ดีแม้ว่า นี่เป็นส่วนใหญ่เพื่อให้ฉันสามารถคำนวณพื้นที่ที่มีขอบเขต (ตามคำสั่งเล็ก ๆ พูดได้ 50 ไมล์) ... ฉันหวังว่ามันจะสมเหตุสมผล
เจสันไวท์ฮอร์น

gis.stackexchange.com/questions/3264/...มีคำถามเดียวกัน (การสร้างพื้นที่วิ่งจากจุดและระยะทาง)
แดนเอส

0

นี่คือทางออกของ Python:

    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

ฉันใช้วิธีการที่อธิบายไว้ด้านล่างในการกำหนดพิกัดต่อไปที่กำหนดตลับลูกปืนและระยะทางจากพิกัดก่อนหน้านี้ ฉันมีปัญหาเรื่องความแม่นยำด้วยวิธีการอื่นที่ฉันอ่านจากอินเทอร์เน็ต

ฉันใช้สิ่งนี้ในการกำหนดพื้นที่ของที่ดินซึ่งเป็นรูปหลายเหลี่ยมและพล็อตรูปหลายเหลี่ยมนั้นใน Google Earth ชื่อเรื่องของดินแดนมีตลับลูกปืนและระยะทางเขียนด้วยวิธีนี้: "NorthOrSouth x องศา y นาที EastOrWest, z เมตรถึงชี้ n;"

ดังนั้นเริ่มจากพิกัดที่กำหนดของจุดอ้างอิงก่อนอื่นฉันคำนวณระยะทางต่อละติจูดหนึ่งองศาและลองจิจูดหนึ่งองศาโดยใช้สูตรแฮเวอร์ซีนเพราะสิ่งนี้จะแตกต่างกันไปตามตำแหน่ง จากนั้นฉันจะหาพิกัดต่อไปจากตรีโกณมิติไซน์และสูตรโคไซน์

ด้านล่างเป็นจาวาสคริปต์:

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
สูตรคาร์ทีเซียนสำหรับพื้นที่รูปหลายเหลี่ยมที่คุณพยายามใช้ที่นี่ไม่สามารถใช้ได้กับระยะทางและมุมที่คำนวณบนพื้นผิวโค้ง (เช่นทรงกลม) สูตรนี้ทำให้เกิดข้อผิดพลาดเพิ่มเติมโดยใช้ละติจูดและลองจิจูดราวกับว่าพวกเขาเป็นพิกัดคาร์ทีเซียน สถานการณ์เดียวที่มีการพิจารณาการใช้งานจะเป็นสิ่งที่แน่นอน (สำหรับรูปหลายเหลี่ยมขนาดเล็กมาก) ซึ่งไม่จำเป็นต้องใช้สูตรแฮเวอรีน โดยรวมแล้วมันดูเหมือนว่ารหัสนี้ทำงานหนักเกินไปจนไม่ได้กำไร
whuber
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.