졸업작품으로 안전한 보행길 경로를 찾아주는 지도 프로젝트를 만들고 있는데..
우리 세상은 알고리즘처럼 2차원 배열이나 노드의 집합이 아니기때문에.. 지도를 일정한 간격으로 규격화해야했다.
이 부분이 굉장히 힘들었는데 기록으로 남겨놓으려한다.
방법
1. 출발지와 목적지의 좌표를 계산하여 사각형 범위를 구한다. ( = Map Size )
2. 범위를 2차원 배열처럼 규격화한다(?)
3. 해당 범위내에서 적합한 경로를 찾는다(??)
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
2번 방법을하기위해 많은 고민을 했는데
첫번째. 2차원 배열처럼 정사각형으로 해당 범위를 규격화하기.
→ 실제 지도는 이동가능한 공간이 뒤죽박죽 삐뚤빼뚤이기 때문에 적합하지 않다고 생각했다.
두번째. 육각형의 hexgon grid로 규격화하기
→ 첫번째 방법이 안된다고 생각한 후, 다시 알아봤는데 게임공간?에서는 2차원 공간을 6각형으로 나누어서 계산한다고 한다.
이걸 하면서 아래의 글이 정말 많은 도움이됬다.
Django(Python)에 Hexgrid 적용하기
우선 hexgon grid의 개념이나 사용방법은 위의 블로그 글이나,
아래의 문서를 보면서 큰 개념을 잡았다.
https://www.redblobgames.com/grids/hexagons/
다행이도 hexgrid가 제공되는 오픈소스가 있었다.
여기서 힘들었던게,
- pip install hexgrid 와
- pip install hexgrid-py가 있다.
pip install hexgrid-py를 해야한다...
(오픈소스 깃허브 링크)
https://github.com/gojuno/hexgrid-py/blob/master/hexgrid.py
위에 개념들을 거의다 구현이 되어있다.
오픈소스 내부 코드를 보면서 본인한테 맞게 살짝살짝 변경하면서 사용하면 될 것 같다.
My Code
import hexgrid # han : pip install hexgrid-py
#그리드 그려보자
def gird_draw(request):
#-----------------return hex corner ---------------------
center=hexgrid.Point((float(startX)+float(endX))/2,(float(startY)+float(endY))/2) #중앙
rate = 110.574 / (111.320 * math.cos(37.55582994870823 * math.pi / 180)) #서울의 중앙을 잡고, 경도값에 대한 비율
grid = hexgrid.Grid(hexgrid.OrientationFlat, center, Point(rate*0.00015,0.00015), morton.Morton(2, 32)) #Point = Size
sPoint=grid.hex_at(Point(float(startX),float(startY))) # hex_at : point to hex -> 출발지 Point -> hex좌표
ePoint=grid.hex_at(Point(float(endX),float(endY))) #목적지
map_size=max(abs(sPoint.q),abs(sPoint.r)) #열col(q) 행row(r)
#return center extends neighbor : hex list
neighbor=[]
neighbor =grid.hex_neighbors(grid.hex_at(center),map_size+5) #hex_neighbor : type(Hex, int) -> list
print("hexgrid 개수 : ",len(neighbor))
#test make hex to corner
cornerlist = []
for item in neighbor:
cornerlist.append(grid.hex_corners(item))
polylist =[]
for hex in cornerlist:
hexPolygon = []
for corner in hex :
temp = [corner.y , corner.x]
hexPolygon.append(temp)
polylist.append(hexPolygon)
print("hexgrid 꼭지점 개수 : ",len(polylist))
hex_line={"type":"Feature","geometry":{"type":"Polygon","coordinates":polylist}}
hex_polygon = {"type":"FeatureCollection","features":[hex_line]}
return HttpResponse(json.dumps({'pistes' : pistes, 'hex_polygon':hex_polygon}),content_type="application/json") #python to json
여기서 살짝 설명을 해보자면 아래의 순서와 같다.
1. 중앙 잡기 (hex (0,0))
- 먼저 중앙을 잡아야한다. 구현된 오픈소스에도 필요하지만,
hexgrid의 개념을 이해하고 보다 사용하기 쉽게? 가독성 있게..? 사용하려면 중앙점을 잡고,
중앙 6각형으로 부터 이웃된 hexgrid의 좌표를 설정하는게 좋다.
2. Grid 객체 생성
grid = hexgrid.Grid(hexgrid.OrientationFlat, center, Point(rate*0.00015,0.00015), morton.Morton(2, 32)) #Point = Size
이 한줄로 객체를 생성할 수 있는데, 참조되는 파라미터를 순서대로 번호로 살펴보면
1번은, hexgrid의 2가지 타입중 Flat 타입을 고른다는 것이다. (Hexgrid의 바닥면 기준)
2번은, Center : Point 좌표를
3번은, Grid의 크기
4번은, Z곡선의 값 같은데... 솔직히 Morton이 무엇인지 잘모르겠다. 아래의 링크를 참고하여 설정했다.
(아는 사람은 언제든지 댓글한번만 달아주세요ㅠㅠ)
https://pypi.org/project/morton-py/
3. 실좌표 hex좌표로 변환
.hex_at 메서드로 Point 좌표를 중심 좌표로 부터의 hex 좌표로 변환할 수 있다.
4. 이웃된 hexgrid : hex_neighbors 함수
이웃된 hexgrid를 구하고, 각 grid의 꼭지점 좌표를 봔환해준다.
* 위도(lat), 경도(lon) 순
Html 렌더링
hex_polygon으로 렌더링된 데이터를 html에서 Leaflet 라이브러리를 이용하여
polygon 형태로 map에 추가해준다.
//hex line (시각화)
tempdata = result.hex_polygon['features'][0]['geometry']['coordinates']; //hexgrid (꼭지점의 좌표를 가짐)
$.each(tempdata,function(index,grid){
L.polygon([grid]).addTo(leaf_map); // y(위도) x(경도)
});
결과
그러면 이렇게 hexgrid polygon 형태로 지도를 규격화 할수있다.
규격화된 각각의 도형은 중심좌표를 가지고 있고, 이제 이 좌표를 활용해 적합한 경로를 안내해 주고자 한다.
Polygon 위에 Markers 추가해보기
https://thalals.tistory.com/33
전에 표시했던 가로등 마커를 polygon 위에 적용해보았다.
어려울거 없이 단순하게 polygon 코드 아래에 markers 코드를 추가해 주었다.
'Django > 개인 프로젝트1(안전한 보행길 지도)' 카테고리의 다른 글
[Django] Python 지도라이브러리 Folium 과 leaflet 차이점(Folium VS Leaflet.js) (0) | 2021.08.11 |
---|---|
Django Leaflet.js 지도 라이브러리 불러오기 (0) | 2021.08.11 |
Django Templates 폴더 App 폴더 바깥쪽으로 빼서 한번에 관리하기 (0) | 2021.08.11 |
1. Django 프로젝트 생성 (0) | 2021.08.10 |
[Leaflet] Django에 Leaflet Marker 표시하기(Point Array) (0) | 2021.05.14 |