Problems detecting 180 degree rotation
I have an algorithm that calculates the amount an object has rotated.
It calculates between -180 and 180 degrees to deal with both clockwise and anticlockwise. However when the rotation is just about 180 degrees, due to rounding it ends up detecting a mix of -180 and 180 degree rotations when comparing different parts of the shape, depending on how rounding occurs this throws the actual rotation out by quite a bit. The 开发者_运维技巧answer to this would be to use the absolute value however this ends up breaks rotation direction.
Here is the code
double newAngle = objOneAngle - objTwoAngle;
if (newAngle< -180)
newAngle += 360;
else if (newAngle > 180)
newAngle -= 360;
Any thoughts on the best way to enhance the above code to deal with 180 degree rotations?
EDIT: The most obvious method that comes to mind is to split up the positive and negative values, and then choose the best set, based on size or some other metric, but there must be a simpler more elegant solution?
Measuring some rotations as a little more than 180 degrees and some as a little less shouldn't be a problem in itself. I suspect the real problem lies in how you're combining these rotations from "different parts of the shape". For instance, if you are averaging the rotations then this will give absolutely crazy results. Here are three approaches you can take.
(1) Compute a "typical rotation" figure in some way that isn't bothered by the discrepancy: for instance, just pick one of the rotations at random. (If it's possible for a few of them to be badly wrong, there are more robust things you can do.) Now adjust all your rotations so that the "typical" one goes to zero:
for (i=0; i<nSamples; ++i) {
rotations[i] -= typicalRotation;
if (rotations[i]<-180) rotations[i] += 360;
else if (rotations[i]>180) rotations[i] -= 360;
}
Now average these (or do whatever sort of thing you're doing with them), and then correct by doing the same operation in reverse.
(2) As for (1), but either use the rotations as they stand or adjust them all by 180deg before and after processing. Choose which to do by, for instance, counting rotations between -90 and +90 and seeing whether they're more or less than half of all your rotations.
(3) Instead of averaging rotation angles, for each angle compute (cos theta, sin theta) and average those. Then use atan2
to convert the average back into an angle. (The idea is that angles are "really" points on a circle, so it's better to work with these points rather than with the angles. When you do this, the ambiguity between -180 and +180 degrees just goes away.)
If what you're doing really is averaging, my favourite of these is 3. Your mileage may vary.
The usual way to deal with rounding errors in floating point comparisons is to add a small tolerance:
double newAngle = objOneAngle - objTwoAngle;
if (newAngle < -180.000001)
newAngle += 360;
else if (newAngle > 180.000001)
newAngle -= 360;
This way values close enough to 180 are not modified.
精彩评论