libs/kimath: improve numerical robustness of ApproxParallel/ApproxCollinear for segments of largely different lengths

This commit is contained in:
Tomasz Wlostowski 2022-10-04 20:52:30 +02:00
parent ca5d87e46d
commit 6ed3618ce5
2 changed files with 57 additions and 28 deletions

View File

@ -277,34 +277,9 @@ public:
return ( d1 <= 1 && d2 <= 1 );
}
bool ApproxCollinear( const SEG& aSeg ) const
{
ecoord p, q, r;
CanonicalCoefs( p, q, r );
ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
return std::abs( dist1 ) <= 1 && std::abs( dist2 ) <= 1;
}
bool ApproxParallel( const SEG& aSeg, int aDistanceThreshold = 1 ) const
{
ecoord p, q, r;
CanonicalCoefs( p, q, r );
ecoord dist1 = ( p * aSeg.A.x + q * aSeg.A.y + r ) / sqrt( p * p + q * q );
ecoord dist2 = ( p * aSeg.B.x + q * aSeg.B.y + r ) / sqrt( p * p + q * q );
return std::abs( dist1 - dist2 ) <= aDistanceThreshold;
}
bool ApproxPerpendicular( const SEG& aSeg ) const
{
SEG perp = PerpendicularSeg( A );
return aSeg.ApproxParallel( perp );
}
bool ApproxCollinear( const SEG& aSeg, int aDistanceThreshold = 1 ) const;
bool ApproxParallel( const SEG& aSeg, int aDistanceThreshold = 1 ) const;
bool ApproxPerpendicular( const SEG& aSeg ) const;
bool Overlaps( const SEG& aSeg ) const
{
@ -395,6 +370,8 @@ private:
bool intersects( const SEG& aSeg, bool aIgnoreEndpoints = false, bool aLines = false,
VECTOR2I* aPt = nullptr ) const;
bool mutualDistance( const SEG& aSeg, ecoord& aD1, ecoord& aD2 ) const;
private:
///< index within the parent shape (used when m_is_local == false)
int m_index;

View File

@ -347,3 +347,55 @@ int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
return aDetermineSide ? dist : std::abs( dist );
}
bool SEG::mutualDistance( const SEG& aSeg, ecoord& aD1, ecoord& aD2 ) const
{
SEG a( *this );
SEG b( aSeg );
if( a.SquaredLength() < b.SquaredLength() )
{
std::swap(a, b);
}
ecoord p = ecoord{ a.A.y } - a.B.y;
ecoord q = ecoord{ a.B.x } - a.A.x;
ecoord r = -p * a.A.x - q * a.A.y;
ecoord l = p * p + q * q;
ecoord det1 = p * b.A.x + q * b.A.y + r;
ecoord det2 = p * b.B.x + q * b.B.y + r;
aD1 = isqrt( rescale( det1, det1, l ) );
aD2 = isqrt( rescale( det2, det2, l ) );
return true;
}
bool SEG::ApproxCollinear( const SEG& aSeg, int aDistanceThreshold ) const
{
ecoord d1, d2;
mutualDistance( aSeg, d1, d2 );
return std::abs( d1 ) <= aDistanceThreshold && std::abs( d2 ) <= aDistanceThreshold;
}
bool SEG::ApproxParallel( const SEG& aSeg, int aDistanceThreshold ) const
{
ecoord d1, d2;
mutualDistance( aSeg, d1, d2 );
return std::abs( d1 - d2 ) <= (ecoord) aDistanceThreshold;
}
bool SEG::ApproxPerpendicular( const SEG& aSeg ) const
{
SEG perp = PerpendicularSeg( A );
return aSeg.ApproxParallel( perp );
}