Performance: avoid sqrt at all costs.

This commit is contained in:
Jeff Young 2022-07-16 18:41:59 +01:00
parent ded4840130
commit b727bfc16d
6 changed files with 37 additions and 94 deletions

View File

@ -795,14 +795,9 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
case SHAPE_T::POLY:
if( IsFilled() )
{
return m_poly.Collide( VECTOR2I( aPosition ), maxdist );
}
else
{
SHAPE_POLY_SET::VERTEX_INDEX dummy;
return m_poly.CollideEdge( VECTOR2I( aPosition ), dummy, maxdist );
}
return m_poly.CollideEdge( VECTOR2I( aPosition ), nullptr, maxdist );
default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() );

View File

@ -1161,7 +1161,7 @@ public:
* @param aClosestVertex is the index of the closes vertex to \p aPoint.
* @return bool - true if there is a collision, false in any other case.
*/
bool CollideVertex( const VECTOR2I& aPoint, VERTEX_INDEX& aClosestVertex,
bool CollideVertex( const VECTOR2I& aPoint, VERTEX_INDEX* aClosestVertex = nullptr,
int aClearance = 0 ) const;
/**
@ -1174,7 +1174,7 @@ public:
* @param aClosestVertex is the index of the closes vertex to \p aPoint.
* @return bool - true if there is a collision, false in any other case.
*/
bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX& aClosestVertex,
bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX* aClosestVertex = nullptr,
int aClearance = 0 ) const;
/**

View File

@ -1700,7 +1700,7 @@ void SHAPE_POLY_SET::Append( const VECTOR2I& aP, int aOutline, int aHole )
bool SHAPE_POLY_SET::CollideVertex( const VECTOR2I& aPoint,
SHAPE_POLY_SET::VERTEX_INDEX& aClosestVertex,
SHAPE_POLY_SET::VERTEX_INDEX* aClosestVertex,
int aClearance ) const
{
// Shows whether there was a collision
@ -1708,10 +1708,8 @@ bool SHAPE_POLY_SET::CollideVertex( const VECTOR2I& aPoint,
// Difference vector between each vertex and aPoint.
VECTOR2D delta;
double distance, clearance;
// Convert clearance to double for precision when comparing distances
clearance = aClearance;
ecoord distance_squared;
ecoord clearance_squared = SEG::Square( aClearance );
for( CONST_ITERATOR iterator = CIterateWithHoles(); iterator; iterator++ )
{
@ -1719,18 +1717,21 @@ bool SHAPE_POLY_SET::CollideVertex( const VECTOR2I& aPoint,
delta = *iterator - aPoint;
// Compute distance
distance = delta.EuclideanNorm();
distance_squared = delta.SquaredEuclideanNorm();
// Check for collisions
if( distance <= clearance )
if( distance_squared <= clearance_squared )
{
if( !aClosestVertex )
return true;
collision = true;
// Update aClearance to look for closer vertices
clearance = distance;
// Update clearance to look for closer vertices
clearance_squared = distance_squared;
// Store the indices that identify the vertex
aClosestVertex = iterator.GetIndex();
*aClosestVertex = iterator.GetIndex();
}
}
@ -1739,27 +1740,31 @@ bool SHAPE_POLY_SET::CollideVertex( const VECTOR2I& aPoint,
bool SHAPE_POLY_SET::CollideEdge( const VECTOR2I& aPoint,
SHAPE_POLY_SET::VERTEX_INDEX& aClosestVertex,
SHAPE_POLY_SET::VERTEX_INDEX* aClosestVertex,
int aClearance ) const
{
// Shows whether there was a collision
bool collision = false;
bool collision = false;
ecoord clearance_squared = SEG::Square( aClearance );
for( CONST_SEGMENT_ITERATOR iterator = CIterateSegmentsWithHoles(); iterator; iterator++ )
{
const SEG currentSegment = *iterator;
int distance = currentSegment.Distance( aPoint );
ecoord distance_squared = currentSegment.SquaredDistance( aPoint );
// Check for collisions
if( distance <= aClearance )
if( distance_squared <= clearance_squared )
{
if( !aClosestVertex )
return true;
collision = true;
// Update aClearance to look for closer edges
aClearance = distance;
// Update clearance to look for closer edges
clearance_squared = distance_squared;
// Store the indices that identify the vertex
aClosestVertex = iterator.GetIndex();
*aClosestVertex = iterator.GetIndex();
}
}

View File

@ -375,49 +375,20 @@ bool ZONE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
}
void ZONE::SetSelectedCorner( const VECTOR2I& aPosition, int aAccuracy )
{
SHAPE_POLY_SET::VERTEX_INDEX corner;
// If there is some corner to be selected, assign it to m_CornerSelection
if( HitTestForCorner( aPosition, aAccuracy * 2, corner )
|| HitTestForEdge( aPosition, aAccuracy, corner ) )
{
if( m_CornerSelection == nullptr )
m_CornerSelection = new SHAPE_POLY_SET::VERTEX_INDEX;
*m_CornerSelection = corner;
}
}
bool ZONE::HitTestForCorner( const VECTOR2I& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const
SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
{
return m_Poly->CollideVertex( VECTOR2I( refPos ), aCornerHit, aAccuracy );
}
bool ZONE::HitTestForCorner( const VECTOR2I& refPos, int aAccuracy ) const
{
SHAPE_POLY_SET::VERTEX_INDEX dummy;
return HitTestForCorner( refPos, aAccuracy, dummy );
}
bool ZONE::HitTestForEdge( const VECTOR2I& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const
SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
{
return m_Poly->CollideEdge( VECTOR2I( refPos ), aCornerHit, aAccuracy );
}
bool ZONE::HitTestForEdge( const VECTOR2I& refPos, int aAccuracy ) const
{
SHAPE_POLY_SET::VERTEX_INDEX dummy;
return HitTestForEdge( refPos, aAccuracy, dummy );
}
bool ZONE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
// Calculate bounding box for zone

View File

@ -321,9 +321,6 @@ public:
}
///
// Like HitTest but selects the current corner to be operated on
void SetSelectedCorner( const VECTOR2I& aPosition, int aAccuracy );
int GetLocalFlags() const { return m_localFlgs; }
void SetLocalFlags( int aFlags ) { m_localFlgs = aFlags; }
@ -423,43 +420,25 @@ public:
*
* @param refPos is the VECTOR2I to test.
* @param aAccuracy increase the item bounding box by this amount.
* @param aCornerHit [out] is the index of the closest vertex found, useless when return
* value is false.
* @param aCornerHit [out, optional] is the index of the closest vertex found when return
* value is true
* @return true if some corner was found to be closer to refPos than aClearance; false
* otherwise.
*/
bool HitTestForCorner( const VECTOR2I& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const;
/**
* Test if the given VECTOR2I is near a corner.
* @param refPos is the VECTOR2I to test.
* @param aAccuracy increase the item bounding box by this amount.
* @return true if some corner was found to be closer to refPos than aClearance; false
* otherwise.
*/
bool HitTestForCorner( const VECTOR2I& refPos, int aAccuracy ) const;
SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit = nullptr ) const;
/**
* Test if the given VECTOR2I is near a segment defined by 2 corners.
*
* @param refPos is the VECTOR2I to test.
* @param aAccuracy increase the item bounding box by this amount.
* @param aCornerHit [out] is the index of the closest vertex found, useless when return
* value is false.
* @param aCornerHit [out, optional] is the index of the closest vertex found when return
* value is true.
* @return true if some edge was found to be closer to refPos than aClearance.
*/
bool HitTestForEdge( const VECTOR2I& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const;
/**
* Test if the given VECTOR2I is near a segment defined by 2 corners.
*
* @param refPos is the VECTOR2I to test.
* @param aAccuracy increase the item bounding box by this amount.
* @return true if some edge was found to be closer to refPos than aClearance.
*/
bool HitTestForEdge( const VECTOR2I& refPos, int aAccuracy ) const;
SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit = nullptr ) const;
/**
* @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect,

View File

@ -214,14 +214,12 @@ BOOST_AUTO_TEST_CASE( Collide )
*/
BOOST_AUTO_TEST_CASE( CollideVertex )
{
// Variable to store the index of the corner hit
SHAPE_POLY_SET::VERTEX_INDEX cornerHit;
// Check that the set collides with the colliding points
for( const VECTOR2I& point : common.holeyPoints )
{
BOOST_CHECK_MESSAGE( common.holeyPolySet.CollideVertex( point, cornerHit, 0 ), " Point "
<< point.x << ", " << point.y << " does not collide with holeyPolySet polygon" );
BOOST_CHECK_MESSAGE( common.holeyPolySet.CollideVertex( point, nullptr, 0 ),
" Point " << point.x << ", " << point.y <<
" does not collide with holeyPolySet polygon" );
}
}
@ -231,14 +229,9 @@ BOOST_AUTO_TEST_CASE( CollideVertex )
*/
BOOST_AUTO_TEST_CASE( CollideVertexWithClearance )
{
// Variable to store the index of the corner hit
SHAPE_POLY_SET::VERTEX_INDEX cornerHit;
// Check that the set collides with the colliding points
for( const VECTOR2I& point : common.holeyPoints )
{
BOOST_CHECK( common.holeyPolySet.CollideVertex( point + VECTOR2I( 1, 1 ), cornerHit, 2 ) );
}
BOOST_CHECK( common.holeyPolySet.CollideVertex( point + VECTOR2I( 1, 1 ), nullptr, 2 ) );
}