From ac8f0096ced9580c0aaeb628fcd6fe3d512e1e65 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Mon, 9 Mar 2026 18:10:50 -0400 Subject: [PATCH] Lazy-allocate a few pad and padstack things --- pcbnew/pad.cpp | 58 +++++++++++++++++++++++++++++++-------------- pcbnew/pad.h | 27 ++++++++++++--------- pcbnew/padstack.cpp | 38 ++++++++++++++++++++++++----- pcbnew/padstack.h | 5 +++- 4 files changed, 92 insertions(+), 36 deletions(-) diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index 589d29caeb..44056d348d 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -114,7 +114,6 @@ PAD::PAD( FOOTPRINT* parent ) : for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, BoardCopperLayerCount() ) ) m_zoneLayerOverrides[layer] = ZLO_NONE; - m_lastGalZoomLevel = 0.0; } @@ -954,7 +953,9 @@ const std::shared_ptr& PAD::GetEffectivePolygon( PCB_LAYER_ID aL aLayer = Padstack().EffectiveLayerFor( aLayer ); - return m_effectivePolygons[ aLayer ][ aErrorLoc ]; + const PAD_DRAW_CACHE_DATA& drawCache = getDrawCache(); + + return drawCache.m_effectivePolygons.at( aLayer )[ aErrorLoc ]; } @@ -1049,14 +1050,16 @@ std::shared_ptr PAD::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING fla aLayer = Padstack().EffectiveLayerFor( aLayer ); - wxCHECK_MSG( m_effectiveShapes.contains( aLayer ), nullptr, + const PAD_DRAW_CACHE_DATA& drawCache = getDrawCache(); + + wxCHECK_MSG( drawCache.m_effectiveShapes.contains( aLayer ), nullptr, wxString::Format( wxT( "Missing shape in PAD::GetEffectiveShape for layer %s." ), magic_enum::enum_name( aLayer ) ) ); - wxCHECK_MSG( m_effectiveShapes.at( aLayer ), nullptr, + wxCHECK_MSG( drawCache.m_effectiveShapes.at( aLayer ), nullptr, wxString::Format( wxT( "Null shape in PAD::GetEffectiveShape for layer %s." ), magic_enum::enum_name( aLayer ) ) ); - return m_effectiveShapes[aLayer]; + return drawCache.m_effectiveShapes.at( aLayer ); } @@ -1065,7 +1068,7 @@ std::shared_ptr PAD::GetEffectiveHoleShape() const if( m_shapesDirty ) BuildEffectiveShapes(); - return m_effectiveHoleShape; + return getDrawCache().m_effectiveHoleShape; } @@ -1078,6 +1081,15 @@ int PAD::GetBoundingRadius() const } +PAD::PAD_DRAW_CACHE_DATA& PAD::getDrawCache() const +{ + if( !m_drawCache ) + m_drawCache = std::make_unique(); + + return *m_drawCache; +} + + void PAD::BuildEffectiveShapes() const { std::lock_guard RAII_lock( m_dataMutex ); @@ -1087,17 +1099,20 @@ void PAD::BuildEffectiveShapes() const if( !m_shapesDirty ) return; - m_effectiveBoundingBox = BOX2I(); + PAD_DRAW_CACHE_DATA& drawCache = getDrawCache(); + + drawCache.m_effectiveBoundingBox = BOX2I(); + drawCache.m_effectiveShapes.clear(); Padstack().ForEachUniqueLayer( [&]( PCB_LAYER_ID aLayer ) { const SHAPE_COMPOUND& layerShape = buildEffectiveShape( aLayer ); - m_effectiveBoundingBox.Merge( layerShape.BBox() ); + drawCache.m_effectiveBoundingBox.Merge( layerShape.BBox() ); } ); // Hole shape - m_effectiveHoleShape = nullptr; + drawCache.m_effectiveHoleShape = nullptr; VECTOR2I half_size = m_padStack.Drill().size / 2; int half_width; @@ -1115,9 +1130,10 @@ void PAD::BuildEffectiveShapes() const RotatePoint( half_len, GetOrientation() ); - m_effectiveHoleShape = std::make_shared( m_pos - half_len, m_pos + half_len, - half_width * 2 ); - m_effectiveBoundingBox.Merge( m_effectiveHoleShape->BBox() ); + drawCache.m_effectiveHoleShape = std::make_shared( m_pos - half_len, + m_pos + half_len, + half_width * 2 ); + drawCache.m_effectiveBoundingBox.Merge( drawCache.m_effectiveHoleShape->BBox() ); // All done m_shapesDirty = false; @@ -1126,11 +1142,13 @@ void PAD::BuildEffectiveShapes() const const SHAPE_COMPOUND& PAD::buildEffectiveShape( PCB_LAYER_ID aLayer ) const { - m_effectiveShapes[aLayer] = std::make_shared(); + PAD_DRAW_CACHE_DATA& drawCache = getDrawCache(); + + drawCache.m_effectiveShapes[aLayer] = std::make_shared(); auto add = [this, aLayer]( SHAPE* aShape ) { - m_effectiveShapes[aLayer]->AddShape( aShape ); + getDrawCache().m_effectiveShapes[aLayer]->AddShape( aShape ); }; VECTOR2I shapePos = ShapePos( aLayer ); // Fetch only once; rotation involves trig @@ -1273,7 +1291,7 @@ const SHAPE_COMPOUND& PAD::buildEffectiveShape( PCB_LAYER_ID aLayer ) const } } - return *m_effectiveShapes[aLayer]; + return *drawCache.m_effectiveShapes[aLayer]; } @@ -1289,11 +1307,14 @@ void PAD::BuildEffectivePolygon( ERROR_LOC aErrorLoc ) const if( !m_polyDirty[ aErrorLoc ] ) return; + PAD_DRAW_CACHE_DATA& drawCache = getDrawCache(); + Padstack().ForEachUniqueLayer( [&]( PCB_LAYER_ID aLayer ) { // Polygon - std::shared_ptr& effectivePolygon = m_effectivePolygons[ aLayer ][ aErrorLoc ]; + std::shared_ptr& effectivePolygon = + drawCache.m_effectivePolygons[ aLayer ][ aErrorLoc ]; effectivePolygon = std::make_shared(); TransformShapeToPolygon( *effectivePolygon, aLayer, 0, GetMaxError(), aErrorLoc ); @@ -1306,7 +1327,8 @@ void PAD::BuildEffectivePolygon( ERROR_LOC aErrorLoc ) const Padstack().ForEachUniqueLayer( [&]( PCB_LAYER_ID aLayer ) { - std::shared_ptr& effectivePolygon = m_effectivePolygons[ aLayer ][ aErrorLoc ]; + std::shared_ptr& effectivePolygon = + drawCache.m_effectivePolygons[ aLayer ][ aErrorLoc ]; for( int cnt = 0; cnt < effectivePolygon->OutlineCount(); ++cnt ) { @@ -1334,7 +1356,7 @@ const BOX2I PAD::GetBoundingBox() const if( m_shapesDirty ) BuildEffectiveShapes(); - return m_effectiveBoundingBox; + return getDrawCache().m_effectiveBoundingBox; } diff --git a/pcbnew/pad.h b/pcbnew/pad.h index 355a708df5..41b1799299 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -1070,6 +1070,21 @@ protected: private: const SHAPE_COMPOUND& buildEffectiveShape( PCB_LAYER_ID aLayer ) const; + struct PAD_DRAW_CACHE_DATA + { + // Must be set to true to force rebuild shapes to draw (after geometry change for instance) + typedef std::map> LAYER_SHAPE_MAP; + typedef std::map, 2>> LAYER_POLYGON_MAP; + + BOX2I m_effectiveBoundingBox; + LAYER_SHAPE_MAP m_effectiveShapes; + std::shared_ptr m_effectiveHoleShape; + LAYER_POLYGON_MAP m_effectivePolygons; + double m_lastGalZoomLevel = 0.0; + }; + + PAD_DRAW_CACHE_DATA& getDrawCache() const; + void doCheckPad( PCB_LAYER_ID aLayer, UNITS_PROVIDER* aUnitsProvider, bool aForPadProperties, const std::function& aErrorHandler ) const; @@ -1085,17 +1100,7 @@ private: // Mutex for shape building, poly building and zone layer overrides mutable std::mutex m_dataMutex; - // Must be set to true to force rebuild shapes to draw (after geometry change for instance) - typedef std::map> LAYER_SHAPE_MAP; - mutable BOX2I m_effectiveBoundingBox; - mutable LAYER_SHAPE_MAP m_effectiveShapes; - mutable std::shared_ptr m_effectiveHoleShape; - - typedef std::map, 2>> LAYER_POLYGON_MAP; - mutable LAYER_POLYGON_MAP m_effectivePolygons; - // Last zoom level used to draw the pad: the LAYER_PAD_HOLEWALLS layer shape - // depend on the zoom level. So keep trace on the last used zoom level - mutable double m_lastGalZoomLevel; + mutable std::unique_ptr m_drawCache; mutable int m_effectiveBoundingRadius; diff --git a/pcbnew/padstack.cpp b/pcbnew/padstack.cpp index 87aeae6c4a..fca75fe87a 100644 --- a/pcbnew/padstack.cpp +++ b/pcbnew/padstack.cpp @@ -88,7 +88,7 @@ PADSTACK& PADSTACK::operator=( const PADSTACK &aOther ) m_mode = aOther.m_mode; m_layerSet = aOther.m_layerSet; - m_customName = aOther.m_customName; + SetCustomName( aOther.CustomName() ); m_orientation = aOther.m_orientation; m_copperProps = aOther.m_copperProps; m_frontMaskProps = aOther.m_frontMaskProps; @@ -136,7 +136,7 @@ bool PADSTACK::operator==( const PADSTACK& aOther ) const if( m_layerSet != aOther.m_layerSet ) return false; - if( m_customName != aOther.m_customName ) + if( CustomName() != aOther.CustomName() ) return false; if( m_orientation != aOther.m_orientation ) @@ -1378,7 +1378,7 @@ int PADSTACK::Compare( const PADSTACK* aLeft, const PADSTACK* aRight ) if( aLeft->m_layerSet != aRight->m_layerSet ) return aLeft->m_layerSet.Seq() < aRight->m_layerSet.Seq(); - if( ( diff = aLeft->m_customName.Cmp( aRight->m_customName ) ) != 0 ) + if( ( diff = wxString( aLeft->CustomName() ).Cmp( aRight->CustomName() ) ) != 0 ) return diff; TEST( aLeft->m_orientation.AsTenthsOfADegree(), aRight->m_orientation.AsTenthsOfADegree() ); @@ -1439,7 +1439,7 @@ double PADSTACK::Similarity( const PADSTACK& aOther ) const if( m_layerSet != aOther.m_layerSet ) similarity *= 0.9; - if( m_customName != aOther.m_customName ) + if( CustomName() != aOther.CustomName() ) similarity *= 0.9; if( m_orientation != aOther.m_orientation ) @@ -1531,7 +1531,33 @@ PCB_LAYER_ID PADSTACK::EndLayer() const wxString PADSTACK::Name() const { - return m_customName; + return CustomName(); +} + + +const wxChar* PADSTACK::CustomName() const +{ + if( m_customName ) + return *m_customName; + + return wxEmptyString; +} + + +void PADSTACK::SetCustomName( const wxString& aCustomName ) +{ + if( aCustomName.IsEmpty() ) + { + m_customName.reset(); + } + else if( m_customName ) + { + *m_customName = aCustomName; + } + else + { + m_customName = std::make_unique( aCustomName ); + } } @@ -1758,4 +1784,4 @@ int PADSTACK::POST_MACHINING_PROPS::Compare( const PADSTACK::POST_MACHINING_PROP void PADSTACK::SetMode( MODE aMode ) { m_mode = aMode; -} \ No newline at end of file +} diff --git a/pcbnew/padstack.h b/pcbnew/padstack.h index c5c19a5887..24d528ef21 100644 --- a/pcbnew/padstack.h +++ b/pcbnew/padstack.h @@ -338,6 +338,9 @@ public: ///! Returns the name of this padstack in IPC-7351 format wxString Name() const; + const wxChar* CustomName() const; + void SetCustomName( const wxString& aCustomName ); + EDA_ANGLE GetOrientation() const { return m_orientation; } void SetOrientation( EDA_ANGLE aAngle ) { @@ -531,7 +534,7 @@ private: LSET m_layerSet; ///! An override for the IPC-7351 padstack name - wxString m_customName; + std::unique_ptr m_customName; ///! The rotation of the pad relative to an outer reference frame EDA_ANGLE m_orientation;