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: case SHAPE_T::POLY:
if( IsFilled() ) if( IsFilled() )
{
return m_poly.Collide( VECTOR2I( aPosition ), maxdist ); return m_poly.Collide( VECTOR2I( aPosition ), maxdist );
}
else else
{ return m_poly.CollideEdge( VECTOR2I( aPosition ), nullptr, maxdist );
SHAPE_POLY_SET::VERTEX_INDEX dummy;
return m_poly.CollideEdge( VECTOR2I( aPosition ), dummy, maxdist );
}
default: default:
UNIMPLEMENTED_FOR( SHAPE_T_asString() ); UNIMPLEMENTED_FOR( SHAPE_T_asString() );

View File

@ -1161,7 +1161,7 @@ public:
* @param aClosestVertex is the index of the closes vertex to \p aPoint. * @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. * @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; int aClearance = 0 ) const;
/** /**
@ -1174,7 +1174,7 @@ public:
* @param aClosestVertex is the index of the closes vertex to \p aPoint. * @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. * @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; 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, bool SHAPE_POLY_SET::CollideVertex( const VECTOR2I& aPoint,
SHAPE_POLY_SET::VERTEX_INDEX& aClosestVertex, SHAPE_POLY_SET::VERTEX_INDEX* aClosestVertex,
int aClearance ) const int aClearance ) const
{ {
// Shows whether there was a collision // 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. // Difference vector between each vertex and aPoint.
VECTOR2D delta; VECTOR2D delta;
double distance, clearance; ecoord distance_squared;
ecoord clearance_squared = SEG::Square( aClearance );
// Convert clearance to double for precision when comparing distances
clearance = aClearance;
for( CONST_ITERATOR iterator = CIterateWithHoles(); iterator; iterator++ ) for( CONST_ITERATOR iterator = CIterateWithHoles(); iterator; iterator++ )
{ {
@ -1719,18 +1717,21 @@ bool SHAPE_POLY_SET::CollideVertex( const VECTOR2I& aPoint,
delta = *iterator - aPoint; delta = *iterator - aPoint;
// Compute distance // Compute distance
distance = delta.EuclideanNorm(); distance_squared = delta.SquaredEuclideanNorm();
// Check for collisions // Check for collisions
if( distance <= clearance ) if( distance_squared <= clearance_squared )
{ {
if( !aClosestVertex )
return true;
collision = true; collision = true;
// Update aClearance to look for closer vertices // Update clearance to look for closer vertices
clearance = distance; clearance_squared = distance_squared;
// Store the indices that identify the vertex // 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, bool SHAPE_POLY_SET::CollideEdge( const VECTOR2I& aPoint,
SHAPE_POLY_SET::VERTEX_INDEX& aClosestVertex, SHAPE_POLY_SET::VERTEX_INDEX* aClosestVertex,
int aClearance ) const int aClearance ) const
{ {
// Shows whether there was a collision // 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++ ) for( CONST_SEGMENT_ITERATOR iterator = CIterateSegmentsWithHoles(); iterator; iterator++ )
{ {
const SEG currentSegment = *iterator; const SEG currentSegment = *iterator;
int distance = currentSegment.Distance( aPoint ); ecoord distance_squared = currentSegment.SquaredDistance( aPoint );
// Check for collisions // Check for collisions
if( distance <= aClearance ) if( distance_squared <= clearance_squared )
{ {
if( !aClosestVertex )
return true;
collision = true; collision = true;
// Update aClearance to look for closer edges // Update clearance to look for closer edges
aClearance = distance; clearance_squared = distance_squared;
// Store the indices that identify the vertex // 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, 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 ); 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, 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 ); 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 bool ZONE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{ {
// Calculate bounding box for zone // 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; } int GetLocalFlags() const { return m_localFlgs; }
void SetLocalFlags( int aFlags ) { m_localFlgs = aFlags; } void SetLocalFlags( int aFlags ) { m_localFlgs = aFlags; }
@ -423,43 +420,25 @@ public:
* *
* @param refPos is the VECTOR2I to test. * @param refPos is the VECTOR2I to test.
* @param aAccuracy increase the item bounding box by this amount. * @param aAccuracy increase the item bounding box by this amount.
* @param aCornerHit [out] is the index of the closest vertex found, useless when return * @param aCornerHit [out, optional] is the index of the closest vertex found when return
* value is false. * value is true
* @return true if some corner was found to be closer to refPos than aClearance; false * @return true if some corner was found to be closer to refPos than aClearance; false
* otherwise. * otherwise.
*/ */
bool HitTestForCorner( const VECTOR2I& refPos, int aAccuracy, bool HitTestForCorner( const VECTOR2I& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const; SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit = nullptr ) 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;
/** /**
* Test if the given VECTOR2I is near a segment defined by 2 corners. * Test if the given VECTOR2I is near a segment defined by 2 corners.
* *
* @param refPos is the VECTOR2I to test. * @param refPos is the VECTOR2I to test.
* @param aAccuracy increase the item bounding box by this amount. * @param aAccuracy increase the item bounding box by this amount.
* @param aCornerHit [out] is the index of the closest vertex found, useless when return * @param aCornerHit [out, optional] is the index of the closest vertex found when return
* value is false. * value is true.
* @return true if some edge was found to be closer to refPos than aClearance. * @return true if some edge was found to be closer to refPos than aClearance.
*/ */
bool HitTestForEdge( const VECTOR2I& refPos, int aAccuracy, bool HitTestForEdge( const VECTOR2I& refPos, int aAccuracy,
SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) 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.
* @return true if some edge was found to be closer to refPos than aClearance.
*/
bool HitTestForEdge( const VECTOR2I& refPos, int aAccuracy ) const;
/** /**
* @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect, * @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect,

View File

@ -214,14 +214,12 @@ BOOST_AUTO_TEST_CASE( Collide )
*/ */
BOOST_AUTO_TEST_CASE( CollideVertex ) 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 // Check that the set collides with the colliding points
for( const VECTOR2I& point : common.holeyPoints ) for( const VECTOR2I& point : common.holeyPoints )
{ {
BOOST_CHECK_MESSAGE( common.holeyPolySet.CollideVertex( point, cornerHit, 0 ), " Point " BOOST_CHECK_MESSAGE( common.holeyPolySet.CollideVertex( point, nullptr, 0 ),
<< point.x << ", " << point.y << " does not collide with holeyPolySet polygon" ); " 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 ) 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 // Check that the set collides with the colliding points
for( const VECTOR2I& point : common.holeyPoints ) for( const VECTOR2I& point : common.holeyPoints )
{ BOOST_CHECK( common.holeyPolySet.CollideVertex( point + VECTOR2I( 1, 1 ), nullptr, 2 ) );
BOOST_CHECK( common.holeyPolySet.CollideVertex( point + VECTOR2I( 1, 1 ), cornerHit, 2 ) );
}
} }