PNS: Allow width-caused DRC violations at start of route

Also fix an issue where DRC violations introduced by the
width change action could be committed in walk/shove mode.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14805
This commit is contained in:
Jon Evans 2023-05-25 23:10:00 -04:00
parent fbe185b99b
commit 942ee13cd1
5 changed files with 78 additions and 26 deletions

View File

@ -619,6 +619,7 @@ bool PNS_KICAD_IFACE_BASE::ImportSizes( PNS::SIZES_SETTINGS& aSizes, PNS::ITEM*
} }
aSizes.SetTrackWidth( trackWidth ); aSizes.SetTrackWidth( trackWidth );
aSizes.SetBoardMinTrackWidth( bds.m_TrackMinWidth );
aSizes.SetTrackWidthIsExplicit( !bds.m_UseConnectedTrackWidth || bds.m_TempOverrideTrackWidth ); aSizes.SetTrackWidthIsExplicit( !bds.m_UseConnectedTrackWidth || bds.m_TempOverrideTrackWidth );
int viaDiameter = bds.m_ViasMinSize; int viaDiameter = bds.m_ViasMinSize;

View File

@ -1156,6 +1156,16 @@ void LINE_PLACER::routeStep( const VECTOR2I& aP )
{ {
m_tail = prevTail; m_tail = prevTail;
m_head = prevHead; m_head = prevHead;
// If we fail to walk out of the initial point (no tail), instead of returning an empty
// line, return a zero-length line so that the user gets some feedback that routing is
// happening. This will get pruned later.
if( m_tail.PointCount() == 0 )
{
m_tail.Line().Append( m_p_start );
m_tail.Line().Append( m_p_start, true );
}
fail = true; fail = true;
} }
@ -1224,10 +1234,10 @@ bool LINE_PLACER::route( const VECTOR2I& aP )
{ {
routeStep( aP ); routeStep( aP );
if (!m_head.PointCount() ) if( !m_head.PointCount() )
return false; return false;
return m_head.CPoint(-1) == aP; return m_head.CPoint( -1 ) == aP;
} }
@ -1235,7 +1245,12 @@ const LINE LINE_PLACER::Trace() const
{ {
SHAPE_LINE_CHAIN l( m_tail.CLine() ); SHAPE_LINE_CHAIN l( m_tail.CLine() );
l.Append( m_head.CLine() ); l.Append( m_head.CLine() );
l.Simplify();
// Only simplify if we have more than two points, because if we have a zero-length seg as the
// only part of the trace, we don't want it to be removed at this stage (will be the case if
// the routing start point violates DRC due to track width in shove/walk mode, for example).
if( l.PointCount() > 2 )
l.Simplify();
LINE tmp( m_head ); LINE tmp( m_head );
@ -1515,12 +1530,14 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis
aEndItem->SetNet( m_currentNet ); aEndItem->SetNet( m_currentNet );
} }
} }
// Collisions still prevent fixing unless "Allow DRC violations" is checked
if( !Settings().AllowDRCViolations() && m_world->CheckColliding( &pl ) )
return false;
} }
// Collisions still prevent fixing unless "Allow DRC violations" is checked
// Note that collisions can occur even in walk/shove modes if the beginning of the trace
// collides (for example if the starting track width is too high)
if( !Settings().AllowDRCViolations() && m_world->CheckColliding( &pl ) )
return false;
const SHAPE_LINE_CHAIN& l = pl.CLine(); const SHAPE_LINE_CHAIN& l = pl.CLine();
if( !l.SegmentCount() ) if( !l.SegmentCount() )

View File

@ -318,16 +318,23 @@ bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem,
if( m_world->CheckColliding( &dummyStartLine, ITEM::ANY_T ) ) if( m_world->CheckColliding( &dummyStartLine, ITEM::ANY_T ) )
{ {
ITEM_SET dummyStartSet( &dummyStartLine ); // If the only reason we collide is track width; it's better to allow the user to start
NODE::ITEM_VECTOR highlightedItems; // anyway and just highlight the resulting collisions, so they can change width later.
dummyStartLine.SetWidth( m_sizes.BoardMinTrackWidth() );
markViolations( m_world.get(), dummyStartSet, highlightedItems ); if( m_world->CheckColliding( &dummyStartLine, ITEM::ANY_T ) )
{
ITEM_SET dummyStartSet( &dummyStartLine );
NODE::ITEM_VECTOR highlightedItems;
for( ITEM* item : highlightedItems ) markViolations( m_world.get(), dummyStartSet, highlightedItems );
m_iface->HideItem( item );
SetFailureReason( _( "The routing start point violates DRC." ) ); for( ITEM* item : highlightedItems )
return false; m_iface->HideItem( item );
SetFailureReason( _( "The routing start point violates DRC." ) );
return false;
}
} }
} }
else if( m_mode == PNS_MODE_ROUTE_DIFF_PAIR ) else if( m_mode == PNS_MODE_ROUTE_DIFF_PAIR )
@ -372,18 +379,27 @@ bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem,
if( m_world->CheckColliding( &dummyStartLineA, ITEM::ANY_T ) if( m_world->CheckColliding( &dummyStartLineA, ITEM::ANY_T )
|| m_world->CheckColliding( &dummyStartLineB, ITEM::ANY_T ) ) || m_world->CheckColliding( &dummyStartLineB, ITEM::ANY_T ) )
{ {
ITEM_SET dummyStartSet; // If the only reason we collide is track width; it's better to allow the user to start
NODE::ITEM_VECTOR highlightedItems; // anyway and just highlight the resulting collisions, so they can change width later.
dummyStartLineA.SetWidth( m_sizes.BoardMinTrackWidth() );
dummyStartLineB.SetWidth( m_sizes.BoardMinTrackWidth() );
dummyStartSet.Add( dummyStartLineA ); if( m_world->CheckColliding( &dummyStartLineA, ITEM::ANY_T )
dummyStartSet.Add( dummyStartLineB ); || m_world->CheckColliding( &dummyStartLineB, ITEM::ANY_T ) )
markViolations( m_world.get(), dummyStartSet, highlightedItems ); {
ITEM_SET dummyStartSet;
NODE::ITEM_VECTOR highlightedItems;
for( ITEM* item : highlightedItems ) dummyStartSet.Add( dummyStartLineA );
m_iface->HideItem( item ); dummyStartSet.Add( dummyStartLineB );
markViolations( m_world.get(), dummyStartSet, highlightedItems );
SetFailureReason( _( "The routing start point violates DRC." ) ); for( ITEM* item : highlightedItems )
return false; m_iface->HideItem( item );
SetFailureReason( _( "The routing start point violates DRC." ) );
return false;
}
} }
} }
@ -696,8 +712,7 @@ void ROUTER::updateView( NODE* aNode, ITEM_SET& aCurrent, bool aDragging )
if( !aNode ) if( !aNode )
return; return;
if( Settings().Mode() == RM_MarkObstacles || m_forceMarkObstaclesMode ) markViolations( aNode, aCurrent, removed );
markViolations( aNode, aCurrent, removed );
aNode->GetUpdatedItems( removed, added ); aNode->GetUpdatedItems( removed, added );

View File

@ -73,6 +73,9 @@ public:
bool TrackWidthIsExplicit() const { return m_trackWidthIsExplicit; } bool TrackWidthIsExplicit() const { return m_trackWidthIsExplicit; }
void SetTrackWidthIsExplicit( bool aIsExplicit ) { m_trackWidthIsExplicit = aIsExplicit; } void SetTrackWidthIsExplicit( bool aIsExplicit ) { m_trackWidthIsExplicit = aIsExplicit; }
int BoardMinTrackWidth() const { return m_boardMinTrackWidth; }
void SetBoardMinTrackWidth( int aWidth ) { m_boardMinTrackWidth = aWidth; }
int DiffPairWidth() const { return m_diffPairWidth; } int DiffPairWidth() const { return m_diffPairWidth; }
int DiffPairGap() const { return m_diffPairGap; } int DiffPairGap() const { return m_diffPairGap; }
@ -135,6 +138,7 @@ private:
int m_minClearance; int m_minClearance;
int m_trackWidth; int m_trackWidth;
bool m_trackWidthIsExplicit; bool m_trackWidthIsExplicit;
int m_boardMinTrackWidth;
VIATYPE m_viaType; VIATYPE m_viaType;
int m_viaDiameter; int m_viaDiameter;

View File

@ -214,7 +214,22 @@ void ROUTER_PREVIEW_ITEM::drawLineChain( const SHAPE_LINE_CHAIN_BASE* aL, KIGFX:
gal->SetIsFill( false ); gal->SetIsFill( false );
for( int s = 0; s < aL->GetSegmentCount(); s++ ) for( int s = 0; s < aL->GetSegmentCount(); s++ )
gal->DrawLine( aL->GetSegment( s ).A, aL->GetSegment( s ).B ); {
SEG seg = aL->GetSegment( s );
if( seg.A == seg.B )
{
gal->SetIsFill( true );
gal->SetIsStroke( false );
gal->DrawCircle( seg.A, gal->GetLineWidth() / 2 );
gal->SetIsFill( false );
gal->SetIsStroke( true );
}
else
{
gal->DrawLine( seg.A, seg.B );
}
}
const SHAPE_LINE_CHAIN* lineChain = dynamic_cast<const SHAPE_LINE_CHAIN*>( aL ); const SHAPE_LINE_CHAIN* lineChain = dynamic_cast<const SHAPE_LINE_CHAIN*>( aL );