geometry: more robust colinearity test in SHAPE_LINE_CHAIN::Simplify()

We now test the midpoint (B) of the 3 consecutive polyline points (A, B, C), since (assuming the angle between AB and BC is > 90 degrees) AC is always longer than
AB or BC. This minimizes the distance computation rounding error (in the previous algorithm, taking the point C for colineraity test) if AB is short and BC is very long, the test would
often fail due to rouding error in projection/line distance computation
This commit is contained in:
Tomasz Wlostowski 2022-06-03 22:30:44 +02:00
parent e6ebc2b9b9
commit 3aed13278d
1 changed files with 23 additions and 33 deletions

View File

@ -1740,46 +1740,36 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify( bool aRemoveColinear )
i = 0;
// stage 2: eliminate colinear segments
while( i < np - 2 )
for( i = 1 ; i < np - 1 ; i ++ )
{
const VECTOR2I p0 = pts_unique[i];
const VECTOR2I p1 = pts_unique[i + 1];
int n = i;
const VECTOR2I p_prev = pts_unique[i - 1];
const VECTOR2I midpoint = pts_unique[i];
const VECTOR2I p_next = pts_unique[i + 1];
if( aRemoveColinear && shapes_unique[i] == SHAPES_ARE_PT
&& shapes_unique[i + 1] == SHAPES_ARE_PT )
if( aRemoveColinear && shapes_unique[i - 1] == SHAPES_ARE_PT
&& shapes_unique[i] == SHAPES_ARE_PT )
{
while( n < np - 2
&& ( SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1
|| SEG( p0, p1 ).Collinear( SEG( p1, pts_unique[n + 2] ) ) ) )
n++;
const auto distToMidpoint = SEG( p_prev, p_next ).LineDistance( midpoint );
const auto isMidpointColinear = SEG( p_prev, p_next ).Collinear( SEG( p_prev, midpoint ) );
if( distToMidpoint <= 1 || isMidpointColinear )
{
pts_unique.erase( pts_unique.begin() + i );
shapes_unique.erase( shapes_unique.begin() + i );
i--;
np--;
continue;
}
}
}
m_points.push_back( p0 );
for( i = 0 ; i < np; i ++ )
{
m_points.push_back( pts_unique[i] );
m_shapes.push_back( shapes_unique[i] );
if( n > i )
i = n;
if( n == np - 2 )
{
m_points.push_back( pts_unique[np - 1] );
m_shapes.push_back( shapes_unique[np - 1] );
return *this;
}
i++;
}
if( np > 1 )
{
m_points.push_back( pts_unique[np - 2] );
m_shapes.push_back( shapes_unique[np - 2] );
}
m_points.push_back( pts_unique[np - 1] );
m_shapes.push_back( shapes_unique[np - 1] );
assert( m_points.size() == m_shapes.size() );
return *this;