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

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

詳細はこちら
OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

C++

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

Q&A

2回答

1718閲覧

線分と円の交差判定でプログラムの何が間違えているのか知りたい。

退会済みユーザー

退会済みユーザー

総合スコア0

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

C++

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

0グッド

0クリップ

投稿2021/02/01 12:50

編集2021/02/02 12:34

提示画像ですが。少しでも上下にずれるとfalse 当たっていない。と表示されます。これはエッジケースなのでしょうか?
ブロックは四角ですが円の当たり判定です。プレイヤーは正方形の上の線を線分として定義しています。

イメージ説明

cpp

1 2/*################################################### 3* 円と矩形の当たり判定 4*####################################################*/ 5 6 7//2つが異なっているかどうか? 8int acute_obtuse_diff(const float a, const float b) 9{ 10 if (a == 0) 11 { 12 if (b != 0) 13 { 14 return true; 15 } 16 else 17 { 18 return false; 19 } 20 21 } 22 else if (a > 0) 23 { 24 if (b <= 0) 25 { 26 return true; 27 } 28 else { 29 return false; 30 } 31 } 32 else if (a < 0) 33 { 34 if (a >= 0) 35 { 36 return true; 37 } 38 else 39 { 40 return false; 41 } 42 } 43} 44 45// 線分と円の当たり判定 46bool Line_Circle_col(const Line LineAB, const glm::vec2 Cpos, const float R) 47{ 48 49 glm::vec2 n = LineAB.end - LineAB.start; //A 50 n = glm::normalize(n); //Aを正規化 51 glm::vec2 Bvec = Cpos - LineAB.start; //B 52 53 float b = n.x * Bvec.y - Bvec.x * n.y; //最短距離 54// printf("b: %f\n",b); 55 56 57 if (b < R) 58 { 59 60 glm::vec2 AA1 = LineAB.end - LineAB.start; 61 glm::vec2 BB1 = Cpos - LineAB.start; 62 63 glm::vec2 AA2 = Cpos - LineAB.end; 64 glm::vec2 BB2 = LineAB.end - LineAB.start; 65 66 67 float AA = glm::dot(AA1, BB1); //内積 68 float BB = glm::dot(AA2, BB2); //内積 69 70 printf("AA %f\n",AA); 71 printf("BB %f\n",BB); 72 73 74 75 //2つが異なるかどうか? 76 if (acute_obtuse_diff(AA,BB) == true) 77 { 78 printf("A \n"); 79 return true; 80 } 81 else 82 { 83 printf("B\n"); 84 glm::vec2 SS = Cpos - LineAB.start; 85 glm::vec2 DD = Cpos - LineAB.end; 86 87 88 89 90 //printf("SS: %d\n",SS.length()); 91 // printf("DD: %d\n",DD.length()); 92 93 if ( (SS.length() < R) || (DD.length() < R) ) 94 { 95 printf("2\n"); 96 97 return true; 98 } 99 else { 100 false; 101 } 102 } 103 } 104 else { 105 printf("C\n"); 106 return false; 107 } 108} 109 110 111bool Intersect_2D(Box_Collision_2D& a, Circle_Collision_2D& circle) 112{ 113 // 線分 114 Line Line_up = Line{ glm::vec2(0,0),glm::vec2(0,0) }; 115 Line Line_down = Line{ glm::vec2(0,0),glm::vec2(0,0) }; 116 Line Line_left = Line{ glm::vec2(0,0),glm::vec2(0,0) }; 117 Line Line_right = Line{glm::vec2(0,0),glm::vec2(0,0) }; 118 119 glm::vec2 Cpos = circle.getPosition(); //円の座標 120 float R = circle.getSize(); //半径 121 //printf("R: %f\n",R); 122 123 glm::ivec2 pos; 124 glm::ivec2 pos2; 125 126 // up 127 Line_up.start = a.getPosition(); 128 129 pos = a.getPosition(); 130 pos.x += a.getSize().x; 131 Line_up.end = pos; 132 133 // down 134 pos = a.getPosition(); 135 pos.y += a.getSize().y; 136 Line_down.start = pos; 137 138 pos = a.getPosition(); 139 pos.x += a.getSize().x; 140 pos.y += a.getSize().y; 141 Line_down.end = pos; 142 143 // left 144 pos = a.getPosition(); 145 Line_left.start = pos; 146 147 pos = a.getPosition(); 148 pos.y += a.getSize().y; 149 Line_left.end = pos; 150 151 // right 152 pos = a.getPosition(); 153 pos.x += a.getSize().x; 154 Line_right.start = pos; 155 156 pos = a.getPosition(); 157 pos.y += a.getSize().y; 158 pos.x += a.getSize().x; 159 Line_right.end = pos; 160 161 ////////////////////////////////////// 162 163 if (Line_Circle_col(Line_up,Cpos,R) == true) 164 { 165 //printf("UP \n"); 166 return true; 167 } 168 else { 169 return false; 170 } 171 172 return false; 173}

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

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

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

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

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

