質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

3550閲覧

"点Pは線分AB上にある"をプログラムすると型が違うので計算できない

Tololololo

総合スコア118

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

1クリップ

投稿2018/12/28 06:45

編集2018/12/28 06:54

線分AB上に点Pが存在しているかの判定をしたく、そのコードを作ろうと考えています。(直線と線分を混同しないように気をつけてください。)

※注意: 画像にあるように円の中点から直線AB(ax+by+c=0とした)の交点を求めて、それを点Pとしています。そのため点Pは点Oの位置によって動いたりすることが前提です。
イメージ説明

平面ベクトル点の存在範囲より

上記のURLを参考にすると、プログラム上では
"s+t=1 &&
s>=0 &&
t>=0"

この3つの条件さえ合っていれば線分AB上内に点Pが存在していることになります。

ここからが問題なのですが、OP = sOA + tOBの公式についてです。
sとtの比較を実現するためにはそれぞれ s=t= の式に直し、実数を比較しなければなりません。
しかし、ベクトルOPは "点P-点O" で表すことができるのでプログラム上で書くと(glm::vec2 P - glm::vec2 O)となり、結果もglm::vec2で出てきます。
glm::vec2は主に(x,y)を表すためのものですが、この程で計算を進めていくと以下のような問題に突き当たります。

C++

1s = (OP+OB)/(OA+OB); // glm::vec2 2if ( s>=0 &&...) {...} // glm::vec2 >= int

つまり型が違うので比較ができないのです。
ここでいくつか質問があります。

  1. 私のベクトルの算出方法が間違っているのでしょうか?もし間違いであれば正しいベクトルの算出方法を教えてください。

  2. これは余談ですが、ベクトル計算は単位ベクトルに直す必要がありますか?ありませんか?

jozu👍を押しています

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

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

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

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

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

guest

回答4

0

こんにちは。

s = (OP+OB)/(OA+OB)

ベクトルのままでも計算はできると思いますが、線形代数学をそれなりに把握していないと厳しいと思います。(私も既に記憶の彼方です。)
線形代数をある程度使いこなせるのでないならば、展開して処理した方が楽ですよ。

OP = sOA + tOBは、OP, OA, OBをそれぞれ、(Xp, Yp), (Xa, Ya), (Xb, Yb)とすると、
Xp = s・Xa + t・Xb
Yp = s・Ya + t・Yb
という式になりますね。これを解けば良いです。

1.私のベクトルの算出方法が間違っているのでしょうか?もし間違いであれば正しいベクトルの算出方法を教えてください。

sと0が型違いで比較できないのでしたら、sの算出方法に間違い(勘違い?)があることは間違いないです。公式上sはスカラー値ですから0と比較できます。

ベクトルは一種の行列です。行列の演算など線形代数について学習されることをお勧めします。
もしくは、冒頭のように展開してから解くのもよいと思いますよ。

2.これは余談ですが、ベクトル計算は単位ベクトルに直す必要がありますか?ありませんか?

このケースでは絶対値も重要ですから、単位ベクトルに直す意味はないように感じます。(つまり、必要はない。)

投稿2018/12/28 09:02

Chironian

総合スコア23272

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

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

Bongo

2018/12/28 13:19

Chironianさんのご回答に一票入れたいと思います。 ご質問者さんへのコメントとして、こんな考え方もいかがかとのご参考に... 求めたい(s, t)というのは、Oを原点とする点Pの座標をOA、OBを基底とするひしゃげた平行四辺形の座標系に変換した結果と考えることができそうです。 ですので、^tを転置...つまり行ベクトルを列ベクトルに直すものとして、・を積として表記すると、OPと(s, t)には... OP^t = (OA^t OB^t)・(s, t)^t の関係があると言えるでしょう(コメント欄だと数式の表現力が足りなくてもどかしいですね)。 これをベクトルの成分の方程式に展開すると、Chironianさんのおっしゃる... Xp = s・Xa + t・Xb Yp = s・Ya + t・Yb の形になるはずです。 ^-1が逆行列を表すものとすると、最初の式の両辺に(OA^t OB^t)^-1を左から掛けて、さらに両辺を入れ替えると... (s, t)^t = (OA^t OB^t)^-1・OP^t となります。OPの座標を表す列ベクトルに、OAとOBの座標を並べた2x2行列の逆行列を左から掛ければsとtが出てくるということになりますね。 http://eman-physics.net/math/linear08.html のような記事もご参考になりそうです。
guest

0

ベストアンサー

質問内容への回答ではありませんが…

「ある点Oから,2点{A,B}を通る直線に垂線を下した位置Pが,AとBの間にあるかどうかを判定したい」という話であれば,

ベクトル T = B - A; if( ( (O - A)*T >= 0 ) && ( ( O - B )*T <= 0 ) ) { 線分上にある }

として判定できると思います.(ここで * は内積)

投稿2018/12/28 11:46

fana

総合スコア11654

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

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

Tololololo

2018/12/28 12:04

Chironianさんには申し訳ないのですが、BAを付け替えました。 コードが短いという点と*の正体が内積だったことが判明したためです。 難しい質問に答えていただいたみなさまありがとうございました
guest

0

点と線分の距離を求める が参考になると思います。

これは距離を求めていますが、その過程で点が線分上にあるか (線分上に垂線を下ろせるか) を判定しています。

過去の質問 でこれを C++ に書き直したコードを記載しています。
数式の導出は、最初の Qiita の記事をご参照ください。

投稿2018/12/28 07:00

tiitoi

総合スコア21956

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

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

0

下の図で、赤矢印で示した角度が 一方は 90 度以下、他方が 90度以上なら p は A - B の線上に存在します。
(どちらかまたは両方が 90 度である場合を含んでいることに注意)
下の図でいえば、 A 点側の角度は 90 度以下, B 点側の角度は 90 度以上です。
だから、その途中に角度 90 になる p があるということです。

イメージ説明

90 度で 0 になるものといえば cos() です。
そして内積は cos に関連した値です。
少なくとも1つが 0 か 両者の符号が異なっているというのは、 2 つの内積を掛算して、値が 0 以下になるか調べればよいのです。

if ((vec(A-O),vec(B-A)の内積) * vec(B-O),vec(B-A)の内積 <= 0 ) {
線分上にある
}

上の条件式にある2 つの内積は、A, O, B の座標値から計算できます。
なおここでは符号だけに注目するので、単位ベクトルにするとかの考慮は不要です。

参考

  • ベクトルの内積

http://www.geisya.or.jp/~mwm48961/kou2/dot_product0.html

投稿2018/12/31 02:34

編集2018/12/31 02:36
katoy

総合スコア22324

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問