みさご解体新書

2点間の直線距離

概要

何かの直線距離を求めるという行為はアニメーションの中で最も利用される計算かもしれない。たとえばオブジェクト同士の距離に応じて、色や大きさが変わるなどの手法はよく利用される。その他、オブジェクト同士が衝突しているかの判定でも利用される。

解説/アルゴリズム

一次元での直線距離

O -100 90 190

一次元、つまり数直線上にある x1x_1x2x_2 の直線距離は、2 点の差の絶対値 x1x2|x_1-x_2| となる。

function dist(x1: number, x2: number): number {
  return Math.abs(x1 - x2);
}

dist(-100, 90);

二次元での直線距離/二点間距離

O x y 393 A(62,356) B(278,28) x1 x2 y1 y2

座標平面上の 2 点 A(x1,y1),B(x2,y2)A(x_1, y_1), B(x_2, y_2) 間の距離を求めたい。

x1x2,y1y2x_1 \neq x_2, y_1 \neq y_2 のとき、(x1,y2)(x_1, y_2) を点 C とすると、 ACB\triangle ACB は直角三角形になるので、三平方の定理を使用すると、 AB=AC2+BC2AB = \sqrt{AC^2+BC^2} となる。

さらに、

  • AC2=x2x12=(x2x1)2AC^2=|x_2-x_1|^2=(x_2-x_1)^2
  • BC2=y2y12=(y2y1)2BC^2=|y_2-y_1|^2=(y_2-y_1)^2

であるから、先ほどの式 AB=AC2+BC2AB = \sqrt{AC^2+BC^2} に代入すると、

AB=(x2x1)2+(y2y1)2AB = \sqrt{(x_2-x_1)^2+(y_2-y_1)^2} となり、 x1=x2x_1 = x_2 または y1=y2y_1 = y_2 のときも同様となる。

function dist(x1: number, y1: number, x2: number, y2: number): number {
  return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
}

dist(10, 10, 20, 20);

三次元での直線距離

A B C D a b c

ABAB の長さを求めるために、まず ABC\triangle ABC に三平方の定理を使用すると、

AB2=BC2+c2AB^2 = BC^2 + c^2

この BC2BC^2BCD\triangle BCD に三平方の定理を使用すると、 BC2=a2+b2BC^2 = a^2 + b^2 ということが分かるから、上の式に代入すると、

AB2=a2+b2+c2AB^2 = a^2 + b^2 + c^2

両辺の平方根を取ると、

AB=a2+b2+c2AB = \sqrt{a^2+b^2+c^2}

この a,b,ca,b,c は軸ごとの差であるから、

AB=(x1x2)2+(y1y2)2+(z1z2)2AB = \sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2}

つまり、二次元の場合と同じように、軸ごとに差の二乗を取り、総和を計算すれば 2 点間距離が求まる。

function dist(
  x1: number,
  y1: number,
  z1: number,
  x2: number,
  y2: number,
  z2: number
): number {
  return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2);
}

dist(10, 10, 10, 20, 20, 20);

片方が原点の場合

function len(x: number, y: number): number {
  return Math.sqrt(x * x + y * y);
}

// (0, 0)から(10, 10)までの距離
len(10, 10);

片方が原点の場合は引き算をする必要がないので三平方の定理のような形になる。

function dist(x1: number, y1: number, x2: number, y2: number): number {
  return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
}

function len(x: number, y: number): number {
  return Math.sqrt(x * x + y * y);
}

const x1 = 10;
const y1 = 10;
const x2 = 20;
const y2 = 20;

// 14.142135623730951
console.log(dist(x1, y1, x2, y2));
// 14.142135623730951
console.log(len(x2 - x1, y2 - y1));

なので、片方の位置を (0, 0) になるように調整しても二点間距離を求めることができる。

上記では、 (x1, y1), (x2, y2) を (x1 - x1, y1 - y1), (x2 -x1, y2- y1) に変換して、 (x1, y1) を原点に移動させた。これで二点のうち片方が原点になったので len() に適用ができる。

ループ対応

画面の左端から出ると右端から出てくるように、ループで繋がっている環境での 2 点間距離の計算方法。