Rotation of a 2D Vector

(1/1)

Richard Marks:
Rotation of a 2D Vector

Often in game programming you will want to rotate some 2D point around some other point.

Below is a "simple" implementation in C, and another in C++ just to show another way of thinking about the problem.

C version
Code:

// rotate.h
#ifndef ROTATE_H
#define ROTATE_H
typedef struct { float X, Y; } V2D, *V2DPtr;
extern V2DPtr Rotate2DVector(V2DPtr point, V2DPtr pivot, int angleInDegrees);
#endif

// rotate.c
#include "rotate.h"
#include "mathtables.h"
V2DPtr Rotate2DVector(V2DPtr point, V2DPtr pivot, int angleInDegrees)
{
float x, y, c, s;
c = CosMathTable(angleInDegrees);
s = SinMathTable(angleInDegrees);
point->X -= pivot->X;
point->Y -= pivot->Y;
x = point->X * c - point->Y * s;
y = point->X * s + point->Y * c;
point->X = x + pivot->X;
point->Y = y + pivot->Y;
return point;
}

// mathtables.h
#ifndef MATHTABLES_H
#define MATHTABLES_H
extern float _sinMathTable[];
extern float _cosMathTable[];
extern float SinMathTable(int angleInDegrees);
extern float CosMathTable(int angleInDegrees);
extern int InitializeMathTables();
#endif

// mathtables.c
#include <math.h>
#include "mathtables.h"
float _sinMathTable[360];
float _cosMathTable[360];
static int Clamp360(int* value)
{
if (*value < 0)
{
*value = 360 + (*value % 360);
}
if (*value > 359)
{
*value = *value % 360;
}
}
float SinMathTable(int angleInDegrees)
{
Clamp360(&angleInDegrees);
return _sinMathTable[angleInDegrees];
}
float CosMathTable(int angleInDegrees)
{
Clamp360(&angleInDegrees);
return _cosMathTable[angleInDegrees];
}
int InitializeMathTables()
{
int i;
float pi = 3.1415926536f;
for (i = 0; i < 360; i++)
{
float radians = (float)(i / (180.0f * pi));
_sinMathTable[i] = (float)sin(radians);
_cosMathTable[i] = (float)cos(radians);
}
}

// example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
extern int ExampleOfRotatingA2DVector();
#endif

// example.c
#include "rotate.h"
#include "example.h"

// This example assumes that there are a few library functions
// that are up to the user to implement

// int EnableGraphicsMode(); - sets up the graphics screen
// int DisableGraphicsMode(); - shuts down graphics screen
// int ClearScreen() - clears the graphics screen
// int DrawPixel(int x, int y) - draws a single white pixel on the graphics screen
// int KeyDown(int keyCode) - returns true when the specified key is held down

// the keyCode parameter is assumed to have a bunch of #defined values

int ExampleOfRotatingA2DVector()
{
int angleInDegrees;
V2D point = (V2D){ 100, 100 };
V2D pivot = (V2D){ 150, 100 };

angleInDegrees = 0;

EnableGraphicsMode();

ClearScreen();

while(!KeyDown(ESCAPE_KEY))
{
Rotate2DVector(&point, &pivot, angleInDegrees);

DrawPixel((int)point.X, (int)point.Y);

if (++angleInDegrees > 359)
{
ClearScreen();
angleInDegrees = 0;
}
}

DisableGraphicsMode();
return 0;
}

// main.c
#include "example.h"
#include "mathtables.h"
int main(int argc, char* argv[])
{
InitializeMathTables();
ExampleOfRotatingA2DVector();
return 0;
}


C++ version
Code:

// rotate.h
#ifndef ROTATE_H
#define ROTATE_H
class V2D
{
public:
V2D(float x = 0.0f, float y = 0.0f);
~V2D();
V2D(const V2D& other);
const V2D& operator=(const V2D& other);
V2D& Rotate(const V2D& pivot, int angleInDegrees);

float X, Y;
};
#endif

// rotate.cpp
#include "rotate.h"
#include "mathtables.h"

V2D::V2D(float x, float y) : X(x), Y(y) {}
V2D::~V2D(){}
V2D::V2D(const V2D& other){ X = other.X; Y = other.Y; }
const V2D& V2D::operator=(const V2D& other){X = other.X; Y = other.Y; return *this; }
V2D& V2D::Rotate(V2D& point, const V2D& pivot, int angleInDegrees)
{
float c = MathTables::Cos(angleInDegrees);
float s = MathTables::Sin(angleInDegrees);
X -= pivot.X;
Y -= pivot.Y;
float x = X * c - Y * s;
float y = X * s + Y * c;
X = x + pivot.X;
Y = y + pivot.Y;
return *this;
}

// mathtables.h
#ifndef MATHTABLES_H
#define MATHTABLES_H
class MathTables
{
public:
static float _sin[];
static float _cos[];
static float Sin(int angleInDegrees);
static float Cos(int angleInDegrees);
static void Initialize();
private:
MathTables();
};

#endif

// mathtables.cpp
#include <math.h>
#include "mathtables.h"

float MathTables::_sin[360];
float MathTables::_cos[360];
static int Clamp360(int& value)
{
if (value < 0)
{
value = 360 + (value % 360);
}
if (value > 359)
{
value = value % 360;
}
}
float MathTables::Sin(int angleInDegrees)
{
Clamp360(&angleInDegrees);
return MathTables::_sin[angleInDegrees];
}
float MathTables::Cos(int angleInDegrees)
{
Clamp360(&angleInDegrees);
return MathTables::_cos[angleInDegrees];
}
void MathTables::Initialize()
{
int i;
float pi = 3.1415926536f;
for (i = 0; i < 360; i++)
{
float radians = (float)(i / (180.0f * pi));
MathTables::_sin[i] = (float)sin(radians);
MathTables::_cos[i] = (float)cos(radians);
}
}

// example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
class ExampleOfRotatingA2DVector
{
public:
ExampleOfRotatingA2DVector();
};

#endif

// example.cpp
#include "rotate.h"
#include "example.h"

// This example assumes that there is a small library of classes
// that are up to the user to implement

// class GraphicsDevice; - handles all graphics operations

// void GraphicsDevice::Enable() - sets up the graphics screen
// void GraphicsDevice::Disable() - shuts down the graphics screen
// void GraphicsDevice::Clear() - clears the graphics screen
// void GraphicsDevice::DrawPixel(int x, int y) - draws a single white pixel on the graphics screen

// class InputDevice; - handles all keyboard input operations
// namespace KeyCodes { enum Keys; } - all available key codes
// bool InputDevice::KeyDown(KeyCodes::Keys keyCode) - returns true when the specified key is held down

ExampleOfRotatingA2DVector::ExampleOfRotatingA2DVector()
{
GraphicsDevice graphics;
InputDevice input;

V2D point(100, 100);
V2D pivot(150, 100);

int angleInDegrees = 0;

graphics.Enable();
graphics.Clear();

while(!input.KeyDown(KeyCodes::EscapeKey))
{
point.Rotate(pivot, angleInDegrees);

graphics.DrawPixel(point.X, point.Y);

if (++angleInDegrees > 359)
{
graphics.Clear();
angleInDegrees = 0;
}
}

graphics.Disable();
}

// main.cpp
#include "example.h"
#include "mathtables.h"
int main(int argc, char* argv[])
{
MathTables::Initialize();
ExampleOfRotatingA2DVector example;
return 0;
}


Take note that there are several files for each project.

I hope you learned something.

oenone:
You could add some magical SSE assembly, to make it more efficient ;-)

http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions#Example

Navigation

[0] Message Index