Home > Blockchain >  Shortest distance around a circular axis; using degrees
Shortest distance around a circular axis; using degrees

Time:06-03

Premise

A simple SDL program of an entity (single dot/pixel) that rotates around (in a circle), then moves in that direction.

Problem

I'm unable to properly calculate the shortest distance from one degree to another; especially when those degrees cross the bounds of the 360/0 mark.

350 - 10 : Clockwise

Goal

Calculate whether the shortest distance from an 'origin' degree to a 'destination' is Clockwise, or Counter Clockwise, while factoring in the transversal over the 360 degree mark.

Program Display

SDL Program

Attempting to fulfill these concepts

Circle Directions 0 - 45 : Clockwise 313 - 225 : Counter Clockwise 350 - 10 : Clockwise

Code

Main

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;
        }
    }
}

Walker

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;
    }
};

CodePudding user response:

If it wasn't for the 0/360 cross, it would just be a matter of getting the difference between the two angles, the sign of that difference would tell you if it's clockwise or not.

On, top of that, if you get the difference between two angles for which the shortest path DOES cross the boundary, you'd end up with a difference with an absolute value greater than 180 (since the distance ends up going around the circle the other way.

So all you need to do is get the difference between the two angles, and "fix" it if it's too large.

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;
}
  • Related