diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index dd9ae39d2a..c4ecdaabf3 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -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 ) diff --git a/pcbnew/pad.h b/pcbnew/pad.h index cd9087f314..751d7b588b 100644 --- a/pcbnew/pad.h +++ b/pcbnew/pad.h @@ -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. diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 9a10d573c1..d767127e35 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -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 );