ПХП и СКЛ: Израчунавање или испитивање растојања великог круга између тачака ширине и дужине помоћу Хаверсине формуле

Хаверсине формула - Израчунајте удаљеност велике кружнице помоћу ПХП-а или МиСКЛ-а

Овог месеца сам прилично програмирао на ПХП-у и МиСКЛ-у с обзиром на ГИС. Прегледавајући мрежу, заправо сам тешко пронашао неке од њих Географски прорачуни да нађем удаљеност између две локације, па сам желео да их поделим овде.

Мапа лета Европа са великом кружном раздаљином

Једноставан начин израчунавања удаљености између две тачке је помоћу питагорејске формуле за израчунавање хипотенузе троугла (А² + Б² = Ц²). Ово је познато као Еуклидска удаљеност.

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

Велики круг даљине

Руте које се прелазе велике удаљености око Земље познате су као Велики круг даљине. То јест ... најкраћа удаљеност између две тачке на сфери је различита од тачака на равној мапи. Комбинујте то са чињеницом да линије географске ширине и дужине нису једнако удаљене ... и имате тежак прорачун.

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

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

Удаљеност која користи закривљеност Земље је укључена у Формула хаверсина, који користи тригонометрију како би омогућио закривљеност земље. Када пронађете растојање између 2 места на земљи (док врана лети), права линија је заиста лук.

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

ПХП: Израчунајте удаљеност између 2 тачке ширине и дужине

У сваком случају, ево ПХП формуле за израчунавање удаљености између две тачке (заједно са претварањем миље у односу на километар) заокружено на две децимале.

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

СКЛ: Преузимање свих записа у опсегу израчунавањем удаљености у миљама помоћу географске ширине и дужине

Такође је могуће користити СКЛ за израчун како бисте пронашли све записе на одређеној удаљености. У овом примеру, поставићу упит МиТабле у МиСКЛ-у како бих пронашао све записе који су мањи или једнаки променљивој $ дистанце (у миљама) до моје локације на $ латитуде и $ лонгитуде:

Упит за преузимање свих записа у оквиру одређеног растојање израчунавањем удаљености у миљама између две тачке географске ширине и дужине су:

$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."

Ово ћете морати прилагодити:

  • $ географске дужине - ово је ПХП променљива где пролазим дужину тачке.
  • $ ширина - ово је ПХП променљива где пролазим дужину тачке.
  • $ раздаљина - ово је удаљеност на којој бисте желели да нађете све записе мање или једнаке.
  • табела - ово је табела ... желећете да је замените именом вашег стола.
  • ширина - ово је поље ваше географске ширине.
  • дужина - ово је поље ваше географске дужине.

СКЛ: Преузимање свих записа у опсегу израчунавањем удаљености у километрима помоћу географске ширине и дужине

Ево и СКЛ упита који користи километре у МиСКЛ:

$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."

Ово ћете морати прилагодити:

  • $ географске дужине - ово је ПХП променљива где пролазим дужину тачке.
  • $ ширина - ово је ПХП променљива где пролазим дужину тачке.
  • $ раздаљина - ово је удаљеност на којој бисте желели да нађете све записе мање или једнаке.
  • табела - ово је табела ... желећете да је замените именом вашег стола.
  • ширина - ово је поље ваше географске ширине.
  • дужина - ово је поље ваше географске дужине.

Користила сам овај код у платформи за мапирање предузећа, коју смо користили за малопродају са преко 1,000 локација широм Северне Америке, и то је функционисало прелепо.

