Improve feedback when routing in highlight collisions mode.

In particular, when Allow DRC violations is NOT turned on and we
bump in to an obstacle.
This commit is contained in:
Jeff Young 2021-01-01 17:17:55 +00:00
parent 44b2c907c6
commit fc1b0ec11f
8 changed files with 57 additions and 126 deletions

View File

@ -60,13 +60,13 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
if( holeA && holeA->Collide( shapeB, holeClearance + lineWidthB ) ) if( holeA && holeA->Collide( shapeB, holeClearance + lineWidthB ) )
{ {
Mark( MK_HOLE ); Mark( Marker() | MK_HOLE );
return true; return true;
} }
if( holeB && holeB->Collide( shapeA, holeClearance + lineWidthA ) ) if( holeB && holeB->Collide( shapeA, holeClearance + lineWidthA ) )
{ {
aOther->Mark( MK_HOLE ); aOther->Mark( aOther->Marker() | MK_HOLE );
return true; return true;
} }
@ -76,8 +76,8 @@ bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferent
if( holeA->Collide( holeB, holeToHoleClearance ) ) if( holeA->Collide( holeB, holeToHoleClearance ) )
{ {
Mark( MK_HOLE ); Mark( Marker() | MK_HOLE );
aOther->Mark( MK_HOLE ); aOther->Mark( aOther->Marker() | MK_HOLE );
return true; return true;
} }
} }

View File

@ -47,6 +47,7 @@ LINE::LINE( const LINE& aOther )
m_hasVia = aOther.m_hasVia; m_hasVia = aOther.m_hasVia;
m_marker = aOther.m_marker; m_marker = aOther.m_marker;
m_rank = aOther.m_rank; m_rank = aOther.m_rank;
m_blockingObstacle = aOther.m_blockingObstacle;
copyLinks( &aOther ); copyLinks( &aOther );
} }
@ -70,6 +71,7 @@ LINE& LINE::operator=( const LINE& aOther )
m_rank = aOther.m_rank; m_rank = aOther.m_rank;
m_owner = aOther.m_owner; m_owner = aOther.m_owner;
m_snapThreshhold = aOther.m_snapThreshhold; m_snapThreshhold = aOther.m_snapThreshhold;
m_blockingObstacle = aOther.m_blockingObstacle;
copyLinks( &aOther ); copyLinks( &aOther );

View File

@ -68,7 +68,8 @@ public:
* Makes an empty line. * Makes an empty line.
*/ */
LINE() : LINE() :
LINK_HOLDER( LINE_T ) LINK_HOLDER( LINE_T ),
m_blockingObstacle( nullptr )
{ {
m_hasVia = false; m_hasVia = false;
m_width = 1; // Dummy value m_width = 1; // Dummy value
@ -86,7 +87,8 @@ public:
LINK_HOLDER( aBase ), LINK_HOLDER( aBase ),
m_line( aLine ), m_line( aLine ),
m_width( aBase.m_width ), m_width( aBase.m_width ),
m_snapThreshhold( aBase.m_snapThreshhold ) m_snapThreshhold( aBase.m_snapThreshhold ),
m_blockingObstacle( nullptr )
{ {
m_net = aBase.m_net; m_net = aBase.m_net;
m_layers = aBase.m_layers; m_layers = aBase.m_layers;
@ -99,7 +101,8 @@ public:
* @param aVia * @param aVia
*/ */
LINE( const VIA& aVia ) : LINE( const VIA& aVia ) :
LINK_HOLDER( LINE_T ) LINK_HOLDER( LINE_T ),
m_blockingObstacle( nullptr )
{ {
m_hasVia = true; m_hasVia = true;
m_via = aVia; m_via = aVia;
@ -204,6 +207,9 @@ public:
virtual void Unmark( int aMarker = -1 ) const override; virtual void Unmark( int aMarker = -1 ) const override;
virtual int Marker() const override; virtual int Marker() const override;
void SetBlockingObstacle( ITEM* aObstacle ) { m_blockingObstacle = aObstacle; }
ITEM* GetBlockingObstacle() const { return m_blockingObstacle; }
void DragSegment( const VECTOR2I& aP, int aIndex, bool aFreeAngle = false ); void DragSegment( const VECTOR2I& aP, int aIndex, bool aFreeAngle = false );
void DragCorner( const VECTOR2I& aP, int aIndex, bool aFreeAngle = false ); void DragCorner( const VECTOR2I& aP, int aIndex, bool aFreeAngle = false );
@ -214,7 +220,6 @@ public:
bool HasLockedSegments() const; bool HasLockedSegments() const;
void Clear(); void Clear();
void Merge ( const LINE& aOther );
OPT_BOX2I ChangedArea( const LINE* aOther ) const; OPT_BOX2I ChangedArea( const LINE* aOther ) const;
@ -240,14 +245,16 @@ private:
VECTOR2I snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP, VECTOR2I snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP,
int aIndex ) const; int aIndex ) const;
SHAPE_LINE_CHAIN m_line; ///> The actual shape of the line SHAPE_LINE_CHAIN m_line; ///> The actual shape of the line.
int m_width; ///> our width int m_width; ///> Our width.
int m_snapThreshhold; ///> Width to smooth out jagged segments int m_snapThreshhold; ///> Width to smooth out jagged segments.
bool m_hasVia; ///> Optional via at the end point bool m_hasVia; ///> Optional via at the end point.
VIA m_via; VIA m_via;
ITEM* m_blockingObstacle; ///> For mark obstacle mode.
}; };
} }

