From 7994c5916967c5e9d91d81957cff4731ca2f4cba Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Sun, 10 Jan 2021 00:04:57 +0100 Subject: [PATCH] libs/kimath: POLY_GRID_PARTITION must use truncating (round-to-zero) rescale function for correct grid generation. --- .../include/geometry/poly_grid_partition.h | 30 ++++++++++++------- libs/kimath/src/math/util.cpp | 8 ++++- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/libs/kimath/include/geometry/poly_grid_partition.h b/libs/kimath/include/geometry/poly_grid_partition.h index f69e549a30..83bd7a85d5 100644 --- a/libs/kimath/include/geometry/poly_grid_partition.h +++ b/libs/kimath/include/geometry/poly_grid_partition.h @@ -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 ); diff --git a/libs/kimath/src/math/util.cpp b/libs/kimath/src/math/util.cpp index 4ace387b8d..dd74dc4d43 100644 --- a/libs/kimath/src/math/util.cpp +++ b/libs/kimath/src/math/util.cpp @@ -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; + }