• Advertisement
Sign in to follow this  

Rotating between adjacent columns of a cylinder

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

If you intended to correct an error in the post then please contact us.

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 ){
			// 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 ){
			// 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 this post

Link to post
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.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement