Fix rounding issues

Rescaling and rotating has been leaving 1nm errors due to integer
truncation in VECTOR2I.  This rounds integers using KiROUND before
returning
This commit is contained in:
Seth Hillbrand 2021-01-09 13:04:42 -08:00
parent 4f6134b60d
commit b2cfd7f479
1 changed files with 42 additions and 8 deletions

View File

@ -31,6 +31,7 @@
#include <limits>
#include <iostream>
#include <sstream>
#include <type_traits>
#include <math/util.h>
@ -376,15 +377,33 @@ VECTOR2<T>& VECTOR2<T>::operator-=( const T& aScalar )
template <class T>
VECTOR2<T> VECTOR2<T>::Rotate( double aAngle ) const
{
// Avoid 0 radian rotation, case very frequently found
if( aAngle == 0.0 )
// Avoid common radian rotations that may allow for angular error
if( aAngle == 0.0 || aAngle == 2 * M_PI )
return VECTOR2<T> ( T( x ), T( y ) );
if( aAngle == M_PI_2 )
return VECTOR2<T>( -T( y ), T( x ) );
if( aAngle == M_PI )
return VECTOR2<T>( -T(x), -T( y ) );
if( aAngle == 3 * M_PI_2 )
return VECTOR2<T>( T( y ), -T( x ) );
double sa = sin( aAngle );
double ca = cos( aAngle );
return VECTOR2<T> ( T( (double) x * ca - (double) y * sa ),
T( (double) x * sa + (double) y * ca ) );
if( std::is_integral<T>::value )
{
return VECTOR2<T> ( KiROUND( (double) x * ca - (double) y * sa ),
KiROUND( (double) x * sa + (double) y * ca ) );
}
else
{
return VECTOR2<T> ( T( (double) x * ca - (double) y * sa ),
T( (double) x * sa + (double) y * ca ) );
}
}
@ -397,9 +416,24 @@ VECTOR2<T> VECTOR2<T>::Resize( T aNewLength ) const
extended_type l_sq_current = (extended_type) x * x + (extended_type) y * y;
extended_type l_sq_new = (extended_type) aNewLength * aNewLength;
return VECTOR2<T> (
( x < 0 ? -1 : 1 ) * sqrt( rescale( l_sq_new, (extended_type) x * x, l_sq_current ) ),
( y < 0 ? -1 : 1 ) * sqrt( rescale( l_sq_new, (extended_type) y * y, l_sq_current ) ) ) * sign( aNewLength );
if( std::is_integral<T>::value )
{
return VECTOR2<T> (
( x < 0 ? -1 : 1 ) *
KiROUND( std::sqrt( rescale( l_sq_new, (extended_type) x * x, l_sq_current ) ) ),
( y < 0 ? -1 : 1 ) *
KiROUND( std::sqrt( rescale( l_sq_new, (extended_type) y * y, l_sq_current ) ) )
* sign( aNewLength ) );
}
else
{
return VECTOR2<T> (
( x < 0 ? -1 : 1 ) *
std::sqrt( rescale( l_sq_new, (extended_type) x * x, l_sq_current ) ),
( y < 0 ? -1 : 1 ) *
std::sqrt( rescale( l_sq_new, (extended_type) y * y, l_sq_current ) ) )
* sign( aNewLength );
}
}
@ -467,7 +501,7 @@ VECTOR2<T> VECTOR2<T>::operator*( const T& aFactor ) const
template <class T>
VECTOR2<T> VECTOR2<T>::operator/( const T& aFactor ) const
{
VECTOR2<T> vector( x / aFactor, y / aFactor );
VECTOR2<T> vector( KiROUND( x / aFactor ), KiROUND( y / aFactor ) );
return vector;
}