点P(x_p,y_p)と点Q(x_q,y_q)を通る直線Lが存在したたとき、ある点A(x_a,y_a)を直線Lに対して垂直方向にn倍移動させた時の座標を求めたいです。
現在、すごいまわりくどい方法で座標を算出しているのですが、もっと簡単な方法で座標を求められると思うため、質問いたしました。
現在書いているコードのアルゴリズムは以下のような感じです。
-
外積を用い、点Aと直線Lまでの距離Rを算出
-
点Aから点Pまでの距離Tを算出
-
ベクトルPQの角度αを求め、線分PQを点Pを軸に-α度回転させ、一度X軸に平行な直線L'を算出
-
点Aも同様に-α度回転させる(点A')
-
点A'から直線L'に垂線を下ろした時、交わる点H'の座標を求める
(y座標はy_p、x座標はx_p+(T^2-R^2))
-
点H'をX軸方向にn倍する
-
ステップ6で求めた点をステップ3で求めた角度αを元にもう一度回転させる
以上により求めたい角度を求めています。
簡単な求め方を教えてください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
点Aから直線に下ろした垂線の足さえ求まれば、あとは以下のようにすればよいです。
- 垂線の足 h を求める。
- ベクトル hA を N 倍する。
垂線の足hは、内積の性質
ベクトルa, b のなす角をθとしたとき、 cosθ = a・b / |a||b|
を使って、以下のようにして求めます。
geometry - Finding a perpendicular vector from a line to a point - Mathematics Stack Exchange
コード
計算部分
python
1import matplotlib.pyplot as plt 2import numpy as np 3 4# 直線が通る2点 5p1 = np.array([1, 2]) 6p2 = np.array([4, 3]) 7 8# 点 9P = np.array([2, 3]) 10N = 4.5 # 何倍するか 11 12# 計算している部分 13v = (p2 - p1) / np.linalg.norm(p2 - p1) # 直線の方向を表す単位ベクトル 14h = (P - p1) @ v * v + p1 # 点 P から直線に対して下ろした垂線 15Q = h + (P - h) * N # N 倍した点
可視化
python
1# 2# 可視化 3# 4fig, ax = plt.subplots(figsize=(6, 6)) 5ax.set_xlim(0, 6) 6ax.set_ylim(0, 6) 7ax.grid() 8 9# 点 p1, p2, P, Q, h を描画する。 10def plot_point(p, name): 11 ax.annotate(f"{name} ({p[0]:.1f}, {p[1]:.1f})", p, p + 0.2, fontsize=13) 12 ax.scatter(*p, s=30, c="r") 13 14 15plot_point(p1, "p1") 16plot_point(p2, "p2") 17plot_point(h, "h") 18plot_point(P, "P") 19plot_point(Q, "Q") 20 21ax.annotate("", P, h, color="k", arrowprops=dict(arrowstyle="->")) 22ax.annotate("", Q, h, color="k", arrowprops=dict(arrowstyle="->")) 23 24# 直線を描画する。 25x = np.linspace(0, 5, 100) 26y = v[1] / v[0] * (x - p1[0]) + p1[1] 27ax.plot(x, y)
投稿2020/01/14 08:21
編集2020/01/14 08:28総合スコア21956
0
点P(x_p,y_p)と点Q(x_q,y_q)を通る直線Lが存在したたとき、ある点A(x_a,y_a)を直線Lに対して垂直方向にn倍移動させた時の座標を求めるという問題を、プログラムではなく一度、手で解くというのはどうでしょうか。
この問題は高校数学の知識で解ける問題です。
ちょっと手間がかかりますが、求めたい点の座標(X,Y)を、紙とペンでゴリゴリ計算していくと
XとYがx_p,y_p,x_q,y_q,x_a,y_a,nをつかった式で表されるはずです。
つまり、XとYに対する公式が得られます。
あとはプログラムでこのXとYの公式の計算を実装するだけで、1行ほどで終わると思います。
紙とペンで解くのは面倒ですが、何度もこの問題を解く必要がある場合は毎回1~7の手順を踏むよりかは公式を作ってしまってそこに代入するだけの方が、計算コスト的に一番だと思います。
参考になれば幸いです。
投稿2020/01/14 01:19
総合スコア143
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
んーと……直線Lへ点Aから垂線Mを下ろしたとき、直線LとMの交点をR と置くと、欲しいのは線分ARを直線Lから離れる方向へn倍した点、ですよね。
直線 ax+by+c=0 に垂直で,(x0,y0) を通る直線の方程式は,b(x−x0)−a(y−y0)=0
という公式がありますので、事前に直線Lの方程式からa,b,cを求めておけば、垂線Mの方程式が出ます。
このとき、直線LとMの交点 Rは、両方の方程式が分かっているので連立方程式を解くことに他なりません。
これで点Rが分かりましたら、R(x_r,y_r)を基点として点Aへの座標の差(ベクトル)が出ます。
あとはこれをn倍すればよい……のかな?
投稿2020/01/14 01:04
総合スコア13703
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
(1) PとQが通る直線Lが原点を通るように (-x_p,-y_p) だけ並行移動
(2) PとQが通る直線LがX軸と並行になるように回転
(3) AをX軸で対象になるように移動(n倍)
(4) (2)の逆変換
(5) (1)の逆変換
を行列演算でまとめて
Python
1CONV_A = np.linalg.inv(T).dot(np.linalg.inv(R)).dot(F).dot(R).dot(T).dot(A) 2#T: 並行移動行列 3#R: 回転移動行列 4#F: 対象移動行列
のように行うのはどうでしょうか。
Python
1import numpy as np 2import matplotlib.pyplot as plt 3 4# 3つの点をランダムで生成 5P = np.random.uniform(0,10,(2)) 6Q = np.random.uniform(0,10,(2)) 7A = np.append(np.random.uniform(0,10,(2)), 1) 8 9# 並行移動行列(Pを原点に移動) 10T = np.array([[1,0,-P[0]],[0,1,-P[1]],[0,0,1]]) 11# 回転行列(PQがX軸と並行になるように回転) 12rad = np.arctan((Q[1]-P[1])/(Q[0]-P[0])) 13R = np.array([[np.cos(-rad),-np.sin(-rad),0],[np.sin(-rad),np.cos(-rad),0],[0,0,1]]) 14# X軸に対する対称変換行列 15F = np.array([[1,0,0],[0,-1,0],[0,0,1]]) 16# まとめて変換 17CONV_A = np.linalg.inv(T).dot(np.linalg.inv(R)).dot(F).dot(R).dot(T).dot(A) 18 19# グラフにて確認 20f = lambda x:(Q[1]-P[1])/(Q[0]-P[0])*(x-P[0])+P[1] 21x = np.linspace(0, 10, 100) 22y = f(x) 23ax = plt.subplot() 24ax.set_aspect('equal') 25ax.plot(x,y,'-') 26ax.plot(P[0], P[1], 'bo') 27ax.plot(Q[0], Q[1], 'bo') 28ax.plot(A[0], A[1], 'ro') 29ax.plot(CONV_A[0], CONV_A[1], 'rx') 30plt.show()
投稿2020/01/14 05:37
総合スコア15898
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/01/14 12:10