예전에 프로젝트를 진행하던 중 특정 지점 반경 Nkm내의 지점들을 검색해야할 필요가 있었다.
당시 반경 Nkm를 구할 방법을 찾지 않고 생각한 바로는 동, 서 방향으로 N/2 만큼 북, 남 방향으로 N/2 정사각형에 해당하는 좌표를 between을 통해 구현할까 생각했었다. 하지만 해당 내용의 구현은 우선순위가 가장 낮았고 없어도 되는 기능이여서 구현하지 않고 지나갔었다.
지리 데이터를 사용할 일이 생겨 찾아보니 GIS정보를 DB에서 다룰 수 있는 Postgis가 존재했다. 이에 대해 정리하고자 한다.
좌표 데이터를 사용하기 전 좌표를 저장하는 방식에 대해 알아야 한다. 지구는 평면이 아니다. 심지어 완벽한 구도 아니다. 따라서 정확한 좌표를 표기하기 위한 방법이 필요하다.
GCS(Geographic Coordinate System)
: 3차원의 지구 모델에서 위도와 경도로 좌표를 나타낸 것이다.
3차원 지구모델은 지구를 회전 타원체라 가정하고 해당 타원의 중심으로 부터 위도 경도를 통해 특정 좌표를 나타내는 방식이다.
예를 들면 판교의 좌표를 설정하기 위해 판교의 지표면과 가장 유사한 회전 타원체를 골라 사용한다. 이는 판교에서는 정확할 수 있지만 샌프란시스코의 실리콘밸리에서는 정확하지 않다. 판교 지표면에 맞춰있지 샌프란시스코의 지표면과는 꽤 차이가 발생한다.
이렇듯 GCS에서는 특정 지역에 해당하는(특정 지역에 맞는) 여러 좌표계가 존재한다.
PCS(Projected Coordinate System)
: 우리가 대부분 사용하는 지도는 3차원이 아니라 평면지도이다. 이는 대부분 PCS이며 평면에 투영한 결과를 나타낸다.
공간 참고 시스템(좌표계와 같다고 생각해도 됨)마다 고유의 SRID가 존재한다. GIS정보를 입력하게 되는 경우 좌표계 값을 입력해야 하며 같은 좌표계끼리만 계산이 가능하다.
좌표가 값이 뭔가 엄청 크다 싶으면 십중팔구 이 좌표계를 사용하고 있는 겁니다. 좌표계 원점을 (1000000, 2000000)로 옮기거든요.
- UTM-K (Bessel) : 5178
- 도로명 지도(새 주소 지도)에서 사용
- UTM-K (GRS80) : 5179
- 네이버지도에서 사용
브이월드에 가게 되면 아래와 같은 표가 존재하는데 이때 데이터 좌표계가 SRID값을 의미한다.
대부분의 DB에서는 지리정보를 제공하기 위해 별도의 자료형을 가지고 있다. 이들을 공간데이터 타입이라 한다. 대표적으로 POINT, POLYGON, MULTIPOINT, MULTIPOLYGON등이 존재한다.
공간데이터 타입에 대해 공간함수 또한 제공한다. 공간 함수는 교집합, 일치 여부, 객체간 거리, 포함 여부 등을 지원한다.
3.23버전부터 LONGBLOB을 통해 지도를 파일단위로 지원하기 시작했으며 5.0이후는 Geometry를 통해 공간 데이터 타입을 지원하기 시작했다.
GIS정보를 활용할 때는 Postgresql을 주로 사용한다. 이는 Postgresql에는 강력한 GIS확장인 POSTGIS가 존재하기 때문이다. MySQL에서도 공간함수를 사용한 쿼리를 발생시킬 수 있지만 성능이 부족하다.
반경 검색의 경우 2가지 방법을 통해 구할 수 있다.
MySQL에서는 2번을 직접 구현해야 한다. 하지만 PostgreSQL에서는 ST_Dwithin
를 통해 간편하게 반경내의 값을 가져올 수 있다.
SELECT b.tower_id, b.geom
FROM broadcasting_towers b
WHERE ST_DWithin(b.geom, 'SRID=3857;POINT(3072163.4 7159374.1)', 4000)
AND ST_DWithin(b.geom, 'SRID=3857;POINT(3072163.4 7159374.1)', b.sending_range);
https://postgis.net/docs/ST_DWithin.html
https://gdsc-university-of-seoul.github.io/About-Coordinate-System/
https://www.esri.com/arcgis-blog/products/arcgis-pro/mapping/gcs_vs_pcs/