Komentari

  1. 1

    Пуно вам хвала на подели. Ово је био једноставан посао копирања и лепљења и одлично функционише. Уштедели сте ми пуно времена.
    ФИИ за свакога ко преноси на Ц:
    доубле дег2рад (доубле дег) {ретурн степен * (3.14159265358979323846 / 180.0); }

  2. 2

    Врло леп комад поста - одлично је функционисао - морао сам само да променим назив стола који држи лат-лонг. Ради прилично брзо на .. Имам релативно мали број лат-лонг-а (<400), али мислим да би ово било лепо. Лепа веб локација такође - управо сам је додао на свој налог на дел.ицио.ус и редовно ћу проверавати.

  3. 4
  4. 5
  5. 8
  6. 10
  7. 11
  8. 12
  9. 14

    Горња формула ми штеди пуно времена. Много вам хвала.
    Такође морам да се пребацујем између НМЕА формата и степени. Пронашао сам формулу на овој УРЛ адреси на дну странице. http://www.errorforum.com/knowledge-base/16273-converting-nmea-sentence-latitude-longitude-decimal-degrees.html

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

    Хвала вам!
    Хари

  10. 15
  11. 16
  12. 17
  13. 18

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

  14. 19
  15. 20

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

    Много мање интензиван приступ је покретање првог (сировог) избора користећи КВАДРАТну површину дефинисану израчунатом удаљеностом, тј. „Селецт * фром табленаме вхере географска ширина између лат1 и лат2 и дужина између лон1 и лон2“. лат1 = циљна ширина - латдифф, лат2 = таргетлатитуде + латдифф, слично са лон. латдифф ~ = растојање / 111 (за км), или растојање / 69 за миље, јер је 1 степен географске ширине ~ 111 км (мала варијација јер је земља благо овална, али довољна за ову сврху). лондифф = удаљеност / (абс (цос (дег2рад (географска ширина)) * 111)) - или 69 миља (заправо можете узети мало већи квадрат да бисте узели у обзир варијације). Затим узмите резултат и унесите га у радијални селектор. Само не заборавите да узмете у обзир координате изван граница - тј. Опсег прихватљиве географске дужине је -180 до +180 и опсег прихватљиве географске ширине је -90 до +90 - у случају да ваша латдифф или лондифф ради изван овог опсега . Имајте на уму да у већини случајева ово можда није применљиво, јер утиче само на прорачуне преко линије кроз Пацифички океан од пола до пола, иако пресеца део Чукотке и део Аљаске.

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

    • 21
      • 22

        Фантастичан савет! Заправо сам радио са програмером који је написао функцију која је повукла унутрашњи квадрат, а затим рекурзивну функцију која је направила 'квадрате' по ободу како би укључила и изузела преостале тачке. Резултат је био невероватно брз - могао је да процени милионе поена у микросекундама.

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

        • 23

          Доуг,

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

  16. 24

    Поздрав свима, ово је моја пробна СКЛ изјава:

    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

    и Мискл ми говори да та удаљеност не постоји као колона, могу да користим редослед по, могу и без ВХЕРЕ, и успева, али не са њом ...

  17. 26

    Ово је сјајно, али баш као што птице лете. Било би сјајно покушати на овај начин некако уклопити АПИ за гоогле мапе (можда користећи путеве итд.) Само да бисте дали идеју користећи други облик превоза. Још увек нисам направио симулирану функцију жарења у ПХП-у која би могла да понуди ефикасно решење проблема путујућег продавца. Али мислим да ћу можда моћи поново да употребим неки ваш код да бих то учинио.

  18. 27
  19. 28
  20. 29
  21. 30
  22. 31
  23. 32
  24. 36

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

  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
  38. 55
  39. 56
  40. 58

    хвала што сте објавили овај користан чланак,  
    али из неког разлога бих желео да питам
    како добити растојање између коорда унутар мискл дб и коорда које је корисник уметнуо у пхп?
    за јаснији опис:
    1.корисник мора да убаци [ид] за одабир одређених података из дб-а и самих корисника
    2. пхп датотека добија циљне податке (координе) помоћу [ид] и затим израчунава удаљеност између корисника и циљне тачке

    или можете једноставно добити удаљеност од доњег кода?

    $ кри = „СЕЛЕЦТ *, (((ацос (син ((„. $ латитуде. ”* пи () / 180)) * син ((` Латитуде` * пи () / 180)) + цос ((„. $ латитуде. ”* пи () / 180)) * цос ((` Латитуде` * пи () / 180)) * цос (((„. $ лонгитуде.“ - `Лонгитуде`) * пи () / 180) ))) * 180 / пи ()) * 60 * 1.1515 * 1.609344) као удаљеност ОД `МиТабле` ВХЕРЕ удаљеност> =". $ Дистанце. " >>>> могу ли да "извадим" удаљеност одавде?
    Хвала још једном,
    Тимми С.

  41. 60

    ок, све што сам покушао не ради. Мислим, оно што имам делује, али растојања су далеко.

    Да ли би ико могао да види шта није у реду са овим кодом?

    иф (иссет ($ _ ПОСТ ['субмиттед'])) {$ з = $ _ПОСТ ['поштански број']; $ р = $ _ПОСТ ['радијус']; ецхо „Резултати за“. $ з; $ скл = мискл_куери („СЕЛЕЦТ ДИСТИНЦТ м.зипцоде, м.МктНаме, м.ЛоцАддСт, м.ЛоцАддЦити, м.ЛоцАддСтате, м.к1, м.и1, м.верифиед, з1.лат, з2.лон, з1. град, з1.држава ОД мрк м, зип з1, зип з2 ГДЕ је м.зипцоде = з1.зипцоде И з2.зипцоде = $ з АНД (3963 * ацос (скраћи (син (з2.лат / 57.2958) * син (м. и1 / 57.2958) + цос (з2.лат / 57.2958) * цос (м.и1 / 57.2958) * цос (м.к1 / 57.2958 - з2.лон / 57.2958), 8))) <= $ р ") или умри (мискл_еррор ()); вхиле ($ ров = мискл_фетцх_арраи ($ скл)) {$ сторе1 = $ ров ['МктНаме']. "”; $ сторе = $ ров ['ЛоцАддСт']. ””; $ сторе. = $ ров ['ЛоцАддЦити']. ",". $ ров ['ЛоцАддСтате']. " “. $ Ров ['поштански број']; $ латитуде1 = $ ров ['лат']; $ лонгитуде1 = $ ров ['лон']; $ латитуде2 = $ ров ['и1']; $ лонгитуде2 = $ ров ['к1']; $ цити = $ ров ['град']; $ стате = $ ров ['стате']; $ дис = гетнев ($ латитуде1, $ лонгитуде1, $ латитуде2, $ лонгитуде2, $ унит = 'Ми'); // $ дис = удаљеност ($ лат1, $ лон1, $ лат2, $ лон2); $ верификовано = $ ров ['верификовано']; иф ($ верифиед == '1') {ецхо “”; ецхо “”. $ сторе. ””; ецхо $ дис. " миља далеко"; одјек ""; } елсе {ецхо “”. $ сторе. ””; ецхо $ дис. " миља далеко"; одјек ""; }}}

    моје функције.пхп код
    функција гетнев ($ латитуде1, $ лонгитуде1, $ латитуде2, $ лонгитуде2, $ унит = 'Ми') {$ тхета = $ лонгитуде1 - $ лонгитуде2; $ раздаљина = (син (дег2рад ($ латитуде1)) * син (дег2рад ($ латитуде2))) + (цос (дег2рад ($ латитуде1)) * цос (дег2рад ($ латитуде2)) * цос (дег2рад ($ тхета)) ); $ дистанце = ацос ($ удаљеност); $ удаљеност = рад2дег ($ удаљеност); $ растојање = $ растојање * 60 * 1.1515; прекидач ($ јединица) {случај 'Ми': прекид; случај 'Км': $ дистанце = $ дистанце * 1.609344; } ретурн (заокружено ($ удаљеност, 2)); }

    Хвала унапред

  42. 61
  43. 62

    Хеј Доуглас, сјајан чланак. Сматрам да је ваше објашњење географских концепата и кода заиста занимљиво. Мој једини предлог био би размак и увлачење кода за приказ (попут Стацковерфлов-а, на пример). Разумем да желите да уштедите простор, али уобичајени размак / увлачење кода би ми као програмеру олакшао читање и сецирање. У сваком случају, то је мала ствар. Настави са добрим радом.

  44. 64
  45. 65
  46. 66
  47. 67
  48. 68
  49. 69
  50. 70

    чини се бржим (мискл 5.9) да се двоструко користи формула у селецт-у и где:
    $ формула = “(((ацос (син ((„. $ латитуде. ”* пи () / 180)) * син ((` Латитуде` * пи () / 180)) + цос ((„. $ латитуде. ”* Пи () / 180)) * цос ((` Латитуде` * пи () / 180)) * цос ((((„. $ Лонгитуде." - `Лонгитуде`) * пи () / 180)))) * 180 / пи ()) * 60 * 1.1515 * 1.609344) ”;
    $ скл = 'СЕЛЕЦТ *,'. $ формула. ' као удаљеност ОД табеле ГДЕ '.. $ формула.' <= '. $ удаљеност;

  51. 71
  52. 72

    Хвала вам пуно на стрижењу овог чланка. Веома је корисно.
    ПХП је испрва створен као једноставна платформа за скриптовање названа „Персонал Хоме Паге“. У данашње време ПХП (скраћеница од Хипертект Препроцессор) је алтернатива Мицрософтовој технологији Ацтиве Сервер Пагес (АСП).

    ПХП је језик отвореног кода на страни сервера који се користи за креирање динамичких веб страница. Може се уградити у ХТМЛ. ПХП се обично користи заједно са МиСКЛ базом података на Линук / УНИКС веб серверима. То је вероватно најпопуларнији скриптни језик.

  53. 73

    Нашао сам да горе решење не ради како треба.
    Морам да променим у:

    $ ккк = “СЕЛЕЦТ *, (((ацос (син ((“. $ латитуде. ”* пи () / 180)) * син ((` латт` * пи () / 180)) + цос ((“. $ латитуде. “* пи () / 180)) * цос ((` латт` * пи () / 180)) * цос ((((.. лонгитуде. “-` лонгт`) * пи () / 180) ))) * 180 / пи ()) * 60 * 1.1515) као удаљеност ОД `регистра`“;

  54. 75
  55. 76

    Здраво, молим вас, заиста ће ми требати ваша помоћ око овога.

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

    Међутим, користећи вашу формулу, он преузима све редове у мом дб-у

    $ резултати = ДБ :: селецт (ДБ :: рав (“СЕЛЕЦТ *, (((ацос (син ((“. $ латитуде. ”* пи () / 180)) * син ((лат * пи () / 180 )) + цос ((„.. латитуде.” * пи () / 180)) * цос ((лат * пи () / 180)) * цос (((„. $ лонгитуде.“ - лнг) * пи ( ) / 180)))) * 180 / пи ()) * 60 * 1.1515 * 1.609344) као удаљеност ОД маркера ИМАЈУ удаљеност> = “. $ Удаљеност));

    [{„Ид“: 1, „наме“: „Франкие Јохнние & Луиго Тоо“, „аддресс“: „939 В Ел Цамино Реал, Моунтаин Виев, ЦА“, „лат“: 37.386337280273, „лнг“: - 122.08582305908, ”Дистанце”: 16079.294719663}, {„ид”: 2, „наме”: „Пицерија Источне обале Амичија”, „адреса”: „790 Цастро Ст, Моунтаин Виев, Калифорнија”, „лат”: 37.387138366699, „лнг”: -122.08323669434, "удаљеност": 16079.175940152}, {"ид": 3, "име": "Капп'с Пизза Бар & Грилл", "адреса": "191 Цастро Ст, Моунтаин Виев, ЦА", "лат": 37.393886566162, ”Лнг”: - 122.07891845703, „удаљеност”: 16078.381373826}, {„ид”: 4, „наме”: „Пица округлог стола: Моунтаин Виев”, „аддресс”: „570 Н Схорелине Блвд, Моунтаин Виев, ЦА”, "Лат": 37.402652740479, "лнг": - 122.07935333252, "дистанце": 16077.420540582}, {"ид": 5, "наме": "Тизза & Алба'с Пизза & Паста", "аддресс": "619 Есцуела Аве, Моунтаин Поглед, Калифорнија ”,” лат ”: 37.394012451172,” лнг ”: - 122.09552764893,“ удаљеност ”: 16078.563225154}, {“ ид ”: 6,“ наме ”:“ Ореганова пица на дрва ”,“ адреса ”:” 4546 Ел Цамино Реал, Лос Алтос, Калифорнија ”,” лат ”: 37.401725769043,” лнг ”: - 122.11464691162,“ дистанце ”: 16077.937560795}, {“ ид ”: 7,” наме ”:” Тхе барс анд гриллс ”,“ аддресс ”:” 24 Вхителеи Стреет, Манцхестер ”,” лат ”: 53.485118865967,” лнг ”: - 2.1828699111938,“ дистанце ”: 8038.7620112314}]

    Желим да дохватим само редове са 20 миља, али доноси све редове. Молим те, шта радим погрешно

Шта ви мислите?

Ова страница користи Акисмет како би смањила нежељену пошту. Сазнајте како се ваш коментар обрађује.