guest

回答2

0

提示画像ですが。円と線分が水平?になった時にエッジケースが存在するみたいで線分と点のとの最短距離が円の半径より短くなるという現象が起きてしまいます。

その画像を見ても,何が{円,線分,点}なのかが不明ですが…

「点」というのが「円の中心」を指す語なのだと仮定すると,
「円の中心」から,「線分」が乗る直線に下した垂線の長さが円の半径よりも小さくなることはごく一般的な事柄でしょうから,

  • 仮にそんな状況すら扱えない話だということなのであれば,それは目的に対して役に立たない話だということになるのではないでしょうか.

しかし,本当にそうでしょうか?
「話は真っ当だけども,単に実装にミスがある」という仮定の方が可能性がありそうに思いませんか?

例えば,私としては,そのコードをぱっと見すると

if (AA != BB)

とかいうのがとても怪しく感じます.
2つのfloat値を ==!= で比較するような処理という時点で,何やらやばそうな予感がします.
さらに数行上まで見ると「2つの内積計算値が完全に等しいかどうか」という判定をしているらしい→その意味合いも理解できません.

これは一体何の判定なのでしょうか?
本当にその実装は間違ってないのでしょうか?
実装している「話:アルゴリズム」には,本当にそんな判定が存在するのですか?

投稿2021/02/02 01:59

fana

総合スコア11985

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

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

退会済みユーザー

退会済みユーザー

2021/02/02 02:04 編集

提示コードを修正ましたがやはり何かおかしいです。また直線ではなく線分なのですが直線なのでしょうか?
fana

2021/02/02 03:36

あたらしく書かれた acute_obtuse_diff もまた,ぱっと見で異常感が感じられる.
退会済みユーザー

退会済みユーザー

2021/02/02 03:37

マジですか?wちゃんと確認したのですがどこが問題なのでしょうか?
fana

2021/02/02 03:54

else if (a < 0) { if (a >= 0) 「確認」とは何か?
退会済みユーザー

退会済みユーザー

2021/02/02 04:07

鈍角、純角と90度のとき0になるのでそうかいたのですが間違えでしたか。。。。
fana

2021/02/02 04:11

↑に引用したifの並びは異常じゃないの? 「aは負の値だぞ」→「マジかよ! ところで,aの値って0以上だろうか?」とかおかしくね?
退会済みユーザー

退会済みユーザー

2021/02/02 04:16

あっ間違えていました。。。2つの値が異なる時にtrueになるこれは間違いなのでしょうか?
fana

2021/02/02 04:21

そう言われても, 何が正しくて何が違うのかについては,あなたは知っているだろうけども,こっちは知らないわけで.
退会済みユーザー

退会済みユーザー

2021/02/02 04:22

すいませんでした。
fana

2021/02/02 05:04

こっちはぱっと見の0.5秒とかで見つかるような怪しい矛盾点を突っ込んでいるだけであって,その矛盾点を解消したところで,それがそのアルゴリズムの実装の一部としての「正しい」意味合いのものになるのかどうかは知らないので,そこはあなたが判断なり確認なりする事柄ですぞ, という意味.
fana

2021/02/02 05:28

で, > if (acute_obtuse_diff(AA,BB) == true) ここって,単に if( AA*BB <= 0 ) とかだとダメな感じですか?
fana

2021/02/02 05:45 編集

これは動作とは無関係ですが,同じ演算を複数回やってる箇所はまとめるとすっきりする(だろうし,そういうことがバグの発生率を減らすことにつながる)のでは,とか. 最初に線分に沿う単位方向ベクトルnを求めているので, ifの中で再度 glm::vec2 AA1 = LineAB.end - LineAB.start; glm::vec2 BB2 = LineAB.end - LineAB.start; みたいなのを求めずとも,nを使える. ここの処理では n の長さには意味がないので. SSとDDも同様にそれより前に同じものを計算済みだからそれを用いれば良いと思う.
退会済みユーザー

退会済みユーザー

2021/02/02 06:02

なるほど。わかりました。
fana

2021/02/02 08:37

> float b = ... 最初は std::abs で絶対値にしてあったような…?
退会済みユーザー

退会済みユーザー

2021/02/02 09:22

間違えにきずき治しました。
guest

0

「点と直線の距離」と「点と線分の距離」とは異なります。

発生しているのは、前者が半径より小さくなっている、であり、質問文にある、「線分と点のとの最短距離が円の半径より短くなる」場合、trueが返るようにコーディングされているように読めます。

まずは、最初の2つの差異を説明できるようになってください。
これは、プログラミング以前の、中学程度の数学の問題です。

投稿2021/02/02 01:52

編集2021/02/02 01:54
YT0014

総合スコア1748

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問