これも結構間違えた実装してました…
前提
以下の変数AB、CDは直線です。それぞれ対応する方程式「ax + by + c = 0」のa、b、cをプロパティとして持っています。
つまり、「AB.a * x + AB.b * y + AB.c = 0」が直線ABを表す方程式となります。
また、aが0のときbは1、bが0のときaは1とします。「0x + by + c = 0」を変形すればいいので問題はありません。
aもbも0の場合は、そもそも直線とみなさないことにします。
コード
const getIntersection = (AB, CD) => { if (AB.a * CD.b === CD.a * AB.b) { return false; } const y = (CD.a * AB.c - AB.a * CD.c) / (AB.a * CD.b - CD.a * AB.b); // AB.a * CD.b - CD.a * AB.b !== 0 let x; if (AB.a === 0) { x = -1 * (CD.b * y + CD.c) / CD.a; } else { x = -1 * (AB.b * y + AB.c) / AB.a; } return new Point(x, y); };
軽い解説
まず、 AB.a * CD.b === CD.a * AB.b
ですが、この式は整理すると AB.a / AB.b === CD.a / CD.b
となり、傾きが等しいことを示す式となります。しかし、AB.bまたはCD.bが0のとき、この式は正しく動いてくれません。そこで、はじめのような式となります。
次に、交点のy座標を求めます。これは、 AB.a * CD.b !== CD.a * AB.b
つまり AB.a * CD.b - CD.a * AB.b !== 0
であるので、0除算でないことが保証されています。よって安全に求めることができます。
最後に交点のx座標を求めます。ここではどうしてもゼロ除算の可能性が生まれるので、場合分けを行っています。
もしAB.aが0ならば、AB.a * CD.b は 0です。この行にくるためには AB.a * CD.b !== CD.a * AB.b
でなければなりません。よってよってCD.a * AB.b は0ではありません.AB.bは1なので、明らかにCD.aは0ではありません。これで、CD.aで割ることができます。
else節ではAB.aが0でないので、安全にAB.aで割ることができます。
終わりに
x座標のところが見落としがちです。気をつけましょう(←見落としたまま半年放置してた)。