ページ 1 / 1
角度の出し方について
Posted: 2008年12月27日(土) 20:34
by みかんのかわ
C言語で、今画面上に3つの点をランダムで出し、その点を結んで
直角三角形を描画し、その角度を求めるということをしようとしています。
(各点はランダムで出しますが必ずどこかひとつの角が直角になるようにします。)
三角形の2辺の長さと直角ということを利用し、残りの角のひとつを出したいと考えています。
やり方として、三平方の定理で角度を出す、「COSθ=b/a」(b,aは三角形の辺の長さです)
を使用してやろうと考えております。
その角度θを今プログラム的に求めたいと考えているのですが、やり方がよくわかりません。
θをどのようにもとめればよいでしょうか?
(COSθ=b/aからθ=の式にうまく直せないというか)
説明がしずらくわかりずらくなってしまったかもしれませんが、よろしくお願いいたします。
Re:角度の出し方について
Posted: 2008年12月27日(土) 21:07
by box
> やり方として、三平方の定理で角度を出す、「COSθ=b/a」(b,aは三角形の辺の長さです)
どの2辺のことかを言わないと、その式が成立するかどうかはわかりません。
仮に、2辺a,bが斜辺と他の1辺のことだとすると、
acosという標準関数を使えばθが求まります。
Re:角度の出し方について
Posted: 2008年12月27日(土) 21:14
by dic
画像の計算式が分かっていれば求まると思いますが
どこにつまづいているのでしょうか?
Re:角度の出し方について
Posted: 2008年12月27日(土) 22:27
by non
意味がよくわかりませんので質問を。
> C言語で、今画面上に3つの点をランダムで出し、その点を結んで
> 直角三角形を描画し、その角度を求めるということをしようとしています。
直角三角形を描画したいと考えていいですよね。
角度を求めるのは、その後ということで。
> 三角形の2辺の長さと直角ということを利用し、残りの角のひとつを出したいと考えています。
まず、2点を乱数で発生させ、もう1点を直角三角形になる場所に発生させたいと考えて
よろしいでしょうか?
> やり方として、三平方の定理で角度を出す、「COSθ=b/a」(b,aは三角形の辺の長さです)
> を使用してやろうと考えております。
これは、3点目の頂点を出すためではなく、描画した後の角度を求めるためなのでしょうか?
> その角度θを今プログラム的に求めたいと考えているのですが、やり方がよくわかりません。
> θをどのようにもとめればよいでしょうか?
> (COSθ=b/aからθ=の式にうまく直せないというか)
この部分だけなら、boxさんが言われるようにアークコサイン(acos)という関数があります。
「みかんのかわ」さんは、高校生以上ですよね。
さて、3点目の頂点を発生させる方法は、できているのでしょうか?
こっちの方が難しいのでは?
Re:角度の出し方について
Posted: 2008年12月27日(土) 22:40
by たいちう
> C言語で、今画面上に3つの点をランダムで出し、その点を結んで
> 直角三角形を描画し、その角度を求めるということをしようとしています。
> (各点はランダムで出しますが必ずどこかひとつの角が直角になるようにします。)
そもそもこの方針が間違いなのではないかと。
一般的にランダムの3つの点が作る三角形は直角三角形ではないですよ。
ランダムな直角三角形がほしいなら次の2つの方法をお勧めします。
(1)力任せ
while (1) {
// ランダムで三角形を作成
// 判定(内積を使うと良いでしょう)
if (直角三角形か?) break;
}
(2)直角三角形を直接作る(∠BACが直角)
// ランダムで点Aを決める
// ランダムで点Bを決める
// ランダムでACの長さを決める
-AB <= |AC| <= ABの範囲が良いかな。なんとなく。
符号によってCをABから見てどちら側にするかを決める。
// Cを計算で求める
ABの傾きをatan2で角度にして、Aを基準に三角関数でCの座標を求める。
力任せの方法は簡単ですが、内積の判定に幅を持たせないと使い物にならないでしょう。
直角三角形を直接作る方法は一例です。目的に合わせたより良い方法があるならば
それを使ってください。
Re:角度の出し方について
Posted: 2008年12月27日(土) 23:01
by non
方法1は問題外
方法2はいいけど、乱数を向きと長さの2つを発生させなきゃいけないし、
式も結構面倒かな。2点を通る直線の式からそれに直交する式を求めることになる。
その後、長さから座標を求める。大変だ。
また、軸に平行な場合を、場合分けしなきゃいけなくなる。
そこで、方法3として、
まず、2点の乱数を発生させ、この2点を直径とする円の方程式を求め、円周上の
点を角度0~2πで乱数発生させたほうが簡単だと思う。
Re:角度の出し方について
Posted: 2008年12月28日(日) 13:38
by たいちう
方法1が問題外なのは同意。半分ネタです。
> 方法2はいいけど、乱数を向きと長さの2つを発生させなきゃいけないし、
> 式も結構面倒かな。2点を通る直線の式からそれに直交する式を求めることになる。
> その後、長さから座標を求める。大変だ。
> また、軸に平行な場合を、場合分けしなきゃいけなくなる。
それほど大変じゃないですよ。
2点を通る直線の式も直交する直線の式も求める必要はありません。
ABの角度は引き算とatan2で求まるので、ACの角度はこれにπ/4を足すだけ。
x座標については、cx = ax + (ACの長さ)*cos(ACの角度)となります。
ACの長さに負の範囲もあるし、atan2なので、場合分けも要りません。
方法3は私も思いついていましたが(負け惜しみ)、
こっちの方がよほど簡単ですね。深く考えませんでした。
Re:角度の出し方について
Posted: 2008年12月28日(日) 15:26
by non
> ABの角度は引き算とatan2で求まるので、ACの角度はこれにπ/4を足すだけ。
> x座標については、cx = ax + (ACの長さ)*cos(ACの角度)となります。
> ACの長さに負の範囲もあるし、atan2なので、場合分けも要りません。
なるほど、それなら、大変じゃないですね。
しかし、本人からはRESがないので、何がわからないのか、定かでないですね。
Re:角度の出し方について
Posted: 2008年12月28日(日) 15:29
by Dixq (管理人)
2点をatan2で角度計算し、他の2点をatan2で角度計算し、成す角を引き算で求めるのじゃダメですかね?
Re:角度の出し方について
Posted: 2008年12月28日(日) 15:37
by たかぎ
いっそ何も考えずに、余弦定理で角度を求めるというのもひとつの手ですね。
Re:角度の出し方について
Posted: 2008年12月29日(月) 13:08
by みかんのかわ
書き込みが遅くなって申し訳ありません。
>boxさん
>dicさん
説明が足らず申し訳ありませんでした。
dicさんの載せてくださった図をお借りしていうと、
辺c,a(斜辺とθに接する他の一辺)がわかっているときの角度θを求めたかったのです。
cos(θ);系の関数がある事は知っていましたがacos(θ);があることを
知りませんでした。ありがとうございます。
>nonさん
>たいちうさん
こちらも説明不足ですみませんでした。
実際は、二点をランダムで出し、その二つの点(仮にA,Bとします)を直線で結び、
その後直角となるような三点目を出す
(先に出したAを通り、かつy軸に平行な線を出し、その線上の点からランダム決める)、というやり方をしておりました。
>Dixq (管理人)さん
atan2のやり方ですが、確かにそれでもできるかもしれませんが、少し面倒な感じがしますかね。
>たかぎさん
確かに三辺の長さを求めて角度を出すということもありかもしれません。
acos(θ);から求めたい角度が出せるとわかりましたので解決させていただきます。
みなさん解答ありがとうございました。
Re:角度の出し方について
Posted: 2008年12月29日(月) 13:24
by Dixq (管理人)
いやいや、全然メンドクサクなんてないですよ。
例えば(0,0),(1,0),(1,1)の3点からなる45°2つの直角三角形の角度を計算してみます。
#include <stdio.h>
#include <math.h>
#define PI 3.14159265
typedef struct{double x,y;}pt_t;
int main(){
pt_t pt[3]={{0,0},{1,0},{1,1}};
for(int i=0; i<3; i++){
double angle1=atan2(pt[(i+1)%3].y-pt.y,pt[(i+1)%3].x-pt.x);
double angle2=atan2(pt[(i+2)%3].y-pt.y,pt[(i+2)%3].x-pt.x);
printf("角度 = %.3f[rad] %.1f[°]\n",angle2-angle1,(angle2-angle1)/PI*180);
}
}
実行結果
角度 = 0.785[rad] 45.0[°]
角度 = 1.571[rad] 90.0[°]
角度 = 0.785[rad] 45.0[°]
こんな感じで角度を計算したら成す各を引き算で表示したらいいだけです。
%使ってるのでちょっとややこしく見えるかもしれませんが、要は
angle1 = 2つ目の点 と 1つ目の点との角度
angle2 = 3つ目の点 と 1つ目の点との角度
で、angle2 - angle1 で成す角が出るわけです。
atan2は最初の問題もすぐ解決出来るでしょう
2点をランダムで作り、その角度をatan2で調べ(角度angleとする)、そのangleを+PI/2したら直角ですから、
どちらかの点からangleの方向にランダムな長さで引っ張ってやればいいと思います。
void EnterPt(pt_t pt[3]){
/* ここでpt[0]とpt[1]に-10~10のランダムな数を入れる */
double angle = atan2(pt[1].y-pt[0].y,pt[1].x-pt[0].x) + PI/2;
double length = (double)rand()/RAND_MAX*20-10;
pt[2].x = pt[0].x+cos(angle)*length;
pt[2].y = pt[0].y+sin(angle)*length;
}
普段シューティングばかり作ってるのでいつも考えがシューティングになってしまいますが・・。
こんな感じでどうでしょう。ランダムな数を入れる部分は簡単なので、注釈にしておきました。
後は座標pt[0]とpt[1]から直角になるようにpt[2]を計算する処理です。
長さも-10~10のランダムになるようになっています。
角度、元の座標、距離が決まれば移動先の座標はcosとsinでわかりますよね。
pt[0]からその長さその角度で飛んでいけばいいのです。
Re:角度の出し方について
Posted: 2008年12月30日(火) 04:59
by lbfuvab
解決したみたいなのでnonさんの方法3を実装してみました。(私的に一番好みだったので)
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
#define sqr(a) ((a)*(a))
#define PI 3.14159265
typedef struct{
double x,y;
} Point_t;
void main(void){
Point_t pt[3],o; //oは円の中心
double r,angle,angle2; //rは半径、angleは3点目決定に使う角度、angle2は各角の角度算出用
int i;
srand(time(NULL));
for(i=0;i<2;i++){
pt.x=(rand()/(double)RAND_MAX)*50;
pt.y=(rand()/(double)RAND_MAX)*50;
}
o.x=(pt[0].x+pt[1].x)/2;
o.y=(pt[0].y+pt[1].y)/2;
r=sqrt(sqr(pt[0].x-o.x)+sqr(pt[0].y-o.y));
angle=(rand()/(double)RAND_MAX)*PI*2;
pt[2].x=o.x+(cos(angle)*r);
pt[2].y=o.y+(sin(angle)*r);
for(i=0;i<3;i++){
angle2=
atan2(pt[(i+1)%3].y-pt.y, pt[(i+1)%3].x-pt.x)-
atan2(pt[(i+2)%3].y-pt.y, pt[(i+2)%3].x-pt.x)
;
if(angle2<0.0)
angle2+=PI*2;
if(angle2>PI)
angle2=PI*2-angle2;
printf(
"%8.3f%8.3f%8.3f\n",
pt.x,
pt.y,
angle2*180/PI
);
}
}