View Single Post
Re: POD-bot back into shape.
Old
  (#335)
Pierre-Marie Baty
Roi de France
 
Pierre-Marie Baty's Avatar
 
Status: Offline
Posts: 5,049
Join Date: Nov 2003
Location: 46°43'60N 0°43'0W 0.187A
Default Re: POD-bot back into shape. - 02-04-2004

@Whistler:

Nope ! it's NOT okay, because even if your resulting angles are in bounds, they are NOT ANYMORE modulo 360 versions of the original one !


it's as if you were doing
Code:
if ((angle < -180) || (angle >= 180))
   angle = RANDOM_FLOAT (-180, 180);
... with a bit of exxageration, I concede

Nevertheless your code is wrong, and I can prove it.
Instead of running your test program, rather run this one:
Code:
void main (void)
{
   float random_angle;
   float result_angle;
   int count = 0;
 
   while (1)
   {
	  random_angle = RANDOM_FLOAT (-100000000, 100000000);
 
	  result_angle = AngleNormalize (random_angle);
	  if ((result_angle < -180) || (result_angle >= 180))
	  {
		  printf ("ERROR! in=%f out=%f count=%d\n", random_angle, result_angle, count);
		  getchar ();
	  }
 
	  result_angle = AngleNormalize360 (random_angle);
	  if ((result_angle < 0) || (result_angle >= 360))
	  {
		  printf ("ERROR! in=%f out=%f count=%d\n", random_angle, result_angle, count);
		  getchar ();
	  }
 
	  count++;
   }
}
You will see that your code fails for large values of angle.

And NOT only this, but if you add a
Code:
	 printf ("in=%f out=%f\n", random_angle, result_angle);
	 getchar ();
for each angle that is tested, and compare the input and the output, you'll notice that the output is NOT a modulo 360 representative of the input. You have an error that goes increasing with larger values.

Believe me, I've tested it all thoroughly, thanks to you pointing me that bug, and I've found the right code. It goes like this:
Code:
float WrapAngle (float angle)
{
   // this function adds or substracts 360 enough times needed to the angle_to_wrap angle in
   // order to set it into the range -180/+180 and returns the resulting angle. Letting the
   // engine have a hand on angles that are outside these bounds may cause the game to freeze
   // by screwing up the engine math code.
 
   // check for wraparound of angle
   if (angle >= 180)
	  angle -= 360 * abs (((int) angle + 180) / 360);
   if (angle < -180)
	  angle += 360 * abs (((int) angle - 180) / 360);
 
   // needs a 2nd pass to check for floating part truncation (rounded 180)
   if (angle == 180.0)
	  angle = -180;
 
   return (angle);
}
 
float WrapAngle360 (float angle)
{
   // this function adds or substracts 360 enough times needed to the angle_to_wrap angle in
   // order to set it into the range +0/+360 and returns the resulting angle Letting the
   // engine have a hand on angles that are outside these bounds may cause the game to freeze
   // by screwing up the engine math code.
 
   // check for wraparound of angle
   if (angle >= 360)
	  angle -= 360 * abs ((int) angle / 360);
   if (angle < 0)
	  angle += 360 * abs (((int) angle - 360) / 360);
 
   // needs a 2nd pass to check for floating part truncation (rounded 180)
   if (angle == 360.0)
	  angle = 0;
 
   return (angle);
}
And if you think about it it's perfectly logical. The function asks itself, how many times can I add OR substract 360 to the current angle to have it in the bounds ? Then, taking the absolute of this value, it either adds (if value was initially inferior) OR substract (if value was initially superior) - hence the abs(), as many times 360 as needed and the resulting angle is GUARANTEED to be in bounds, and a modulo of 360.

The only check left to do is the floating point truncation (precision error) that would make the final angle land accurately on a rounded 180 (which would be just above the limit).



RACC home - Bots-United: beer, babies & bots (especially the latter)
"Learn to think by yourself, else others will do it for you."

Last edited by Pierre-Marie Baty; 02-04-2004 at 16:57..