📐

# 点と直線の距離の求め方

2023/09/13に公開

## 考え方

1. 右の三角形の底辺
2. 左の三角形の対辺

に着目すると、一つ目は正射影のことなので

• 「ベクトル ac」と「ベクトル ab の法線の正規化」の内積

で求まり、二つ目は直立射影のことなので

• 「ベクトル ac」と「ベクトル ab の正規化」の外積

で求まる。

## 計算手順

``````a = V[400, 320]
b = V[240,  80]
c = V[480,  80]
ab = b - a  # => (-160, -240)
ac = c - a  # => (80, -240)
``````

``````ac.dot(ab.perp.normalize).round  # => 200
``````

``````ab.normalize.cross(ac).round  # => 200
``````

## 直線に衝突した円を反射させる例

``````# 直線
a = V[400, 320]
b = V[240,  80]
ab = b - a  # => (-160, -240)
``````
``````# 円
c = V[480,  80]
speed = V[-1.0, 0.0]
``````
``````# 判定
ac = c - a           # => (80, -240)
abn = ab.normalize   # => (-0.5547001962252291, -0.8320502943378436)
len = abn.cross(ac)  # => 199.6920706410825
gap = len - radius   # => -1.3079293589175052
if gap.round.negative?
speed += -speed.project_onto_normalized(abn.perp) * 2
end
speed                # => (0.38461538461538436, -0.923076923076923)
``````
コード
``````class App < Base
def initialize
super

self.width, self.height = V[800, 400]

a = window_wh * V[0.5, 0.8]  # => (400.0, 320.0)
b = window_wh * V[0.3, 0.2]  # => (240.0, 80.0)
c = window_wh * V[0.6, 0.2]  # => (480.0, 80.0)

@points.concat([a, b, c])

@mode = 0
end

def button_down(id)
super

if id == Gosu::KB_Z
@mode = @mode.next.modulo(2)
end
end

def draw
super

a, b, c = @points
ab = b - a
ac = c - a
d = a + ac.project_onto(ab.perp)
e = a + ac.reject_from(ab.perp)

vector_draw(a, b, "a", "b")

if true
point_draw(c)
end

if @mode == 1
vputs "(abの正規化)×ac = #{ab.normalize_or_zero.cross(ac).round}"
vputs "ac･(abの法線の正規化) = #{ac.dot(ab.perp.normalize_or_zero).round}"

line_draw(a, a + ab.perp * 2)
line_draw(a, c)
line_draw(b, b + ab)
line_draw(a, a - ab)
line_draw(c, d)
line_draw(c, e)
vector_draw(a, d, "", "d")
vector_draw(a, e, "", "e")
end
end

def font_size_default
16
end

show
end
``````