Don't use approximated shapes for router hulls.

We only do 45-degree routing anyway so we might as well build an
octagonal-based hull from the get-go.

Fixes https://gitlab.com/kicad/code/kicad/issues/7672

Fixes https://gitlab.com/kicad/code/kicad/issues/9544

Fixes https://gitlab.com/kicad/code/kicad/issues/9833
This commit is contained in:
Jeff Young 2021-12-01 19:43:10 +00:00
parent 09ed60feb3
commit 3c0b10b022
3 changed files with 39 additions and 44 deletions

View File

@ -1116,9 +1116,7 @@ int BOARD_DESIGN_SETTINGS::GetLayerClass( PCB_LAYER_ID aLayer ) const
int BOARD_DESIGN_SETTINGS::GetDRCEpsilon() const int BOARD_DESIGN_SETTINGS::GetDRCEpsilon() const
{ {
// You can loosen the max epsilon manually but we cap it at the board's inherent return Millimeter2iu( ADVANCED_CFG::GetCfg().m_DRCEpsilon );
// accuracy given by the maximum error when approximating curves
return std::max( m_MaxError, Millimeter2iu( ADVANCED_CFG::GetCfg().m_DRCEpsilon ) );
} }

View File

@ -953,36 +953,18 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
solid->SetHole( slot ); solid->SetHole( slot );
} }
auto shapes = std::dynamic_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() ); std::shared_ptr<SHAPE> shape = aPad->GetEffectiveShape();
if( shapes && shapes->Size() == 1 ) if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 )
{ {
solid->SetShape( shapes->Shapes()[0]->Clone() ); std::vector<SHAPE*> subshapes;
shape->GetIndexableSubshapes( subshapes );
solid->SetShape( subshapes[0]->Clone() );
} }
else else
{ {
// TODO: Support PNS hull generation for compound shapes and use the actual shape here solid->SetShape( shape->Clone() );
// NOTE: Because PNS hulls can't handle compound shapes yet, there will always be a
// discrepancy between the PNS and the DRC engine in some cases (such as custom shape pads
// that use polygons with nonzero width). No matter where you put the error, this causes
// issues, but the "lesser evil" is to allow routing in more cases (and have DRC errors that
// need to be cleaned up) vs. having situations that are valid to DRC but can't be routed
// because the extra error outside the pad is a clearance violation to the router.
//
// See https://gitlab.com/kicad/code/kicad/-/issues/9544
// and https://gitlab.com/kicad/code/kicad/-/issues/7672
SHAPE_POLY_SET outline;
aPad->TransformShapeWithClearanceToPolygon( outline, UNDEFINED_LAYER, 0, ARC_HIGH_DEF,
ERROR_INSIDE );
SHAPE_SIMPLE* shape = new SHAPE_SIMPLE();
for( auto iter = outline.CIterate( 0 ); iter; iter++ )
shape->Append( *iter );
solid->SetShape( shape );
} }
return solid; return solid;
@ -1434,30 +1416,30 @@ void PNS_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aClearance, bool
ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, m_view ); ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, m_view );
static KICAD_T tracksOrVias[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, EOT };
static KICAD_T tracks[] = { PCB_TRACE_T, PCB_ARC_T, EOT };
if( aClearance >= 0 ) if( aClearance >= 0 )
{ {
pitem->SetClearance( aClearance ); pitem->SetClearance( aClearance );
switch( m_dispOptions->m_ShowTrackClearanceMode ) switch( m_dispOptions->m_ShowTrackClearanceMode )
{ {
case PCB_DISPLAY_OPTIONS::DO_NOT_SHOW_CLEARANCE:
pitem->ShowTrackClearance( false );
pitem->ShowViaClearance( false );
break;
case PCB_DISPLAY_OPTIONS::SHOW_TRACK_CLEARANCE_WITH_VIA_ALWAYS: case PCB_DISPLAY_OPTIONS::SHOW_TRACK_CLEARANCE_WITH_VIA_ALWAYS:
case PCB_DISPLAY_OPTIONS::SHOW_WHILE_ROUTING_OR_DRAGGING: case PCB_DISPLAY_OPTIONS::SHOW_WHILE_ROUTING_OR_DRAGGING:
pitem->ShowTrackClearance( true ); pitem->ShowClearance( pitem->GetParent()->IsType( tracksOrVias ) );
pitem->ShowViaClearance( true );
break; break;
case PCB_DISPLAY_OPTIONS::SHOW_TRACK_CLEARANCE_WITH_VIA_WHILE_ROUTING: case PCB_DISPLAY_OPTIONS::SHOW_TRACK_CLEARANCE_WITH_VIA_WHILE_ROUTING:
pitem->ShowTrackClearance( !aEdit ); pitem->ShowClearance( pitem->GetParent()->IsType( tracksOrVias ) && !aEdit );
pitem->ShowViaClearance( !aEdit );
break; break;
case PCB_DISPLAY_OPTIONS::SHOW_TRACK_CLEARANCE_WHILE_ROUTING: case PCB_DISPLAY_OPTIONS::SHOW_TRACK_CLEARANCE_WHILE_ROUTING:
pitem->ShowTrackClearance( !aEdit ); pitem->ShowClearance( pitem->GetParent()->IsType( tracks ) && !aEdit );
pitem->ShowViaClearance( false ); break;
default:
pitem->ShowClearance( false );
break; break;
} }
} }

View File

@ -27,6 +27,7 @@
#include <geometry/shape_circle.h> #include <geometry/shape_circle.h>
#include <geometry/shape_simple.h> #include <geometry/shape_simple.h>
#include <geometry/shape_compound.h> #include <geometry/shape_compound.h>
#include <geometry/shape_poly_set.h>
#include <wx/log.h> #include <wx/log.h>
@ -112,9 +113,16 @@ const SHAPE_LINE_CHAIN SOLID::Hull( int aClearance, int aWalkaroundThickness, in
} }
else else
{ {
// fixme - shouldn't happen but one day we should move SHAPE_POLY_SET hullSet;
// TransformShapeWithClearanceToPolygon() to the Geometry Library
return SHAPE_LINE_CHAIN(); for( SHAPE* shape : cmpnd->Shapes() )
{
hullSet.AddOutline( buildHullForPrimitiveShape( shape, aClearance,
aWalkaroundThickness ) );
}
hullSet.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
return hullSet.Outline( 0 );
} }
} }
else else
@ -140,9 +148,16 @@ const SHAPE_LINE_CHAIN SOLID::HoleHull( int aClearance, int aWalkaroundThickness
} }
else else
{ {
// fixme - shouldn't happen but one day we should move SHAPE_POLY_SET hullSet;
// TransformShapeWithClearanceToPolygon() to the Geometry Library
return SHAPE_LINE_CHAIN(); for( SHAPE* shape : cmpnd->Shapes() )
{
hullSet.AddOutline( buildHullForPrimitiveShape( shape, aClearance,
aWalkaroundThickness ) );
}
hullSet.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
return hullSet.Outline( 0 );
} }
} }
else else