Fix router clearance check for pads with different sizes on each layer
When using FRONT_INNER_BACK padstack mode on a 2-layer board, the router would incorrectly report clearance violations. This happened because syncPad() created an INNER_LAYERS SOLID with PNS_LAYER_RANGE(1, 0), which got swapped to (0, 1) by the constructor. This caused the SOLID to be indexed on both F_Cu and B_Cu, leading to incorrect collision checks that used the wrong pad size. Fixes https://gitlab.com/kicad/code/kicad/-/issues/20355
This commit is contained in:
@@ -1245,6 +1245,16 @@ std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPa
|
||||
auto makeSolidFromPadLayer =
|
||||
[&]( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
// For FRONT_INNER_BACK mode, skip creating a SOLID for inner layers when there are
|
||||
// no inner layers (2-layer board). Otherwise PNS_LAYER_RANGE(1, 0) would be swapped
|
||||
// to (0, 1) and indexed on both F_Cu and B_Cu, causing incorrect collision checks.
|
||||
if( aPad->Padstack().Mode() == PADSTACK::MODE::FRONT_INNER_BACK
|
||||
&& aLayer != F_Cu && aLayer != B_Cu
|
||||
&& aPad->BoardCopperLayerCount() <= 2 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
|
||||
|
||||
if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
|
||||
|
||||
@@ -25,15 +25,15 @@
|
||||
#include <settings/settings_manager.h>
|
||||
#include <optional>
|
||||
|
||||
#include <pcbnew/board.h>
|
||||
#include <pcbnew/pad.h>
|
||||
#include <pcbnew/pcb_track.h>
|
||||
#include <pcbnew/board.h>
|
||||
|
||||
#include <router/pns_item.h>
|
||||
#include <router/pns_kicad_iface.h>
|
||||
#include <router/pns_node.h>
|
||||
#include <router/pns_router.h>
|
||||
#include <router/pns_item.h>
|
||||
#include <router/pns_via.h>
|
||||
#include <router/pns_kicad_iface.h>
|
||||
|
||||
static bool isCopper( const PNS::ITEM* aItem )
|
||||
{
|
||||
@@ -505,3 +505,38 @@ BOOST_AUTO_TEST_CASE( PCBViaBackdrillCloneRetainsData )
|
||||
checkVia( *viaClone );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that PNS_LAYER_RANGE(1, 0) is swapped to (0, 1).
|
||||
*
|
||||
* This is a minimal regression test for https://gitlab.com/kicad/code/kicad/-/issues/20355
|
||||
* The actual fix is in pns_kicad_iface.cpp syncPad() which skips creating an
|
||||
* INNER_LAYERS SOLID on 2-layer boards. This test verifies the layer range behavior
|
||||
* that motivated the fix.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE( PNSLayerRangeSwapBehavior )
|
||||
{
|
||||
// On a 2-layer board with FRONT_INNER_BACK mode, BoardCopperLayerCount() returns 2.
|
||||
// The code would calculate PNS_LAYER_RANGE(1, 2 - 2) = PNS_LAYER_RANGE(1, 0)
|
||||
// Since start > end, the constructor swaps them to (0, 1), which would span
|
||||
// both F_Cu and B_Cu incorrectly.
|
||||
|
||||
PNS_LAYER_RANGE innerLayersRange2Layer( 1, 0 ); // What would happen on 2-layer board
|
||||
|
||||
// Verify the swap behavior that causes the bug
|
||||
BOOST_CHECK_EQUAL( innerLayersRange2Layer.Start(), 0 );
|
||||
BOOST_CHECK_EQUAL( innerLayersRange2Layer.End(), 1 );
|
||||
BOOST_CHECK( innerLayersRange2Layer.Overlaps( 0 ) ); // F_Cu
|
||||
BOOST_CHECK( innerLayersRange2Layer.Overlaps( 1 ) ); // B_Cu
|
||||
|
||||
// On a 4-layer board, inner layers are 1 and 2, so PNS_LAYER_RANGE(1, 4-2) = (1, 2)
|
||||
PNS_LAYER_RANGE innerLayersRange4Layer( 1, 2 ); // Correct for 4-layer board
|
||||
|
||||
BOOST_CHECK_EQUAL( innerLayersRange4Layer.Start(), 1 );
|
||||
BOOST_CHECK_EQUAL( innerLayersRange4Layer.End(), 2 );
|
||||
BOOST_CHECK( !innerLayersRange4Layer.Overlaps( 0 ) ); // F_Cu - should not overlap
|
||||
BOOST_CHECK( innerLayersRange4Layer.Overlaps( 1 ) ); // In1_Cu
|
||||
BOOST_CHECK( innerLayersRange4Layer.Overlaps( 2 ) ); // In2_Cu
|
||||
BOOST_CHECK( !innerLayersRange4Layer.Overlaps( 3 ) ); // B_Cu - should not overlap
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user