Bagaimana cara menghitung kotak pembatas untuk diberi jarak dan garis lintang / bujur

13

Saya harus dapat menghitung kotak atau lingkaran untuk garis lintang WGS84 dan bujur WGS84 tertentu, dan jarak tetapi tidak tahu harus mulai dari mana!

Jarak dari awal Lat / Lon akan 10km atau kurang.

Apakah mungkin bagi seseorang untuk memberi saya beberapa petunjuk / Contoh tentang cara melakukan ini

ntoken
sumber
Untuk lingkaran yang tidak mencakup kedua kutub, jawaban terperinci diberikan di gis.stackexchange.com/questions/19221/… . Tapi ini bukan cerita lengkapnya, seperti yang dibalas oleh balasan saat ini: Anda dapat melakukan kompromi kompleksitas-akurasi-program. Perhatikan juga, bahwa ada masalah "membungkus" dalam menentukan kotak pembatas saat Anda bekerja di lat-lon (kesulitan terjadi pada meridian + -180 derajat). Untuk solusi untuk ini, lihat gis.stackexchange.com/questions/17788/… .
Whuber
Apakah Anda benar-benar membutuhkan kotak, atau apakah 4 poin di dekat titik tertentu sudah cukup? Diberi titik p, cari 4 titik d jarak pada arah NE, SW, SE, dan NW dari p.
Kirk Kuykendall
@Kirk - Jika Anda memiliki koordinat 4 poin, maka Anda memiliki kotak ...
martinstoeckli
@martinstoeckli benar, saya hanya berharap untuk menyederhanakan masalah dengan tidak harus memvisualisasikan seperti apa kotak yang diproyeksikan ke bola terlihat seperti. Perhatikan juga masalahnya dapat digeneralisasi untuk memperjelas bahwa sisi kotak tidak harus jatuh pada garis lintang / bujur yang sama (kotak yang diputar dengan kata lain).
Kirk Kuykendall
@Kirk - Ahh well, jika Anda membutuhkannya dengan tepat, maka Anda benar tentu saja. Saya pikir kotak itu hanya berguna untuk menemukan kandidat yang mungkin dengan cepat. Untuk memeriksa apakah dua titik berada dalam jarak tertentu (lingkaran), rumus haversine yang lebih kompleks dapat digunakan.
martinstoeckli

Jawaban:

15

WGS-apa? WGS-84? Bergantung pada keakuratan yang Anda butuhkan, Anda mungkin perlu mengetahui lebih banyak informasi - dugaan saya adalah itu sebabnya Anda tidak dapat memilih, meskipun tidak ada yang peduli untuk meninggalkan komentar yang mengatakan mengapa.

Berikut ini dua cara:

Tidak akurat, tetapi mungkin 'cukup baik'

Satu derajat garis lintang adalah sekitar 10001.965729 / 90 kilometer (jarak dari khatulistiwa ke kutub, dibagi sembilan puluh derajat) atau 111,113 kilometer, menggunakan datum WGS-84. Ini adalah perkiraan karena bentuk bumi, dan karena jarak berubah ketika Anda mendekati kutub (satu alasan untuk menggunakan garis lintang, bukan garis bujur - pada akhirnya jarak satu derajat garis bujur adalah nol!) Bumi juga tidak sempurna bola. Keduanya adalah alasan untuk menggunakan pendekatan berbasis proyeksi dan datum yang lebih kompleks, dalam jawaban kedua saya.

10001.965729km = 90 degrees
1km = 90/10001.965729 degrees = 0.0089982311916 degrees
10km = 0.089982311915998 degrees

Ini menggunakan derajat desimal, bukan derajat / menit / detik.

Jadi, kotak pembatas Anda akan menjadi poin Anda, plus dan minus 0,08999 derajat. Atau Anda bisa menggunakan angka ini sebagai jari-jari, memberi Anda lingkaran pembatas .

Setiap orang GIS yang membaca ini akan ngeri. Namun, sebagian besar akan akurat, tergantung di mana Anda berada di dunia. Untuk radius 10 km itu harus baik-baik saja.

Jauh lebih akurat, tetapi lebih banyak kode

Gunakan perpustakaan proyeksi dan tentukan datum Anda, dll. Saya merekomendasikan Proj4; ini banyak digunakan sehingga Google mengembalikan banyak hasil untuk pertanyaan tentang itu, dan ada pembungkus Delphi . Jika Anda kesulitan menggunakannya, kirimkan pertanyaan lain di sini di SO - tidak termasuk untuk yang ini. Situs web Proj4 memiliki contoh-contoh menggunakan API dasar, dan meskipun ini dalam bahasa C, situs web ini harus mudah diterjemahkan. Referensi API mereka adalah tempat terbaik untuk memulai, diikuti oleh FAQ .

