PHP и SQL: Пресметајте или побарајте големо растојание на кругот помеѓу точките на географска ширина и должина со формулата Haversine

Haversine Формула - Пресметајте го големото растојание на кругот со PHP или MySQL

Овој месец програмирав доста во PHP и MySQL во однос на ГИС. Душкајќи по мрежата, навистина ми беше тешко да најдам дел од Географски пресметки да најдам растојание помеѓу две локации, па затоа сакав да ги споделам тука.

Мапа на летови Европа со голема далечина на кругови

Едноставен начин за пресметување на растојание помеѓу две точки е користење на Питагоровата формула за пресметување на хипотенузата на триаголник (A² + B² = C²). Ова е познато како Евклидовска оддалеченост.

Тоа е интересен почеток, но не се однесува на географијата, бидејќи растојанието е помеѓу линиите на географска ширина и должина не е еднакво растојание разделени Како што се приближувате до екваторот, линиите на ширина се оддалечуваат. Ако користите некаква едноставна равенка на трианглацијата, може да се измери растојанието точно на една локација и страшно погрешно на другата, заради закривеноста на Земјата.

Големо растојание на кругот

Патеките што се патуваат на долги растојанија околу Земјата се познати како Големо растојание на кругот. Тоа е… најкраткото растојание помеѓу две точки на една сфера е различно од точките на рамната мапа. Комбинирајте го тоа со фактот дека линиите на ширина и должина не се еднакво оддалечени ... и имате тешка пресметка.

Еве фантастично видео објаснување за тоа како функционираат Големите кругови.

Формулата Хаверсин

Растојанието со искривување на Земјата е вградено во Формула на аверсин, која користи тригонометрија за да овозможи искривување на земјата. Кога наоѓате растојание помеѓу 2 места на земјата (додека лета врана), права линија е навистина лак.

Ова се применува при летање со авион - дали некогаш сте ја погледнале вистинската мапа на летови и сте забележале дека се заоблени? Тоа е затоа што е пократко да се лета во лак помеѓу две точки отколку директно до локацијата.

PHP: Пресметајте го растојанието помеѓу 2 точки на географска ширина и должина

Како и да е, еве ја PHP формулата за пресметување на растојанието помеѓу две точки (заедно со конверзијата Мил наспроти Километар) заокружено на две децимални места.

function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'miles') {
  $theta = $longitude1 - $longitude2; 
  $distance = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta))); 
  $distance = acos($distance); 
  $distance = rad2deg($distance); 
  $distance = $distance * 60 * 1.1515; 
  switch($unit) { 
    case 'miles': 
      break; 
    case 'kilometers' : 
      $distance = $distance * 1.609344; 
  } 
  return (round($distance,2)); 
}

SQL: Преземање на сите записи во опсег со пресметување на растојанието во милји користејќи географска ширина и должина

Исто така е можно да се користи SQL за да се направи пресметка за да се најдат сите записи на одредено растојание. Во овој пример, ќе побарам MyTable во MySQL да ги најдам сите записи што се помали или еднакви на променливото $ растојание (во милји) до мојата локација на $ географска ширина и $ должина:

Барање за преземање на сите записи во рамките на одредено растојание со пресметување на растојанието во милји помеѓу две точки на географска ширина и должина се:

$query = "SELECT *, (((acos(sin((".$latitude."*pi()/180)) * sin((`latitude`*pi()/180)) + cos((".$latitude."*pi()/180)) * cos((`latitude`*pi()/180)) * cos(((".$longitude."- `longitude`)*pi()/180)))) * 180/pi()) * 60 * 1.1515) as distance FROM `table` WHERE distance <= ".$distance."

Needе треба да го прилагодите ова:

  • должина $ - ова е PHP променлива каде што минувам по должината на точката.
  • $ географска ширина - ова е PHP променлива каде што минувам по должината на точката.
  • $ растојание - ова е растојанието што сакате да ги најдете сите записи помалку или еднакви.
  • маса - ова е табелата… ќе сакате да ја замените со името на вашата табела.
  • географска ширина - ова е полето на вашата географска ширина.
  • должина - ова е полето на вашата должина.

