内積と外積の特徴
内積
垂直なら0
左に傾くと正
右に傾くと負
外積
平行なら0
左に傾くと負
右に傾くと正
公式を確認する
内積と外積は、四則演算のみを使って求める方法と、平方根や三角関数を駆使して求める二つの方法がある。前者はイメージしにくいが速い。後者はイメージしやすいが遅い。それぞれの方法で計算して結果を確認する。
a = V[40, 80]
b = V[40, 20]
c = V[50, 50]
d = V[60, 45]
ab = b - a # => (0, -60)
cd = d - c # => (10, -5)
内積 (x1 * x2 + y1 * y2)
値は同じ方向を向いているほど大きくなる。言いかえると逆を向いているほど負の値になる。最初の真横を向いている図をイメージしてみると、同じ方向と逆の中間なので 0 になるのも納得できる。
cd.dot(ab) # => 300
cd.length * ab.length * cos(cd.angle_between(ab)) # => 300.0000000000001
cd を ab に正射影したときの影の長さを求める場合は相手の方を正規化する。
cd.dot(ab.normalize) # => 5.0
cd.length * ab.normalize.length * cos(cd.angle_between(ab)) # => 5.000000000000002
正規化した長さは 1 なので上の2つ目の式は、次のようにも書ける。
cd.length * cos(cd.angle_between(ab)) # => 5.000000000000002
これは三角関数の公式「底辺 = 斜辺 * cosθ」になっているのがわかる。
上の方法では一方を正規化したが、もし両方を正規化した場合は cd の長さを 1 としたときの割合になる。
cd.normalize.dot(ab.normalize) # => 0.4472135954999579
cd.normalize.length * ab.normalize.length * cos(cd.angle_between(ab)) # => 0.447213595499958
これも2つ目の式の なんとか.normalize.length
は 1 なので二つ目は次のように書ける。
cos(cd.angle_between(ab)) # => 0.44721359549995804
外積 (x1 * y2 - x2 * y1)
ただ符号が知りたい場合や、2つの線分を辺と考えたときにできる平行四辺形の面積を知りたいときはこれ。
cd.cross(ab) # => -600
cd.length * ab.length * sin(cd.angle_between(ab)) # => -600.0
直立投影(cd の真横から強い光を当てたとき壁にできる影の長さ)を求める場合は相手側を正規化する。
cd.cross(ab.normalize) # => -10.0
cd.length * ab.normalize.length * sin(cd.angle_between(ab)) # => -10.0
この2つ目の式は内積のときと似ていて「対辺 = 斜辺 * sinθ」になっている。
もし両方を正規化した場合は cd の長さを 1 としたときの割合になる。
cd.normalize.cross(ab.normalize) # => -0.8944271909999159
cd.normalize.length * ab.normalize.length * sin(cd.angle_between(ab)) # => -0.8944271909999157
こちらも正規化した長さは 1 なので
sin(cd.angle_between(ab)) # => -0.8944271909999159
と書ける。
このように、イメージしにくいけど速い方法と、イメージしやすいけど遅い方法、どちらの方法を使っても同じ値になるのがわかる。また内積も外積も似たようなもので乱暴に言えば求めたいのが横か縦かの違いにすぎない。
右辺と左辺を入れ替えるには?
内積の場合は掛け算なので入れ替えても結果は同じ。
cd.dot(ab) # => 300
ab.dot(cd) # => 300
一方、外積は入れ替えると符号が反転する。
cd.cross(ab) # => -600
ab.cross(cd) # => 600
だからといって入れ替えられないわけではなく入れ替えた上で全体にマイナス符号をつければ同じ式になる。
cd.cross(ab) # => -600
-ab.cross(cd) # => -600
横からの投影の名称について
始点が同じ2つのベクトルからできる三角形(片方が直線で片方が斜辺とする)では、内積は底辺が求まり、外積は対辺が求まる。このとき底辺のことを「正射影」と呼ぶ。しかし外積で求まる対辺の名称がずっとわからず「真横から強い光を当てて壁にできる影やジャンプしたときの高さ」と言っているのだが長い。調べてみてもどうも名称が定まっておらず
- Vertical Projection
- 直立射影
- 垂直射影
などと書いてある。
参照
コード
class App < Base
def initialize
super
self.width, self.height = V[800, 160]
a = window_wh * V[0.40, 0.80]
b = window_wh * V[0.40, 0.20]
c = window_wh * V[0.50, 0.50]
d = window_wh * V[0.60, 0.50]
@points.concat([a, b, c, d])
@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, d = @points
ab = b - a
cd = d - c
if @mode == 0
vputs "内積"
vputs "ab・cd = #{ab.dot(cd).round}"
vputs "|ab||cd|cosθ = #{(ab.length * cd.length * cos(ab.angle_between(cd))).round}"
end
if @mode == 1
vputs "外積"
vputs "ab×cd = #{ab.cross(cd).round}"
vputs "|ab||cd|sinθ = #{(ab.length * cd.length * sin(ab.angle_between(cd))).round}"
end
vector_draw(a, b, "a", "b")
vector_draw(c, d, "c", "d")
end
def font_size_default
16
end
show
end
Discussion