(追記 2017/03/29)
以下の実装は「反時計周り」での角度の判断です
http://qiita.com/7of9/items/dd241297a7231485767d
の実装をする過程で必要となる以下の処理
ベクトルがある角度範囲に入っているかどうかの判定
方法
V: 判定されるベクトル
min: 角度範囲の最小
max: 角度範囲の最大
clockwiseの角度(min, V) <= clockwiseの角度(min, max)の場合は範囲に入っていると判定する
C実装 v0.1
http://ideone.com/UTmyiu
(下のv0.2を実装時にforkするつもりが書き換えてしまった。。。)
ベース http://qiita.com/7of9/items/dad7e8fdcda777a9fdd0
の実装に以下の変更をした。
- get_angle_clockwise()にてinnerが0度の場合0を返すようにした
- bool isInside()追加
- bool isInside_wrapper()追加
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <float.h>
//-----------------------------------------------------
// { to calculate angles between 2 vectors
float get_length(float vs[2])
{
return sqrt( pow(vs[0],2) + pow(vs[1],2) );
}
float get_dot_product(float vs[2], float ws[2])
{
return vs[0]*ws[0] + vs[1]*ws[1];
}
float get_determinant(float vs[2], float ws[2])
{
return vs[0]*ws[1] - vs[1]*ws[0];
}
float get_inner_product(float vs[2], float ws[2])
{
float cosx = get_dot_product(vs,ws);
cosx = cosx / (get_length(vs) * get_length(ws));
float rad = acos(cosx);
return rad * 180.0 / acos(-1.0);
}
float get_angle_clockwise(float As[2], float Bs[2])
{
float inner = get_inner_product(As, Bs);
float det = get_determinant(As, Bs);
if (det < 0.0) {
return inner;
} else {
if (fabs(inner) < FLT_EPSILON) { // 0.0
return 0.0;
}
return 360.0 - inner;
}
}
float get_angle_clockwise_wrapper(float x1, float x2, float y1, float y2)
{
float Xs[2];
float Ys[2];
Xs[0] = x1;
Xs[1] = x2;
Ys[0] = y1;
Ys[1] = y2;
return get_angle_clockwise(Xs, Ys);
}
// } to calculate angles between 2 vectors
//-----------------------------------------------------
bool isInside(float avec[2], float minvec[2], float maxvec[2])
{
float aAndMin = get_angle_clockwise(minvec, avec);
float minAndMax = get_angle_clockwise(minvec, maxvec);
#if 0 // debug
printf("%f %f\n", aAndMin, minAndMax);
#endif
return (aAndMin <= minAndMax);
}
bool isInside_wrapper(float avec1, float avec2, float minvec1, float minvec2,
float maxvec1, float maxvec2)
{
float as[2];
float mins[2];
float maxs[2];
as[0] = avec1;
as[1] = avec2;
mins[0] = minvec1;
mins[1] = minvec2;
maxs[0] = maxvec1;
maxs[1] = maxvec2;
return isInside(as, mins, maxs);
}
int main(void) {
printf("%d \n", isInside_wrapper(1,1, 0,1, 1,0)); // inside
printf("%d \n", isInside_wrapper(0,1, 0,1, 1,0)); // inside
printf("%d \n", isInside_wrapper(1,0, 0,1, 1,0)); // inside
printf("%d \n", isInside_wrapper(-1,-1, 0,1, 1,0)); // outside
float ax, ay;
float deg2rad = acos(-1.0) / 180.0;
ax = 1.0 * cos(105 * deg2rad);
ay = 1.0 * sin(105 * deg2rad);
printf("%d \n", isInside_wrapper(ax,ay, 0,1, 1,0)); // outside
ax = 1.0 * cos(359 * deg2rad);
ay = 1.0 * sin(359 * deg2rad);
printf("%d \n", isInside_wrapper(ax,ay, 0,1, 1,0)); // outside
ax = 1.0 * cos(365 * deg2rad);
ay = 1.0 * sin(365 * deg2rad);
printf("%d \n", isInside_wrapper(ax,ay, 0,1, 1,0)); // inside
return 0;
}
結果
Success time: 0 memory: 2156 signal:0
1
1
1
0
0
0
1
意図通り
C実装 v0.2 > atan2使用
http://qiita.com/7of9/items/dad7e8fdcda777a9fdd0#comment-13daf3bd7163fb0e0e08
にてatan2()を使う改善実装を教えていただいた。
それに基づいて変更したのが以下。
引数などのnamingは良くない。
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <float.h>
//-----------------------------------------------------
// { to calculate angles between 2 vectors
float get_angle_clockwise_atan2(float Avec[2], float Bvec[2])
{
float angle_rad = atan2(Avec[1], Avec[0]) - atan2(Bvec[1], Bvec[0]);
float angle_deg = angle_rad * 180.0 / acos(-1.0);
if (angle_deg >= 0.0) {
return angle_deg;
} else {
return angle_deg + 360.0;
}
}
float get_angle_clockwise_wrapper(float x1, float y1, float x2, float y2)
{
float Avec[2];
float Bvec[2];
Avec[0] = x1;
Avec[1] = y1;
Bvec[0] = x2;
Bvec[1] = y2;
return get_angle_clockwise_atan2(Avec, Bvec);
}
// } to calculate angles between 2 vectors
//-----------------------------------------------------
bool isInside(float avec[2], float minvec[2], float maxvec[2])
{
float aAndMin = get_angle_clockwise_atan2(minvec, avec);
float minAndMax = get_angle_clockwise_atan2(minvec, maxvec);
#if 0 // debug
printf("%f %f\n", aAndMin, minAndMax);
#endif
return (aAndMin <= minAndMax);
}
bool isInside_wrapper(float a_x, float a_y, float min_x, float min_y,
float max_x, float max_y)
{
float avec[2];
float minvec[2];
float maxvec[2];
avec[0] = a_x;
avec[1] = a_y;
minvec[0] = min_x;
minvec[1] = min_y;
maxvec[0] = max_x;
maxvec[1] = max_y;
return isInside(avec, minvec, maxvec);
}
int main(void) {
printf("%d \n", isInside_wrapper(1,1, 0,1, 1,0)); // inside
printf("%d \n", isInside_wrapper(0,1, 0,1, 1,0)); // inside
printf("%d \n", isInside_wrapper(1,0, 0,1, 1,0)); // inside
printf("%d \n", isInside_wrapper(-1,-1, 0,1, 1,0)); // outside
float ax, ay;
float deg2rad = acos(-1.0) / 180.0;
ax = 1.0 * cos(105 * deg2rad);
ay = 1.0 * sin(105 * deg2rad);
printf("%d \n", isInside_wrapper(ax,ay, 0,1, 1,0)); // outside
ax = 1.0 * cos(359 * deg2rad);
ay = 1.0 * sin(359 * deg2rad);
printf("%d \n", isInside_wrapper(ax,ay, 0,1, 1,0)); // outside
ax = 1.0 * cos(365 * deg2rad);
ay = 1.0 * sin(365 * deg2rad);
printf("%d \n", isInside_wrapper(ax,ay, 0,1, 1,0)); // inside
return 0;
}
結果
Success time: 0 memory: 2156 signal:0
1
1
1
0
0
0
1