TIL

[Python] Shapely를 이용하여 도형과 직선의 교점 구하기

d00you 2021. 12. 6. 16:18

파이썬의 shapely 라이브러리를 이용하면 점, 선, 원 등을 라이브러리에서 제공하는 함수를 사용하여 쉽게 만들 수 있습니다.

사실 파이썬으로 도형을 만들 때는 좌표공간 위에 매개 방정식을 통해서도 만들어 줄 수 있는데요,
그럼에도 굳이 shapely 라이브러리를 사용하고자 한 이유는 두 도형 간의 교점을 기준으로 segment를 나눠주는 작업을 하고 싶었기 때문입니다.

그림과 같이 원과 선이 있다면, 각 교점에 의해 세 개의 segment가 만들어진다.


수학적으로 접근할 때, 원의 방정식에 직선의 방정식 대입하여 방정식의 해를 구하여 교점을 아는 방법도 있습니다.

하지만 좀 더 graphical하게 접근해볼 수도 있겠죠. 두 도형의 교점이 교집합의 원소라고 하면 그 외 부분은 차집합의 원소입니다. 즉, 교점을 기준으로 만들어진 segment들은 차집합의 원소라고 할 수 있겠네요.

그런데 마침 shapely 라이브러리에는 도형 간의 차집합을 구하는 difference 함수가 존재합니다. 또한 차집합으로 형성된 element 즉 segment에 접근 가능한 객체도 생성이 됩니다.

 

 


직접 파이썬을 사용하기에 앞서, shapely library를 다운받지 않았다면 아래 명령어를 통해 설치해주시기 바랍니다.

pip install shapely

저는 주피터 노트북 사용자이기 때문에 아나콘다 프롬프트에 해당 명령어를 입력해주었습니다.

shaply 라이브러리를 이용하여 특정 위치에 점을 찍고 싶다면

from shapely.geometry import Point 

point = Point(0., 0.)

위와 같이 (0., 0.)이라는 위치의 점을 뜻하는 point라는 객체를 생성할 수 있습니다.

shaply 라이브러리를 이용하여 직선을 만들고 싶다면
위와 같이 (-1,-1)과 (1,1)을 잇는 직선을 뜻하는 line이라는 객체를 생성할 수 있습니다.

from shapely.geometry import LineString 

line = LineString([(-1., -1.),(1., 1.)])

 

shaply 라이브러리를 이용하여 원을 만들고 싶다면
Point 함수로 원의 중점을 지정해주고 buffer라는 operation을 이용하여 반지름을 지정해주면 됩니다.

circle = Point(0., 0.).buffer(1.).boundary

저는 속이 꽉 찬원이 아닌, 원의 경계선을 만들어 주고 싶었기 때문에 .boundary 옵션을 붙여주었습니다.


이제 차집합을 사용하여 segment를 구해봅시다.

segment = line.difference(circle)[1]

위와 같이 .difference 함수를 사용하면 차집합의 원소가 구해지고, segment들이 직선이니까 양 끝점의 좌표를 통해 표시됩니다.
인덱스를 통해 각 원소에 접근 가능한데, 0번 인덱스는 위 사진에서 segment1, 1번 인덱스는 segment2, 2번 인덱스는 segment3을 뜻합니다.

.coords 옵션을 통해 1번 인덱스에 해당하는 좌표를 뽑아보면

print(shapely.get_coordinates(segment))

결과는 우리가 설정해준대로 unit circle과 y=x 직선의 교점, 그리고 직선의 양 끝점이 출력됨을 알 수 있습니다.

array([[-1.        , -1.        ],
       [-0.35355339, -0.35355339],
       [ 0.35355339,  0.35355339],
       [ 1.        ,  1.        ]])

즉, segment들의 양 끝점이 출력되고요, 이를 통해 교점은 물론 segment들의 직선의 방정식도 알 수 있겠죠?

 

이 방법을 이용하여 mesh or grid와 직선의 교점도 구할 수 있는데, 데이터를 이산화(discretize)할 때 요긴하게 사용할 수 있습니다. 


읽어주셔서 감사합니다. 궁금한 점이 있다면 얼마든지 댓글로 질문해주세요!