Error When Applying Rotation, Polygon Shrink Over Time?

Started by
8 comments, last by szecs 11 years, 10 months ago
I'm making my own polygon class for a game I'm making. However, whenever I try to apply rotation to 'em, it shrinks the entire polygon. After around 1000 rotations the shrinking becomes apparent, and visually you can notice them shrinking rapidly. Is there any way to minimize this? I'm assuming it's some precision errors? Here's my code below, I'm hoping it's enough to see my problem.

(X and Y are macros btw)

void Poly2D::rotateBy(const float angle){

const float sinA = sinf(angle), cosA = cosf(angle);

for(ushort i = 0; i < vertLength; i++){

float &x = vertices[X], &y = vertices[Y];

//move to origin for rotating
x -= center -> x;
y -= center -> y;

x = (x * cosA) - (y * sinA);
y = (x * sinA) + (y * cosA);

//move back
x += center -> x;
y += center -> y;

std::cout << x << ", " << y << std::endl;

}
}
Advertisement
This is common in graphics due to compounding rounding issues. I would suggest keeping the original polygon co-ordinates untouched, and do rendering based on a copy which is the original polygon rotated by the accumulated rotations. Also consider letting the GPU do the work, as it's pretty good at applying a transformation to a sequence of primitives.

This is common in graphics due to compounding rounding issues. I would suggest keeping the original polygon co-ordinates untouched, and do rendering based on a copy which is the original polygon rotated by the accumulated rotations. Also consider letting the GPU do the work, as it's pretty good at applying a transformation to a sequence of primitives.


Thanks, I figured that was the issue, I'll resolve it quite easily now. Also I'm not very good at things like GLSL, lol.
Strange... I took your advice, and I created another array to hold a copy of the vertex data to apply the rotations to... now it's wanting to rotate on like every axis?

void Poly2D::rotateBy(const float angle){

//accumulated rotation... what's the efficient way to clamp this?
rotation += angle;

const float sinA = sinf(rotation), cosA = cosf(rotation);

for(ushort i = 0; i < vertLength; i++){

//this is just a copy of the vertex data
rotVertices[X] = vertices[X];
rotVertices[Y] = vertices[Y];

float &x = rotVertices[X], &y = rotVertices[Y];

x -= center -> x;
y -= center -> y;

x = (x * cosA) - (y * sinA);
y = (x * sinA) + (y * cosA);

x += center -> x;
y += center -> y;

}
}
//accumulated rotation... what's the efficient way to clamp this?
rotation += angle;[/quote]
You don't. Unless your polygon is rotating at an insane rate you will not run out of accuracy any time soon. Don't worry about it (if you really want to, and with small increments (i.e. less than a full rotation) you can simply decrement it by 2pi if it gets greater than 2pi, sparing the expensive general-purpose real remainder operation)

What do you mean by rotating on every axis? There's only one possible rotation axis in your code which is the virtual depth axis through the object's center. Do you mean the vertices start rotating with incorrect centers or something? Could you elaborate and possibly post all of the rotation-related code, my guess is you forgot to change vertices to rotVertices somewhere.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

It's... really hard to explain, it's rotating very strangely. It's supposed to rotate only on the Z axis, and was doing just that a while ago...

header:

#ifndef POLY2D_H
#define POLY2D_H

#include "Global.h"
#include "Dim2D.h"

class Poly2D{

Dim2D<float>* center;
float rotation;

short (*vertices)[2];
float (*rotVertices)[2]; //rotated vertices

const ushort vertLength;

void setCenter();

public:

Poly2D(Dim2D<short>* list[], const ushort len);
~Poly2D();

void translate(Dim2D<short>*& amount);
void rotateBy(const float angle);

void draw();

};

#endif


definition file:

#include "Poly2D.h"

Poly2D::Poly2D(Dim2D<short>* list[], const ushort len):center(new Dim2D<float>()), vertices(new short[len][2]),
rotVertices(new float[len][2]), vertLength(len), rotation(0.0f){

for(ushort i = 0; i < len; i++){

vertices[X] = list -> x;
vertices[Y] = list -> y;
rotVertices[X] = (float)list -> x;
rotVertices[Y] = (float)list -> y;

}

setCenter();

}

Poly2D::~Poly2D(){

}

void Poly2D::setCenter(){

float cx = 0.0f, cy = 0.0f;

for(ushort i = 0; i < vertLength; i++){
cx += rotVertices[X];
cy += rotVertices[Y];
}

cx = cx / (float)vertLength;
cy = cy / (float)vertLength;

center -> x = cx;
center -> y = cy;

}

void Poly2D::translate(Dim2D<short>*& amount){
//todo: update this
for(ushort i = 0; i < vertLength; i++){
vertices[X] += (float)amount -> x;
vertices[Y] += (float)amount -> y;
}

setCenter();

}

void Poly2D::rotateBy(const float angle){

rotation += angle;

const float sinA = sinf(rotation), cosA = cosf(rotation);

for(ushort i = 0; i < vertLength; i++){

//reset vertices
rotVertices[X] = vertices[X];
rotVertices[Y] = vertices[Y];

float &x = rotVertices[X], &y = rotVertices[Y];

x -= center -> x;
y -= center -> y;

x = (x * cosA) - (y * sinA);
y = (x * sinA) + (y * cosA);

x += center -> x;
y += center -> y;

}
}

void Poly2D::draw(){

glEnableClientState(GL_VERTEX_ARRAY);

glLoadIdentity();
glPushMatrix();

glVertexPointer(2, GL_FLOAT, 0, rotVertices);
glDrawArrays(GL_POLYGON, 0, vertLength);

glPopMatrix();

glDisableClientState(GL_VERTEX_ARRAY);

}
Guys, please help... I'm really desperate to get this done... please, can anyone explain this unfixable, sudden problem? It ONLY does this when I reset the rotated polygon and try to rotate it from there...
It's a typical mistake, sorry to say that.

x = (x * cosA) - (y * sinA);
y = (x * sinA) + (y * cosA);

These equations work on the original coordinates. But in the first equation, you overwrite the x, and you use the overwritten x in the second equation. you have to use temporary variables.

This was the mistake all along, but the angle was small first, so the mistake only resulted in shrinking.


Something like:

x -= center -> x;
y -= center -> y;

float x_temp = (x * cosA) - (y * sinA);
float y_temp = (x * sinA) + (y * cosA);

//move back
x = x_temp + center -> x;
y = y_temp + center -> y;


There are precision errors, but these shouldn't be apparent under so few rotations. I use this kind of accumulated rotation in a few places, and I never needed to use correction on the vertices.
I love you.

That fixed everything, and I can finally more forward with the program.

THANK.YOU.

In case anyone was wondering, this is what I was trying to describe:

I'm glad.
Now you can express your love by rating up my post wink.png

This topic is closed to new replies.

Advertisement