🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

4回答

11367閲覧

ある点をある直線に対して垂直方向に移動させた時の座標の求め方

mikanken

総合スコア10

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

2クリップ

投稿2020/01/13 19:39

点P(x_p,y_p)と点Q(x_q,y_q)を通る直線Lが存在したたとき、ある点A(x_a,y_a)を直線Lに対して垂直方向にn倍移動させた時の座標を求めたいです。

現在、すごいまわりくどい方法で座標を算出しているのですが、もっと簡単な方法で座標を求められると思うため、質問いたしました。

現在書いているコードのアルゴリズムは以下のような感じです。

  1. 外積を用い、点Aと直線Lまでの距離Rを算出

  2. 点Aから点Pまでの距離Tを算出

  3. ベクトルPQの角度αを求め、線分PQを点Pを軸に-α度回転させ、一度X軸に平行な直線L'を算出

  4. 点Aも同様に-α度回転させる(点A')

  5. 点A'から直線L'に垂線を下ろした時、交わる点H'の座標を求める

  (y座標はy_p、x座標はx_p+(T^2-R^2))

  1. 点H'をX軸方向にn倍する

  2. ステップ6で求めた点をステップ3で求めた角度αを元にもう一度回転させる

以上により求めたい角度を求めています。

簡単な求め方を教えてください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

点Aから直線に下ろした垂線の足さえ求まれば、あとは以下のようにすればよいです。

  1. 垂線の足 h を求める。
  2. ベクトル 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
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mikanken

2020/01/14 12:10

計算量も少なく可視化付きでわかりやすかったためベストアンサーとさせていただきました!
guest

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

tkymtmt

総合スコア143

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mikanken

2020/01/14 01:33

一度計算したいと思います。ありがとうございました。
guest

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

tacsheaven

総合スコア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

magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2020/01/14 07:00

角度ベースで回転するよりも 直線方向と直線に垂直な方向で正規直交基底を作って 座標変換したほうがよいかと (逆変換は転置になる)
magichan

2020/01/14 09:50

ozwkさん たしかに角度を求めるよりもその方がシンプルになりますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問