C > 幾何学 > ベクトルがある角度範囲に入っているか判定 > 反時計回りでの判断

(追記 2017/03/29)

**<font color=red>以下の実装は「反時計周り」での角度の判断です</font>**

<hr>

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()追加

```c
#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;
}
```

```txt:結果
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()を使う改善実装を教えていただいた。

それに基づいて変更したのが以下。

http://ideone.com/UTmyiu

引数などのnamingは良くない。

```c
#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;
}
```

```txt:結果
Success	time: 0 memory: 2156 signal:0
1 
1 
1 
0 
0 
0 
1 
```