Lazy-allocate a few pad and padstack things

This commit is contained in:
Jon Evans
2026-03-09 18:10:50 -04:00
parent 755280dec1
commit ac8f0096ce
4 changed files with 92 additions and 36 deletions
+40 -18
View File
@@ -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<SHAPE_POLY_SET>& 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<SHAPE> 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<SHAPE_SEGMENT> 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<PAD_DRAW_CACHE_DATA>();
return *m_drawCache;
}
void PAD::BuildEffectiveShapes() const
{
std::lock_guard<std::mutex> 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<SHAPE_SEGMENT>( m_pos - half_len, m_pos + half_len,
half_width * 2 );
m_effectiveBoundingBox.Merge( m_effectiveHoleShape->BBox() );
drawCache.m_effectiveHoleShape = std::make_shared<SHAPE_SEGMENT>( 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<SHAPE_COMPOUND>();
PAD_DRAW_CACHE_DATA& drawCache = getDrawCache();
drawCache.m_effectiveShapes[aLayer] = std::make_shared<SHAPE_COMPOUND>();
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<SHAPE_POLY_SET>& effectivePolygon = m_effectivePolygons[ aLayer ][ aErrorLoc ];
std::shared_ptr<SHAPE_POLY_SET>& effectivePolygon =
drawCache.m_effectivePolygons[ aLayer ][ aErrorLoc ];
effectivePolygon = std::make_shared<SHAPE_POLY_SET>();
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<SHAPE_POLY_SET>& effectivePolygon = m_effectivePolygons[ aLayer ][ aErrorLoc ];
std::shared_ptr<SHAPE_POLY_SET>& 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;
}
+16 -11
View File
@@ -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<PCB_LAYER_ID, std::shared_ptr<SHAPE_COMPOUND>> LAYER_SHAPE_MAP;
typedef std::map<PCB_LAYER_ID, std::array<std::shared_ptr<SHAPE_POLY_SET>, 2>> LAYER_POLYGON_MAP;
BOX2I m_effectiveBoundingBox;
LAYER_SHAPE_MAP m_effectiveShapes;
std::shared_ptr<SHAPE_SEGMENT> 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<void( int aErrorCode, const wxString& aMsg )>& 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<PCB_LAYER_ID, std::shared_ptr<SHAPE_COMPOUND>> LAYER_SHAPE_MAP;
mutable BOX2I m_effectiveBoundingBox;
mutable LAYER_SHAPE_MAP m_effectiveShapes;
mutable std::shared_ptr<SHAPE_SEGMENT> m_effectiveHoleShape;
typedef std::map<PCB_LAYER_ID, std::array<std::shared_ptr<SHAPE_POLY_SET>, 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<PAD_DRAW_CACHE_DATA> m_drawCache;
mutable int m_effectiveBoundingRadius;
+32 -6
View File
@@ -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<wxString>( aCustomName );
}
}
@@ -1758,4 +1784,4 @@ int PADSTACK::POST_MACHINING_PROPS::Compare( const PADSTACK::POST_MACHINING_PROP
void PADSTACK::SetMode( MODE aMode )
{
m_mode = aMode;
}
}
+4 -1
View File
@@ -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<wxString> m_customName;
///! The rotation of the pad relative to an outer reference frame
EDA_ANGLE m_orientation;