# Rotating between adjacent columns of a cylinder

This topic is 3983 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I have a 2d array of objects called crystals. They are organised in the 3d world into the shape of a cylinder (only the outside of the cylinder, excluding the top and bottom), into columns and rows and I need to be able to rotate the cylinder between the columns.
if( m_cylinder->m_isRotating ){
float rotate_amount = 0.0f;

if( m_cylinder->m_rotateDirection == Cylinder::LEFT )
rotate_amount = (evt.timeSinceLastFrame * m_cylinder->m_rotateSpeed);
else if( m_cylinder->m_rotateDirection == Cylinder::RIGHT )
// '-' because we're rotating backwards (anti-clockwise)
rotate_amount = -(evt.timeSinceLastFrame * m_cylinder->m_rotateSpeed);
// if there is no rotation
else if( m_cylinder->m_rotateDirection == Cylinder::NONE )
return FrameListener::frameStarted(evt);

m_cylinder->m_currentSegmentRot += rotate_amount;

// add the rotation onto the current rotation of the cylinder
m_cylinder->rotate(Ogre::Vector3(0.0f, 1.0f, 0.0f), Ogre::Degree(rotate_amount));

// find if we have completed another segment rotation (rotation of the cylinder between two adjacent columns)
float seg_mod = fmod(m_cylinder->m_currentSegmentRot, m_cylinder->m_segmentSize);
// if the second param for 'fmod' == 0.0f, 'fmod' returns NaN
if( _isnan(seg_mod) != 0 )
throw new OGRE_EXCEPTION("Cylinder segment size is 0", "Floating point NaN error");

// If the rotation is done (if we have reached another column [end of a segment]).
// The second part of the condition is to check if the result of the mod is within a certain epsilon
// value due to the inexact nature of computer floating-point math.
if( seg_mod >= -0.1f && seg_mod <= 0.1f ){
// we have finished rotating through a segment, set the rotation exactly
if( m_cylinder->m_rotateDirection == Cylinder::LEFT ){
m_cylinder->m_currentColumn--;
// if we need to wrap around to the last column (rotation from first column around to last)
if( m_cylinder->m_currentColumn < 0 )
m_cylinder->m_currentColumn = m_cylinder->getNumColumns()-1;
}

else if( m_cylinder->m_rotateDirection == Cylinder::RIGHT ){
m_cylinder->m_currentColumn++;
// if we need to wrap around to the first column (rotation from last column around to first)
if( m_cylinder->m_currentColumn > m_cylinder->getNumColumns() )
m_cylinder->m_currentColumn = 0;
}

// set the final rotation, so the correct column is clearly centered
m_cylinder->m_finalRotation = m_cylinder->m_currentColumn * m_cylinder->m_segmentSize;

// reset the rotation of the cylinder and set it to the result after the rotation
//		m_cylinder->m_cylinderSceneNode->resetOrientation();
//		m_cylinder->rotate(Ogre::Vector3(0.0f, 1.0f, 0.0f), Ogre::Degree(m_cylinder->m_finalRotation));

// no more rotation
m_cylinder->m_isRotating = false;
m_cylinder->m_rotateDirection = Cylinder::NONE;
m_cylinder->m_currentSegmentRot = 0.0f;
}

}// if the cylinder is rotating


So, the cylinder is rotated according to a speed 'm_rotateSpeed', which is the degrees in seconds that the cylinder spins. 'm_finalRotation' is the final rotation of the cylinder after it has finished rotating to another column. The degrees between each column is 'm_segmentSize' (the columns are equally spaced). 'm_currentSegmentRot' is the amount that has been rotated in this current segment (from the previous column to the next). The 'rotate' function simply adds on the rotation to the current rotation of the scene node, it doesn't set the absolute rotation. With 2 columns and 2 rows (where the segment size is 180 degrees) it seems to generally work fine. But I increased that to 4 columns and 2 rows and it doesn't rotate properly, sometimes skipping the column it should be stopping at, and sometimes skipping even more. Could this be a problem with using mod and floating-point numbers? Is there a better method that someone can recommend?

##### Share on other sites
I'd say the problem is fmod and the epsilon check, since you only stop rotation if you pass the epsilon check.

Let's say float m_cylinder->m_segmentSize = 90.0 and m_cylinder->m_currentSegmentRot = 90.11

Now seg_mod = fmod(m_cylinder->m_currentSegmentRot, m_cylinder->m_segmentSize) = 0.11 //assuming no precision issues.

Your check is seg_mod >= -0.1 (NO) && seg_mod <= 0.1 (NO, since seg_mod = 0.11). Although you reached the column the check fails and thus the rotation isn't stopped.

You could get rest = m_cylinder->m_segmentSize - m_cylinder->m_currentSegmentRot instead and set rotate_amount = min(rotate_amount, rest). Then you should be in epsilon range.

• 18
• 11
• 17
• 9
• 51
• ### Forum Statistics

• Total Topics
631397
• Total Posts
2999793
×