libs/kimath: POLY_GRID_PARTITION must use truncating (round-to-zero) rescale function for correct grid generation.

This commit is contained in:
Tomasz Wlostowski 2021-01-10 00:04:57 +01:00
parent b2cfd7f479
commit 7994c59169
2 changed files with 26 additions and 12 deletions

View File

@ -55,6 +55,8 @@
* - idem for the edge to the right of (p), just reverse the edge types
* - if the cell doesn't contain any edges, scan horizontal cells to the left and right (switching sides with each iteration)
* until an edge if found.
* NOTE: the rescale_trunc() function is used for grid<->world coordinate conversion because it rounds towards 0 (not to nearest)
* It's important as rouding to nearest (which the standard rescale() function does) will shift the grid by half a cell.
*/
class POLY_GRID_PARTITION
@ -218,12 +220,18 @@ private:
return false;
}
int rescale_trunc( int aNumerator, int aValue, int aDenominator ) const
{
int64_t numerator = (int64_t) aNumerator * (int64_t) aValue;
return numerator / aDenominator;
}
// convertes grid cell coordinates to the polygon coordinates
const VECTOR2I grid2poly( const VECTOR2I& p ) const
{
int px = rescale( p.x, m_bbox.GetWidth(), m_gridSize ) + m_bbox.GetPosition().x;
int py = rescale( p.y, m_bbox.GetHeight(), m_gridSize ) + m_bbox.GetPosition().y; // (int) floor( (double) p.y / m_gridSize * (double) m_bbox.GetHeight() + m_bbox.GetPosition().y );
int px = rescale_trunc( p.x, m_bbox.GetWidth(), m_gridSize ) + m_bbox.GetPosition().x;
int py = rescale_trunc( p.y, m_bbox.GetHeight(), m_gridSize ) + m_bbox.GetPosition().y;
return VECTOR2I( px, py );
}
@ -235,18 +243,18 @@ private:
int grid2polyX( int x ) const
{
return rescale( x, m_bbox.GetWidth(), m_gridSize ) + m_bbox.GetPosition().x;
return rescale_trunc( x, m_bbox.GetWidth(), m_gridSize ) + m_bbox.GetPosition().x;
}
int grid2polyY( int y ) const
{
return rescale( y, m_bbox.GetHeight(), m_gridSize ) + m_bbox.GetPosition().y;
return rescale_trunc( y, m_bbox.GetHeight(), m_gridSize ) + m_bbox.GetPosition().y;
}
const VECTOR2I poly2grid( const VECTOR2I& p ) const
{
int px = rescale( p.x - m_bbox.GetPosition().x, m_gridSize, m_bbox.GetWidth() );
int py = rescale( p.y - m_bbox.GetPosition().y, m_gridSize, m_bbox.GetHeight() );
int px = rescale_trunc( p.x - m_bbox.GetPosition().x, m_gridSize, m_bbox.GetWidth() );
int py = rescale_trunc( p.y - m_bbox.GetPosition().y, m_gridSize, m_bbox.GetHeight() );
if( px < 0 )
px = 0;
@ -265,7 +273,7 @@ private:
int poly2gridX( int x ) const
{
int px = rescale( x - m_bbox.GetPosition().x, m_gridSize, m_bbox.GetWidth() );
int px = rescale_trunc( x - m_bbox.GetPosition().x, m_gridSize, m_bbox.GetWidth() );
if( px < 0 )
px = 0;
@ -278,7 +286,7 @@ private:
int poly2gridY( int y ) const
{
int py = rescale( y - m_bbox.GetPosition().y, m_gridSize, m_bbox.GetHeight() );
int py = rescale_trunc( y - m_bbox.GetPosition().y, m_gridSize, m_bbox.GetHeight() );
if( py < 0 )
py = 0;
@ -379,7 +387,7 @@ private:
for( int x = gx0; x <= gx1; x++ )
{
int px = grid2polyX( x );
int py = ( edge.A.y + rescale( dir.y, px - edge.A.x, dir.x ) );
int py = ( edge.A.y + rescale_trunc( dir.y, px - edge.A.x, dir.x ) );
int yy = poly2gridY( py );
indices.insert( m_gridSize * yy + x );
@ -402,7 +410,7 @@ private:
for( int y = gy0; y <= gy1; y++ )
{
int py = grid2polyY( y );
int px = ( edge.A.x + rescale( dir.x, py - edge.A.y, dir.y ) );
int px = ( edge.A.x + rescale_trunc( dir.x, py - edge.A.y, dir.y ) );
int xx = poly2gridX( px );
indices.insert( m_gridSize * y + xx );

View File

@ -32,7 +32,13 @@ template<>
int rescale( int aNumerator, int aValue, int aDenominator )
{
int64_t numerator = (int64_t) aNumerator * (int64_t) aValue;
return numerator / aDenominator;
// round to nearest
if( ( numerator < 0 ) ^ ( aDenominator < 0 ) )
return ( numerator - aDenominator / 2 ) / aDenominator;
else
return ( numerator + aDenominator / 2 ) / aDenominator;
}