空間ベクトル
2 次元から 3 次元へ
「地図で場所を示すのに東西と南北の 2 つの情報があれば十分でしたが、飛行機の位置を示すには高さ(高度)も必要」——これが 3 次元ベクトルが必要になる理由です。
2 次元のベクトル に第 3 成分を加えて、3 次元ベクトル を定義します——「x, y に加えて z(高さ・奥行き)の方向も扱えるようにする」のです。
基本ベクトル(それぞれ x, y, z 方向の「単位矢印」):
任意のベクトルはこれらの線形結合で書けます——「x方向に 、y方向に 、z方向に だけ動かす」:
3 次元での演算
加算・スカラー倍
「2 次元のときと全く同じルール」——成分が 1 つ増えただけです:
大きさ
「2 次元でピタゴラスの定理を使ったように、3 次元でも同じ発想」——3 つの成分すべてを二乗して足して平方根:
内積
「2 次元の内積の成分版と全く同じ構造」——成分が 1 つ増えて 3 項になるだけです:
外積(クロス積)
「2 つのベクトルが決める平面に対して、直角に突き刺さる矢印を作る演算」——これが外積で、3 次元特有の操作です。ドライバーを 2 方向で決まる平面にねじ込むイメージです。
3 次元特有の演算で、結果はベクトル(2 つのベクトル両方に垂直):
外積の大きさ は、 と が作る平行四辺形の面積に等しいです——「外積の長さ = 2 本の矢印で作った平行四辺形の広さ」と覚えましょう。
インタラクティブ図解:3D ベクトル(回転視点)
3 次元空間のベクトルを透視投影で表示します。マウスを左右に動かすと視点が回転します。
var OX = 300, OY = 190;
var t = 0;
function project(x, y, z, rotY) {
// Y軸まわりの回転
var cosR = Math.cos(rotY), sinR = Math.sin(rotY);
var rx = x * cosR + z * sinR;
var ry = y;
var rz = -x * sinR + z * cosR;
// 簡易透視投影
var fov = 400;
var d = fov / (fov + rz + 200);
return [OX + rx * d * 80, OY - ry * d * 80, d];
}
function drawLine3D(x1,y1,z1,x2,y2,z2,rotY,color,lw,dash) {
var p1 = project(x1,y1,z1,rotY);
var p2 = project(x2,y2,z2,rotY);
ctx.beginPath(); ctx.moveTo(p1[0],p1[1]); ctx.lineTo(p2[0],p2[1]);
ctx.strokeStyle=color; ctx.lineWidth=lw||1;
if(dash){ctx.setLineDash([4,3]);}else{ctx.setLineDash([]);}
ctx.stroke(); ctx.setLineDash([]);
}
function arrow3D(x1,y1,z1,x2,y2,z2,rotY,color,lw) {
var p1=project(x1,y1,z1,rotY);
var p2=project(x2,y2,z2,rotY);
var dx=p2[0]-p1[0],dy=p2[1]-p1[1];
var len=Math.sqrt(dx*dx+dy*dy);
if(len<2)return;
var ux=dx/len,uy=dy/len;
var hw=8,hl=12;
ctx.beginPath();ctx.moveTo(p1[0],p1[1]);ctx.lineTo(p2[0]-ux*hl,p2[1]-uy*hl);
ctx.strokeStyle=color;ctx.lineWidth=lw||2;ctx.stroke();
ctx.beginPath();ctx.moveTo(p2[0],p2[1]);
ctx.lineTo(p2[0]-ux*hl-uy*hw,p2[1]-uy*hl+ux*hw);
ctx.lineTo(p2[0]-ux*hl+uy*hw,p2[1]-uy*hl-ux*hw);
ctx.closePath();ctx.fillStyle=color;ctx.fill();
}
function label3D(x,y,z,rotY,text,color) {
var p=project(x,y,z,rotY);
ctx.fillStyle=color;ctx.font='bold 13px sans-serif';
ctx.fillText(text,p[0]+6,p[1]-6);
}
function loop() {
ctx.clearRect(0, 0, W, H);
t += 0.008;
var rotY = (mx / W) * Math.PI * 2;
var axLen = 3;
// 軸
drawLine3D(-0.2,0,0,axLen,0,0,rotY,'#30363d',1.5);
drawLine3D(0,-0.2,0,0,axLen,0,rotY,'#30363d',1.5);
drawLine3D(0,0,-0.2,0,0,axLen,rotY,'#30363d',1.5);
var xp=project(axLen+0.2,0,0,rotY);
var yp=project(0,axLen+0.2,0,rotY);
var zp=project(0,0,axLen+0.2,rotY);
ctx.fillStyle='#8b949e';ctx.font='13px sans-serif';
ctx.fillText('x',xp[0],xp[1]);
ctx.fillText('y',yp[0],yp[1]);
ctx.fillText('z',zp[0],zp[1]);
// ベクトル a = (2, 1, 0)
var ax=2,ay=1,az=0;
// ベクトル b = (0.5, 1, 2)
var bx=0.5,by=1,bz=2;
// a+b
var sx=ax+bx,sy=ay+by,sz=az+bz;
// 平行四辺形の点線
drawLine3D(ax,ay,az,sx,sy,sz,rotY,'#30363d',1,true);
drawLine3D(bx,by,bz,sx,sy,sz,rotY,'#30363d',1,true);
// 外積 a×b
var cpx = ay*bz - az*by;
var cpy = az*bx - ax*bz;
var cpz = ax*by - ay*bx;
var cpLen = Math.sqrt(cpx*cpx+cpy*cpy+cpz*cpz);
// 外積(正規化して 2.5 倍)
if (cpLen > 0.01) {
var scale = 2.5 / cpLen;
arrow3D(0,0,0,cpx*scale,cpy*scale,cpz*scale,rotY,'#ffa657',2.5);
label3D(cpx*scale,cpy*scale,cpz*scale,rotY,'a⃗×b⃗','#ffa657');
}
// ベクトル a
arrow3D(0,0,0,ax,ay,az,rotY,'#58a6ff',3);
label3D(ax,ay,az,rotY,'a⃗=('+ax+','+ay+','+az+')','#58a6ff');
// ベクトル b
arrow3D(0,0,0,bx,by,bz,rotY,'#f0883e',3);
label3D(bx,by,bz,rotY,'b⃗=('+bx+','+by+','+bz+')','#f0883e');
// a+b
arrow3D(0,0,0,sx,sy,sz,rotY,'#56d364',3);
label3D(sx,sy,sz,rotY,'a⃗+b⃗','#56d364');
// 平面 (a と b が張る平面の格子)
var alpha = Math.sin(t)*0.5+0.5;
for(var gi=-1;gi<=2;gi++){
drawLine3D(gi*ax*0.5,gi*ay*0.5,gi*az*0.5,
gi*ax*0.5+bx,gi*ay*0.5+by,gi*az*0.5+bz,
rotY,'#58a6ff15',1);
drawLine3D(gi*bx*0.5,gi*by*0.5,gi*bz*0.5,
gi*bx*0.5+ax,gi*by*0.5+ay,gi*bz*0.5+az,
rotY,'#f0883e15',1);
}
// 情報パネル
ctx.fillStyle='#0d1117e0';
ctx.fillRect(8,8,230,110);
ctx.strokeStyle='#30363d';ctx.lineWidth=1;
ctx.strokeRect(8,8,230,110);
ctx.font='12px monospace';
ctx.fillStyle='#58a6ff';
ctx.fillText('a⃗ = (2, 1, 0)',16,28);
ctx.fillStyle='#f0883e';
ctx.fillText('b⃗ = (0.5, 1, 2)',16,46);
ctx.fillStyle='#56d364';
ctx.fillText('a⃗+b⃗ = ('+sx+', '+sy+', '+sz+')',16,64);
ctx.fillStyle='#ffa657';
ctx.fillText('a⃗·b⃗ = '+(ax*bx+ay*by+az*bz),16,82);
ctx.fillText('a⃗×b⃗ = ('+(ay*bz-az*by).toFixed(1)+','+(az*bx-ax*bz).toFixed(1)+','+(ax*by-ay*bx).toFixed(1)+')',16,100);
requestAnimationFrame(loop);
}
loop();
平面の方程式
「床・壁・天井のような平らな面を数式で表す」——空間の平面はベクトルを使って 2 通りで表せます。
法線ベクトルを使った形
「平面に対して垂直に立てた矢印」が法線ベクトルです——「この矢印の方向が分かれば、平面の向きが分かる」というアイデアです。
法線ベクトル(平面に垂直なベクトル) と、平面上の 1 点 から:
展開すると:
パラメータ表示
「基点から 2 方向に自由に動けるすべての点の集合」——平面上の 1 点 P と 2 つの独立ベクトル , を使って:
直線の方程式(空間)
「点 P を出発して、決まった方向 にどこまでも進む線」——点 P を通り、方向ベクトル の直線:
または媒介変数表示(パラメータ を変化させると直線上の点が得られる):
点と平面の距離
「2 次元で点と直線の距離を求めたのと同じ発想」——点 から平面 までの距離(2 次元と同様の形):
2 平面の関係
「2 枚の板が平行か垂直かを調べる」——法線ベクトルの関係を見れば分かります:
平面 と の法線ベクトルを 、 とすると:
- 平行 ——「法線が同じ方向 = 平面が平行」
- 垂直 ——「法線が直交 = 平面が垂直」
2 平面のなす角 :
まとめ
- 3D ベクトルは成分が 3 つ:——「x, y, z の 3 方向を同時に扱う」
- 内積は 2D と同様:——「成分が 1 つ増えるだけ」
- 外積は 3D 固有:結果がベクトル、両ベクトルに垂直——「2 本の矢印が作る面の「法線」を生み出す演算」
- 平面の方程式:(法線ベクトル を持つ)——「平面の向きは法線ベクトル 1 本で決まる」
次回は数の世界を実数から複素数へ拡張し、複素数平面(アルガン図)を学びます。