LoginSignup
3
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-06-12

(追記 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 
3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4