diff --git a/common/advanced_config.cpp b/common/advanced_config.cpp index f58c0c0369..a291c76668 100644 --- a/common/advanced_config.cpp +++ b/common/advanced_config.cpp @@ -251,7 +251,6 @@ ADVANCED_CFG::ADVANCED_CFG() m_DebugZoneFiller = false; m_DebugPDFWriter = false; - m_SkipBoundingBoxOnFpLoad = false; m_SmallDrillMarkSize = 0.35; m_HotkeysDumper = false; m_DrawBoundingBoxes = false; @@ -336,9 +335,6 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg ) configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::DebugPDFWriter, &m_DebugPDFWriter, false ) ); - configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::SkipBoundingBoxFpLoad, - &m_SkipBoundingBoxOnFpLoad, false ) ); - configParams.push_back( new PARAM_CFG_DOUBLE( true, AC_KEYS::SmallDrillMarkSize, &m_SmallDrillMarkSize, 0.35, 0.0, 3.0 ) ); diff --git a/include/advanced_config.h b/include/advanced_config.h index a19a3c03dd..bd4f4f3497 100644 --- a/include/advanced_config.h +++ b/include/advanced_config.h @@ -144,11 +144,6 @@ public: */ bool m_DebugPDFWriter; - /** - * Skip bounding box calculation when loading footprints - */ - bool m_SkipBoundingBoxOnFpLoad; - /** * The diameter of the drill marks on print and plot outputs (in mm), * when the "Drill marks" option is set to "Small mark" diff --git a/pcbnew/autorouter/ar_autoplacer.cpp b/pcbnew/autorouter/ar_autoplacer.cpp index 5f28fccb81..0614fd5452 100644 --- a/pcbnew/autorouter/ar_autoplacer.cpp +++ b/pcbnew/autorouter/ar_autoplacer.cpp @@ -557,7 +557,7 @@ int AR_AUTOPLACER::testFootprintOnBoard( FOOTPRINT* aFootprint, bool TstOtherSid side = AR_SIDE_BOTTOM; otherside = AR_SIDE_TOP; } - EDA_RECT fpBBox = aFootprint->GetFootprintRect(); + EDA_RECT fpBBox = aFootprint->GetBoundingBox( false, false ); fpBBox.Move( -aOffset ); buildFpAreas( aFootprint, 0 ); @@ -591,12 +591,10 @@ int AR_AUTOPLACER::getOptimalFPPlacement( FOOTPRINT* aFootprint ) double min_cost, curr_cost, Score; bool testOtherSide; - aFootprint->CalculateBoundingBox(); - lastPosOK = m_matrix.m_BrdBox.GetOrigin(); wxPoint fpPos = aFootprint->GetPosition(); - EDA_RECT fpBBox = aFootprint->GetFootprintRect(); + EDA_RECT fpBBox = aFootprint->GetBoundingBox( false, false ); // Move fpBBox to have the footprint position at (0,0) fpBBox.Move( -fpPos ); @@ -785,10 +783,7 @@ FOOTPRINT* AR_AUTOPLACER::pickFootprint( ) for( FOOTPRINT* footprint : m_board->Footprints() ) - { - footprint->CalculateBoundingBox(); fpList.push_back( footprint ); - } sort( fpList.begin(), fpList.end(), sortFootprintsByComplexity ); @@ -1049,7 +1044,6 @@ end_of_tst: // Place footprint. placeFootprint( footprint, true, m_curPosition ); - footprint->CalculateBoundingBox(); genModuleOnRoutingMatrix( footprint ); footprint->SetIsPlaced( true ); footprint->SetNeedsPlaced( false ); @@ -1075,8 +1069,5 @@ end_of_tst: m_matrix.UnInitRoutingMatrix(); - for( FOOTPRINT* fp : m_board->Footprints() ) - fp->CalculateBoundingBox(); - return cancelled ? AR_CANCELLED : AR_COMPLETED; } diff --git a/pcbnew/autorouter/spread_footprints.cpp b/pcbnew/autorouter/spread_footprints.cpp index bdf61192af..0e9a53f5c5 100644 --- a/pcbnew/autorouter/spread_footprints.cpp +++ b/pcbnew/autorouter/spread_footprints.cpp @@ -69,7 +69,7 @@ void fillRectList( CSubRectArray& vecSubRects, std::vector & aFootpr for( unsigned ii = 0; ii < aFootprintList.size(); ii++ ) { - EDA_RECT fpBox = aFootprintList[ii]->GetFootprintRect(); + EDA_RECT fpBox = aFootprintList[ii]->GetBoundingBox( false, false ); TSubRect fpRect( ( fpBox.GetWidth() + PADDING ) / scale, ( fpBox.GetHeight() + PADDING ) / scale, ii ); vecSubRects.push_back( fpRect ); @@ -167,7 +167,7 @@ void moveFootprintsInArea( CRectPlacement& aPlacementArea, std::vector GetFootprintRect(); + EDA_RECT fpBBox = footprint->GetBoundingBox( false, false ); wxPoint mod_pos = pos + ( footprint->GetPosition() - fpBBox.GetOrigin() ) + aFreeArea.GetOrigin(); @@ -197,7 +197,6 @@ void SpreadFootprints( std::vector* aFootprints, wxPoint aSpreadArea if( footprint->IsLocked() ) continue; - footprint->CalculateBoundingBox(); footprintList.push_back( footprint ); } @@ -240,7 +239,7 @@ void SpreadFootprints( std::vector* aFootprints, wxPoint aSpreadArea subsurface += footprint->GetArea( PADDING ); // Calculate min size of placement area: - EDA_RECT bbox = footprint->GetFootprintRect(); + EDA_RECT bbox = footprint->GetBoundingBox( false, false ); fp_max_width = std::max( fp_max_width, bbox.GetWidth() ); fp_max_height = std::max( fp_max_height, bbox.GetHeight() ); diff --git a/pcbnew/board.cpp b/pcbnew/board.cpp index 13ac522924..8f71a6fc5f 100644 --- a/pcbnew/board.cpp +++ b/pcbnew/board.cpp @@ -59,6 +59,7 @@ wxPoint BOARD_ITEM::ZeroOffset( 0, 0 ); BOARD::BOARD() : BOARD_ITEM_CONTAINER( (BOARD_ITEM*) NULL, PCB_T ), m_boardUse( BOARD_USE::NORMAL ), + m_timeStamp( 1 ), m_paper( PAGE_INFO::A4 ), m_project( nullptr ), m_designSettings( new BOARD_DESIGN_SETTINGS( nullptr, "board.design_settings" ) ), @@ -1061,7 +1062,7 @@ EDA_RECT BOARD::ComputeBoundingBox( bool aBoardEdgesOnly ) const } else { - area.Merge( footprint->GetBoundingBox( showInvisibleText ) ); + area.Merge( footprint->GetBoundingBox( true, showInvisibleText ) ); } } @@ -1725,7 +1726,7 @@ FOOTPRINT* BOARD::GetFootprint( const wxPoint& aPosition, PCB_LAYER_ID aActiveLa // Filter non visible footprints if requested if( !aVisibleOnly || IsFootprintLayerVisible( layer ) ) { - EDA_RECT bb = candidate->GetFootprintRect(); + EDA_RECT bb = candidate->GetBoundingBox( false, false ); int offx = bb.GetX() + bb.GetWidth() / 2; int offy = bb.GetY() + bb.GetHeight() / 2; diff --git a/pcbnew/board.h b/pcbnew/board.h index 94fbd87a30..47adcef6dc 100644 --- a/pcbnew/board.h +++ b/pcbnew/board.h @@ -193,6 +193,7 @@ class BOARD : public BOARD_ITEM_CONTAINER private: /// What is this board being used for BOARD_USE m_boardUse; + int m_timeStamp; // actually a modification counter wxString m_fileName; MARKERS m_markers; @@ -213,9 +214,9 @@ private: std::shared_ptr m_connectivity; PAGE_INFO m_paper; - TITLE_BLOCK m_titles; // text in lower right of screen and plots + TITLE_BLOCK m_titles; // text in lower right of screen and plots PCB_PLOT_PARAMS m_plotOptions; - PROJECT* m_project; // project this board is a part of + PROJECT* m_project; // project this board is a part of /** * All of the board design settings are stored as a JSON object inside the project file. The @@ -266,6 +267,9 @@ public: */ BOARD_USE GetBoardUse() const { return m_boardUse; } + void IncrementTimeStamp() { m_timeStamp++; } + int GetTimeStamp() { return m_timeStamp; } + /** * Find out if the board is being used to hold a single footprint for editing/viewing. * diff --git a/pcbnew/cross-probing.cpp b/pcbnew/cross-probing.cpp index 4589621799..e04117e7d6 100644 --- a/pcbnew/cross-probing.cpp +++ b/pcbnew/cross-probing.cpp @@ -214,7 +214,7 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) if( footprint ) { - bbox = footprint->GetBoundingBox( false ); // No invisible text in bbox calc + bbox = footprint->GetBoundingBox( true, false ); // No invisible text in bbox calc if( pad ) m_toolManager->RunAction( PCB_ACTIONS::highlightItem, true, (void*) pad ); diff --git a/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor.cpp b/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor.cpp index a61b96f0f6..11bba48451 100644 --- a/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor.cpp +++ b/pcbnew/dialogs/dialog_edit_footprint_for_fp_editor.cpp @@ -718,8 +718,6 @@ bool DIALOG_FOOTPRINT_FP_EDITOR::TransferDataFromWindow() draw3D->clear(); draw3D->insert( draw3D->end(), m_shapes3D_list.begin(), m_shapes3D_list.end() ); - m_footprint->CalculateBoundingBox(); - commit.Push( _( "Modify footprint properties" ) ); return true; diff --git a/pcbnew/dialogs/dialog_exchange_footprints.cpp b/pcbnew/dialogs/dialog_exchange_footprints.cpp index 830ab97aa1..822204d77e 100644 --- a/pcbnew/dialogs/dialog_exchange_footprints.cpp +++ b/pcbnew/dialogs/dialog_exchange_footprints.cpp @@ -558,7 +558,6 @@ void PCB_EDIT_FRAME::ExchangeFootprint( FOOTPRINT* aExisting, FOOTPRINT* aNew, const_cast( aNew->m_Uuid ) = aExisting->m_Uuid; aNew->SetProperties( aExisting->GetProperties() ); aNew->SetPath( aExisting->GetPath() ); - aNew->CalculateBoundingBox(); aCommit.Remove( aExisting ); aCommit.Add( aNew ); diff --git a/pcbnew/dialogs/dialog_footprint_properties.cpp b/pcbnew/dialogs/dialog_footprint_properties.cpp index 1ffde91b70..9c34473944 100644 --- a/pcbnew/dialogs/dialog_footprint_properties.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties.cpp @@ -780,8 +780,6 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataFromWindow() draw3D->clear(); draw3D->insert( draw3D->end(), m_shapes3D_list.begin(), m_shapes3D_list.end() ); - m_footprint->CalculateBoundingBox(); - // This is a simple edit, we must create an undo entry if( m_footprint->GetEditFlags() == 0 ) // i.e. not edited, or moved commit.Push( _( "Modify footprint properties" ) ); diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index bbbcdcd846..0c168f346f 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -1632,9 +1632,6 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() footprint->GetOrientation() ); } - if( footprint ) - footprint->CalculateBoundingBox(); - m_parent->SetMsgPanel( m_currentPad ); // redraw the area where the pad was diff --git a/pcbnew/footprint.cpp b/pcbnew/footprint.cpp index 96fef4b154..ad19b427c4 100644 --- a/pcbnew/footprint.cpp +++ b/pcbnew/footprint.cpp @@ -45,13 +45,16 @@ FOOTPRINT::FOOTPRINT( BOARD* parent ) : BOARD_ITEM_CONTAINER((BOARD_ITEM*) parent, PCB_FOOTPRINT_T ), + m_boundingBoxCacheTimeStamp( 0 ), + m_visibleBBoxCacheTimeStamp( 0 ), + m_textExcludedBBoxCacheTimeStamp( 0 ), + m_hullCacheTimeStamp( 0 ), m_initial_comments( 0 ) { m_attributes = 0; m_layer = F_Cu; m_orient = 0; m_fpStatus = FP_PADS_are_LOCKED; - m_hullDirty = true; m_arflag = 0; m_rot90Cost = m_rot180Cost = 0; m_link = 0; @@ -69,8 +72,6 @@ FOOTPRINT::FOOTPRINT( BOARD* parent ) : m_value = new FP_TEXT( this, FP_TEXT::TEXT_is_VALUE ); m_3D_Drawings.clear(); - - UpdateBoundingHull(); } @@ -82,22 +83,28 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) : m_attributes = aFootprint.m_attributes; m_fpStatus = aFootprint.m_fpStatus; m_orient = aFootprint.m_orient; - m_boundingBox = aFootprint.m_boundingBox; - m_hullDirty = aFootprint.m_hullDirty; - m_hull = aFootprint.m_hull; m_rot90Cost = aFootprint.m_rot90Cost; m_rot180Cost = aFootprint.m_rot180Cost; m_lastEditTime = aFootprint.m_lastEditTime; m_link = aFootprint.m_link; m_path = aFootprint.m_path; - m_localClearance = aFootprint.m_localClearance; - m_localSolderMaskMargin = aFootprint.m_localSolderMaskMargin; - m_localSolderPasteMargin = aFootprint.m_localSolderPasteMargin; - m_localSolderPasteMarginRatio = aFootprint.m_localSolderPasteMarginRatio; - m_zoneConnection = aFootprint.m_zoneConnection; - m_thermalWidth = aFootprint.m_thermalWidth; - m_thermalGap = aFootprint.m_thermalGap; + m_cachedBoundingBox = aFootprint.m_cachedBoundingBox; + m_boundingBoxCacheTimeStamp = aFootprint.m_boundingBoxCacheTimeStamp; + m_cachedVisibleBBox = aFootprint.m_cachedVisibleBBox; + m_visibleBBoxCacheTimeStamp = aFootprint.m_visibleBBoxCacheTimeStamp; + m_cachedTextExcludedBBox = aFootprint.m_cachedTextExcludedBBox; + m_textExcludedBBoxCacheTimeStamp = aFootprint.m_textExcludedBBoxCacheTimeStamp; + m_cachedHull = aFootprint.m_cachedHull; + m_hullCacheTimeStamp = aFootprint.m_hullCacheTimeStamp; + + m_localClearance = aFootprint.m_localClearance; + m_localSolderMaskMargin = aFootprint.m_localSolderMaskMargin; + m_localSolderPasteMargin = aFootprint.m_localSolderPasteMargin; + m_localSolderPasteMarginRatio = aFootprint.m_localSolderPasteMarginRatio; + m_zoneConnection = aFootprint.m_zoneConnection; + m_thermalWidth = aFootprint.m_thermalWidth; + m_thermalGap = aFootprint.m_thermalGap; std::map ptrMap; @@ -170,9 +177,6 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) : m_initial_comments = aFootprint.m_initial_comments ? new wxArrayString( *aFootprint.m_initial_comments ) : nullptr; - - if( m_hullDirty ) - UpdateBoundingHull(); } @@ -221,22 +225,28 @@ FOOTPRINT& FOOTPRINT::operator=( FOOTPRINT&& aOther ) m_attributes = aOther.m_attributes; m_fpStatus = aOther.m_fpStatus; m_orient = aOther.m_orient; - m_boundingBox = aOther.m_boundingBox; - m_hull = aOther.m_hull; - m_hullDirty = aOther.m_hullDirty; m_rot90Cost = aOther.m_rot90Cost; m_rot180Cost = aOther.m_rot180Cost; m_lastEditTime = aOther.m_lastEditTime; m_link = aOther.m_link; m_path = aOther.m_path; - m_localClearance = aOther.m_localClearance; - m_localSolderMaskMargin = aOther.m_localSolderMaskMargin; - m_localSolderPasteMargin = aOther.m_localSolderPasteMargin; - m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio; - m_zoneConnection = aOther.m_zoneConnection; - m_thermalWidth = aOther.m_thermalWidth; - m_thermalGap = aOther.m_thermalGap; + m_cachedBoundingBox = aOther.m_cachedBoundingBox; + m_boundingBoxCacheTimeStamp = aOther.m_boundingBoxCacheTimeStamp; + m_cachedVisibleBBox = aOther.m_cachedVisibleBBox; + m_visibleBBoxCacheTimeStamp = aOther.m_visibleBBoxCacheTimeStamp; + m_cachedTextExcludedBBox = aOther.m_cachedTextExcludedBBox; + m_textExcludedBBoxCacheTimeStamp = aOther.m_textExcludedBBoxCacheTimeStamp; + m_cachedHull = aOther.m_cachedHull; + m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp; + + m_localClearance = aOther.m_localClearance; + m_localSolderMaskMargin = aOther.m_localSolderMaskMargin; + m_localSolderPasteMargin = aOther.m_localSolderPasteMargin; + m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio; + m_zoneConnection = aOther.m_zoneConnection; + m_thermalWidth = aOther.m_thermalWidth; + m_thermalGap = aOther.m_thermalGap; // Move reference and value m_reference = aOther.m_reference; @@ -292,10 +302,6 @@ FOOTPRINT& FOOTPRINT::operator=( FOOTPRINT&& aOther ) m_keywords = aOther.m_keywords; m_properties = aOther.m_properties; - // Ensure auxiliary data is up to date - CalculateBoundingBox(); - UpdateBoundingHull(); - m_initial_comments = aOther.m_initial_comments; // Clear the other item's containers since this is a move @@ -319,22 +325,28 @@ FOOTPRINT& FOOTPRINT::operator=( const FOOTPRINT& aOther ) m_attributes = aOther.m_attributes; m_fpStatus = aOther.m_fpStatus; m_orient = aOther.m_orient; - m_boundingBox = aOther.m_boundingBox; - m_hull = aOther.m_hull; - m_hullDirty = aOther.m_hullDirty; m_rot90Cost = aOther.m_rot90Cost; m_rot180Cost = aOther.m_rot180Cost; m_lastEditTime = aOther.m_lastEditTime; m_link = aOther.m_link; m_path = aOther.m_path; - m_localClearance = aOther.m_localClearance; - m_localSolderMaskMargin = aOther.m_localSolderMaskMargin; - m_localSolderPasteMargin = aOther.m_localSolderPasteMargin; - m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio; - m_zoneConnection = aOther.m_zoneConnection; - m_thermalWidth = aOther.m_thermalWidth; - m_thermalGap = aOther.m_thermalGap; + m_cachedBoundingBox = aOther.m_cachedBoundingBox; + m_boundingBoxCacheTimeStamp = aOther.m_boundingBoxCacheTimeStamp; + m_cachedVisibleBBox = aOther.m_cachedVisibleBBox; + m_visibleBBoxCacheTimeStamp = aOther.m_visibleBBoxCacheTimeStamp; + m_cachedTextExcludedBBox = aOther.m_cachedTextExcludedBBox; + m_textExcludedBBoxCacheTimeStamp = aOther.m_textExcludedBBoxCacheTimeStamp; + m_cachedHull = aOther.m_cachedHull; + m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp; + + m_localClearance = aOther.m_localClearance; + m_localSolderMaskMargin = aOther.m_localSolderMaskMargin; + m_localSolderPasteMargin = aOther.m_localSolderPasteMargin; + m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio; + m_zoneConnection = aOther.m_zoneConnection; + m_thermalWidth = aOther.m_thermalWidth; + m_thermalGap = aOther.m_thermalGap; // Copy reference and value *m_reference = *aOther.m_reference; @@ -401,10 +413,6 @@ FOOTPRINT& FOOTPRINT::operator=( const FOOTPRINT& aOther ) m_keywords = aOther.m_keywords; m_properties = aOther.m_properties; - // Ensure auxiliary data is up to date - CalculateBoundingBox(); - UpdateBoundingHull(); - m_initial_comments = aOther.m_initial_comments ? new wxArrayString( *aOther.m_initial_comments ) : nullptr; @@ -504,9 +512,6 @@ void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode ) } } - if( aBoardItem->Type() != PCB_FP_TEXT_T ) - m_hullDirty = true; - aBoardItem->ClearEditFlags(); aBoardItem->SetParent( this ); } @@ -586,52 +591,19 @@ void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode ) if( parentGroup && !( parentGroup->GetFlags() & STRUCT_DELETED ) ) parentGroup->RemoveItem( aBoardItem ); - - if( aBoardItem->Type() != PCB_FP_TEXT_T ) - m_hullDirty = true; -} - - -void FOOTPRINT::CalculateBoundingBox() -{ - m_boundingBox = GetFootprintRect(); } double FOOTPRINT::GetArea( int aPadding ) const { - double w = std::abs( static_cast( m_boundingBox.GetWidth() ) ) + aPadding; - double h = std::abs( static_cast( m_boundingBox.GetHeight() ) ) + aPadding; + EDA_RECT bbox = GetBoundingBox( false, false ); + + double w = std::abs( static_cast( bbox.GetWidth() ) ) + aPadding; + double h = std::abs( static_cast( bbox.GetHeight() ) ) + aPadding; return w * h; } -EDA_RECT FOOTPRINT::GetFootprintRect() const -{ - EDA_RECT area; - - area.SetOrigin( m_pos ); - area.SetEnd( m_pos ); - area.Inflate( Millimeter2iu( 0.25 ) ); // Give a min size to the area - - for( BOARD_ITEM* item : m_drawings ) - { - if( item->Type() == PCB_FP_SHAPE_T ) - area.Merge( item->GetBoundingBox() ); - } - - for( PAD* pad : m_pads ) - area.Merge( pad->GetBoundingBox() ); - - for( FP_ZONE* zone : m_fp_zones ) - area.Merge( zone->GetBoundingBox() ); - - // Groups do not contribute to the rect, only their members - - return area; -} - - EDA_RECT FOOTPRINT::GetFpPadsLocalBbox() const { EDA_RECT area; @@ -657,61 +629,122 @@ EDA_RECT FOOTPRINT::GetFpPadsLocalBbox() const const EDA_RECT FOOTPRINT::GetBoundingBox() const { - return GetBoundingBox( true ); + return GetBoundingBox( true, true ); } -const EDA_RECT FOOTPRINT::GetBoundingBox( bool aIncludeInvisibleText ) const +const EDA_RECT FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const { - EDA_RECT area = GetFootprintRect(); - - // Add in items not collected by GetFootprintRect(): - for( BOARD_ITEM* item : m_drawings ) - { - if( item->Type() != PCB_FP_SHAPE_T ) - area.Merge( item->GetBoundingBox() ); - } - - // This can be further optimized when aIncludeInvisibleText is true, but currently - // leaving this as is until it's determined there is a noticeable speed hit. - bool valueLayerIsVisible = true; - bool refLayerIsVisible = true; - BOARD* board = GetBoard(); + BOARD* board = GetBoard(); if( board ) { - // The first "&&" conditional handles the user turning layers off as well as layers - // not being present in the current PCB stackup. Values, references, and all - // footprint text can also be turned off via the GAL meta-layers, so the 2nd and - // 3rd "&&" conditionals handle that. - valueLayerIsVisible = board->IsLayerVisible( m_value->GetLayer() ) - && board->IsElementVisible( LAYER_MOD_VALUES ) - && board->IsElementVisible( LAYER_MOD_TEXT_FR ); - - refLayerIsVisible = board->IsLayerVisible( m_reference->GetLayer() ) - && board->IsElementVisible( LAYER_MOD_REFERENCES ) - && board->IsElementVisible( LAYER_MOD_TEXT_FR ); + if( aIncludeText && aIncludeInvisibleText ) + { + if( m_boundingBoxCacheTimeStamp >= board->GetTimeStamp() ) + return m_cachedBoundingBox; + } + else if( aIncludeText ) + { + if( m_visibleBBoxCacheTimeStamp >= board->GetTimeStamp() ) + return m_cachedVisibleBBox; + } + else + { + if( m_textExcludedBBoxCacheTimeStamp >= board->GetTimeStamp() ) + return m_cachedTextExcludedBBox; + } } + EDA_RECT area; - if(( m_value->IsVisible() && valueLayerIsVisible ) || aIncludeInvisibleText ) - area.Merge( m_value->GetBoundingBox() ); + area.SetOrigin( m_pos ); + area.SetEnd( m_pos ); + area.Inflate( Millimeter2iu( 0.25 ) ); // Give a min size to the area - if(( m_reference->IsVisible() && refLayerIsVisible ) || aIncludeInvisibleText ) - area.Merge( m_reference->GetBoundingBox() ); + for( BOARD_ITEM* item : m_drawings ) + { + if( item->Type() == PCB_FP_SHAPE_T ) + area.Merge( item->GetBoundingBox() ); + } + + for( PAD* pad : m_pads ) + area.Merge( pad->GetBoundingBox() ); + + for( FP_ZONE* zone : m_fp_zones ) + area.Merge( zone->GetBoundingBox() ); + + // Groups do not contribute to the rect, only their members + + if( aIncludeText ) + { + for( BOARD_ITEM* item : m_drawings ) + { + if( item->Type() == PCB_FP_TEXT_T ) + area.Merge( item->GetBoundingBox() ); + } + + // This can be further optimized when aIncludeInvisibleText is true, but currently + // leaving this as is until it's determined there is a noticeable speed hit. + bool valueLayerIsVisible = true; + bool refLayerIsVisible = true; + + if( board ) + { + // The first "&&" conditional handles the user turning layers off as well as layers + // not being present in the current PCB stackup. Values, references, and all + // footprint text can also be turned off via the GAL meta-layers, so the 2nd and + // 3rd "&&" conditionals handle that. + valueLayerIsVisible = board->IsLayerVisible( m_value->GetLayer() ) + && board->IsElementVisible( LAYER_MOD_VALUES ) + && board->IsElementVisible( LAYER_MOD_TEXT_FR ); + + refLayerIsVisible = board->IsLayerVisible( m_reference->GetLayer() ) + && board->IsElementVisible( LAYER_MOD_REFERENCES ) + && board->IsElementVisible( LAYER_MOD_TEXT_FR ); + } + + + if( ( m_value->IsVisible() && valueLayerIsVisible ) || aIncludeInvisibleText ) + area.Merge( m_value->GetBoundingBox() ); + + if( ( m_reference->IsVisible() && refLayerIsVisible ) || aIncludeInvisibleText ) + area.Merge( m_reference->GetBoundingBox() ); + } + + if( board ) + { + if( aIncludeText && aIncludeInvisibleText ) + { + m_boundingBoxCacheTimeStamp = board->GetTimeStamp(); + m_cachedBoundingBox = area; + } + else if( aIncludeText ) + { + m_visibleBBoxCacheTimeStamp = board->GetTimeStamp(); + m_cachedVisibleBBox = area; + } + else + { + m_textExcludedBBoxCacheTimeStamp = board->GetTimeStamp(); + m_cachedTextExcludedBBox = area; + } + } return area; } -void FOOTPRINT::UpdateBoundingHull() +SHAPE_POLY_SET FOOTPRINT::GetBoundingHull() const { - m_hull = CalculateBoundingHull(); - m_hullDirty = false; -} + BOARD* board = GetBoard(); + + if( board ) + { + if( m_hullCacheTimeStamp >= board->GetTimeStamp() ) + return m_cachedHull; + } -SHAPE_POLY_SET FOOTPRINT::CalculateBoundingHull() const -{ SHAPE_POLY_SET rawPolys; SHAPE_POLY_SET hull; @@ -765,34 +798,16 @@ SHAPE_POLY_SET FOOTPRINT::CalculateBoundingHull() const std::vector convex_hull; BuildConvexHull( convex_hull, rawPolys ); - SHAPE_POLY_SET hullPoly; - hullPoly.NewOutline(); + m_cachedHull.RemoveAllContours(); + m_cachedHull.NewOutline(); for( const wxPoint& pt : convex_hull ) - hullPoly.Append( pt ); + m_cachedHull.Append( pt ); - return hullPoly; -} + if( board ) + m_hullCacheTimeStamp = board->GetTimeStamp(); - -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; + return m_cachedHull; } @@ -887,7 +902,7 @@ bool FOOTPRINT::IsOnLayer( PCB_LAYER_ID aLayer ) const bool FOOTPRINT::HitTest( const wxPoint& aPosition, int aAccuracy ) const { - EDA_RECT rect = m_boundingBox;//.GetBoundingBoxRotated( GetPosition(), m_Orient ); + EDA_RECT rect = GetBoundingBox( false, false ); return rect.Inflate( aAccuracy ).Contains( aPosition ); } @@ -904,11 +919,11 @@ bool FOOTPRINT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) arect.Inflate( aAccuracy ); if( aContained ) - return arect.Contains( m_boundingBox ); + return arect.Contains( false, false ); else { // If the rect does not intersect the bounding box, skip any tests - if( !aRect.Intersects( GetBoundingBox() ) ) + if( !aRect.Intersects( GetBoundingBox( false, false ) ) ) return false; // Determine if any elements in the FOOTPRINT intersect the rect @@ -926,7 +941,7 @@ bool FOOTPRINT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) for( BOARD_ITEM* item : m_drawings ) { - if( item->HitTest( arect, false, 0 ) ) + if( item->Type() != PCB_FP_TEXT_T && item->HitTest( arect, false, 0 ) ) return true; } @@ -1274,11 +1289,7 @@ double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const const BOX2I FOOTPRINT::ViewBBox() const { - EDA_RECT area = GetFootprintRect(); - - // Calculate extended area including text fields - area.Merge( m_reference->GetBoundingBox() ); - area.Merge( m_value->GetBoundingBox() ); + EDA_RECT area = GetBoundingBox( true, true ); // Add the Clearance shape size: (shape around the pads when the clearance is shown. Not // optimized, but the draw cost is small (perhaps smaller than optimization). @@ -1344,6 +1355,11 @@ void FOOTPRINT::Rotate( const wxPoint& aRotCentre, double aAngle ) if( item->Type() == PCB_FP_TEXT_T ) static_cast( item )->KeepUpright( orientation, newOrientation ); } + + m_boundingBoxCacheTimeStamp = 0; + m_visibleBBoxCacheTimeStamp = 0; + m_textExcludedBBoxCacheTimeStamp = 0; + m_hullCacheTimeStamp = 0; } @@ -1408,12 +1424,11 @@ void FOOTPRINT::Flip( const wxPoint& aCentre, bool aFlipLeftRight ) if( aFlipLeftRight ) Rotate( aCentre, 1800.0 ); - CalculateBoundingBox(); + m_boundingBoxCacheTimeStamp = 0; + m_visibleBBoxCacheTimeStamp = 0; + m_textExcludedBBoxCacheTimeStamp = 0; - if( m_hullDirty ) - UpdateBoundingHull(); - else - m_hull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos ); + m_cachedHull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos ); std::swap( m_poly_courtyard_front, m_poly_courtyard_back ); } @@ -1458,12 +1473,10 @@ void FOOTPRINT::SetPosition( const wxPoint& aPos ) } } - m_boundingBox.Move( delta ); - - if( m_hullDirty ) - UpdateBoundingHull(); - else - m_hull.Move( delta ); + m_cachedBoundingBox.Move( delta ); + m_cachedVisibleBBox.Move( delta ); + m_cachedTextExcludedBBox.Move( delta ); + m_cachedHull.Move( delta ); } @@ -1520,8 +1533,10 @@ void FOOTPRINT::MoveAnchorPosition( const wxPoint& aMoveVector ) } } - CalculateBoundingBox(); - m_hull.Move( moveVector ); + m_cachedBoundingBox.Move( moveVector ); + m_cachedVisibleBBox.Move( moveVector ); + m_cachedTextExcludedBBox.Move( moveVector ); + m_cachedHull.Move( moveVector ); } @@ -1561,8 +1576,11 @@ void FOOTPRINT::SetOrientation( double aNewAngle ) } } - CalculateBoundingBox(); - m_hull.Rotate( -DECIDEG2RAD( angleChange ), GetPosition() ); + m_boundingBoxCacheTimeStamp = 0; + m_visibleBBoxCacheTimeStamp = 0; + m_textExcludedBBoxCacheTimeStamp = 0; + + m_cachedHull.Rotate( -DECIDEG2RAD( angleChange ), GetPosition() ); } diff --git a/pcbnew/footprint.h b/pcbnew/footprint.h index 136215f48c..f9c34540e0 100644 --- a/pcbnew/footprint.h +++ b/pcbnew/footprint.h @@ -139,26 +139,6 @@ public: */ void ClearAllNets(); - /** - * Calculate the bounding box in board coordinates. - */ - void CalculateBoundingBox(); - - /** - * Build and returns the boundary box of the footprint excluding any text. - * - * @return The rectangle containing the footprint. - */ - EDA_RECT GetFootprintRect() const; - - /** - * Return the last calculated bounding box of the footprint (does not recalculate it). - * (call CalculateBoundingBox() to recalculate it). - * - * @return The rectangle containing the footprint. - */ - EDA_RECT GetBoundingBoxBase() const { return m_boundingBox; } - /** * Return the bounding box containing pads when the footprint is on the front side, * orientation 0, position 0,0. @@ -175,19 +155,11 @@ public: * * This operation is slower but more accurate than calculating a bounding box. */ - SHAPE_POLY_SET GetBoundingHull(); SHAPE_POLY_SET GetBoundingHull() const; - /** - * Update the cached bounding Hull with current data - */ - SHAPE_POLY_SET CalculateBoundingHull() const; - - void UpdateBoundingHull(); - // Virtual function const EDA_RECT GetBoundingBox() const override; - const EDA_RECT GetBoundingBox( bool aIncludeInvisibleText ) const; + const EDA_RECT GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const; PADS& Pads() { return m_pads; } const PADS& Pads() const { return m_pads; } @@ -716,11 +688,15 @@ private: LIB_ID m_fpid; // The #LIB_ID of the FOOTPRINT. int m_attributes; // Flag bits ( see FOOTPRINT_ATTR_T ) int m_fpStatus; // For autoplace: flags (LOCKED, FIELDS_AUTOPLACED) - 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 + mutable EDA_RECT m_cachedBoundingBox; + mutable int m_boundingBoxCacheTimeStamp; + mutable EDA_RECT m_cachedVisibleBBox; + mutable int m_visibleBBoxCacheTimeStamp; + mutable EDA_RECT m_cachedTextExcludedBBox; + mutable int m_textExcludedBBoxCacheTimeStamp; + mutable SHAPE_POLY_SET m_cachedHull; + mutable int m_hullCacheTimeStamp; ZONE_CONNECTION m_zoneConnection; int m_thermalWidth; diff --git a/pcbnew/footprint_edit_frame.cpp b/pcbnew/footprint_edit_frame.cpp index 47172e72bf..4278c5ed77 100644 --- a/pcbnew/footprint_edit_frame.cpp +++ b/pcbnew/footprint_edit_frame.cpp @@ -581,7 +581,7 @@ const BOX2I FOOTPRINT_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) if( hasGraphicalItem ) { - return footprint->GetFootprintRect(); + return footprint->GetBoundingBox( false, false ); } else { diff --git a/pcbnew/microwave/microwave_footprint.cpp b/pcbnew/microwave/microwave_footprint.cpp index e257678e9f..aadb35ccf1 100644 --- a/pcbnew/microwave/microwave_footprint.cpp +++ b/pcbnew/microwave/microwave_footprint.cpp @@ -175,7 +175,6 @@ FOOTPRINT* MICROWAVE_TOOL::createFootprint( MICROWAVE_FOOTPRINT_SHAPE aFootprint } // Update the footprint and board - footprint->CalculateBoundingBox(); editFrame.OnModify(); return footprint; diff --git a/pcbnew/microwave/microwave_inductor.cpp b/pcbnew/microwave/microwave_inductor.cpp index 770a2b805a..d16f3259b8 100644 --- a/pcbnew/microwave/microwave_inductor.cpp +++ b/pcbnew/microwave/microwave_inductor.cpp @@ -388,7 +388,9 @@ FOOTPRINT* MICROWAVE_TOOL::createMicrowaveInductor( MICROWAVE_INDUCTOR_PATTERN& // Calculate the elements. std::vector buffer; const INDUCTOR_S_SHAPE_RESULT res = BuildCornersList_S_Shape( buffer, aInductorPattern.m_Start, - aInductorPattern.m_End, aInductorPattern.m_Length, aInductorPattern.m_Width ); + aInductorPattern.m_End, + aInductorPattern.m_Length, + aInductorPattern.m_Width ); switch( res ) { @@ -471,6 +473,5 @@ FOOTPRINT* MICROWAVE_TOOL::createMicrowaveInductor( MICROWAVE_INDUCTOR_PATTERN& valPos.y += footprint->Value().GetTextSize().y; footprint->Value().SetPosition( valPos ); - footprint->CalculateBoundingBox(); return footprint; } diff --git a/pcbnew/microwave/microwave_polygon.cpp b/pcbnew/microwave/microwave_polygon.cpp index 7274ad2771..d8a6290c26 100644 --- a/pcbnew/microwave/microwave_polygon.cpp +++ b/pcbnew/microwave/microwave_polygon.cpp @@ -349,7 +349,6 @@ FOOTPRINT* MICROWAVE_TOOL::createPolygonShape() shape->SetWidth( 0 ); PolyEdges.clear(); - footprint->CalculateBoundingBox(); editFrame.OnModify(); return footprint; } diff --git a/pcbnew/pcb_base_frame.cpp b/pcbnew/pcb_base_frame.cpp index cc9ce8fa2a..511fae7542 100644 --- a/pcbnew/pcb_base_frame.cpp +++ b/pcbnew/pcb_base_frame.cpp @@ -691,6 +691,8 @@ void PCB_BASE_FRAME::OnModify() GetScreen()->SetModify(); GetScreen()->SetSave(); + GetBoard()->IncrementTimeStamp(); + UpdateStatusBar(); UpdateMsgPanel(); } diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index a7ecdb03ae..310c955bae 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -1448,7 +1448,7 @@ void PCB_PAINTER::draw( const FOOTPRINT* aFootprint, int aLayer ) #if 0 // For debug purpose only: draw the footing bounding box double bboxThickness = 1.0 / m_gal->GetWorldScale(); m_gal->SetLineWidth( bboxThickness ); - EDA_RECT rect = aFootprint->GetBoundingBoxBase(); + EDA_RECT rect = aFootprint->GetBoundingBox(); m_gal->DrawRectangle( VECTOR2D( rect.GetOrigin() ), VECTOR2D( rect.GetEnd() ) ); double bboxThickness = 3.0 / m_gal->GetWorldScale(); diff --git a/pcbnew/plugins/altium/altium_pcb.cpp b/pcbnew/plugins/altium/altium_pcb.cpp index 2788f61b93..0ce53eed60 100644 --- a/pcbnew/plugins/altium/altium_pcb.cpp +++ b/pcbnew/plugins/altium/altium_pcb.cpp @@ -471,13 +471,6 @@ void ALTIUM_PCB::Parse( const CFB::CompoundFileReader& aReader, m_board->GetDesignSettings().m_AuxOrigin += movementVector; m_board->GetDesignSettings().m_GridOrigin += movementVector; - // Finish Board by recalculating footprint boundingboxes - for( FOOTPRINT* footprint : m_board->Footprints() ) - { - footprint->CalculateBoundingBox(); - footprint->UpdateBoundingHull(); - } - // Otherwise we cannot save the imported board m_board->SetModified(); } diff --git a/pcbnew/plugins/eagle/eagle_plugin.cpp b/pcbnew/plugins/eagle/eagle_plugin.cpp index ef6f47798c..11f05e8351 100644 --- a/pcbnew/plugins/eagle/eagle_plugin.cpp +++ b/pcbnew/plugins/eagle/eagle_plugin.cpp @@ -1237,10 +1237,6 @@ void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements ) footprint->Reference().SetLocalCoord(); footprint->Value().SetLocalCoord(); - // Calculate the bounding boxes - footprint->CalculateBoundingBox(); - footprint->UpdateBoundingHull(); - // Get next element element = element->GetNext(); } diff --git a/pcbnew/plugins/fabmaster/fabmaster_plugin.cpp b/pcbnew/plugins/fabmaster/fabmaster_plugin.cpp index 75fd900d52..612d318fc9 100644 --- a/pcbnew/plugins/fabmaster/fabmaster_plugin.cpp +++ b/pcbnew/plugins/fabmaster/fabmaster_plugin.cpp @@ -24,7 +24,7 @@ /** * @file pcad_plugin.cpp - * @brief Pcbnew PLUGIN for FABMASTER ASCII *.txt/*.fab format. + * @brief Pcbnew PLUGIN for FABMASTER ASCII *.txt / *.fab format. */ #include "fabmaster_plugin.h" diff --git a/pcbnew/plugins/fabmaster/import_fabmaster.cpp b/pcbnew/plugins/fabmaster/import_fabmaster.cpp index 46867b97c7..3c5dd6eec4 100644 --- a/pcbnew/plugins/fabmaster/import_fabmaster.cpp +++ b/pcbnew/plugins/fabmaster/import_fabmaster.cpp @@ -2248,9 +2248,6 @@ bool FABMASTER::loadFootprints( BOARD* aBoard ) fp->Flip( fp->GetPosition(), true ); } - fp->CalculateBoundingBox(); - fp->UpdateBoundingHull(); - aBoard->Add( fp, ADD_MODE::APPEND ); } } diff --git a/pcbnew/plugins/geda/gpcb_plugin.cpp b/pcbnew/plugins/geda/gpcb_plugin.cpp index 073aa6c87c..a7d8ea02b0 100644 --- a/pcbnew/plugins/geda/gpcb_plugin.cpp +++ b/pcbnew/plugins/geda/gpcb_plugin.cpp @@ -687,9 +687,6 @@ FOOTPRINT* GPCB_FPL_CACHE::parseFOOTPRINT( LINE_READER* aLineReader ) } } - // Recalculate the bounding box - footprint->CalculateBoundingBox(); - footprint->UpdateBoundingHull(); return footprint.release(); } diff --git a/pcbnew/plugins/kicad/pcb_parser.cpp b/pcbnew/plugins/kicad/pcb_parser.cpp index 8554b2b272..7f39604ad8 100644 --- a/pcbnew/plugins/kicad/pcb_parser.cpp +++ b/pcbnew/plugins/kicad/pcb_parser.cpp @@ -3212,17 +3212,6 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments footprint->SetFPID( fpid ); footprint->SetProperties( properties ); - // We want to calculate the bounding box in most cases except if the advanced config is set - // and its a general footprint load. This improves debugging greatly under MSVC where full - // STL iterator debugging is present and loading a massive amount of footprints can lead to - // 2 minute load times. - if( !ADVANCED_CFG::GetCfg().m_SkipBoundingBoxOnFpLoad || m_board != nullptr - || reader->GetSource().Contains( "clipboard" ) ) - { - footprint->CalculateBoundingBox(); - footprint->UpdateBoundingHull(); - } - return footprint.release(); } diff --git a/pcbnew/plugins/legacy/legacy_plugin.cpp b/pcbnew/plugins/legacy/legacy_plugin.cpp index 561e5ae449..1bace4c7e8 100644 --- a/pcbnew/plugins/legacy/legacy_plugin.cpp +++ b/pcbnew/plugins/legacy/legacy_plugin.cpp @@ -1370,9 +1370,6 @@ void LEGACY_PLUGIN::loadFOOTPRINT( FOOTPRINT* aFootprint ) else if( TESTLINE( "$EndMODULE" ) ) { - aFootprint->CalculateBoundingBox(); - aFootprint->UpdateBoundingHull(); - return; // preferred exit } } diff --git a/pcbnew/plugins/pcad/pcb_footprint.cpp b/pcbnew/plugins/pcad/pcb_footprint.cpp index 3b8fc9e52a..0d95659e81 100644 --- a/pcbnew/plugins/pcad/pcb_footprint.cpp +++ b/pcbnew/plugins/pcad/pcb_footprint.cpp @@ -611,9 +611,6 @@ void PCB_FOOTPRINT::AddToBoard() if( m_FootprintItems[i]->m_objType == wxT( 'V' ) ) ((PCB_VIA*) m_FootprintItems[ i ] )->AddToFootprint( footprint, m_rotation, false ); } - - footprint->CalculateBoundingBox(); - footprint->UpdateBoundingHull(); } diff --git a/pcbnew/tools/pcb_grid_helper.cpp b/pcbnew/tools/pcb_grid_helper.cpp index f6370fae69..7efed4e32d 100644 --- a/pcbnew/tools/pcb_grid_helper.cpp +++ b/pcbnew/tools/pcb_grid_helper.cpp @@ -490,11 +490,11 @@ void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos addAnchor( position, ORIGIN | SNAPPABLE, footprint ); // Add the footprint center point if it is markedly different from the origin - VECTOR2I center = footprint->GetFootprintRect().Centre(); + VECTOR2I center = footprint->GetBoundingBox( false, false ).Centre(); VECTOR2I grid( GetGrid() ); if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() ) - addAnchor( footprint->GetFootprintRect().Centre(), ORIGIN | SNAPPABLE, footprint ); + addAnchor( center, ORIGIN | SNAPPABLE, footprint ); break; } diff --git a/pcbnew/tools/pcb_selection_tool.cpp b/pcbnew/tools/pcb_selection_tool.cpp index c14eb29a3a..d3df6d9efe 100644 --- a/pcbnew/tools/pcb_selection_tool.cpp +++ b/pcbnew/tools/pcb_selection_tool.cpp @@ -2282,7 +2282,7 @@ int PCB_SELECTION_TOOL::hitTestDistance( const wxPoint& aWhere, BOARD_ITEM* aIte case PCB_FOOTPRINT_T: { FOOTPRINT* footprint = static_cast( aItem ); - EDA_RECT bbox = footprint->GetFootprintRect(); + EDA_RECT bbox = footprint->GetBoundingBox( false, false ); footprint->GetBoundingHull().Collide( loc, aMaxDistance, &distance ); diff --git a/pcbnew/tools/placement_tool.cpp b/pcbnew/tools/placement_tool.cpp index 2147e0189c..b88e889e64 100644 --- a/pcbnew/tools/placement_tool.cpp +++ b/pcbnew/tools/placement_tool.cpp @@ -95,7 +95,8 @@ ALIGNMENT_RECTS GetBoundingBoxes( const T& aItems ) if( item->Type() == PCB_FOOTPRINT_T ) { FOOTPRINT* footprint = static_cast( item ); - rects.emplace_back( std::make_pair( boardItem, footprint->GetFootprintRect() ) ); + rects.emplace_back( std::make_pair( boardItem, + footprint->GetBoundingBox( false, false ) ) ); } else {