SQL: Преземање на сите записи во опсег со пресметување на растојанието во километри користејќи географска ширина и должина

И еве го прашањето SQL користејќи километри во MySQL:

$query = "SELECT *, (((acos(sin((".$latitude."*pi()/180)) * sin((`latitude`*pi()/180)) + cos((".$latitude."*pi()/180)) * cos((`latitude`*pi()/180)) * cos(((".$longitude."- `longitude`) * pi()/180)))) * 180/pi()) * 60 * 1.1515 * 1.609344) as distance FROM `table` WHERE distance <= ".$distance."

Needе треба да го прилагодите ова:

  • должина $ - ова е PHP променлива каде што минувам по должината на точката.
  • $ географска ширина - ова е PHP променлива каде што минувам по должината на точката.
  • $ растојание - ова е растојанието што сакате да ги најдете сите записи помалку или еднакви.
  • маса - ова е табелата… ќе сакате да ја замените со името на вашата табела.
  • географска ширина - ова е полето на вашата географска ширина.
  • должина - ова е полето на вашата должина.

Јас го искористив овој код во платформа за мапирање на претпријатие што ја искористивме за продавница за малопродажба со над 1,000 локации низ Северна Америка и работеше прекрасно.

76 Коментари

  1. 1

    Ви благодарам многу за споделувањето. Ова беше лесна работа за копирање и лепење и работи одлично. Ме заштеди многу време.
    FYI за секој што пренесува C:
    двоен deg2rad (двоен deg) {return deg * (3.14159265358979323846 / 180.0); }

  2. 2

    Многу убаво објавување - работеше многу убаво - само требаше да го сменам името на табелата што ја држеше долгата. Работи прилично брзо за да .. Имам разумно мал број долги долги долгови (<400), но мислам дека ова би се развиело убаво. Убава страница исто така - само што ја додадов на мојата сметка на del.icio.us и редовно ќе проверувам.

  3. 4
  4. 5

    Пребарував цел ден за пресметки на далечина и го најдов алгоритмот харверзин, благодарение на вас што дадовте пример како да го поставите во изјава sql. Благодарам и поздрав, Даниел

  5. 8

    мислам дека на вашиот SQL му треба изјава.
    наместо КАДЕ растојание <= $ оддалеченост можеби ќе треба
    користете ПОВЕЕ растојание <= $ растојание

    инаку благодарам што ми заштеди еден куп време и енергија.

    • 9
  6. 10
  7. 11
  8. 12

    Ви благодариме многу за споделувањето на овој код. Ми заштеди многу време за развој. Исто така, благодарение на вашите читатели за укажувањето дека ИМАТЕ изјава е неопходна за MySQL 5.x. Многу корисно.

  9. 14

    Горенаведената формула ми заштедува многу време. Ти благодарам многу.
    Исто така, мора да се префрлам помеѓу форматот NMEA и степени. Најдов формула на оваа URL на дното на страницата. http://www.errorforum.com/knowledge-base/16273-converting-nmea-sentence-latitude-longitude-decimal-degrees.html

    Дали некој знае како да го потврди ова?

    Ви благодариме!
    Хари

  10. 15
  11. 16

    Исто така, открив дека КАДЕ не работи за мене. Го сменија во ХАВИНГ и сè работи совршено. Отпрвин не ги прочитав коментарите и ги напишав повторно со вгнезден избор. И двајцата ќе работат добро.

  12. 17

    Ви благодариме многу за скриптата напишана во mysql, само мораше да направам неколку мали прилагодувања (ДАЛИ) 🙂
    Голема работа

  13. 18

    Неверојатно корисно, ви благодарам многу! Имав некои проблеми со новиот „ПОВЕЛЕЕ“, наместо со „КАДЕ“, но штом ги прочитав коментарите тука (по околу половина час мелење заби од фрустрација = П), сфатив дека работи убаво. Ви благодарам ^ _ ^

  14. 19
  15. 20

    Имајте на ум дека изберете изјава како што ќе биде многу компјутерски интензивна и затоа бавно. Ако имате многу од тие прашања, тоа може многу брзо да ги смали работите.

    Многу помалку интензивен пристап е да се изврши прв (суров) избор со користење на ПОДРАЧНО подрачје дефинирано со пресметано растојание т.е. „избери * од табелата каде што географската ширина помеѓу lat1 и lat2 и должина помеѓу lon1 и lon2“. lat1 = таргет-географска ширина - латдиф, lat2 = таргет-географска ширина + латдиф, слично на лон. Латдиф ~ = растојание / 111 (за км), или растојание / 69 за милји бидејќи 1 степен географска ширина е 111 2 км (мала варијација бидејќи земјата е малку овална, но доволна за оваа намена). лондиф = растојание / (апс (кос (deg111rad (географска ширина)) * 69)) - или 180 милји (всушност може да се земе малку поголем квадрат со цел да се земат предвид варијациите). Потоа земете го резултатот од тоа и нахранете го во радијалниот избор. Само не заборавајте да земете сметка за надвор од границите на координатите - т.е. опсегот на прифатлива географска должина е од -180 до +90 и опсегот на прифатлива географска ширина е од -90 до +XNUMX - во случај вашиот латдиф или лондиф да работи надвор од овој опсег . Имајте на ум дека во повеќето случаи ова може да не биде применливо бидејќи влијае само на пресметките преку линијата низ Тихиот океан од пол до пол, иако пресекува дел од Чукотка и дел од Алјаска.

    Она што го постигнуваме со ова е значително намалување на бројот на поени против кои ја правите оваа пресметка. Ако имате милион глобални поени во базата на податоци распределени приближно рамномерно и сакате да пребарувате на 100 км, тогаш вашето прво (брзо) пребарување е на површина од 10000 квадратни километри и веројатно ќе даде околу 20 резултати (засновано на рамномерна распределба на површина од околу 500 милиони квадратни километри), што значи дека ја извршувате сложената пресметка на растојанието 20 пати за ова прашање наместо милион пати.

    • 21

      Мала грешка во примерот… тоа би било за 50 км (не 100) бидејќи гледаме во „радиусот“ на нашиот квадрат.

      • 22

        Фантастичен совет! Јас всушност работев со развивач кој напиша функција што го влече внатрешниот квадрат, а потоа и рекурзивна функција што ги направи „квадратите“ околу периметарот за да ги вклучи и исклучи преостанатите точки. Резултатот беше неверојатно брз резултат - тој можеше да процени милиони поени во микросекунди.

        Мојот пристап погоре е дефинитивно „груб“, но способен. Благодарам уште еднаш!

        • 23

          Даг,

          Се обидував да користам mysql и php за да проценам дали долгата точка е во рамките на многуаголникот. Дали знаете дали вашиот пријател-развивач објави примери за тоа како да ја исполните оваа задача. Или знаете некои добри примери. Благодарам однапред.

  16. 24

    Здраво на сите, ова е мојата тест изјава SQL:

    SELECT DISTINCT area_id, (
    (
    (
    acos( sin( ( 13.65 * pi( ) /180 ) ) * sin( (
    `lat_dec` * pi( ) /180 ) ) + cos( ( 13.65 * pi( ) /180 ) ) * cos( (
    `lat_dec` * pi( ) /180 )
    ) * cos( (
    ( 51.02 - `lon_dec` ) * pi( ) /180 )
    )
    )
    ) *180 / pi( )
    ) *60 * 1.1515 * 1.609344
    ) AS distance
    FROM `post_codes` WHERE distance <= 50

    и Mysql ми кажува дека растојанието, не постои како колона, можам да користам нарачка до, можам да го направам тоа без КАДЕ, и работи, но не со него

  17. 26

    Ова е одлично, сепак е исто како што летаат птиците. Би било одлично да се обидете и да го вклучите API на мапите на Google некако во ова (можеби користејќи патишта и сл.) Само да дадете идеја користејќи поинаква форма на превоз. Сè уште немам направено симулирана функција за заварување во PHP што ќе може да понуди ефикасно решение за проблемот со продавачот што патува. Но, мислам дека можеби ќе успеам да користам дел од твојот код за да го сторам тоа.

  18. 27

    Здраво Даглас,
    многу ви благодарам за овој напис - вие само заштедивте многу време.
    чувај се,
    нимрод @ Израел

  19. 28

    Добра статија! Најдов многу статии кои опишуваат како да пресметам растојание помеѓу две точки, но навистина ја барав SQL фрагментот.

  20. 29
  21. 30
  22. 31
  23. 32
  24. 36

    2 дена истражување за конечно да ја пронајдам оваа страница што го решава мојот проблем. Изгледа подобро да го разбијам мојот ВолфрамАлфа и да ги исчистам моите математики. Промената од КАДЕ во ХАВИНГ ја има мојата скрипта во работна состојба. ВИ БЛАГОДАРАМ

  25. 37
    • 38

      Благодарам Георги. Продолжував да не ја наоѓам колоната „далечина“ Откако ќе го сменам КАДЕ да имам, работеше како шарм!

  26. 39

    Посакувам ова да беше првата страница што ќе ја пронајдам на оваа страница. Откако испробав многу различни команди, ова единствено работеше правилно и минимални промени потребни за да одговара на мојата сопствена база на податоци.
    Фала многу!

  27. 40

    Посакувам ова да беше првата страница што ќе ја пронајдам на оваа страница. Откако испробав многу различни команди, ова единствено работеше правилно и минимални промени потребни за да одговара на мојата сопствена база на податоци.
    Фала многу!

  28. 41
  29. 42
  30. 43
  31. 45
  32. 46
  33. 47

    Знам дека оваа формула работи, но не можам да видам каде е земен предвид радиусот на земјата. Може ли некој да ме просветли, ве молам?

  34. 49
  35. 50
  36. 52
  37. 53

    Постојано добивам грешка во грешка: Непозната колона „Растојание“ во „каде реченица“ на барањето MySQL.

  38. 55
  39. 56
  40. 58

    благодарам што ја објавивте оваа корисна статија,  
    но поради некоја причина би сакал да прашам
    како да се добие растојанието помеѓу координатите во mysql db и координатите вметнати во php од страна на корисникот?
    за појасно опишете:
    1. корисникот треба да вметне [id] за избор на специфицирани податоци од db и координациите на самиот корисник
    2. PHP-датотеката ги добива целните податоци (координати) со помош на [id] и потоа пресметува растојание помеѓу корисникот и целната точка

    или едноставно може да се добие растојание од кодот подолу?

    $ qry = "Избери *, (((acos (sin ((". $ географска ширина. "* pi () / 180)) * sin ((" Latitude "* pi () / 180)) + cos ((". $ географска ширина. "* pi () / 180)) * cos ((" Географска ширина "* pi () / 180)) * cos (((". $ должина. "-" Лонгитуда ") * pi () / 180) ))) * 180 / pi ()) * 60 * 1.1515 * 1.609344) како растојание ОД `MyTable` WHERE растојание> =„. $ Растојание “. >>>> дали можам да ја „извадам“ оддалеченоста од тука?
    благодарам уште еднаш,
    Тими С.

  41. 60

    ок, сè што пробав не работи. Мислам, она што го имам делува, но далечините се далеку.

    Може некој да види што не е во ред со овој код?

    ако (издавач ($ _ ПОСТ ['доставено']))) {$ z = $ _POST ['поштенски код']; $ r = $ _POST ['радиус']; ехо „Резултати за„. $ z; $ sql = mysql_query („Изберете дистинкт m.zipcode, m.MktName, m.LocAddSt, m.LocAddCity, m.LocAddState, m.x1, m.y1, m.verified, z1.lat, z2.lon, z1. град, z1.state ОД mrk m, zip z1, zip z2 КАДЕ m.zipcode = z1.zipcode AND z2.zipcode = $ z AND (3963 * acos (truncate (sin (z2.lat / 57.2958) * sin) y1 / 57.2958) + cos (z2.lat / 57.2958) * cos (m.y1 / 57.2958) * cos (m.x1 / 57.2958 - z2.lon / 57.2958), 8))) <= $ r ") или умре (mysql_error ()); додека ($ row = mysql_fetch_array ($ sql)) {$ store1 = $ row ['MktName']. ""; $ store = $ row ['LocAddSt']. ””; $ store. = $ row ['LocAddCity']. ",". $ row ['LocAddState']. " „. $ Ред ['поштенски код']; $ географска ширина1 = $ ред ['lat']; $ должина1 = $ ред ['лон']; $ географска ширина2 = $ ред ['y1']; $ должина2 = $ ред ['x1']; $ град = $ ред ['град']; $ држава = $ ред ['држава']; $ dis = getnew ($ географска ширина 1, $ должина 1, $ ширина 2, $ должина 2, $ единица = 'Ми'); // $ dis = растојание ($ lat1, $ lon1, $ lat2, $ lon2); $ проверено = $ ред ['потврдено']; ако ($ проверено == '1') {ехо “”; ехо “”. $ продавница. ””; ехо $ дис. ”Милја (и) далеку”; ехо „“; } other {echo “”. $ store. ””; ехо $ дис. ”Милја (и) далеку”; ехо „“; }}}

    моите функции.php код
    функција getnew ($ географска ширина 1, $ должина 1, $ ширина 2, $ должина 2, $ единица = 'Ми') {$ тета = $ должина 1 - $ должина 2; $ растојание = (sin (deg2rad ($ latitude1)) * sin (deg2rad ($ latitude2))) + + (cos (deg2rad ($ latitude1)) * cos (deg2rad ($ ширина2)) * cos (deg2rad ($ тета)) ); $ далечина = acos ($ далечина); $ далечина = rad2deg ($ растојание); $ далечина = $ далечина * 60 * 1.1515; прекинувач ($ единица) {case 'Mi': break; случај 'Km': $ оддалеченост = $ растојание * 1.609344; } поврат (круг ($ далечина, 2)); }

    Благодарам однапред

  42. 61
  43. 62

    Еј Даглас, одличен напис. Вашето објаснување за географските концепти и кодот го најдов навистина интересно. Мојот единствен предлог би бил да го поставам просторот и да го вметнам кодот за приказ (како Stackoverflow, на пример). Јас разбирам дека сакате да заштедите простор, но конвенционалното растојание / вдлабнување на кодот ќе ми олесни на читателот и расекувањето, како програмер, многу полесно. Како и да е, тоа е мала работа. Продолжете со одличната работа.

  44. 64
  45. 65

    овде додека користиме со функција добиваме еден вид растојание .. додека користиме пребарување што доаѓа неговиот друг вид на растојание

  46. 66
  47. 67
  48. 68
  49. 69
  50. 70

    се чини побрзо (mysql 5.9) да се користи двојно повеќе од формулата во изборот и каде:
    $ формула = "(((acos (sin ((". $ географска ширина. "* pi () / 180)) * sin ((" Latitude "* pi () / 180)) + cos ((". $ географска ширина. "* Pi () / 180)) * cos ((" Географска ширина "* pi () / 180)) * cos (((". $ Должина. "-" Лонгитуда ") * pi () / 180)))) * 180 / pi ()) * 60 * 1.1515 * 1.609344) ”;
    $ sql = 'Избери *,'. $ формула. ' како растојание ОД табелата КАДЕ '.. $ формула.' <= '. $ растојание;

  51. 71
  52. 72

    Ви благодариме многу за смолкнување на овој напис. Тоа е многу корисно.
    PHP најпрво беше создадена како едноставна платформа за скриптирање наречена „Лична почетна страница“. Во денешно време PHP (кратенка за хипертекст Препроцесор) е алтернатива на технологијата на Microsoft Active Server Pages (ASP) на Microsoft.

    PHP е јазик од отворен извор од страна на серверот што се користи за создавање динамични веб-страници. Може да биде вграден во HTML. PHP обично се користи заедно со MySQL база на податоци на веб-серверите Linux / UNIX. Тој е веројатно најпопуларниот јазик за скрипти.

  53. 73

    Го најдов погоре решението да не работи правилно.
    Треба да се сменам во:

    $ qqq = "ИЗБОР *, (((acos (sin ((". $ географска ширина. "* pi () / 180)) * sin ((` latt` * pi () / 180)) + cos ((". $ географска ширина. "* pi () / 180)) * cos ((" latt "* pi () / 180)) * cos (((". $ географска должина. "-" longt ") * pi () / 180) ))) * 180 / pi ()) * 60 * 1.1515) како растојание ОД `регистар`;

  54. 75
  55. 76

    Здраво, ве молам навистина ќе ми треба вашата помош за ова.

    Направив барање за добивање до мојот веб-сервер http://localhost:8000/users/findusers/53.47792/-2.23389/20/
    53.47792 = $ географска ширина
    -2.23389 = $ должина
    и 20 = растојанието што сакам да го вратам

    Како и да е, користејќи ја формулата, таа ги презема сите редови во мојата db

    $ резултати = ДБ :: изберете (ДБ :: суров („ИЗБОР *, (((акос (грев ((„. $ географска ширина.) * пи () / 180)) * грев ((лат * пи () / 180 )) + кос ((". $ географска ширина." * пи () / 180)) * кос ((лат * пи () / 180)) * кос (((". $ должина." - lng) * пи ( ) / 180)))) * 180 / pi ()) * 60 * 1.1515 * 1.609344) како растојание ОД обележувачи кои имаат растојание> = “. $ Растојание));

    [{“Id”: 1, ”name”: ”Frankie Johnnie & Luigo Too”, ”address”: ”939 W El Camino Real, Mountain View, CA”, ”lat”: 37.386337280273, ”lng”: - 122.08582305908, ”Далечина”: 16079.294719663}, {“id”: 2, ”име”: ”Пицерија на источниот брег на Амичи”, ”адреса”: ”Ул. Кастро 790, Маунтин Вју, Калифорнија”, ”лат”: 37.387138366699, ”lng”: -122.08323669434, ”далечина”: 16079.175940152}, {“id”: 3, ”име”: ”Kapp's Pizza Bar & Grill”, ”адреса”: ”191 St Castro, Mountain View, CA”, ”lat”: 37.393886566162, ”Lng”: - 122.07891845703, ”растојание”: 16078.381373826}, {“id”: 4, ”име”: ”Тркалезна маса пица: Планински поглед”, ”адреса”: ”Бул. 570 N Shoreline, Маунтин Вју, Калифорнија”, ”Лат”: 37.402652740479, ”lng”: - 122.07935333252, ”оддалеченост”: 16077.420540582}, {“id”: 5, ”име”: ”Tony & Alba's Pizza & Pasta”, ”адреса”: ”Ave 619 Escuela, Mountain View, CA ”,” lat ”: 37.394012451172,” lng ”: - 122.09552764893,” distance ”: 16078.563225154}, {“ id ”: 6,” name ”:” Пица од орегано на дрва ”,” адреса ”:” 4546 Ел Камино Реал, Лос Алтос, Калифорнија ”,” лат ”: 37.401725769043,” lng ”: - 122.11464691162,” растојание ”: 16077.937560795}, {“ id ”: 7,” name ”:” The bars and grills ”,” address ”:” 24 Whiteley Street, Manchester ”,” lat ”: 53.485118865967,” lng ”: - 2.1828699111938,” distance ”: 8038.7620112314}]

    Сакам да преземам само редови со 20 милји, но ги носи сите редови. Те молам што грешам

Што мислите?

Оваа страница користи Akismet за намалување на спам. Научете како се обработува вашиот коментар.