PHP eta SQL: Kalkulatu edo galdetu Latitude eta Longitudea puntuen arteko zirkulu handiko distantzia Haversine formularekin

Haversine Formula - Kalkulatu Zirkulu Handiko Distantzia PHP edo MySQL-rekin

Hilabete honetan PHP eta MySQL programetan dezente programatu dut GISari dagokionez. Sarean barrena zebilen, egia esan, zaila izan nuen zenbait Kalkulu geografikoak bi kokapenen arteko distantzia aurkitzeko, beraz, hemen partekatu nahi nuen.

Hegaldi Mapa Europa Zirkulu Handiko Distantziarekin

Bi punturen arteko distantzia kalkulatzeko modu sinplea formula pitagorikoa erabiliz triangelu baten hipotenusa kalkulatzeko da (A² + B² = C²). Hau izenarekin ezagutzen da Distantzia euklidearra.

Hasiera interesgarria da, baina ez da aplikatzen Geografiarekin, latitudearen eta longitudearen arteko distantzia baita ez distantzia berdina aparte. Ekuatorera hurbildu ahala, latitudearen marrak aldendu egiten dira. Triangulazio ekuazio sinpleen bat erabiltzen baduzu, distantzia kokapen batean zehatz neur dezake eta bestean oso okerra, Lurraren kurbatura dela eta.

Zirkulu Handiko Distantzia

Lurraren inguruan distantzia luzeak egiten dituzten ibilbideak Zirkulu Handiko Distantzia. Hau da, esfera bateko bi punturen arteko distantzia laburrena mapa lauko puntuekiko desberdina da. Konbinatu latitudea eta longitudea lerroak berdinak ez izatearekin ... eta kalkulu zaila duzu.

Hemen duzue zirkulu bikainak nola funtzionatzen duen azaltzen duen bideo zoragarria.

Haversine Formula

Lurraren kurbatura erabiliz distantzia sartzen da Haversine formula, trigonometria erabiltzen duena lurraren kurbadura ahalbidetzeko. Lurreko 2 lekuren arteko distantzia aurkitzen ari zarenean (beleak hegan egiten duen heinean), lerro zuzena arku bat da.

Hori aireko hegaldietan aplika daiteke. Inoiz begiratu al duzu hegaldien benetako mapa eta arkuak direla ikusi duzu? Bi punturen arteko arku batean hegan egitea laburragoa delako kokapenera zuzenean baino.

PHP: Kalkulatu Latitudearen eta Longitudearen 2 Puntuen arteko Distantzia

Dena den, hona hemen bi puntu arteko biribildutako bi punturen arteko distantzia kalkulatzeko PHP formula (Kilometroaren eta Kilometroaren bihurketarekin batera).

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: Erregistro guztiak barruti batean berreskuratzea Latitudea eta Longitudea erabiliz distantzia milian kalkulatuz

SQL erabil daiteke erregistro guztiak distantzia jakin batean aurkitzeko kalkulua egiteko. Adibide honetan, MyTable kontsultatuko dut MySQL-n, $ latitude eta $ longitudean kokapenarekiko $ distantzia aldakorreko (miletan) baino txikiagoak edo berdinak diren erregistro guztiak aurkitzeko:

Erregistro guztiak zehatz baten barruan berreskuratzeko kontsulta distantzia bi latitudearen eta longitudearen arteko distantzia miliatan kalkulatuz hauek dira:

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

Hau pertsonalizatu beharko duzu:

  • $ longitudea - Hau PHP aldagaia da, non puntuaren longitudea pasatzen ari naizen.
  • $ latitudea - Hau PHP aldagaia da, non puntuaren longitudea pasatzen ari naizen.
  • $ distantzia - hau da erregistro guztiak txikiagoak edo berdinak aurkitzea gustatuko litzaizukeen distantzia.
  • taula - Taula hau da ... zure mahaiaren izenarekin ordezkatu nahi duzu.
  • latitude - hau da zure latitudearen eremua.
  • longitudea - hau da zure longitudearen eremua.

