sql >> Database >  >> RDS >> Mysql

Gebruik MySQL ruimtelijke extensies om punten binnen een cirkel te selecteren

Er zijn geen geospatiale uitbreidingsfuncties in MySQL die lengte- en breedtegraadberekeningen ondersteunen. Er is vanaf MySQL 5.7 .

Je vraagt ​​om nabijheidscirkels op het aardoppervlak. U vermeldt in uw vraag dat u lat/long-waarden heeft voor elke rij in uw flags tabel, en ook universele transversale Mercator (UTM) geprojecteerde waarden in een van de verschillende UTM-zones . Als ik me mijn UK Ordnance Survey-kaarten goed herinner, is UTM handig om items op die kaarten te lokaliseren.

Het is eenvoudig om de afstand te berekenen tussen twee punten in dezelfde zone in UTM:de cartesiaanse afstand doet de truc. Maar als punten zich in verschillende zones bevinden, werkt die berekening niet.

Dienovereenkomstig is het voor de toepassing die in uw vraag wordt beschreven, noodzakelijk om de Great Circle Distance , die wordt berekend met behulp van de haversine of een andere geschikte formule.

MySQL, aangevuld met geospatiale extensies, ondersteunt een manier om verschillende vlakke vormen (punten, polylijnen, polygonen, enzovoort) als geometrische primitieven weer te geven. MySQL 5.6 implementeert een ongedocumenteerde afstandsfunctie st_distance(p1, p2) . Deze functie retourneert echter cartesiaanse afstanden. Het is dus helemaal ongeschikt voor op breedte- en lengtegraad gebaseerde berekeningen. Op gematigde breedtegraden beslaat een breedtegraad bijna twee keer zoveel oppervlakteafstand (noord-zuid) als een lengtegraad (oost-west), omdat de breedtegraadlijnen dichter naar elkaar toegroeien, dichter bij de polen.

Een formule voor circulaire nabijheid moet dus echte lengte- en breedtegraden gebruiken.

In uw applicatie vindt u alle flags punten binnen tien statuutmijlen van een gegeven latpoint,longpoint met een vraag als deze:

 SELECT id, coordinates, name, r,
        units * DEGREES(ACOS(LEAST(1.0, COS(RADIANS(latpoint))
                  * COS(RADIANS(latitude))
                  * COS(RADIANS(longpoint) - RADIANS(longitude))
                  + SIN(RADIANS(latpoint))
                  * SIN(RADIANS(latitude))))) AS distance
   FROM flags
   JOIN (
        SELECT 42.81  AS latpoint,  -70.81 AS longpoint, 
               10.0 AS r, 69.0 AS units
        ) AS p ON (1=1)
  WHERE MbrContains(GeomFromText (
        CONCAT('LINESTRING(',
              latpoint-(r/units),' ',
              longpoint-(r /(units* COS(RADIANS(latpoint)))),
              ',', 
              latpoint+(r/units) ,' ',
              longpoint+(r /(units * COS(RADIANS(latpoint)))),
              ')')),  coordinates)

Als u punten binnen 20 km wilt zoeken, wijzigt u deze regel van de zoekopdracht

               20.0 AS r, 69.0 AS units

naar dit, bijvoorbeeld

               20.0 AS r, 111.045 AS units

r is de straal waarin u wilt zoeken. units zijn de afstandseenheden (mijlen, km, stadiën, wat je maar wilt) per breedtegraad op het aardoppervlak.

Deze zoekopdracht gebruikt een begrenzing lat/long samen met MbrContains om punten uit te sluiten die beslist te ver van uw startpunt verwijderd zijn, gebruikt u vervolgens de formule voor de grote cirkelafstand om de afstanden voor de overige punten te genereren. Een uitleg van dit alles is hier te vinden . Als uw tabel de MyISAM-toegangsmethode gebruikt en een ruimtelijke index heeft, MbrContains zal die index misbruiken om u snel te laten zoeken.

Ten slotte selecteert de bovenstaande query alle punten binnen de rechthoek. Om dat te beperken tot alleen de punten in de cirkel en ze te rangschikken op nabijheid, sluit u de zoekopdracht als volgt af:

 SELECT id, coordinates, name
   FROM (
         /* the query above, paste it in here */
        ) AS d
  WHERE d.distance <= d.r
  ORDER BY d.distance ASC 


  1. Hoe wijzig ik het datumformaat in Postgres?

  2. Hoe MySql op Mac te gebruiken

  3. Synthetische gegevensgeneratie

  4. Relatie doorgegeven aan #or moet structureel compatibel zijn. Incompatibele waarden:[:referenties]