KakaoMap API와 교통정보 API를 사용해 아래와 같은 프로그램을 만들어야 했다.
지도 위 CCTV가 존재하는 좌표에 마커가 생성되어 있다. 돌발 이벤트 발생 시 일정 범위내 존재하는 CCTV를 위의 이미지처럼 재생 시킨다.
구현 전, 아이디어만 떠올렸을때는 그냥 범위 지정만 해 주고 CCTV가 범위에 속하는지만 판단해 주면 되는 문제라 단순할 것이라 생각했다. 근데 막상 구현 하려 하니 좌표와 화면의 픽셀을 매칭시켜야 했고, 둘을 어떻게 매칭시켜줘야 할지 떠오르지 않았다.
좌표는 좌표고.. 지정 범위는(width/height) 픽셀이고... 어떻게 해야하지?
지도 위 두 좌표 사이 거리를 임의로 지정해서 픽셀을 맞춰줘야하나? 그게 가능할까? 그리고 만약 그게 가능하다 치더라도 지도의 줌아웃/줌인 시에는 또 다시 계산을 해 줘야 할 것 같고.. 그렇게 되면 너무 공수가 많이 드는 일이 아닌가.
계속 구글링을 해 보았지만 딱히 마음에 드는 답은 찾을 수 없었다. 근데 분명 이게 불가능하지는 않을거란 말이지. 왜냐하면 이런 기능은 분명 어딘가에 쓰이고 있기 때문이다. 그렇기에 나는 구현 방법만 찾으면 된다. 나는 지금 용어를 모르기 때문에 검색에 어려움을 겪고 있는거겠지..
안되겠다. 시선을 돌려보자. 내가 쓰는 지도는 KakaoMaps이다. 일단 카카오맵 API 문서를 다시 봐야겠다. 그리고 눈에 들어오는 놈이 있었다.
지도 영역 밖의 마커위치 추적하기? 지도 영역 밖???? 이거 진짜 쓸만해 보이지 않는가? 설명을 보자.
이거네. 이 예제는 지도 밖의 무언가가 있을 때의 경우이고, 나는 지도 내의 일정범위 안에 속하는 무언가를 찾아내야 한다. 해당 기능 예제 코드는 https://apis.map.kakao.com/web/sample/markerTracker/ 에서 확인 가능하다.
일단 저 예제를 써먹기 위해서는 먼저 예제에 대해 이해를 해야겠다. 뭔가 복잡 심오해 보인다. 처음 보는 단어들도 보이는 것 같다. 저 단어들중에 내가 원하는 기능을 만들기 위해 알아야 했던 단어도 있겠지?
많다... 코드가 뭔가 많고 길고... 뭘 자꾸 잘라내는 것 같긴한데...
로직을 쭉쭉 읽어가다 눈이 멈춘 곳이 있었다.
tracking()? 이름에서부터 감이온다. 이 함수가 바로 내가 찾아 헤매던 로직의 시작이 될 것이라는것이. 한 번 자세히 보자. (좋은 이름의 중요성이 여기서 또...!!)
function tracking() {
var proj = map.getProjection();
// 지도의 영역을 구합니다.
var bounds = map.getBounds();
// 지도의 영역을 기준으로 확장된 영역을 구합니다.
var extBounds = extendBounds(bounds, proj);
// target이 확장된 영역에 속하는지 판단하고
if (extBounds.contain(target.getPosition())) {
// 속하면 tracker를 숨깁니다.
setVisible(false);
} else {
// target이 영역 밖에 있으면 계산을 시작합니다.
// ...
}
위의 코드는 카카오 예제 일부를 그대로 가져 온 것이다. 카카오 예제는 화면 밖으로 나간 좌표를 찾는 예제이다. 코드를 읽어보면 현재 보여지는 지도영역과 확장된 지도영역을 구해 둘을 비교해서 로직을 구현하고 있다.
나는 특정 영역 안에 들어온 좌표를 읽는 기능이 필요하다. 그러므로 카카오 예제와 반대로 if문을 구현해 줄 것이다. 그러기 위해 내가 가장먼저 준비해야 할 것은? extBounds를 내가 원하는만큼 축소시키는 것. extendBounds(bounds, proj)함수를 한번 보자.
function extendBounds(bounds, proj) {
// 주어진 bounds는 지도 좌표 정보로 표현되어 있습니다.
// 이것을 BOUNDS_BUFFER 픽셀 만큼 확장하기 위해서는
// 픽셀 단위인 화면 좌표로 변환해야 합니다.
var sw = proj.pointFromCoords(bounds.getSouthWest());
var ne = proj.pointFromCoords(bounds.getNorthEast());
// 확장을 위해 각 좌표에 BOUNDS_BUFFER가 가진 수치만큼 더하거나 빼줍니다.
sw.x -= BOUNDS_BUFFER;
sw.y += BOUNDS_BUFFER;
ne.x += BOUNDS_BUFFER;
ne.y -= BOUNDS_BUFFER;
// 그리고나서 다시 지도 좌표로 변환한 extBounds를 리턴합니다.
// extBounds는 기존의 bounds에서 상하좌우 30px만큼 확장된 영역 객체입니다.
return new kakao.maps.LatLngBounds(
proj.coordsFromPoint(sw),proj.coordsFromPoint(ne));
}
영역 변경을 위해 sw.x~ne.y부분을 아래 코드로 변경 해 주었다.
sw.x += BOUNDS_BUFFER_X;
sw.y -= BOUNDS_BUFFER_Y;
ne.x -= BOUNDS_BUFFER_X;
ne.y += BOUNDS_BUFFER_Y;
그리고 다시 tracking()으로 돌아가서
if (extBounds.contain(target.getPosition())) {
//extBouds에 속한다면
//원하는 로직을 구현해 주었음.
var imsLat = crtImsMarker.getPosition().getLat();
var imsLng = crtImsMarker.getPosition().getLng();
var cctvLat = target.getPosition().getLat();
var cctvLng = target.getPosition().getLng();
//...
//...(생략)
}
위처럼 바꿔주었다.
머리로 생각했을때는 되는 로직일 것 같은데.. 그래도 뭔가 내가 마음대로 바꾼 코드라 정말 될지 설렘 반 두려움 반이었다. (+ 간절함.. 안되면 또 다른방법을 찾으러 떠나야한다구요ㅠㅠㅠㅠ)
과연 결과는?
.
.
.
성공이다!!!
와 너무 감격스러웠다. 그토록 만들어내고 싶었던 기능이었는데 드디어 구현해냈다... 뭔가 적고보니 별거 아니었던 것 같이 느껴지는데 나름 처음부터 돌고돌아 열심히 찾아냈다. (이것 또한 알고나니까 괜히 더 쉬워보이는 것 같기도 하고..)
여기서도 새로운 단어를 알아냈는데,
Projection 이라는 단어다.
앞부분에서 "좌표와 화면의 픽셀을 매칭시켜야 했고, 둘을 어떻게 매칭시켜줘야 할지 떠오르지 않았다."라고 말했었는데 이걸 해 주는 녀석이 'Projection'이라는 녀석인 것이다. 정확히는 Projected CRS라고 부르는 것 같다.
가장 중요한 부분.
extBounds 설정 부분을 다시 자세히 보면 'proj'이라는 것으로 좌표에 작업을 해 주고 있다. 그리고 tracking()함수 맨 첫 줄을 보면 'var proj = map.getProjection();'부분에서 Projection객체를 가져오고 있다. 카카오Map측에서 해당 기능을 제공해 주는것이다. 만약 사용하는 지도가 해당 기능을 지원해 주고 있지 않다면 QGIS등의 GIS엔진등을 통해 해결해 줘야 할 것으로 보인다. (근데 요즘 제공되는 지도API는 왠만해서는 저 기능을 지원해 줄 것 같긴 하다.)
나는 결국 또 저 Projection이라는 존재를 몰랐기 때문에 고민을 했었던 것이다.(눈물)
나의 고민 과정도.. 박제... 해야지
좌표를 2D로 바꾸고 싶었음 → 어떻게...?(고민 + 폭풍검색 + 못 찾아서 좌절) → 다시 API문서 확인 → 어? 비슷한 기능발견 → 예제 코드 정독 후 수정 → 오 기능 구현 성공!! → 아 내가 찾던게 proj이 하고있는 저 역할이었구나(깨달음)
'개발 As 현생 > 오늘의 뻘짓 & 문제해결' 카테고리의 다른 글
Gradle 프로젝트 외부 라이브러리 직접 추가 (0) | 2023.10.12 |
---|---|
Pycharm Encoding Error (0) | 2023.05.15 |
클라이언트가 죽는 현상에 대한 고찰 (0) | 2022.02.23 |
웹소켓 커넥션에러 이유에 대한 고찰 (0) | 2022.02.12 |