ニ直線の交点を求める

作成理由

  • 久しぶりに外部変形を作ろうとしたんだけどニ直線の交点の求め方を忘れてたので覚え書きとしてまとめてみる

計算方法

ニ点を通る直線

説明
直線の方程式 $$ ax + by + c = 0 $$
変形 $$ ax + by = -c $$
両辺を -c で割る $$ -\frac{a}{c}x – \frac{b}{c}y = 1 $$
定数を変更 $$ a_{1}x + a_{2}y = 1 ( a_{1}=-\frac{a}{c} 、 a_{2}=-\frac{b}{c} )$$
$$点 (x_{1},y_{1}) が直線上にある$$ $$ a_{1}x_{1} + a_{2}y_{1} = 1 $$
$$点 (x_{2},y_{2}) が直線上にある$$ $$ a_{1}x_{2} + a_{2}y_{2} = 1 $$
連立方程式を行列にする $$ \begin{equation}\begin{pmatrix}x_{1} & y_{1} \\x_{2} & y_{2} \end{pmatrix}\begin{pmatrix}a_{1} \\ a_{2}\end{pmatrix}=\begin{pmatrix} 1 \\ 1 \end{pmatrix}\end{equation} $$
逆行列をかける $$ \begin{equation}\begin{pmatrix}a_{1} \\ a_{2}\end{pmatrix}=\begin{pmatrix}x_{1} & y_{1} \\x_{2} & y_{2} \end{pmatrix}^{-1}\begin{pmatrix} 1 \\ 1 \end{pmatrix}\end{equation} $$
  • これで直線の定数が求まった

ニ直線の交点

説明
直線1 $$ a_{11}x + a_{12}y= 1 $$
直線2 $$ a_{21}x + a_{22}y= 1 $$
連立方程式を行列にする $$ \begin{equation}\begin{pmatrix}a_{11} & a_{12} \\a_{21} & a_{22} \end{pmatrix}\begin{pmatrix}x \\ y\end{pmatrix}=\begin{pmatrix} 1 \\ 1 \end{pmatrix}\end{equation} $$
逆行列をかける $$ \begin{equation}\begin{pmatrix}x \\ y\end{pmatrix}=\begin{pmatrix}a_{11} & a_{12} \\a_{21} & a_{22} \end{pmatrix}^{-1}\begin{pmatrix} 1 \\ 1 \end{pmatrix}\end{equation} $$
  • これで交点が求まった

外部変形

  • ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mingw32] にて動作確認しています
REM ニ直線の交点を求める.bat
CHCP 932
echo off
REM #jww
REM #cd
goto %EXE
REM #1ln 【一本目の線を選択してください】
REM #2ln 【ニ本目の線を選択してください】
REM #bz
REM #e
:EXE
copy jwc_temp.txt temp.txt
ruby -Ks -x %~f0
GOTO END
REM #~

◎コメント
◎バッチファイル名は自由
◎以下 ruby スクリプト部分

#! ruby
# encoding: SJIS

$stdout=open("jwc_temp.txt","w")
$stderr=open("tmp_err.txt","w")

include Math
require "matrix"

hhp,m1,m2,v0=0,0,0,Vector[1000.0,1000.0]
open("temp.txt").readlines.map{|e|
  if %r|^hhp(\d)ln|=~e
    hhp=$1.to_i
  elsif %r|^ [\d-]|=~e
    e=e.split.map{|e| e.to_f}
    m1=Matrix[[e[0],e[1]],[e[2],e[3]]] if hhp==1
    m2=Matrix[[e[0],e[1]],[e[2],e[3]]] if hhp==2
    hhp=0
  end}
a1=m1.inv*v0
a2=m2.inv*v0
begin
  pt=Matrix[a1.to_a,a2.to_a].inv*v0
rescue
  puts "heニ直線が平行です"
  exit
end

#線上に乗っているかどうかのチェック
#ベクトルの長さと内積の符号で判断
#線上にある場合の補正を考慮
m1,m2=m1.to_a,m2.to_a
v11,v12=Vector.elements(m1[0]),Vector.elements(m1[1])
v21,v22=Vector.elements(m2[0]),Vector.elements(m2[1])
if (v12-v11).r-(pt-v11).r>-0.1**10  && (v12-v11).inner_product(pt-v11)>-0.1**10 &&
  (v22-v21).r-(pt-v21).r>=-0.1**10 && (v22-v21).inner_product(pt-v21)>-0.1**10
  puts "pt #{pt[0]} #{pt[1]}"
else
  puts "he交点が直線上にありません"
end
__END__
:END
  • また一歩野望に近づいた

別解

  • 出来上がったところで昔考えた外積を使ったバージョンが出てきた
  • それもご丁寧に図解付きなんだけど今となっては何をやってるのかよく分からない
REM ニ直線の交点を求める2.bat
CHCP 932
echo off
REM #jww
REM #cd
goto %EXE
REM #1ln 【一本目の線を選択してください】
REM #2ln 【ニ本目の線を選択してください】
REM #bz
REM #e
:EXE
copy jwc_temp.txt temp.txt
ruby -Ks -x %~f0
GOTO END
REM #~

◎コメント
◎バッチファイル名は自由
◎以下 ruby スクリプト部分

#! ruby
# encoding: SJIS

$stdout=open("jwc_temp.txt","w")
$stderr=open("tmp_err.txt","w")

include Math
require "matrix"

hhp,ln1,ln2=0,[],[]
open("temp.txt").readlines.map{|e|
  if %r|^hhp(\d)ln|=~e
    hhp=$1.to_i
  elsif %r|^ [\d-]|=~e
    ln1=e.split.map{|e| e.to_f} if hhp==1
    ln2=e.split.map{|e| e.to_f} if hhp==2
    hhp=0
  end}
as=Vector.elements(ln1[0,2]+[0])
bs=Vector.elements(ln2[0,2]+[0])
ae=Vector.elements(ln1[2,2]+[0])
be=Vector.elements(ln2[2,2]+[0])
va=ae-as
vb=be-bs
c1=va.cross(bs-as)
c2=va.cross(be-as)
c3=vb.cross(as-bs)
c4=vb.cross(ae-bs)
d1=c1.r/va.r
d2=c2.r/va.r
pt=bs+(d1/(d1+d2))*vb
if vb.cross(as-bs)==vb.cross(ae-bs) or c1[2]*c2[2]>0 or c3[2]*c4[2]>0
  puts "he 交点が求められません"
else
  puts "pt #{pt[0]} #{pt[1]}"
end
__END__
:END

おわりに

  • 外部変形自体は役に立たないけどたまに行列とか使うときに毎回悩んでる気がする
  • ここまでは準備体操でこれからこの辺を応用して節間線種変更の外部変形を考えてみよう思います

コメント