Saya akan menggunakan WGS-84 sebagai datum dasar (representasi bumi) kecuali Anda tahu yang spesifik yang ingin Anda gunakan, atau yang digunakan untuk membuat koordinat Anda. Ini biasa digunakan dan cukup akurat.

Jika posisi Anda berasal dari Google Maps (misalnya), tentukan proyeksi Mercator. Anda mungkin ingin menggunakan proyeksi lain, atau menggunakan, katakanlah, koordinat UTMbukannya lintang dan bujur, tergantung pada sumber data Anda dan jika Anda ingin akurasi tinggi untuk area lokal kecil. (UTM memiliki banyak zona, yang semuanya mengubah distorsi sehingga di dalam zona itu, sangat akurat; jika Anda menggunakan zona untuk koordinat di luarnya, distorsi akan sangat meningkat saat Anda bergerak menjauh. Jika Anda melihat seluruh bumi diproyeksikan dari satu zona, itu mungkin tidak dapat dikenali. Tapi dalam suatu zona, terjemahan UTM akan menjadi sebaik yang Anda bisa dapatkan. Koordinat umumnya ditentukan dalam meter, bukan dalam derajat, sehingga mungkin lebih berguna untuk Anda, mengingat Anda membutuhkan 10 km radius 10km mudah dalam satu zona tunggal, Anda hanya perlu memilih zona yang sesuai berdasarkan koordinat pusat Anda .Sedikit rumit adalah ketika Anda mendekati perbatasan: itu adalah situasi umum, dan itu baik-baik saja, hanya menjadikonsisten dalam cara Anda memilih mana yang Anda gunakan . Proj4 juga akan memungkinkan Anda menerjemahkan proyeksi, sehingga Anda dapat beralih dari Mercator WGS-84 lat / panjang ke zona UTM n , misalnya, atau ke dan dari dua zona UTM.)

David
sumber
2
Untuk tempat kami tinggal, seorang surveyor pernah mengatakan kepada saya bahwa ia menggunakan 1 derajat kira-kira sama dengan 108 km untuk perhitungan mentalnya. Secara mental 10 km kira-kira 0,1 derajat. Karena ini adalah perkiraan kasar yang terbaik untuk memperlakukan mereka akurat hingga 1 digit signifikan (paling banyak 2 atau 3) daripada 0,089982311915998 karena menyiratkan tingkat presisi.
Stephen Quan
1
Ini benar-benar tidak sulit untuk menghitung derajat lebih akurat, dengan mempertimbangkan lintang. Karena komputer membuat perhitungan, tidak ada yang diperoleh dengan perkiraan (lihat fungsi pertama dalam contoh saya).
martinstoeckli
3

Dengan asumsi Anda ingin membuat kueri dalam database, Anda mungkin ingin melakukan pencarian cepat (tidak akurat), dan kemudian menghitung jarak untuk tempat yang dihasilkan dengan tepat. Apakah itu skenario Anda?

Fungsi berikut (dalam PHP, maaf) kira-kira akan menghitung perbedaan dalam lintang dan bujur. Perbedaan ini tergantung pada garis lintang titik pencarian Anda. Gunakan mereka (dengan toleransi kecil) untuk melakukan pencarian cepat di database. Kotak dapat dihitung hanya dengan lintang + -deltaLatitude dan bujur + -deltaLongitude.

deltaLatitude[rad] = distance[m] / earthRadius[m]
deltaLongitude[rad] = distance[m] / (cos(latitude[rad]) * $earthRadius[m])

/**
 * Calculates the deltas in latitude and longitude to use, for a db search
 * around a location in the database.
 * @param float $distance Radius to use for the search [m]
 * @param float $latitude Latitude of the location, we need the angle deltas for [deg decimal]
 * @param float $deltaLatitude Calculated delta in latitude [deg]
 * @param float $deltaLongitude Calculated delta in longitude [deg]
 * @param float $earthRadius Mean earth radius in [m]
 */
public static function angleFromSphericDistance($distance, $latitude,
  &$deltaLatitude, &$deltaLongitude, $earthRadius = 6371000)
{
  $lat = deg2rad($latitude);

  $radiusOnLatitude = cos($lat) * $earthRadius;
  $deltaLatitude = $distance / $earthRadius;
  $deltaLongitude = $distance / $radiusOnLatitude;

  $deltaLatitude = rad2deg($deltaLatitude);
  $deltaLongitude = rad2deg($deltaLongitude);
}