View File

@ -479,6 +479,7 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead )
bool LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, LINE& aNewHead ) bool LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, LINE& aNewHead )
{ {
buildInitialLine( aP, m_head ); buildInitialLine( aP, m_head );
m_head.SetBlockingObstacle( nullptr );
// If we are enforcing DRC violations, push back to the hull // If we are enforcing DRC violations, push back to the hull
if( !Settings().CanViolateDRC() ) if( !Settings().CanViolateDRC() )
@ -486,7 +487,10 @@ bool LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, LINE& aNewHead )
NODE::OPT_OBSTACLE obs = m_currentNode->NearestObstacle( &m_head ); NODE::OPT_OBSTACLE obs = m_currentNode->NearestObstacle( &m_head );
if( obs && obs->m_distFirst != INT_MAX ) if( obs && obs->m_distFirst != INT_MAX )
{
buildInitialLine( obs->m_ipFirst, m_head ); buildInitialLine( obs->m_ipFirst, m_head );
m_head.SetBlockingObstacle( obs->m_item );
}
} }
aNewHead = m_head; aNewHead = m_head;
@ -495,103 +499,6 @@ bool LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, LINE& aNewHead )
} }
const LINE LINE_PLACER::reduceToNearestObstacle( const LINE& aOriginalLine )
{
const auto& l0 = aOriginalLine.CLine();
if ( !l0.PointCount() )
return aOriginalLine;
int l = l0.Length();
int step = l / 2;
VECTOR2I target;
LINE l_test( aOriginalLine );
while( step > 0 )
{
target = l0.PointAlong( l );
SHAPE_LINE_CHAIN l_cur( l0 );
int index = l_cur.Split( target );
l_test.SetShape( l_cur.Slice( 0, index ) );
if ( m_currentNode->CheckColliding( &l_test ) )
l -= step;
else
l += step;
step /= 2;
}
l = l_test.CLine().Length();
while( m_currentNode->CheckColliding( &l_test ) && l > 0 )
{
l--;
target = l0.PointAlong( l );
SHAPE_LINE_CHAIN l_cur( l0 );
int index = l_cur.Split( target );
l_test.SetShape( l_cur.Slice( 0, index ) );
}
return l_test;
}
bool LINE_PLACER::rhStopAtNearestObstacle( const VECTOR2I& aP, LINE& aNewHead )
{
LINE l0;
l0 = m_head;
buildInitialLine( aP, l0 );
LINE l_cur = reduceToNearestObstacle( l0 );
const SHAPE_LINE_CHAIN l_shape = l_cur.CLine();
if( l_shape.SegmentCount() == 0 )
return false;
if( l_shape.SegmentCount() == 1 )
{
SEG s = l_shape.CSegment( 0 );
VECTOR2I dL( DIRECTION_45( s ).Left().ToVector() );
VECTOR2I dR( DIRECTION_45( s ).Right().ToVector() );
SEG leadL( s.B, s.B + dL );
SEG leadR( s.B, s.B + dR );
SEG segL( s.B, leadL.LineProject( aP ) );
SEG segR( s.B, leadR.LineProject( aP ) );
LINE finishL( l0, SHAPE_LINE_CHAIN( { segL.A, segL.B } ) );
LINE finishR( l0, SHAPE_LINE_CHAIN( { segR.A, segR.B } ) );
LINE reducedL = reduceToNearestObstacle( finishL );
LINE reducedR = reduceToNearestObstacle( finishR );
int lL = reducedL.CLine().Length();
int lR = reducedR.CLine().Length();
if( lL > lR )
l_cur.Line().Append( reducedL.CLine() );
else
l_cur.Line().Append( reducedR.CLine() );
l_cur.Line().Simplify();
}
m_head = l_cur;
aNewHead = m_head;
return true;
}
bool LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead ) bool LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead )
{ {
LINE initTrack( m_head ); LINE initTrack( m_head );

View File

@ -404,11 +404,6 @@ private:
*/ */
void routeStep( const VECTOR2I& aP ); void routeStep( const VECTOR2I& aP );
const LINE reduceToNearestObstacle( const LINE& aOriginalLine );
bool rhStopAtNearestObstacle( const VECTOR2I& aP, LINE& aNewHead );
///> route step, walkaround mode ///> route step, walkaround mode
bool rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead); bool rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead);

