Zwracać wszystkie wyniki w promieniu 30 km od określonego punktu szerokości / długości?

21

Mam tabelę z kolumną, the_geomktóra zawiera dane podobne do:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

Które po zastosowaniu funkcji ST_AsEWKT(the_geom)zwraca:

SRID=4326;POLYGON((7.5077921782085 46.9082092877942,7.53493597966353 46.9081898840296,7.53496566473541 46.9249119938446,7.50781341296434 46.9249314035307,7.5077921782085 46.9082092877942))

Muszę wybrać wszystkie dane, które znajdują się w promieniu 30 km od określonego punktu szerokości / długości, na przykład:

  • lat = 46,8167
  • lng = 6,9333

Jednak za każdym razem, gdy próbowałem użyć ST_Distance(), zawsze otrzymywałem wartości mniejsze niż 1, a używanie ST_DWithin()zawsze zwracało wartość true.

dan2k3k4
źródło

Odpowiedzi:

23

Sprawdź następujące zapytanie dla PostgreSQL, aby uzyskać dane w pewnej odległości. Mam nadzieję, że to pomoże.

SELECT *
FROM your_table
WHERE ST_Distance_Sphere(the_geom, ST_MakePoint(your_lon,your_lat)) <= radius_mi * 1609.34
Farhat Abbas
źródło
1
Był w stanie uzyskać: , 46,8167))) <= 18 * 1609.34
dan2k3k4 11.11.13
To świetnie :)
Farhat Abbas
2
Dla każdego, kto się zastanawia, liczba 1609.34 to metry na milę, czyli podstawową jednostkę używaną przez postgres. Aby zrobić kilometry, oczywiście pomnóż przez 1000.
1mike12
2
Notatka pedantyczna: dokładnie 1609.344 (z definicji)
barakarta
6

Wygląda na to, że przechowujesz swoją geometrię w kolumnie geometrii, a nie w kolumnie geograficznej.
To dobrze, ale funkcja ST_Distance zwróci pomiary w jednostkach projekcyjnych zamiast zawsze liczników. W twoim przypadku (4326) będą to stopnie.
Samo użycie bufora z ST_Within też nie będzie działać, ponieważ ST_Buffer będzie mierzył również stopnie.

Możesz albo skonwertować swoje dane, aby korzystały z geografii zamiast z geometrii, lub możesz przekonwertować swój punkt na projekcję, która wykorzystuje mierniki, bufor, a następnie przekonwertować z powrotem na 4326, aby zobaczyć, co się w nim znajduje:

SELECT
    *
FROM <your data>
WHERE ST_Within(the_geom, 
                ST_Transform(ST_Buffer(ST_Transform(ST_SetSRID(ST_MakePoint(6.9333, 46.8167), 4326), 3857), 30000), 4326)) = 1

To rzutuje punkt na 3857 , który jest projekcją popularną w mapach internetowych. Następnie buforuje go o 30 000 metrów, a następnie przenosi z powrotem na 4326, a następnie przekazuje do ST_Within.

Zły geniusz
źródło
Z wyjątkiem tego, że pseudo-merkator nie jest zawodny w odniesieniu do odległości, więc jeśli dane nie są zbliżone do równika, wyniki będą wyłączone, szczególnie w odległości 30 km.
Vince
6

W moim świecie przy użyciu niestandardowego identyfikatora SRID (dla Map Google) działało coś takiego:

SELECT * FROM addresses WHERE ST_DWithin(location, ST_SetSRID(ST_MakePoint(longitude, latitude), 3785), radius);

gdzie typem locationjest geometria (Point, 3785) i longitude, latitudei radiussą zmiennoprzecinkowe (np. -100, 44, 30 dla 100W / 44N / 30 „jednostek” - patrz poniżej)

Zobacz Jaki jest najlepszy sposób na znalezienie wszystkich obiektów w promieniu innego obiektu? w dokumentach postgis:

Ta ST_DWithin(geometry, geometry, distance)funkcja jest przydatnym sposobem wykonywania indeksowanego wyszukiwania odległości. Działa, tworząc prostokąt wyszukiwania wystarczająco duży, aby zawrzeć promień odległości, a następnie wykonując dokładne wyszukiwanie odległości na indeksowanym podzbiorze wyników.

AKTUALIZACJA: jednostki nie są milami dla SRID 3785 ... wydają się być albo radianami lub stopniami, albo coś w tym rodzaju. Ale specyfikacja mojego SRID mówi, że jego jednostki mają albo metry, albo stopnie i zdecydowanie nie jest to żaden z nich, przynajmniej nie bez pewnej konwersji:

alex=# select * from spatial_ref_sys where srid=3785; srid | auth_name | auth_srid | srtext | proj4text
3785 | EPSG | 3785 | PROJCS["Popular Visualisation CRS / Mercator (deprecated)",GEOGCS["Popular Visualisation CRS",DATUM["Popular_Visualisation_Datum",SPHEROID["Popular Visualisation Sphere",6378137,0,AUTHORITY["EPSG","7059"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6055"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4055"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3785"],AXIS["X",EAST],AXIS["Y",NORTH]] | +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs

AlexChaffee
źródło
Jaka jest różnica między 3785 (we wpisie) a 3857?
nastrojony
To są różne prognozy. 3875 vs 3857 - Nie wiem, czy jeden jest lepszy od drugiego
AlexChaffee
1
„EPSG 3785 został wycofany na rzecz innego identycznego EPSG 3857” - github.com/rgeo/rgeo/pull/61
Yarin
2

Myślę, że to powinno działać:

SELECT gid FROM table 
WHERE ST_DWithin(the_geom, ST_SetSRID(ST_Point(6.9333, 46.8167), 4326), 30000)
Francisco Puga
źródło
3
jeśli rzucisz the_geom na geografię, która powinna działać. st_dwithin (geografia (the_geom), geografia (<Point, 4326>), 30000)
cavila