Dengan rumus haversine , Anda dapat menghitung jarak di bola. Gunakan untuk setiap tempat yang ditemukan, untuk mendapatkan jarak "tepat". Dengan cara ini Anda dapat menguji, jika kedua tempat berada dalam radius tertentu (lingkaran bukan kotak).

/**
 * Calculates the great-circle distance between two points, with
 * the Haversine formula.
 * @param float $latitudeFrom Latitude of start point in [deg decimal]
 * @param float $longitudeFrom Longitude of start point in [deg decimal]
 * @param float $latitudeTo Latitude of target point in [deg decimal]
 * @param float $longitudeTo Longitude of target point in [deg decimal]
 * @param float $earthRadius Mean earth radius in [m]
 * @return float Distance between points in [m] (same as earthRadius)
 */
public static function haversineGreatCircleDistance(
  $latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
  // convert from degrees to radians
  $latFrom = deg2rad($latitudeFrom);
  $lonFrom = deg2rad($longitudeFrom);
  $latTo = deg2rad($latitudeTo);
  $lonTo = deg2rad($longitudeTo);

  $latDelta = $latTo - $latFrom;
  $lonDelta = $lonTo - $lonFrom;

  $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
    cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
  return $angle * $earthRadius;
}
martinstoeckli
sumber
3

Untuk menguji apakah lat / lon berada di dalam atau di luar lingkaran pembatas, Anda perlu menghitung jarak dari lat / lon referensi Anda ke titik lat / lon yang ingin Anda uji. Karena jarak Anda 10km atau kurang, saya akan mencoba menggunakan pendekatan Equirectangular untuk mendapatkan jarak daripada Haversine karena kesederhanaan. Untuk mendapatkan jarak dalam km:

x = (lonRef - lon) * cos ( latRef )
y = latRef - lat
distance = EarthRadius * sqrt( x*x + y*y )

Catatan penting: lat / lon dalam rumus ini adalah dalam radian bukan derajat. Nilai khas EarthRadius adalah 6371 km yang akan mengembalikan jarak dalam satuan km. Sekarang ini adalah tes sederhana jika jarak Anda di dalam atau di luar lingkaran. Jika lingkaran pembatas bekerja, saya akan pergi dengan itu.

Untuk persegi panjang pembatas, saya akan menganggap Anda ingin persegi panjang didefinisikan dengan menjadi sejajar dengan garis khatulistiwa. Saya kemudian akan menghitung sudut-sudut kotak berlari menggunakan perhitungan rentang / bantalan (bantalan menjadi 45 derajat, 135 derajat, 225 derajat dan 315 derajat). Dari sana, saya akan menganggap Anda tidak ada di sekitar kutub dan menggunakan titik dalam uji poligon.

TreyA
sumber
2

Di bawah ini adalah kode T-SQL yang saya gunakan untuk membangun kotak pembatas di SQL-Server 2012. Dalam kasus saya, saya mendapatkan nilai desimal untuk Lat, Long. Saya menggunakan ini untuk dengan cepat membatasi jumlah baris sebelum saya menggunakan STDistancefungsi SQL untuk memverifikasi bahwa hasil sebenarnya dalam jarak tertentu. Fungsi geografi sangat mahal dalam SQL Server sehingga dengan membangun kotak pembatas saya dapat sangat mengurangi berapa kali harus dieksekusi.

DECLARE @Lat DECIMAL(20, 13) = 35.7862
   ,@Long DECIMAL(20, 13) = -80.3095
   ,@Radius DECIMAL(7, 2) = 5
   ,@Distance DECIMAL(10, 2)
   ,@Earth_Radius INT = 6371000;

SET @Distance = @Radius * 1609.344;

DECLARE @NorthLat DECIMAL(20, 13) = @Lat + DEGREES(@distance / @Earth_Radius)
   ,@SouthLat DECIMAL(20, 13) = @Lat - DEGREES(@distance / @Earth_Radius)
   ,@EastLong DECIMAL(20, 13) = @Long + DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)))
   ,@WestLong DECIMAL(20, 13) = @Long - DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)));

SELECT *
    FROM CustomerPosition AS cp
    WHERE (
            cp.Lat >= @SouthLat
            AND cp.Lat <= @NorthLat )
        AND (
              cp.Long >= @WestLong
              AND cp.Long <= @EastLong )
Vladimir Oselsky
sumber