Caching ConvexHull routine

Stores a cache of the convex hull similar to the bounding box.  Modifies
the hull based on actions to allow  complex footprint graphics without delay

Fixes https://gitlab.com/kicad/code/kicad/issues/7341
This commit is contained in:
Seth Hillbrand 2021-01-31 06:32:14 -08:00
parent b4a9792e23
commit aa0db969ca
10 changed files with 94 additions and 5 deletions

View File

@ -51,6 +51,7 @@ FOOTPRINT::FOOTPRINT( BOARD* parent ) :
m_layer = F_Cu; m_layer = F_Cu;
m_orient = 0; m_orient = 0;
m_fpStatus = FP_PADS_are_LOCKED; m_fpStatus = FP_PADS_are_LOCKED;
m_hullDirty = true;
m_arflag = 0; m_arflag = 0;
m_rot90Cost = m_rot180Cost = 0; m_rot90Cost = m_rot180Cost = 0;
m_link = 0; m_link = 0;
@ -68,6 +69,8 @@ FOOTPRINT::FOOTPRINT( BOARD* parent ) :
m_value = new FP_TEXT( this, FP_TEXT::TEXT_is_VALUE ); m_value = new FP_TEXT( this, FP_TEXT::TEXT_is_VALUE );
m_3D_Drawings.clear(); m_3D_Drawings.clear();
UpdateBoundingHull();
} }
@ -80,6 +83,8 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
m_fpStatus = aFootprint.m_fpStatus; m_fpStatus = aFootprint.m_fpStatus;
m_orient = aFootprint.m_orient; m_orient = aFootprint.m_orient;
m_boundingBox = aFootprint.m_boundingBox; m_boundingBox = aFootprint.m_boundingBox;
m_hullDirty = aFootprint.m_hullDirty;
m_hull = aFootprint.m_hull;
m_rot90Cost = aFootprint.m_rot90Cost; m_rot90Cost = aFootprint.m_rot90Cost;
m_rot180Cost = aFootprint.m_rot180Cost; m_rot180Cost = aFootprint.m_rot180Cost;
m_lastEditTime = aFootprint.m_lastEditTime; m_lastEditTime = aFootprint.m_lastEditTime;
@ -165,6 +170,9 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
m_initial_comments = aFootprint.m_initial_comments ? m_initial_comments = aFootprint.m_initial_comments ?
new wxArrayString( *aFootprint.m_initial_comments ) : nullptr; new wxArrayString( *aFootprint.m_initial_comments ) : nullptr;
if( m_hullDirty )
UpdateBoundingHull();
} }
@ -214,6 +222,8 @@ FOOTPRINT& FOOTPRINT::operator=( FOOTPRINT&& aOther )
m_fpStatus = aOther.m_fpStatus; m_fpStatus = aOther.m_fpStatus;
m_orient = aOther.m_orient; m_orient = aOther.m_orient;
m_boundingBox = aOther.m_boundingBox; m_boundingBox = aOther.m_boundingBox;
m_hull = aOther.m_hull;
m_hullDirty = aOther.m_hullDirty;
m_rot90Cost = aOther.m_rot90Cost; m_rot90Cost = aOther.m_rot90Cost;
m_rot180Cost = aOther.m_rot180Cost; m_rot180Cost = aOther.m_rot180Cost;
m_lastEditTime = aOther.m_lastEditTime; m_lastEditTime = aOther.m_lastEditTime;
@ -284,6 +294,7 @@ FOOTPRINT& FOOTPRINT::operator=( FOOTPRINT&& aOther )
// Ensure auxiliary data is up to date // Ensure auxiliary data is up to date
CalculateBoundingBox(); CalculateBoundingBox();
UpdateBoundingHull();
m_initial_comments = aOther.m_initial_comments; m_initial_comments = aOther.m_initial_comments;
@ -309,6 +320,8 @@ FOOTPRINT& FOOTPRINT::operator=( const FOOTPRINT& aOther )
m_fpStatus = aOther.m_fpStatus; m_fpStatus = aOther.m_fpStatus;
m_orient = aOther.m_orient; m_orient = aOther.m_orient;
m_boundingBox = aOther.m_boundingBox; m_boundingBox = aOther.m_boundingBox;
m_hull = aOther.m_hull;
m_hullDirty = aOther.m_hullDirty;
m_rot90Cost = aOther.m_rot90Cost; m_rot90Cost = aOther.m_rot90Cost;
m_rot180Cost = aOther.m_rot180Cost; m_rot180Cost = aOther.m_rot180Cost;
m_lastEditTime = aOther.m_lastEditTime; m_lastEditTime = aOther.m_lastEditTime;
@ -390,6 +403,7 @@ FOOTPRINT& FOOTPRINT::operator=( const FOOTPRINT& aOther )
// Ensure auxiliary data is up to date // Ensure auxiliary data is up to date
CalculateBoundingBox(); CalculateBoundingBox();
UpdateBoundingHull();
m_initial_comments = aOther.m_initial_comments ? m_initial_comments = aOther.m_initial_comments ?
new wxArrayString( *aOther.m_initial_comments ) : nullptr; new wxArrayString( *aOther.m_initial_comments ) : nullptr;
@ -490,6 +504,9 @@ void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
} }
} }
if( aBoardItem->Type() != PCB_FP_TEXT_T )
m_hullDirty = true;
aBoardItem->ClearEditFlags(); aBoardItem->ClearEditFlags();
aBoardItem->SetParent( this ); aBoardItem->SetParent( this );
} }
@ -565,6 +582,9 @@ void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode )
if( aBoardItem->GetParentGroup() ) if( aBoardItem->GetParentGroup() )
aBoardItem->GetParentGroup()->RemoveItem( aBoardItem ); aBoardItem->GetParentGroup()->RemoveItem( aBoardItem );
if( aBoardItem->Type() != PCB_FP_TEXT_T )
m_hullDirty = true;
} }
@ -680,9 +700,16 @@ const EDA_RECT FOOTPRINT::GetBoundingBox( bool aIncludeInvisibleText ) const
} }
SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const void FOOTPRINT::UpdateBoundingHull()
{
m_hull = CalculateBoundingHull();
m_hullDirty = false;
}
SHAPE_POLY_SET FOOTPRINT::CalculateBoundingHull() const
{ {
SHAPE_POLY_SET rawPolys; SHAPE_POLY_SET rawPolys;
SHAPE_POLY_SET hull;
for( BOARD_ITEM* item : m_drawings ) for( BOARD_ITEM* item : m_drawings )
{ {
@ -744,6 +771,27 @@ SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const
} }
SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const
{
if( m_hullDirty )
return CalculateBoundingHull();
return m_hull;
}
SHAPE_POLY_SET FOOTPRINT::GetBoundingHull()
{
if( m_hullDirty )
{
m_hull = CalculateBoundingHull();
m_hullDirty = false;
}
return m_hull;
}
void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
{ {
wxString msg, msg2; wxString msg, msg2;
@ -1292,8 +1340,6 @@ void FOOTPRINT::Rotate( const wxPoint& aRotCentre, double aAngle )
if( item->Type() == PCB_FP_TEXT_T ) if( item->Type() == PCB_FP_TEXT_T )
static_cast<FP_TEXT*>( item )->KeepUpright( orientation, newOrientation ); static_cast<FP_TEXT*>( item )->KeepUpright( orientation, newOrientation );
} }
CalculateBoundingBox();
} }
@ -1359,6 +1405,11 @@ void FOOTPRINT::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
Rotate( aCentre, 1800.0 ); Rotate( aCentre, 1800.0 );
CalculateBoundingBox(); CalculateBoundingBox();
if( m_hullDirty )
UpdateBoundingHull();
else
m_hull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos );
} }
@ -1402,6 +1453,11 @@ void FOOTPRINT::SetPosition( const wxPoint& aPos )
} }
m_boundingBox.Move( delta ); m_boundingBox.Move( delta );
if( m_hullDirty )
UpdateBoundingHull();
else
m_hull.Move( delta );
} }
@ -1459,6 +1515,7 @@ void FOOTPRINT::MoveAnchorPosition( const wxPoint& aMoveVector )
} }
CalculateBoundingBox(); CalculateBoundingBox();
m_hull.Move( moveVector );
} }
@ -1497,6 +1554,9 @@ void FOOTPRINT::SetOrientation( double aNewAngle )
static_cast<FP_TEXT*>( item )->SetDrawCoord(); static_cast<FP_TEXT*>( item )->SetDrawCoord();
} }
} }
CalculateBoundingBox();
m_hull.Rotate( -DECIDEG2RAD( angleChange ), GetPosition() );
} }

View File

@ -175,8 +175,16 @@ public:
* *
* This operation is slower but more accurate than calculating a bounding box. * This operation is slower but more accurate than calculating a bounding box.
*/ */
SHAPE_POLY_SET GetBoundingHull();
SHAPE_POLY_SET GetBoundingHull() const; SHAPE_POLY_SET GetBoundingHull() const;
/**
* Update the cached bounding Hull with current data
*/
SHAPE_POLY_SET CalculateBoundingHull() const;
void UpdateBoundingHull();
// Virtual function // Virtual function
const EDA_RECT GetBoundingBox() const override; const EDA_RECT GetBoundingBox() const override;
const EDA_RECT GetBoundingBox( bool aIncludeInvisibleText ) const; const EDA_RECT GetBoundingBox( bool aIncludeInvisibleText ) const;
@ -704,6 +712,10 @@ private:
int m_fpStatus; // For autoplace: flags (LOCKED, FIELDS_AUTOPLACED) int m_fpStatus; // For autoplace: flags (LOCKED, FIELDS_AUTOPLACED)
EDA_RECT m_boundingBox; // Bounding box : coordinates on board, real orientation. EDA_RECT m_boundingBox; // Bounding box : coordinates on board, real orientation.
mutable bool m_hullDirty; // If the hull needs to be re-calculated
SHAPE_POLY_SET m_hull; // Convex wrapping hull of the footprint
ZONE_CONNECTION m_zoneConnection; ZONE_CONNECTION m_zoneConnection;
int m_thermalWidth; int m_thermalWidth;
int m_thermalGap; int m_thermalGap;

View File

@ -1439,6 +1439,12 @@ void PCB_PAINTER::draw( const FOOTPRINT* aFootprint, int aLayer )
m_gal->SetLineWidth( bboxThickness ); m_gal->SetLineWidth( bboxThickness );
EDA_RECT rect = aFootprint->GetBoundingBoxBase(); EDA_RECT rect = aFootprint->GetBoundingBoxBase();
m_gal->DrawRectangle( VECTOR2D( rect.GetOrigin() ), VECTOR2D( rect.GetEnd() ) ); m_gal->DrawRectangle( VECTOR2D( rect.GetOrigin() ), VECTOR2D( rect.GetEnd() ) );
double bboxThickness = 3.0 / m_gal->GetWorldScale();
m_gal->SetLineWidth( bboxThickness );
SHAPE_POLY_SET convex = aFootprint->GetBoundingHull();
m_gal->DrawPolyline( convex.COutline( 0 ) );
#endif #endif
} }
} }

View File

@ -473,8 +473,10 @@ void ALTIUM_PCB::Parse( const CFB::CompoundFileReader& aReader,
// Finish Board by recalculating footprint boundingboxes // Finish Board by recalculating footprint boundingboxes
for( FOOTPRINT* footprint : m_board->Footprints() ) for( FOOTPRINT* footprint : m_board->Footprints() )
{
footprint->CalculateBoundingBox(); footprint->CalculateBoundingBox();
footprint->UpdateBoundingHull();
}
// Otherwise we cannot save the imported board // Otherwise we cannot save the imported board
m_board->SetModified(); m_board->SetModified();
} }

View File

@ -1224,6 +1224,10 @@ void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
footprint->Reference().SetLocalCoord(); footprint->Reference().SetLocalCoord();
footprint->Value().SetLocalCoord(); footprint->Value().SetLocalCoord();
// Calculate the bounding boxes
footprint->CalculateBoundingBox();
footprint->UpdateBoundingHull();
// Get next element // Get next element
element = element->GetNext(); element = element->GetNext();
} }

View File

@ -2226,7 +2226,8 @@ bool FABMASTER::loadFootprints( BOARD* aBoard )
fp->Flip( fp->GetPosition(), true ); fp->Flip( fp->GetPosition(), true );
} }
fp->BuildPolyCourtyards(); fp->CalculateBoundingBox();
fp->UpdateBoundingHull();
aBoard->Add( fp, ADD_MODE::APPEND ); aBoard->Add( fp, ADD_MODE::APPEND );
} }

View File

@ -689,6 +689,7 @@ FOOTPRINT* GPCB_FPL_CACHE::parseFOOTPRINT( LINE_READER* aLineReader )
// Recalculate the bounding box // Recalculate the bounding box
footprint->CalculateBoundingBox(); footprint->CalculateBoundingBox();
footprint->UpdateBoundingHull();
return footprint.release(); return footprint.release();
} }

View File

@ -3191,6 +3191,7 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
|| reader->GetSource().Contains( "clipboard" ) ) || reader->GetSource().Contains( "clipboard" ) )
{ {
footprint->CalculateBoundingBox(); footprint->CalculateBoundingBox();
footprint->UpdateBoundingHull();
} }
return footprint.release(); return footprint.release();

View File

@ -1371,6 +1371,7 @@ void LEGACY_PLUGIN::loadFOOTPRINT( FOOTPRINT* aFootprint )
else if( TESTLINE( "$EndMODULE" ) ) else if( TESTLINE( "$EndMODULE" ) )
{ {
aFootprint->CalculateBoundingBox(); aFootprint->CalculateBoundingBox();
aFootprint->UpdateBoundingHull();
return; // preferred exit return; // preferred exit
} }

View File

@ -613,6 +613,7 @@ void PCB_FOOTPRINT::AddToBoard()
} }
footprint->CalculateBoundingBox(); footprint->CalculateBoundingBox();
footprint->UpdateBoundingHull();
} }