SQL: Erregistro guztiak barruti batean berreskuratzea Latitudea eta Longitudea erabiliz Kilometrotan Distantzia Kalkulatuz

Hemen duzu SQL kontsulta MySQL-n kilometroak erabiliz:

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

Hau pertsonalizatu beharko duzu:

  • $ longitudea - Hau PHP aldagaia da, non puntuaren longitudea pasatzen ari naizen.
  • $ latitudea - Hau PHP aldagaia da, non puntuaren longitudea pasatzen ari naizen.
  • $ distantzia - hau da erregistro guztiak txikiagoak edo berdinak aurkitzea gustatuko litzaizukeen distantzia.
  • taula - Taula hau da ... zure mahaiaren izenarekin ordezkatu nahi duzu.
  • latitude - hau da zure latitudearen eremua.
  • longitudea - hau da zure longitudearen eremua.

Kode hau Ipar Amerika osoan 1,000 kokapen baino gehiago dituen txikizkako denda baterako erabiltzen genuen enpresa mapen plataforman erabili nuen eta ederki funtzionatu zuen.

77 Comments

  1. 1

    Mila esker partekatzeagatik. Kopiatu eta itsatsi lan erraza izan zen eta bikain funtzionatzen du. Denbora asko gorde didazu.
    FYI C-ra eramaten duenarentzat:
    bikoitza deg2rad (bikoitza deg) {return Deg * (3.14159265358979323846 / 180.0); }

  2. 2

    Argitalpen oso polita - oso polita lan egin du - lat-luzea duen mahaiaren izena aldatu behar nuen. Nahiko azkar funtzionatzen du .. Lat-longs (<400) kopuru nahiko txikia daukat, baina uste dut hau polita eskalatuko litzatekeela. Gune polita ere - del.icio.us kontuan gehitu berri dut eta aldizka begiratuko dut.

  3. 4
  4. 5
  5. 8

    Uste dut zure SQL-k adierazpen bat behar duela.
    WHERE distance <= $ distance beharko zenukeen ordez
    erabili HAVING distance <= $ distance

    bestela, eskerrik asko denbora eta energia pila bat aurrezteagatik.

  6. 10
  7. 11
  8. 12

    Mila esker kode hau partekatzeagatik. Garapen denbora asko aurreztu ninduen. Gainera, eskerrik asko zure irakurleei adierazi didatenez, HAVING adierazpena beharrezkoa da MySQL 5.x-rako. Oso lagungarria.

  9. 14
  10. 15
  11. 16

    WHEREk niretzat ez zuela funtzionatu ere aurkitu nuen. HAVING izatera aldatu da eta dena primeran funtzionatzen du. Hasieran ez nituen iruzkinak irakurri eta habia aukeratutako bat erabiliz berridatzi. Biek ondo funtzionatuko dute.

  12. 17
  13. 18

    Izugarri lagungarria, mila esker! Zenbait arazo izan nituen "IZATEA" berriarekin, "NON" baino, baina hemen iruzkinak irakurrita (ordu erdi inguru hortzak frustrazioarekin zapuztu ondoren = P), ondo funtzionatu nuen. Eskerrik asko ^ _ ^

  14. 19
  15. 20

    Gogoan izan horrelako adierazpen hautatuak oso konputazionalki biziak eta, beraz, motelak izango direla. Galdera horietako asko baldin badituzu, gauzak nahiko azkar galarazi ditzake.

    Askoz ere hurbilagoa ez den ikuspegia lehenengo hautaketa (gordina) bat egitea da kalkulatutako distantziaz definitutako SQUARE eremua erabiliz, hau da, "hautatu * taula izenetik non latitudea lat1 eta lat2 artekoa eta lon1 eta lon2 arteko longitudea". lat1 = targetlatitude - latdiff, lat2 = targetlatitude + latdiff, lon-ren antzekoa. latdiff ~ = distantzia / 111 (km-rako) edo distantzia / 69 miliatarako latitudea 1 ~ ~ km-ra dagoenez (aldakuntza txikia lurra apur bat obalatua denez, baina nahikoa da horretarako). londiff = distance / (abs (cos (deg111rad (latitude)) * 2)) - edo 111 kilometrotan (benetan karratu handiago bat har dezakezu aldakuntzak kontutan hartzeko). Ondoren, hartu horren emaitza eta elikatu erradialaren aukerara. Ez ahaztu mugaz kanpoko koordenatuak kontutan hartzea - ​​hau da, longitudea onargarria -69 eta +180 bitartekoa da eta latitudea onargarria -180 eta +90 artekoa da - zure latdiff edo londresak barruti honetatik kanpo badaude. . Kontuan izan kasu gehienetan agian ez dela aplikagarria, ozeano barea zeharkatzen duen lerro baten gaineko kalkuluei soilik eragiten baitie polo batetik polo batera, nahiz eta txukotka zati bat eta Alaska zati bat ebakitzen dituen.

    Horrekin lortzen duguna kalkulu hau egiten duzun puntu kopurua murriztea da. Datu-basean milioi bat puntu global badituzu gutxi gorabehera banatuta eta 100 km-ra bilatu nahi baduzu, zure lehen bilaketa (azkarra) 10000 km karratukoa da eta 20 emaitza inguru lortuko ditu seguruenik (banaketa uniformean oinarrituta azalera 500 M² inguru), horrek esan nahi du distantzia kalkulu konplexua 20 aldiz egiten duzula kontsulta honetarako milioi bat aldiz egin beharrean.

    • 21
      • 22

        Aholku zoragarria! Egia esan, barruko laukia ateratzen zuen funtzio bat idatzi zuen garatzaile batekin eta gero perimetroaren inguruan "laukiak" egiten zituen funtzio errekurtsibo bat gainontzeko puntuak sartu eta baztertzeko. Emaitza emaitza izugarri azkarra izan zen: milioika puntu ebaluatzen zituen mikrosegundotan.

        Nire goiko ikuspegia "gordina" da, zalantzarik gabe, baina gai da. Eskerrik asko berriro!

        • 23

          Doug,

          Mysql eta php erabiltzen saiatu naiz puntu luze lat bat poligono baten barruan dagoen ala ez ebaluatzeko. Ba al dakizu zure garatzaile lagunak zeregin hori betetzeko adibiderik argitaratu duen. Edo adibide onik ezagutzen al duzu? Eskerrik asko aldez aurretik.

  16. 24

    Kaixo guztioi, hau da nire test SQL adierazpena:

    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

    eta Mysql-k esaten dit distantzia hori ez dela zutabe gisa existitzen, ordena arabera erabil dezaket, NONDIK gabe egin dezaket eta funtzionatzen du, baina ez horrekin ...

  17. 26

    Hori bikaina da, hala ere, txoriek hegan egiten duten moduan. Oso ondo legoke google maps APIa nolabait sartzen saiatzea (agian errepideak erabiliz, etab.) Garraiobide desberdin bat erabiliz ideia bat ematea besterik ez. Oraindik ez dut PHP-n uztartze simulatu bat egin, saltzaile ibiltariaren arazoari irtenbide eraginkorra eskaintzeko gai izango zena. Baina uste dut agian zure koderen bat berrerabiltzeko gai izango naizela horretarako.

  18. 27
  19. 28

    Artikulu ona! Bi punturen arteko distantzia nola kalkulatzen duten deskribatzen duten artikulu ugari aurkitu ditut baina benetan SQL zatiaren bila nenbilen.

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

    2 eguneko ikerketa, azkenean nire arazoa konpontzen duen orrialde hau aurkitzeko. Badirudi hobe dudala WolframAlpha kentzea eta nire matematika garbitzea. NON izatetik izatera pasatzeak nire gidoia funtzionamenduan du. ESKERRIK ASKO

  25. 37
    • 38

      Eskerrik asko Georgi. Zutabearen "distantzia" aurkitu gabe jarraitzen nuen. NONDIK IZATEA aldatu nuenean xarma bezala funtzionatu zuen!

  26. 39

    Nahiago nuke hau izan zen honetan aurkitu nuen lehen orria. Hainbat komando probatu ondoren hau izan zen behar bezala funtzionatzen zuen bakarra eta nire datu-basera egokitzeko gutxieneko aldaketekin.
    Eskerrik asko!

  27. 40

    Nahiago nuke hau izan zen honetan aurkitu nuen lehen orria. Hainbat komando probatu ondoren hau izan zen behar bezala funtzionatzen zuen bakarra eta nire datu-basera egokitzeko gutxieneko aldaketekin.
    Eskerrik asko!

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

    Badakit formula horrek funtzionatzen duela, baina ezin dut ikusi lurraren erradioa non hartzen den kontuan. Norbaitek argitu al dezake, mesedez?

  34. 49
  35. 50
  36. 52
  37. 53
  38. 55
  39. 56
  40. 58

    eskerrik asko artikulu lagungarri hau argitaratzeagatik,  
    baina arrazoiren batengatik galdetu nahiko nuke
    nola lortu mysql db barruko koorden eta erabiltzaileek php-ra txertatutako koorden arteko distantzia?
    argiago deskribatzeko:
    1. erabiltzaileak [id] txertatu behar du db eta erabiltzailearen beraren koordenetatik zehaztutako datuak hautatzeko
    2. php fitxategiak xede datuak (koordeak) lortzen ditu [id] erabiliz eta gero kalkulatu erabiltzailearen eta xede puntuaren arteko distantzia

    edo besterik gabe beheko kodetik distantzia lor dezakezu?

    $ qry = “SELECT *, (((acos (sin ((“. $ latitude. ”* pi () / 180)) * sin ((` Latitude` * pi () / 180)) + cos ((“. $ latitudea. "* pi () / 180)) * cos ((` Latitudea * * pi () / 180)) * cos (((". $ longitudea." - `Longitudea ') * pi () / 180) ))) * 180 / pi ()) * 60 * 1.1515 * 1.609344) distance gisa `MyTable` WHERE distance> =“. $ Distance. ” >>>> hemendik distantzia "atera" dezaket?
    eskerrik asko berriro,
    Timmy S

  41. 60

    ados, saiatu naizen guztia ez dabil. Esan nahi dut, dudana funtzionatzen du, baina distantziak urrun daude.

    Ezin al luke inork ikusi kode honekin zer gertatzen den?

    if (isset ($ _ POST ['bidalita'])) {$ z = $ _POST ['posta-kodea']; $ r = $ _POST ['erradioa']; oihartzuna "Emaitzak". $ z; $ sql = mysql_query ("SELECT DISTINCT m.zipcode, m.MktName, m.LocAddSt, m.LocAddCity, m.LocAddState, m.x1, m.y1, m.verified, z1.lat, z2.lon, z1. hiria, z1.state FROM mrk m, zip z1, zip z2 WHERE m.zipcode = z1.zipcode AND z2.zipcode = $ z AND (3963 * acos (truncate (sin (z2.lat / 57.2958) * sin (m. y1 / 57.2958) + cos (z2.lat / 57.2958) * cos (m.y1 / 57.2958) * cos (m.x1 / 57.2958 - z2.lon / 57.2958), 8))) <= $ r ") edo hil (mysql_error ()); while ($ row = mysql_fetch_array ($ sql)) {$ store1 = $ row ['MktName']. "”; $ store = $ row ['LocAddSt']. ””; $ store. = $ row ['LocAddCity']. ",". $ row ['LocAddState']. " “. $ Row ['postal kodea']; $ latitude1 = $ errenkada ['lat']; $ longitudea1 = $ errenkada ['lon']; $ latitude2 = $ errenkada ['y1']; $ longitudea2 = $ errenkada ['x1']; $ hiria = $ errenkada ['hiria']; $ egoera = $ errenkada ['egoera']; $ dis = getnew ($ latitude1, $ longitude1, $ latitude2, $ longitude2, $ unit = 'Mi'); // $ dis = distantzia ($ lat1, $ lon1, $ lat2, $ lon2); $ egiaztatua = $ errenkada ['egiaztatua']; if ($ Verified == '1') {echo ""; echo "". $ store. ""; echo $ dis. ”Milia (k) urrun”; oihartzuna ""; } bestela {oihartzuna "". $ denda. ""; echo $ dis. ”Milia (k) aldera”; oihartzuna ""; }}}

    nire funtzioak.php kodea
    function getnew ($ latitude1, $ longitude1, $ latitude2, $ longitude2, $ unit = 'Mi') {$ theta = $ longitude1 - $ longitude2; $ distantzia = (sin (deg2rad ($ latitude1)) * sin (deg2rad ($ latitude2))) + (cos (deg2rad ($ latitude1)) * cos (deg2rad ($ latitude2)) * cos (deg2rad ($ theta)) ); $ distantzia = acos ($ distantzia); $ distantzia = rad2deg ($ distantzia); $ distantzia = $ distantzia * 60 * 1.1515; switch ($ unit) {case 'Mi': break; 'Km' kasua: $ distantzia = $ distantzia * 1.609344; } itzulera (txanda ($ distantzia, 2)); }

    Eskerrik asko aldez aurretik

  42. 61
  43. 62

    Aupa Douglas, artikulu bikaina. Kontzeptu geografikoen eta kodearen inguruko azalpena oso interesgarria iruditu zait. Iradokizun bakarra bistaratzeko kodea tartekatzea eta koska egitea izango litzateke (Stackoverflow, adibidez). Ulertzen dut espazioa gorde nahi duzula, baina ohiko kodeen arteko tartea / koska asko erraztuko nuke, programatzaile gisa, irakurtzea eta disekzioa egitea. Dena den, gauza txikia da. Segi lan bikainarekin.

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

    badirudi azkarragoa dela (mysql 5.9) hautatzeko eta non formula bikoitza erabiltzea:
    $ formula = "((((acos (sin ((". $ latitude. "* pi () / 180)) * sin ((` Latitude` * pi () / 180)) + cos ((". $ latitude. "* Pi () / 180)) * cos ((` Latitudea` * pi () / 180)) * cos (((". $ Longitudea." - `Longitudea ') * pi () / 180)))) * 180 / pi ()) * 60 * 1.1515 * 1.609344) ”;
    $ sql = 'SELECT *,'. $ formula. ' distantzia gisa TAULATIK NORA '.. $ formula.' <= '. $ distantzia;

  51. 71
  52. 72

    Mila esker artikulu hau mozteagatik. Oso lagungarria da.
    PHP hasieran "Home Page pertsonala" izeneko scripting plataforma soil gisa sortu zen. Gaur egun PHP (Hypertext Preprocessor laburdura) Microsoft-en Active Server Pages (ASP) teknologiaren alternatiba da.

    PHP kode irekiko zerbitzariaren aldeko hizkuntza da, web orri dinamikoak sortzeko erabiltzen dena. HTMLan txertatu daiteke. PHP Linux / UNIX web zerbitzarietan MySQL datu-basearekin batera erabili ohi da. Seguru asko scripting hizkuntza ezagunena da.

  53. 73

    Goiko soluzioa ondo ez dabilela aurkitu dut.
    Honako hauetara aldatu behar dut:

    $ qqq = "SELECT *, (((acos (sin ((". $ latitude. "* pi () / 180)) * sin ((` latt` * pi () / 180)) + cos ((". $ latitudea. “* pi () / 180)) * cos ((` latt` * pi () / 180)) * cos (((". $ longitudea.“ - `longt`) * pi () / 180) ))) * 180 / pi ()) * 60 * 1.1515) distantzia gisa `register'-tik";

  54. 75

    eskerrik asko, jauna, primeran ari zaren ... baina galdera bat daukat puntu hamartarrik gabe atera nahi badut, zer egin dezaket ..?

    Eskerrik asko, aldez aurretik.

  55. 76

    Kaixo, mesedez, zure laguntza beharko dut horretarako.

    Lortu eskaera bat egin nuen nire web zerbitzarira http://localhost:8000/users/findusers/53.47792/-2.23389/20/
    53.47792 = $ latitudea
    -2.23389 = $ longitudea
    eta 20 = berreskuratu nahi dudan distantzia

    Hala ere, zure formula erabiliz, nire db-ko errenkada guztiak berreskuratzen ditu

    $ emaitzak = DB :: select (DB :: raw ("SELECT *, (((acos (sin ((". $ latitude. "* pi () / 180)) * sin ((lat * pi () / 180 )) + cos ((". $ latitude." * pi () / 180)) * cos ((lat * pi () / 180)) * cos (((". $ longitudea." - lng) * pi ( ) / 180)))) * 180 / pi ()) * 60 * 1.1515 * 1.609344) distantzia gisa MARKATURETIK DUTE distantzia> = ". $ Distantzia));

    [{"Id": 1, "name": "Frankie Johnnie & Luigo Too", "address": "939 W El Camino Real, Mountain View, CA", "lat": 37.386337280273, "lng": - 122.08582305908, "Distance": 16079.294719663}, {"id": 2, "name": "Amici's East Coast Pizzeria", "address": "790 Castro St, Mountain View, CA", "lat": 37.387138366699, "lng": -122.08323669434, "distance": 16079.175940152}, {"id": 3, "name": "Kapp's Pizza Bar & Grill", "address": "191 Castro St, Mountain View, CA", "lat": 37.393886566162, "Lng": - 122.07891845703, "distance": 16078.381373826}, {"id": 4, "name": "Round Table Pizza: Mountain View", "address": "570 N Shoreline Blvd, Mountain View, CA", "Lat": 37.402652740479, "lng": - 122.07935333252, "distance": 16077.420540582}, {"id": 5, "name": "Tony & Alba's Pizza & Pasta", "address": "619 Escuela Ave, Mountain Ikusi, CA "," lat ": 37.394012451172," lng ": - 122.09552764893," distance ": 16078.563225154}, {" id ": 6," name ":" Oregano's Wood-Fired Pizza "," address ":" 4546 El Camino Real, Los Altos, CA "," lat ": 37.401725769043," lng ": - 122.11464691162," distance ": 16077.937560795}, {" id ": 7," name ":" The bars and parrilles "," address ":" 24 Whiteley Street, Manchester "," lat ": 53.485118865967," lng ": - 2.1828699111938," distance ": 8038.7620112314}]

    20 kilometroko errenkadak berreskuratu nahi ditut baina ilara guztiak ekartzen ditu. Mesedez, zer egiten ari naiz gaizki

  56. 77

    Antzeko kontsultaren bila nabil, baina pixka bat areagotu nintzen. Laburbilduz, koordenatu guztiak koordenatu bakoitzetik 2 miliatara bildu eta gero talde bakoitzeko zenbat koordenatu zenbatu eta koordenatu gehien dituen talde bakarra atera behar da, nahiz eta talde bat baino gehiago dituzu koordenatu kopuru gehien duten taldeen artean - ausazko taldea atera kopuru handiena bera duten taldeetatik -

Zer deritzozu?

Gune honek Akismet-ek spam erabiltzen du. Ikasi zure iruzkina nola prozesatu den.