
C言語では、数学的な計算をするための関数を math.h をインクルードすることで使うことができるようになります。
今回位は簡単な三角関数である sin、cos について確認していきます。 sin や cos は 2D でも 3D でも頻繁に使われ、物理的な挙動を定義したり、計算するために使います。
さらに三角関数と一次変換という計算方法を組み合わせることで、 画像データの移動、拡大縮小、回転などが自由自在に処理できるようになって、とても便利です。
三角関数を扱うとき、弧度法とラジアンの関係を把握しておく必要があります。
下の用な関係式です。
C言語の三角関数では、ラジアンの値を使います。
例えば cos (60度)を求めたい場合は、下のような式になります。
#include <stdio.h>
#include <math.h>
int main() {
double degree = 60; // 60度
double radian = (degree * 3.1415) / 180.0;
double val = cos(radian);
printf("cos(%2.0lf度) = cos(%1.2lf ラジアン) = %2.3lf\n", degree, radian, val);
}
実行すると、下のような結果になります。
cos(60度) = cos(1.05 ラジアン) = 0.500
三角関数でよく利用する円周率 π は math.h の中で 定数 M_PI として定義されています。
Microsoft の開発環境(Microsoft Visual Studio Community など)を使って開発する場合では、
M_PI などの数学関係の定数を使うために、
#define _USE_MATH_DEFINES
を math.h をインクルードする前に
書いてあげる必要があります。
(※他の環境ではこの行は無視されますので、とりあえず書いておけば問題なく動くかと思います)
#define M_PI 3.14159265358979323846264338327950288
ご参考までに幾つかの計算結果を確認してみます。
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
int main () {
printf(" 0度 = %lf\n", cos( 0.0 * M_PI / 180.0 ));
printf("60度 = %lf\n", cos( 60.0 * M_PI / 180.0));
printf("90度 = %lf\n", cos( 90.0 * M_PI / 180.0));
printf("150度 = %lf\n", cos( 150.0 * M_PI / 180.0));
printf("180度 = %lf\n", cos( 180.0 * M_PI / 180.0));
printf("270度 = %lf\n", cos( 270.0* M_PI / 180.0));
printf("390度 = %lf\n", cos( 390.0* M_PI / 180.0));
printf("-60度 = %lf\n", cos( -60.0* M_PI / 180.0));
}
実行した結果は下のようになります。 マイナスの値や、弧度法ベースで 360度を超えている値でも問題なく扱えます。
0度 = 1.000000
60度 = 0.500000
90度 = 0.000000
150度 = -0.866025
180度 = -1.000000
270度 = -0.000000
390度 = 0.866025
-60度 = 0.500000
cos 関数を使って、簡単な正弦波を描画してみます。
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
#define HEIGHT 10
int main () {
for ( int y = 0; y < HEIGHT; y++) {
for ( int x = 0 ; x < 80 ; x++ ) {
char c = '#';
if ( cos((double)x * M_PI * 10 / 180.0 ) * HEIGHT/2.0 + HEIGHT/2.0 < y ) {
c = '-';
}
printf("%c", c);
}
printf("\n");
}
}
実行すると、cos の角度 0 度~800度(つまり、2回転 + 80度ぶん)の cos 関数の 結果を描画します。
################################################################################
###############-------#############################-------######################
#############-----------#########################-----------####################
############-------------#######################-------------###################
###########---------------#####################---------------##################
##########------------------##################------------------################
########---------------------###############---------------------###############
#######-----------------------#############-----------------------#############-
######-------------------------###########-------------------------###########--
####-----------------------------#######-----------------------------#######----
cos 関数を sin 関数に置き換えて実行すると、下のような結果となります。
################################################################################
########################-------#############################-------#############
######################-----------#########################-----------###########
#####################-------------#######################-------------##########
####################---------------#####################---------------#########
###################------------------##################------------------#######
--###############---------------------###############---------------------######
---#############-----------------------#############-----------------------#####
----###########-------------------------###########-------------------------####
------#######-----------------------------#######-----------------------------##
視覚的に結果が見えると面白いですね!
math.h には sin 関数、cos 関数だけでなく、平方根を求めるための sqrt関数、 小数点以下を切り捨てる floor 関数、四捨五入するための round 関数などがそろっています。
三角関数つながりで、sqrt 関数を使って円を描画してみます。
#include <stdio.h>
#include <math.h>
#define HEIGHT 10
int isCircleInside( double x, double y) {
double cx = 5.0; // 円の中心点 x成分
double cy = 4.0; // 円の中心点 y成分
double r = 3.0; // 円の半径
if ( r < sqrt((x-cx)*(x-cx) + (y-cy)*(y-cy)) ) {
return 0;
}
return 1;
}
int main () {
for ( int y = 0; y < HEIGHT; y++) {
for ( int x = 0 ; x < 40 ; x++ ) {
char c = '.';
if ( isCircleInside( x, y ) ) {
c = '#'; // 円の内側
}
printf("%c", c);
}
printf("\n");
}
}
これを実行すると下のような結果となります。
........................................
.....#..................................
...#####................................
...#####................................
..#######...............................
...#####................................
...#####................................
.....#..................................
........................................
........................................
なんだかちょっと縦長につぶれてしまっているように見えますが、 コンソール上にテキストで円が描画されました。
コードの中の isCircleInside 関数で、 指定の位置(x,y) が円の内側か、外側かを判別し、 内側なら 1 、外側なら 0 を返すようにプログラムしています。
ある点(x, y) が円の外側かを判別するためには、下の図のように、 円の中心点(cx, cy)と調べたい点(x,y)との距離と、円の半径 r を比較することで判別できます。
ある点(x, y) が円の外側かを判別するため式は下の通りです。
if ( r < sqrt((x-cx)*(x-cx) + (y-cy)*(y-cy)) ) {
sqrt 関数は、平方根を計算するための関数です。
ここでは、点(cx, cy) と点(x,y)の距離を計算するために、三平方の定理を使っています。
2点間の距離は sqrt((x-cx)*(x-cx) + (y-cy)*(y-cy))
で計算できますので、
という判定ができます。
この判定方法は、2D や 3D 空間での円と円、円と点の衝突判定にも応用できます。
コメント、ありがとうございます。
ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。
Twitter:@NodachiSoft_jpお名前:以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください
お名前: