Fix thermal spokes for pad stacks.

This commit is contained in:
Jeff Young 2025-04-04 20:35:42 +01:00
parent 82f94e9185
commit 2c9c607b95
3 changed files with 34 additions and 22 deletions

View File

@ -855,6 +855,13 @@ const BOX2I PAD::GetBoundingBox() const
}
// Thermal spokes are built on the bounding box, so we must have a layer-specific version
const BOX2I PAD::GetBoundingBox( PCB_LAYER_ID aLayer ) const
{
return buildEffectiveShape( aLayer ).BBox();
}
void PAD::SetAttribute( PAD_ATTRIB aAttribute )
{
if( m_attribute != aAttribute )

View File

@ -840,6 +840,7 @@ public:
* The bounding box is cached, so this will be efficient most of the time.
*/
const BOX2I GetBoundingBox() const override;
const BOX2I GetBoundingBox( PCB_LAYER_ID aLayer ) const;
/**
* Compare two pads and return 0 if they are equal.

View File

@ -2122,23 +2122,25 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE* aZone, PCB_LAYER_ID aLayer,
VECTOR2I half_size( box.GetWidth() / 2, box.GetHeight() / 2 );
// Function to find intersection of line with box edge
auto intersectLineBox = [&](const VECTOR2D& direction) -> VECTOR2I {
double dx = direction.x;
double dy = direction.y;
auto intersectLineBox =
[&](const VECTOR2D& direction) -> VECTOR2I
{
double dx = direction.x;
double dy = direction.y;
// Short-circuit the axis cases because they will be degenerate in the
// intersection test
if( direction.x == 0 )
return VECTOR2I( 0, dy * half_size.y );
else if( direction.y == 0 )
return VECTOR2I( dx * half_size.x, 0 );
// Short-circuit the axis cases because they will be degenerate in the
// intersection test
if( direction.x == 0 )
return VECTOR2I( 0, dy * half_size.y );
else if( direction.y == 0 )
return VECTOR2I( dx * half_size.x, 0 );
// We are going to intersect with one side or the other. Whichever
// we hit first is the fraction of the spoke length we keep
double tx = std::min( half_size.x / std::abs( dx ),
half_size.y / std::abs( dy ) );
return VECTOR2I( dx * tx, dy * tx );
};
// We are going to intersect with one side or the other. Whichever
// we hit first is the fraction of the spoke length we keep
double tx = std::min( half_size.x / std::abs( dx ),
half_size.y / std::abs( dy ) );
return VECTOR2I( dx * tx, dy * tx );
};
// Precalculate angles for four cardinal directions
const EDA_ANGLE angles[4] = {
@ -2216,9 +2218,8 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE* aZone, PCB_LAYER_ID aLayer,
{
// Do not create this spoke if neither point is in the pad.
if( !pad->GetEffectivePolygon( aLayer, ERROR_OUTSIDE )->Contains( seg.B ) )
{
continue;
}
seg.Reverse();
}
@ -2228,13 +2229,16 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE* aZone, PCB_LAYER_ID aLayer,
{
VECTOR2I direction = ( seg.B - seg.A ).Resize( spoke_half_w );
VECTOR2I offset = direction.Perpendicular().Resize( spoke_half_w );
// Extend the spoke edges by half the spoke width to capture convex pad shapes with a maximum of 45 degrees.
// Extend the spoke edges by half the spoke width to capture convex pad shapes
// with a maximum of 45 degrees.
SEG segL( seg.A - direction - offset, seg.B + direction - offset );
SEG segR( seg.A - direction + offset, seg.B + direction + offset );
// Only create this spoke if both edges intersect the pad and thermal outline
if( trimToOutline( segL ) && trimToOutline( segR ) )
{
// Extend the spoke by the minimum thickness for the zone to ensure full connection width
// Extend the spoke by the minimum thickness for the zone to ensure full
// connection width
direction = direction.Resize( aZone->GetMinThickness() );
SHAPE_LINE_CHAIN spoke;
@ -2265,7 +2269,8 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE* aZone, PCB_LAYER_ID aLayer,
dummy_pad.SetPosition( VECTOR2I( 0, 0 ) );
dummy_pad.SetOffset( aLayer, VECTOR2I( 0, 0 ) );
BOX2I spokesBox = dummy_pad.GetBoundingBox();
BOX2I spokesBox = dummy_pad.GetBoundingBox( aLayer );
VECTOR2I padSize = pad->GetSize( aLayer );
// Add the half width of the zone mininum width to the inflate amount to account for
// the fact that the deflation procedure will shrink the results by half the half the
@ -2276,8 +2281,7 @@ void ZONE_FILLER::buildThermalSpokes( const ZONE* aZone, PCB_LAYER_ID aLayer,
// when rotated at 45 degrees. So we just build spokes at 0 degrees and rotate
// them later.
if( pad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE
|| ( pad->GetShape( aLayer ) == PAD_SHAPE::OVAL
&& pad->GetSizeX() == pad->GetSizeY() ) )
|| ( pad->GetShape( aLayer ) == PAD_SHAPE::OVAL && padSize.x == padSize.y ) )
{
buildSpokesFromOrigin( spokesBox, ANGLE_0 );