지도이야기 | Geo 함수 - 교차구역 구하기

지도 서비스를 이용하여 사용자에게 사용자 위치를 기준으로 하여 맵을 보여줍니다.
구글맵이나 네이버맵은 사용자 현 위치를 기준으로 하여 중심을 잡고 근처 지도를 띄우고 사용자가 앱내 맵을 움직이거나 드래그하게 되면 여러 다양한 곳의 지도 또한 볼 수가 있습니다.

공유킥보드 서비스를 제공하는 저희 회사에서는 그러한 맵을 보여주는 것 외에도 사용자가 보고 있는 앱 내 표시중인 맵에서 우리 회사에서 어떠한 구역을 서비스하고 있고 반납이 불가한 구역은 이런곳이 있다 라는 것을 보여줘야 했습니다.

MySQL을 사용하고 있을 때 무수히 많은 구역을 모두 select 해서 앱에 뿌려주면 시간도 많이 소요되지만 앱 내 지도또한 굉장히 무거워져서 서비스가 죽어버리는 상황까지 발생하게 되는 것입니다.

그때 생각해냈던 것이 범위내 현재 사용자가 보고 있는 곳에 위치하는 구역들만 가져오자 라고 했던 것입니다.(물론 지금은 또 다른 방법을 찾아 적용했습니다..)

그때 찾아보고 사용했던 함수들이 바로 지금부터 설명하고자 하는 것입니다.

st_overlabs() : 지도 겹침 여부

  • geometry가 "공간적으로 겹치는" 경우 True를 반환하는 함수입니다. 즉, 서로 교차를 하지만 완전히 포함하는 것은 false로 본다는 의미입니다.
    아래 이미지를 보면 이해가 조금 더 쉬워질 듯 합니다.

    완전히 포함되서는 안되고 겹치는 경우에만 true를 리턴시키는 함수입니다.

지도 포함 여부

그렇다면 겹치는 경우말고 특정 geometry가 포함되는 경우를 얻기 위해서는 아래 두가지 함수를 사용할 수 있습니다.

st_within(a, b) : a가 b에 포함

  • 해당 함수는 위 이미지의 첫번째 예시처럼 a라는 geometry가 b에 포함되어져 있는가에 대해 구하고자 할 때 사용됩니다.
-- return 1
select 
	ST_Within(Point(2,2), 
	ST_GeomFromText('POLYGON((1 1,4 1, 4 3, 1 3, 1 1))'));
-- return 0
select 
	ST_Within(ST_GeomFromText('POLYGON((1 1,4 1, 4 3, 1 3, 1 1))'), 
    Point(2,2));

SQL을 보아도 첫 sql에서 true가 떨어지는게 보입니다.

st_contains(a, b) : b가 a에 포함

  • 해당 함수는 위 이미지의 두번째 예시처럼 b라는 geometry가 a에 포함되어져 있는가에 대해 구하고자 할 때 사용됩니다.
-- return 1
select 
	ST_Contains(ST_GeomFromText('POLYGON((1 1,4 1, 4 3, 1 3, 1 1))'), 
    POINT(2,2)); 

-- return 0
select 
	ST_Contains(POINT(2,2), 
    ST_GeomFromText('POLYGON((1 1,4 1, 4 3, 1 3, 1 1))')); 

SQL을 보아도 첫 sql에서 true가 떨어지는게 보입니다.

위 두개의 함수는 포함 여부를 구하는 함수이기 때문에 해당 폴리곤의 꼭짓점 포함 여부를 구하고자 할때는 사용할 수 없습니다.

-- return 0
select 
	ST_Contains(ST_GeomFromText('POLYGON((1 1,4 1, 4 3, 1 3, 1 1))'), 
    POINT(1,1)); 

-- return 0
select 
	ST_Within(Point(1,1), 
    ST_GeomFromText('POLYGON((1 1,4 1, 4 3, 1 3, 1 1))')); 

겹치는 것에 대한 처리를 고려하지 않고
하나의 포인트에 대해서 해당 포인트가 polygon안에 포함되어져 있느냐? 에 대한 처리를 할때는 해당 두 함수를 사용해도 좋을 것 같습니다.

st_intersect(a, b) : 겹침, 포함

  • geometry 또는 지형 데이터가 공간의 일부를 공유하면 true를 반환합니다. 겹침, 포함 모두 true를 반환합니다. st_contains(), st_within(), st_overlabs() 에 대한 모든 것들을 true로 반환하기를 원할 때 해당 함수를 사용할 수 있습니다.

반경내 어떤 구역이 있느냐에 대한 처리를 할 때 st_intersect() 함수를 사용하면 되겠쥬!

select * from test_tb
where 
	(ST_Intersects(ST_GeomFromText('POLYGON((1 1,4 1, 4 3, 1 3, 1 1))'), 
    geometry_col))

위와 같은 형식으로 조회를 하되 st_geomFromText 함수에 들어 있는 값은 예시를 위해 들어둔 값이지만 실제 조회하고자 하는 반경에 대한 폴리곤을 넣으면 됩니다.

반경내 두개의 점을 이용하여 폴리곤 만들기


위 이미지에서 해당 직사각형이 APP이고 해당 APP에서는 사용자가 맵 API를 통해서 띄운 지도가 보입니다.
사용자가 맵을 움직이거나 드래그 할때마다 해당 맵에서 표시되는 꼭짓점 두개의 값은 계속해서 변하겠죠?

해당 두값만을 보내준다고 할때 우리는 어떻게 해서 해당 앱내에만 존재하는 구역을 얻어올 수 있을까요?

두점들을 이용해서 나머지 2개의 꼭짓점들을 구하여 폴리곤을 만들면 됩니다!

위 이미지와 같은 순서대로 두점을 이용하여 나머지 두개의 꼭짓점을 얻을 수 있습니다.
네개의 꼭짓점들을 만들고 첫 꼭짓점을 한번 더 넣어주는 이유는 예전 글에도 설명했지만 세번째점과 네벗째 점까지 이어줘야 완전한 폴리곤을 만들 수 있기 때문입니다.
아래와 같은 폴리곤 데이터를 만들 수 있습니다!

[
    [lng1, lat1],
    [lng2, lat1],
    [lng2, lat2],
    [lng1, lat2],
    [lng1, lat1]
]

이렇게 교차하는 구역에 대해 얻어올 수 있는 함수 네가지에 대해 정리를 했습니다.
아무래도 범위내 구역을 구할 때는 st_intersect() 함수를 하나의 위치에 대해서 포함여부를 구할 때는 st_within() 함수를 사용하는 편이 좋을 듯 합니다.

이렇게 반경내 존재하는 구역을 가져오고자 할때 사용할 수 있는 함수에 대해 알아봤습니다.

다음글에서는 geo 관련된 함수들 중에서 언젠가 사용할 수 있을 것 같은 함수들에 대해 작성하려고 합니다.

좋은 웹페이지 즐겨찾기