绕圆轴的最短距离;使用学位

Shortest distance around a circular axis; using degrees

前提

一个实体(单个 dot/pixel)的简单 SDL 程序,它绕着(一个圆圈)旋转,然后朝那个方向移动。

问题

我无法正确计算从一个度数到另一个度数的最短距离;特别是当这些度数超过 360/0 标记的界限时。

目标

计算从 'origin' 度到 'destination' 的最短距离是顺时针还是逆时针,同时考虑 360 度标记的横向。

节目展示

尝试实现这些概念

代码

主要

void draw ( )
{
    /* - - - - - - - - - - - - - - - - - Init - - - - - - - - - - - - - - - - - */
    
    SDL_Event sdl_event;

    WALKER walker;
    
    walker = { POINT { WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 } };    // Entity in center

    /* - - - - - - - - - - - - - - - - - Init - - - - - - - - - - - - - - - - - */
    
    int degree = 0;
    
    walker.rotation.set ( degree, generate_random ( 0, 360 ) );
    
    while ( run_loop )     // Display Animation
    {
        set_render_draw_colors ( );
        
        SDL_RenderDrawPoint ( renderer, walker.origin.x, walker.origin.y );     // Draw: entity dot

        POINT point = walker.rotate ( degree );     // Create: pivot point & rotate per degree

        SDL_RenderDrawLine ( renderer, walker.origin.x, walker.origin.y, point.x, point.y );     // Draw: sightline with acquired orientation

        SDL_RenderPresent ( renderer );

        degree++;

        degree = ( degree > 359 ) ? 0 : degree;

        if ( degree == walker.rotation.destination )
            walker.rotation.set( walker.rotation.destination, generate_random ( 0, 360 ) );
        
        while ( SDL_PollEvent ( &sdl_event )  )
        {
            if ( sdl_event.type == SDL_QUIT )
                run_loop = false;
            else
                break;
        }
    }
}

沃克

struct WALKER
{
    POINT origin     = { 0, 0 };
    POINT point      = { 0, 0 };

    ROTATION rotation;
    
    int point_length = 35;
    
    time_t time_seed;
    
    // Constructors ......................................................... //
    
    WALKER ( POINT origin, POINT point )
    {
        this->origin = origin;
        this->point  = point;
    }
    
    // Constructors (Generic) ... //
    
    WALKER ( )  { };

    ~WALKER ( ) { };

    // Functions ............................................................ //

    double convertToRadian ( int degree )
    {
        return ( degree * PI / 180 );
    }

    int convertToDegree ( float radian )
    {
        return ( radian * 180 ) / PI;
    }
    
    POINT rotate ( int degree )
    {
        POINT point    = { this->origin.x + this->point_length, this->origin.y };
        
        double radians = convertToRadian ( degree );
        
        double sine    = sin ( radians );
        double cosine  = cos ( radians );

        point.x       -= this->origin.x;     // translate point back to origin
        point.y       -= this->origin.y;

        double x_new  = point.x * cosine - point.y * sine;     // rotate point
        double y_new  = point.x * sine   - point.y * cosine;
        
        point.x       = x_new + this->origin.x;     // translate point back
        point.y       = y_new + this->origin.y;
        
        return point;
    }
};

如果不是 0/360 交叉,这只是获得两个角度之间的差异的问题,该差异的符号会告诉您是否顺时针。

最重要的是,如果您得到最短路径穿过边界的两个角度之间的差异,您最终会得到绝对值大于 180 的差异(因为距离最终反过来绕一圈。

因此,您需要做的就是获取两个角度之间的差异,如果差异太大,则“修复”它。

int angle_diff(int from, int to) {
  // Use a modulo to handle angles that go around the circle multiple times.
  int result = to % 360 - from % 360;

  if(result > 180) {
      result -= 360;
  }

  if(result <= -180) {
      result += 360;
  }
  return result;
}