Израчунајте или упитајте раздаљину великог круга између тачака географске ширине и дужине користећи Хаверсине формулу (ПХП, Питхон, МиСКЛ, МССКЛ примери)

Хаверсине формула - Велика кружна удаљеност - ПХП, Питхон, МиСКЛ

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

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

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

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

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

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

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

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

Удаљеност која користи закривљеност Земље је укључена у Формула хаверсина, који користи тригонометрију како би омогућио закривљеност земље. Када пронађете растојање између 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)); 
}

Променљиве су:

  • $Латитуде1 – променљива за географску ширину ваше прве локације.
  • $Лонгитуде1 – променљива за географску дужину ваше прве локације
  • $Латитуде2 – променљива за географску ширину ваше друге локације.
  • $Лонгитуде2 – променљива за географску дужину ваше друге локације.
  • $унит – подразумевано биће миља. Ово се може ажурирати или проследити као километара.

Питхон: Израчунајте растојање између 2 тачке географске ширине и дужине

У сваком случају, ево Питхон формуле за израчунавање удаљености између две тачке (заједно са конверзијом миља у односу на километар) заокружене на две децимале. Свака част мом сину, Биллу Карру који је научник за податке ОпенИНСИГХТС, за код.

from numpy import sin, cos, arccos, pi, round

def rad2deg(radians):
    degrees = radians * 180 / pi
    return degrees

def deg2rad(degrees):
    radians = degrees * pi / 180
    return radians

def getDistanceBetweenPointsNew(latitude1, longitude1, latitude2, longitude2, unit = 'miles'):
    
    theta = longitude1 - longitude2
    
    distance = 60 * 1.1515 * rad2deg(
        arccos(
            (sin(deg2rad(latitude1)) * sin(deg2rad(latitude2))) + 
            (cos(deg2rad(latitude1)) * cos(deg2rad(latitude2)) * cos(deg2rad(theta)))
        )
    )
    
    if unit == 'miles':
        return round(distance, 2)
    if unit == 'kilometers':
        return round(distance * 1.609344, 2)

Променљиве су:

  • географска ширина1 – променљива за вашу прву локацију ширина.
  • географска дужина1 – променљива за вашу прву локацију дужина
  • географска ширина2 – променљива за вашу другу локацију ширина.
  • географска дужина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 локација широм Северне Америке, и то је функционисало прелепо.

Мицрософт СКЛ Сервер Географска удаљеност: СТДистанце

Ако користите Мицрософт СКЛ Сервер, они нуде своју функцију, СТДистанце за израчунавање растојања између две тачке помоћу типа података Географија.

DECLARE @g geography;  
DECLARE @h geography;  
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326);  
SET @h = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326);  
SELECT @g.STDistance(@h);  

Шешир за Манасх Сахоо, потпредседник и архитекта оф Highbridge.

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 миља, али то доноси све редове. Молим те шта радим погрешно

  56. 77

    Тражим сличан упит, али сам се мало појачао – укратко, ово је да групишете све координате у кругу од 2 миље од сваке координате, а затим избројите колико координата у свакој групи и испишете само једну групу која има највише координата – чак и ако имате више од једне групе међу групама које имају највећи број координата – једноставно избаците случајну групу из група са истим највећим бројем –

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

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