NOGDUS

Articles, Tutorials, and other things. => General Game Programming => : Richard Marks March 16, 2010, 04:33:36 AM



: Rotation of a 2D Vector
: Richard Marks March 16, 2010, 04:33:36 AM
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
:
// 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
:
// 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.


: Re: Rotation of a 2D Vector
: oenone April 29, 2010, 05:03:25 AM
You could add some magical SSE assembly, to make it more efficient ;-)

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


Sorry, the copyright must be in the template.
Please notify this forum's administrator that this site is missing the copyright message for SMF so they can rectify the situation. Display of copyright is a legal requirement. For more information on this please visit the Simple Machines website.