Django/개인 프로젝트1(안전한 보행길 지도)

[Django] Python hexagon grid (Map 공간 일정 간격으로 규격화 하기, hexgrid)

민돌v 2021. 5. 14. 21:09
728x90

졸업작품으로 안전한 보행길 경로를 찾아주는 지도 프로젝트를 만들고 있는데..

우리 세상은 알고리즘처럼 2차원 배열이나 노드의 집합이 아니기때문에.. 지도를 일정한 간격으로 규격화해야했다.

 

이 부분이 굉장히 힘들었는데 기록으로 남겨놓으려한다.

방법

1. 출발지와 목적지의 좌표를 계산하여 사각형 범위를 구한다. ( = Map Size )

2. 범위를 2차원 배열처럼 규격화한다(?)

3. 해당 범위내에서 적합한 경로를 찾는다(??)

 

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

2번 방법을하기위해 많은 고민을 했는데

 

첫번째. 2차원 배열처럼 정사각형으로 해당 범위를 규격화하기.

→ 실제 지도는 이동가능한 공간이 뒤죽박죽 삐뚤빼뚤이기 때문에 적합하지 않다고 생각했다.

 

두번째. 육각형의 hexgon grid로 규격화하기

→ 첫번째 방법이 안된다고 생각한 후, 다시 알아봤는데 게임공간?에서는 2차원 공간을 6각형으로 나누어서 계산한다고 한다.

 

이걸 하면서 아래의 글이 정말 많은 도움이됬다. 

우아한 형제들, 기술 블로그(이재일 님 글) 

 

배달아~ 배달 가는길 알려줘!(단호함) - 우아한형제들 기술 블로그

서론배민라이더스에서는 배달거리를 업소와 고객의 주소 정보를 이용해서 지구는 적당히(?) 둥글다는 계산으로 거리계산을 하고 있습니다. ~대충대충코드~```java double theta = from.getLongitude() - to.ge

woowabros.github.io

 

Django(Python)에 Hexgrid 적용하기

우선 hexgon grid의 개념이나 사용방법은 위의 블로그 글이나,

아래의 문서를 보면서 큰 개념을 잡았다.

https://www.redblobgames.com/grids/hexagons/

 

Red Blob Games: Hexagonal Grids

Guide to math, algorithms, and code for hexagonal grids in games

www.redblobgames.com

 

다행이도 hexgrid가 제공되는 오픈소스가 있었다.

여기서 힘들었던게,

- pip install hexgrid 와

- pip install hexgrid-py가 있다.

 

pip install hexgrid-py를 해야한다...

(오픈소스 깃허브 링크)

https://github.com/gojuno/hexgrid-py/blob/master/hexgrid.py

 

gojuno/hexgrid-py

Configurable hex grid on abstract surface. Contribute to gojuno/hexgrid-py development by creating an account on GitHub.

github.com

위에 개념들을 거의다 구현이 되어있다.

오픈소스 내부 코드를 보면서 본인한테 맞게 살짝살짝 변경하면서 사용하면 될 것 같다.

 

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/

 

morton-py

Morton code pack/unpack library

pypi.org

 

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

 

[Leaflet] Django에 Leaflet Marker 표시하기(Point Array)

졸업작품으로 Leaflet.js를 이용해서 map을 만드는 중 DB에 저장된 가로등 좌표를 Point로 받아와 지도위에 marker 표시를 해줄려고 한다. 1. DB에 저장된 좌표 중 범위 설정해서 가져오기 lamp = Lamp.objects.

thalals.tistory.com

전에 표시했던 가로등 마커를 polygon 위에 적용해보았다.

어려울거 없이 단순하게 polygon 코드 아래에 markers 코드를 추가해 주었다.

 

반응형