본문 바로가기
Python

[Python] 특정 점에서 직선에 수선의 발 구하기.

by ds31x 2023. 7. 11.

특정 pnt에서

두 점 segment_s(s), segment_e(e)로 정의된 line segment를 포함하는 line으로

수선의 발(foot of perpendicular line)를 내리는 경우는 다음과 같음.

위 그림에서 x가 바로 foot of perpendicular line임.

 

다음은 foot of perpendicular line (intersection)과 line-segment 중에서 pnt와 가장 가까운 점 (closet_pnt)을 반환하는 function을 구현한 예제임.

def find_intersection_pnt( segment_s, segment_e, pnt):
  
  # Calculate the direction vector of the line segment defined by segment_s and segment_e
  line_segment_vector = (segment_e[0] - segment_s[0], 
                         segment_e[1] - segment_s[1])
  
  # Calculate the direction vector of the perpendicular line
  perpendicular_vector = (-line_segment_vector[1], 
                           line_segment_vector[0])
  
  # Calculate the closest point on the line segment to the foot of the perpendicular line
  # \text{proj}_\textbf{w}\textbf{x}=\dfrac{\bf{x}\cdot\bf{w}}{\|\bf{w}\|^2}\bf{w}
  projection = (pnt[0] - segment_s[0], pnt[1] - segment_s[1]) # set segment_s to origin
  dot_product = projection[0] * line_segment_vector[0] + projection[1] * line_segment_vector[1]

  projection_length = dot_product / (line_segment_vector[0] ** 2 + line_segment_vector[1] ** 2)
  
  intersection_pnt = (segment_s[0] + line_segment_vector[0] * projection_length,
                      segment_s[1] + line_segment_vector[1] * projection_length)
  
  # Check if the intersection_point lies on the line segment
  is_on_segment = (segment_s[0] <= intersection_pnt[0] <= segment_e[0] or
                   segment_s[0] >= intersection_pnt[0] >= segment_e[0]) and \
                  (segment_s[1] <= intersection_pnt[1] <= segment_e[1] or
                   segment_s[1] >= intersection_pnt[1] >= segment_e[1])
                    
  # Calculate the closest point
  if is_on_segment:
    closest_pnt = intersection_pnt
  else:
    # Choose the closest point between the foot of the perpendicular line and the endpoints of the segment
    dist_start = (intersection_pnt[0] - segment_s[0]) ** 2 + (intersection_pnt[1] - segment_s[1]) ** 2
    dist_end = (intersection_pnt[0] - segment_e[0]) ** 2 + (intersection_pnt[1] - segment_e[1]) ** 2
    if dist_start < dist_end:
      closest_pnt = segment_s
    else:
      closest_pnt = segment_e
    
  return intersection_pnt,closest_pnt

# Test
segment_s = (0, 0)
segment_e = (4, 2)
pnt = (5, 5)
intersection,closet_pnt = find_intersection_pnt(segment_s, segment_e, pnt)
print(f"Intersection point: {intersection}")
print(f"closet point: {closet_pnt}")

계산 효율보다는, 가독성에 초점을 맞춘 코드이며 linear algebra에서 orthogonal projection (정사영)을 이용하여 구현함.

https://dsaint31.tistory.com/entry/Math-Orthogonal-Projection-%EC%A0%95%EC%82%AC%EC%98%81

 

[Math] Orthogonal Projection (정사영)

Projection $\textbf{x}_1$ onto $\textbf{w}$ (vector $\bf{x}$를 vector $\bf{w}$에 투영) 를 수식으로 표현하면 다음과 같음. $$\text{proj}_\textbf{w}\textbf{x}=\dfrac{\bf{x}\cdot\bf{w}}{\bf{w}\cdot\bf{w}}\bf{w}=\dfrac{\bf{x}\cdot\bf{w}}{\bf{w

dsaint31.tistory.com

line-segment의 시작점을 origin으로 처리하여 구함.

 

foot of perpendicular는 특정 point가 선에서 어디에 있느냐에 따라 distance의 +,-를 정해지는 경우에 보통 구해지고, 단순히 거리만을 이용할 때는 좀더 단순하게 구할 수 있음. (몇가지 단계만 빠질 뿐 거의 똑같음)

https://dsaint31.tistory.com/entry/Math-Distance-between-Point-and-Plane-%EC%A0%90%EA%B3%BC-%EC%A7%81%EC%84%A0%EC%9D%98-%EA%B1%B0%EB%A6%AC

 

[Math] Distance between Point and Plane : 점과 직선의 거리

position vector $\textbf{x}$ (point $Q$)와 $\textbf{n}\cdot \textbf{p}+b=0$을 만족하는 position vector $\textbf{p}$들로 구성되는 평면(plane $P$)과의 거리는 다음과 같음. $$d=\dfrac{|\textbf{n}\cdot\textbf{x}+b|}{\|\textbf{n}\|}$$ whe

dsaint31.tistory.com

 

위의 구현물과 그림을 그린 코드 gist는 다음과 같음.

https://gist.github.com/dsaint31x/7853330c85e783dba7825faaa7300d5b

 

py_foot_of_perpendicular_line.ipynb

py_foot_of_perpendicular_line.ipynb. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com