View File

@ -333,8 +333,8 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
if( aLine->EndsWithVia() ) if( aLine->EndsWithVia() )
{ {
const VIA& via = aLine->Via(); const VIA& via = aLine->Via();
int viaClearance = GetClearance( obstacle.m_item, &via ); int viaClearance = GetClearance( obstacle.m_item, &via );
int holeClearance = GetHoleClearance( obstacle.m_item, &via ); int holeClearance = GetHoleClearance( obstacle.m_item, &via );
if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 ) if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2; viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
@ -396,6 +396,7 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
{ {
int dist = aLine->CLine().Length() + ( ip.p - via.Pos() ).EuclideanNorm(); int dist = aLine->CLine().Length() + ( ip.p - via.Pos() ).EuclideanNorm();
updateNearest( dist, ip.p, obstacle.m_item, obstacleHull ); updateNearest( dist, ip.p, obstacle.m_item, obstacleHull );
obstacle.m_item->Mark( obstacle.m_item->Marker() | MK_HOLE );
} }
} }
@ -406,6 +407,7 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
{ {
int dist = aLine->CLine().PathLength( ip.p ); int dist = aLine->CLine().PathLength( ip.p );
updateNearest( dist, ip.p, obstacle.m_item, obstacleHull ); updateNearest( dist, ip.p, obstacle.m_item, obstacleHull );
obstacle.m_item->Mark( obstacle.m_item->Marker() | MK_HOLE );
} }
} }
} }

View File

@ -289,6 +289,24 @@ void ROUTER::moveDragging( const VECTOR2I& aP, ITEM* aEndItem )
void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR& aRemoved ) void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR& aRemoved )
{ {
auto updateItem =
[&]( ITEM* currentItem, ITEM* itemToMark )
{
std::unique_ptr<ITEM> tmp( itemToMark->Clone() );
int clearance;
if( itemToMark->Marker() & MK_HOLE )
clearance = aNode->GetHoleClearance( currentItem, itemToMark );
else
clearance = aNode->GetClearance( currentItem, itemToMark );
m_iface->DisplayItem( tmp.get(), -1, clearance );
// Remove the obstacle itself from the view unless we're just marking its hole
if( itemToMark->Marker() & MK_HOLE )
aRemoved.push_back( itemToMark );
};
for( ITEM* item : aCurrent.Items() ) for( ITEM* item : aCurrent.Items() )
{ {
NODE::OBSTACLES obstacles; NODE::OBSTACLES obstacles;
@ -308,17 +326,17 @@ void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR&
for( OBSTACLE& obs : obstacles ) for( OBSTACLE& obs : obstacles )
{ {
int clearance; obs.m_item->Mark( obs.m_item->Marker() | MK_VIOLATION );
updateItem( item, obs.m_item );
}
if( ( obs.m_item->Marker() & MK_HOLE ) > 0 ) if( item->Kind() == ITEM::LINE_T )
clearance = aNode->GetHoleClearance( item, obs.m_item ); {
else LINE* line = static_cast<LINE*>( item );
clearance = aNode->GetClearance( item, obs.m_item );
std::unique_ptr<ITEM> tmp( obs.m_item->Clone() ); // Show clearance on any blocking obstacles
tmp->Mark( tmp->Marker() | MK_VIOLATION ); if( line->GetBlockingObstacle() )
m_iface->DisplayItem( tmp.get(), -1, clearance ); updateItem( item, line->GetBlockingObstacle() );
aRemoved.push_back( obs.m_item );
} }
} }
} }

View File

@ -86,7 +86,7 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS::ITEM* aItem )
m_color.a = 0.8; m_color.a = 0.8;
m_depth = BaseOverlayDepth - aItem->Layers().Start(); m_depth = BaseOverlayDepth - aItem->Layers().Start();
if(( aItem->Marker() & PNS::MK_HOLE ) && aItem->Hole() ) if( ( aItem->Marker() & PNS::MK_HOLE ) && aItem->Hole() )
m_shape = aItem->Hole()->Clone(); m_shape = aItem->Hole()->Clone();
else else
m_shape = aItem->Shape()->Clone(); m_shape = aItem->Shape()->Clone();