Implement shoving of free vias.

Also contains a little bit of cleanup and a lot of commenting.

Fixes: lp:1833216
* https://bugs.launchpad.net/kicad/+bug/1833216

Fixes: lp:1833214
* https://bugs.launchpad.net/kicad/+bug/1833214
This commit is contained in:
Jeff Young 2019-07-24 09:19:03 -06:00
parent a7c41f0c34
commit 79934a327e
9 changed files with 201 additions and 167 deletions

View File

@ -2,7 +2,7 @@
* KiRouter - a push-and-(sometimes-)shove PCB router
*
* Copyright (C) 2013-2014 CERN
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify it
@ -19,12 +19,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <class_board.h>
#include <class_board_item.h>
#include <class_pad.h>
#include <class_track.h> // For ::VIA
#include <pad_shapes.h>
#include "pns_node.h"
#include "pns_item.h"
#include "pns_line.h"
@ -32,72 +27,12 @@ typedef VECTOR2I::extended_type ecoord;
namespace PNS {
static int holeRadius( BOARD_ITEM* aItem )
{
if( aItem->Type() == PCB_PAD_T )
{
const D_PAD* pad = static_cast<const D_PAD*>( aItem );
if( pad->GetDrillSize().x && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
return pad->GetDrillSize().x / 2;
else
return 0;
}
else if( aItem->Type() == PCB_VIA_T )
{
return static_cast<const ::VIA*>( aItem )->GetDrillValue() / 2;
}
return 0;
}
bool ITEM::CollideHoles( const ITEM* aOther, bool aNeedMTV, VECTOR2I& aMTV ) const
{
BOARD_ITEM* a = Parent();
BOARD_ITEM* b = aOther->Parent();
if( !a || !b )
return false;
// Holes with identical locations are allowable
if( a->GetPosition() == b->GetPosition() )
return false;
int radius_a = holeRadius( a );
int radius_b = holeRadius( b );
// Do both objects have holes?
if( radius_a > 0 && radius_b > 0 )
{
int holeToHoleMin = a->GetBoard()->GetDesignSettings().m_HoleToHoleMin;
ecoord min_dist = holeToHoleMin + radius_a + radius_b;
ecoord min_dist_sq = min_dist * min_dist;
const VECTOR2I delta = b->GetPosition() - a->GetPosition();
ecoord dist_sq = delta.SquaredEuclideanNorm();
if( dist_sq < min_dist_sq )
{
if( aNeedMTV )
aMTV = delta.Resize( min_dist - sqrt( dist_sq ) + 3 ); // fixme: apparent rounding error
return true;
}
}
return false;
}
bool ITEM::collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV,
bool aDifferentNetsOnly ) const
bool ITEM::collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
const NODE* aParentNode, bool aDifferentNetsOnly ) const
{
// hole-to-hole is a mechanical constraint (broken drill bits) not an electrical one, so
// it must be checked before checking aDifferentNetsOnly
if( CollideHoles( aOther, aNeedMTV, aMTV ) )
if( aParentNode->GetRuleResolver()->CollideHoles( this, aOther, aNeedMTV, aMTV ) )
return true;
// same nets? no collision!
@ -108,14 +43,17 @@ bool ITEM::collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VEC
if( !m_layers.Overlaps( aOther->m_layers ) )
return false;
return Shape()->Collide( aOther->Shape(), aClearance, aMTV );
if( aNeedMTV )
return Shape()->Collide( aOther->Shape(), aClearance, *aMTV );
else
return Shape()->Collide( aOther->Shape(), aClearance );
}
bool ITEM::Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV,
bool aDifferentNetsOnly ) const
bool ITEM::Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
const NODE* aParentNode, bool aDifferentNetsOnly ) const
{
if( collideSimple( aOther, aClearance, aNeedMTV, aMTV, aDifferentNetsOnly ) )
if( collideSimple( aOther, aClearance, aNeedMTV, aMTV, aParentNode, aDifferentNetsOnly ) )
return true;
// special case for "head" line with a via attached at the end.
@ -125,7 +63,10 @@ bool ITEM::Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I&
int clearance = aClearance - line->Width() / 2;
if( line->EndsWithVia() )
return collideSimple( &line->Via(), clearance, aNeedMTV, aMTV, aDifferentNetsOnly );
{
return collideSimple( &line->Via(), clearance, aNeedMTV, aMTV, aParentNode,
aDifferentNetsOnly );
}
}
return false;

View File

@ -201,26 +201,8 @@ public:
* @param aMTV the minimum translation vector
* @return true, if a collision was found.
*/
virtual bool Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV,
bool aDifferentNetsOnly = true ) const;
/**
* Function CollideHoles()
*
* Similar to Collide(), above, but checks for hole-to-hole-minimum violations.
*/
bool CollideHoles( const ITEM* aOther, bool aNeedMTV, VECTOR2I& aMTV ) const;
/**
* Function Collide()
*
* A shortcut for ITEM::Colllide() without MTV stuff.
*/
bool Collide( const ITEM* aOther, int aClearance, bool aDifferentNetsOnly = true ) const
{
VECTOR2I dummy;
return Collide( aOther, aClearance, false, dummy, aDifferentNetsOnly );
}
virtual bool Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
const NODE* aParentNode, bool aDifferentNetsOnly = true ) const;
/**
* Function Shape()
@ -259,8 +241,8 @@ public:
bool IsRoutable() const { return m_routable; }
private:
bool collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV,
VECTOR2I& aMTV, bool aDifferentNetsOnly ) const;
bool collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
const NODE* aParentNode, bool aDifferentNetsOnly ) const;
protected:
PnsKind m_kind;

View File

@ -60,17 +60,23 @@
#include "pns_debug_decorator.h"
#include "router_preview_item.h"
typedef VECTOR2I::extended_type ecoord;
class PNS_PCBNEW_RULE_RESOLVER : public PNS::RULE_RESOLVER
{
public:
PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER* aRouter );
virtual ~PNS_PCBNEW_RULE_RESOLVER();
virtual bool CollideHoles( const PNS::ITEM* aA, const PNS::ITEM* aB,
bool aNeedMTV, VECTOR2I* aMTV ) const override;
virtual int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB ) const override;
virtual int Clearance( int aNetCode ) const override;
virtual int DpCoupledNet( int aNet ) override;
virtual int DpNetPolarity( int aNet ) override;
virtual bool DpNetPair( PNS::ITEM* aItem, int& aNetP, int& aNetN ) override;
virtual wxString NetName( int aNet ) override;
private:
@ -81,6 +87,7 @@ private:
int clearance;
};
int holeRadius( const PNS::ITEM* aItem ) const;
int localPadClearance( const PNS::ITEM* aItem ) const;
int matchDpSuffix( const wxString& aNetName, wxString& aComplementNet, wxString& aBaseDpName );
@ -160,6 +167,65 @@ PNS_PCBNEW_RULE_RESOLVER::~PNS_PCBNEW_RULE_RESOLVER()
}
int PNS_PCBNEW_RULE_RESOLVER::holeRadius( const PNS::ITEM* aItem ) const
{
if( aItem->Kind() == PNS::ITEM::SOLID_T )
{
const D_PAD* pad = dynamic_cast<const D_PAD*>( aItem->Parent() );
if( pad && pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
return pad->GetDrillSize().x / 2;
}
else if( aItem->Kind() == PNS::ITEM::VIA_T )
{
const ::VIA* via = dynamic_cast<const ::VIA*>( aItem->Parent() );
if( via )
return via->GetDrillValue() / 2;
}
return 0;
}
bool PNS_PCBNEW_RULE_RESOLVER::CollideHoles( const PNS::ITEM* aA, const PNS::ITEM* aB,
bool aNeedMTV, VECTOR2I* aMTV ) const
{
VECTOR2I pos_a = aA->Shape()->Centre();
VECTOR2I pos_b = aB->Shape()->Centre();
// Holes with identical locations are allowable
if( pos_a == pos_b )
return false;
int radius_a = holeRadius( aA );
int radius_b = holeRadius( aB );
// Do both objects have holes?
if( radius_a > 0 && radius_b > 0 )
{
int holeToHoleMin = m_board->GetDesignSettings().m_HoleToHoleMin;
ecoord min_dist = holeToHoleMin + radius_a + radius_b;
ecoord min_dist_sq = min_dist * min_dist;
const VECTOR2I delta = pos_b - pos_a;
ecoord dist_sq = delta.SquaredEuclideanNorm();
if( dist_sq < min_dist_sq )
{
if( aNeedMTV )
*aMTV = delta.Resize( min_dist - sqrt( dist_sq ) + 3 ); // fixme: apparent rounding error
return true;
}
}
return false;
}
int PNS_PCBNEW_RULE_RESOLVER::localPadClearance( const PNS::ITEM* aItem ) const
{
if( !aItem->Parent() || aItem->Parent()->Type() != PCB_PAD_T )

View File

@ -234,7 +234,7 @@ struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
if( m_forceClearance >= 0 )
clearance = m_forceClearance;
if( !aCandidate->Collide( m_item, clearance, m_differentNetsOnly ) )
if( !aCandidate->Collide( m_item, clearance, false, nullptr, m_node, m_differentNetsOnly ) )
return true;
OBSTACLE obs;
@ -269,8 +269,8 @@ int NODE::QueryColliding( const ITEM* aItem, OBSTACLE_VISITOR& aVisitor )
}
int NODE::QueryColliding( const ITEM* aItem,
NODE::OBSTACLES& aObstacles, int aKindMask, int aLimitCount, bool aDifferentNetsOnly, int aForceClearance )
int NODE::QueryColliding( const ITEM* aItem, NODE::OBSTACLES& aObstacles, int aKindMask,
int aLimitCount, bool aDifferentNetsOnly, int aForceClearance )
{
DEFAULT_OBSTACLE_VISITOR visitor( aObstacles, aItem, aKindMask, aDifferentNetsOnly );
@ -469,7 +469,7 @@ bool NODE::CheckColliding( const ITEM* aItemA, const ITEM* aItemB, int aKindMask
if( aItemB->Kind() == ITEM::LINE_T )
clearance += static_cast<const LINE*>( aItemB )->Width() / 2;
return aItemA->Collide( aItemB, clearance );
return aItemA->Collide( aItemB, clearance, false, nullptr, this );
}
@ -608,22 +608,11 @@ void NODE::Add( std::unique_ptr< ITEM > aItem, bool aAllowRedundant )
{
switch( aItem->Kind() )
{
case ITEM::SOLID_T:
Add( ItemCast<SOLID>( std::move( aItem ) ) );
break;
case ITEM::SEGMENT_T:
Add( ItemCast<SEGMENT>( std::move( aItem ) ), aAllowRedundant );
break;
case ITEM::SOLID_T: Add( ItemCast<SOLID>( std::move( aItem ) ) ); break;
case ITEM::SEGMENT_T: Add( ItemCast<SEGMENT>( std::move( aItem ) ), aAllowRedundant ); break;
case ITEM::VIA_T: Add( ItemCast<VIA>( std::move( aItem ) ) ); break;
case ITEM::LINE_T:
assert( false );
break;
case ITEM::VIA_T:
Add( ItemCast<VIA>( std::move( aItem ) ) );
break;
default:
assert( false );
}
@ -660,7 +649,8 @@ void NODE::removeSegmentIndex( SEGMENT* aSeg )
void NODE::removeViaIndex( VIA* aVia )
{
// We have to split a single joint (associated with a via, binding together multiple layers)
// into multiple independent joints. As I'm a lazy bastard, I simply delete the via and all its links and re-insert them.
// into multiple independent joints. As I'm a lazy bastard, I simply delete the via and all
// its links and re-insert them.
JOINT::HASH_TAG tag;
@ -1258,36 +1248,18 @@ void NODE::ClearRanks( int aMarkerMask )
}
int NODE::FindByMarker( int aMarker, ITEM_SET& aItems )
{
for( INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i )
{
if( (*i)->Marker() & aMarker )
aItems.Add( *i );
}
return 0;
}
int NODE::RemoveByMarker( int aMarker )
void NODE::RemoveByMarker( int aMarker )
{
std::list<ITEM*> garbage;
for( INDEX::ITEM_SET::iterator i = m_index->begin(); i != m_index->end(); ++i )
for( ITEM* item : *m_index )
{
if( (*i)->Marker() & aMarker )
{
garbage.push_back( *i );
}
if( item->Marker() & aMarker )
garbage.push_back( item );
}
for( std::list<ITEM*>::const_iterator i = garbage.begin(), end = garbage.end(); i != end; ++i )
{
Remove( *i );
}
return 0;
for( ITEM* item : garbage )
Remove( item );
}
SEGMENT* NODE::findRedundantSegment( const VECTOR2I& A, const VECTOR2I& B, const LAYER_RANGE& lr,

View File

@ -58,11 +58,15 @@ class RULE_RESOLVER
public:
virtual ~RULE_RESOLVER() {}
virtual bool CollideHoles( const ITEM* aA, const ITEM* aB,
bool aNeedMTV, VECTOR2I* aMTV ) const = 0;
virtual int Clearance( const ITEM* aA, const ITEM* aB ) const = 0;
virtual int Clearance( int aNetCode ) const = 0;
virtual int DpCoupledNet( int aNet ) = 0;
virtual int DpNetPolarity( int aNet ) = 0;
virtual bool DpNetPair( ITEM* aItem, int& aNetP, int& aNetN ) = 0;
virtual wxString NetName( int aNet ) = 0;
};
@ -164,7 +168,7 @@ public:
m_ruleResolver = aFunc;
}
RULE_RESOLVER* GetRuleResolver()
RULE_RESOLVER* GetRuleResolver() const
{
return m_ruleResolver;
}
@ -401,8 +405,7 @@ public:
void ClearRanks( int aMarkerMask = MK_HEAD | MK_VIOLATION );
int FindByMarker( int aMarker, ITEM_SET& aItems );
int RemoveByMarker( int aMarker );
void RemoveByMarker( int aMarker );
ITEM* FindItemByParent( const BOARD_CONNECTED_ITEM* aParent );

View File

@ -154,7 +154,7 @@ struct OPTIMIZER::CACHE_VISITOR
int clearance = m_node->GetClearance( aOtherItem, m_ourItem );
if( !aOtherItem->Collide( m_ourItem, clearance ) )
if( !aOtherItem->Collide( m_ourItem, clearance, false, nullptr, m_node ) )
return true;
m_collidingItem = aOtherItem;

View File

@ -35,6 +35,9 @@
#include "time_limit.h"
typedef VECTOR2I::extended_type ecoord;
namespace PNS {
void SHOVE::replaceItems( ITEM* aOld, std::unique_ptr< ITEM > aNew )
@ -149,6 +152,9 @@ SHOVE::SHOVE_STATUS SHOVE::walkaroundLoneVia( LINE& aCurrent, LINE& aObstacle, L
}
/*
* TODO describe....
*/
SHOVE::SHOVE_STATUS SHOVE::processHullSet( LINE& aCurrent, LINE& aObstacle,
LINE& aShoved, const HULL_SET& aHulls )
{
@ -249,6 +255,9 @@ SHOVE::SHOVE_STATUS SHOVE::processHullSet( LINE& aCurrent, LINE& aObstacle,
}
/*
* TODO describe....
*/
SHOVE::SHOVE_STATUS SHOVE::ProcessSingleLine( LINE& aCurrent, LINE& aObstacle, LINE& aShoved )
{
aShoved.ClearSegmentLinks();
@ -304,6 +313,9 @@ SHOVE::SHOVE_STATUS SHOVE::ProcessSingleLine( LINE& aCurrent, LINE& aObstacle, L
}
/*
* TODO describe....
*/
SHOVE::SHOVE_STATUS SHOVE::onCollidingSegment( LINE& aCurrent, SEGMENT* aObstacleSeg )
{
int segIndex;
@ -362,6 +374,9 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSegment( LINE& aCurrent, SEGMENT* aObstacl
}
/*
* TODO describe....
*/
SHOVE::SHOVE_STATUS SHOVE::onCollidingLine( LINE& aCurrent, LINE& aObstacle )
{
LINE shovedLine( aObstacle );
@ -401,6 +416,10 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingLine( LINE& aCurrent, LINE& aObstacle )
return rv;
}
/*
* TODO describe....
*/
SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle )
{
WALKAROUND walkaround( m_currentNode, Router() );
@ -586,6 +605,10 @@ bool SHOVE::pushSpringback( NODE* aNode, const OPT_BOX2I& aAffectedArea, VIA* aD
}
/*
* Push or shove a via by at least aForce. (The via might be pushed or shoved slightly further
* to keep it from landing on an existing joint.)
*/
SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, int aCurrentRank )
{
LINE_PAIR_VEC draggedLines;
@ -659,8 +682,15 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in
m_logger.Log( pushedVia.get(), 1, "pushed-via" );
#endif
if( aVia->Marker() & MK_HEAD )
if( aVia->Marker() & MK_HEAD ) // push
{
m_draggedVia = pushedVia.get();
}
else
{ // shove
if( jt->IsStitchingVia() )
pushLineStack( LINE( *pushedVia ) );
}
replaceItems( aVia, std::move( pushedVia ) );
@ -701,17 +731,24 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in
}
/*
* Calculate the minimum translation vector required to resolve a collision with a via and
* shove the via by that distance.
*/
SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
{
RULE_RESOLVER* rr = m_currentNode->GetRuleResolver();
int clearance = getClearance( aCurrent, aObstacleVia ) ;
LINE_PAIR_VEC draggedLines;
bool lineCollision = false;
bool viaCollision = false;
bool holeCollision = false;
LINE* currentLine = NULL;
VECTOR2I mtvLine;
VECTOR2I mtvVia;
VECTOR2I mtvSolid;
VECTOR2I mtv;
VECTOR2I mtvLine; // Minimum translation vector to correct line collisions
VECTOR2I mtvVia; // MTV to correct via collisions
VECTOR2I mtvHoles; // MTV to correct hole collisions
VECTOR2I mtvSolid; // MTV to correct solid collisions
VECTOR2I mtv; // Union of relevant MTVs (will correct all collisions)
int rank = -1;
if( aCurrent->OfKind( ITEM::LINE_T ) )
@ -728,19 +765,32 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
if( currentLine->EndsWithVia() )
{
viaCollision = CollideShapes( currentLine->Via().Shape(), aObstacleVia->Shape(),
clearance + PNS_HULL_MARGIN, true, mtvVia );
int currentNet = currentLine->Net();
int obstacleNet = aObstacleVia->Net();
if( currentNet != obstacleNet && currentNet >= 0 && obstacleNet >= 0 )
{
viaCollision = CollideShapes( currentLine->Via().Shape(), aObstacleVia->Shape(),
clearance + PNS_HULL_MARGIN, true, mtvVia );
}
// hole-to-hole is a mechanical constraint (broken drill bits), not an electrical
// one, so it has to be checked irrespective of matching nets.
holeCollision = rr->CollideHoles( &currentLine->Via(), aObstacleVia, true, &mtvHoles );
}
if( !lineCollision && !viaCollision )
return SH_OK;
// These aren't /actually/ lengths as we don't bother to do the square-root part,
// but we're just comparing them to each other so it's faster this way.
ecoord lineMTVLength = lineCollision ? mtvLine.SquaredEuclideanNorm() : 0;
ecoord viaMTVLength = viaCollision ? mtvVia.SquaredEuclideanNorm() : 0;
ecoord holeMTVLength = holeCollision ? mtvHoles.SquaredEuclideanNorm() : 0;
if( lineCollision && viaCollision )
mtv = mtvVia.EuclideanNorm() > mtvLine.EuclideanNorm() ? mtvVia : mtvLine;
else if( lineCollision )
if( lineMTVLength >= viaMTVLength && lineMTVLength >= holeMTVLength )
mtv = mtvLine;
else
else if( viaMTVLength >= lineMTVLength && viaMTVLength >= holeMTVLength )
mtv = mtvVia;
else
mtv = mtvHoles;
rank = currentLine->Rank();
}
@ -756,6 +806,9 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
}
/*
* TODO describe....
*/
SHOVE::SHOVE_STATUS SHOVE::onReverseCollidingVia( LINE& aCurrent, VIA* aObstacleVia )
{
int n = 0;
@ -918,6 +971,9 @@ void SHOVE::popLineStack( )
}
/*
* Resolve the next collision.
*/
SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
{
LINE currentLine = m_lineStack.back();
@ -944,20 +1000,22 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
if( !ni->OfKind( ITEM::SOLID_T ) && ni->Rank() >= 0 && ni->Rank() > currentLine.Rank() )
{
// Collision with a higher-ranking object (ie: one that we've already shoved)
//
switch( ni->Kind() )
{
case ITEM::VIA_T:
{
VIA* revVia = (VIA*) ni;
wxLogTrace( "PNS", "iter %d: reverse-collide-via", aIter );
if( currentLine.EndsWithVia() && m_currentNode->CheckColliding( &currentLine.Via(), revVia ) )
if( currentLine.EndsWithVia()
&& m_currentNode->CheckColliding( &currentLine.Via(), (VIA*) ni ) )
{
st = SH_INCOMPLETE;
}
else
{
st = onReverseCollidingVia( currentLine, revVia );
st = onReverseCollidingVia( currentLine, (VIA*) ni );
}
break;
@ -965,9 +1023,8 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
case ITEM::SEGMENT_T:
{
SEGMENT* seg = (SEGMENT*) ni;
wxLogTrace( "PNS", "iter %d: reverse-collide-segment ", aIter );
LINE revLine = assembleLine( seg );
LINE revLine = assembleLine( (SEGMENT*) ni );
popLineStack();
st = onCollidingLine( revLine, currentLine );
@ -982,7 +1039,9 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
}
}
else
{ // "forward" collisions
{
// Collision with a lower-ranking object or a solid
//
switch( ni->Kind() )
{
case ITEM::SEGMENT_T:
@ -1018,6 +1077,12 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
}
/*
* Resolve collisions.
* Each iteration pushes the next colliding object out of the way. Iterations are continued as
* long as they propagate further collisions, or until the iteration timeout or max iteration
* count is reached.
*/
SHOVE::SHOVE_STATUS SHOVE::shoveMainLoop()
{
SHOVE_STATUS st = SH_OK;
@ -1093,11 +1158,15 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveLines( const LINE& aCurrentHead )
m_newHead = OPT_LINE();
m_logger.Clear();
// Pop NODEs containing previous shoves which are no longer necessary
//
ITEM_SET headSet;
headSet.Add( aCurrentHead );
NODE* parent = reduceSpringback( headSet, nullptr );
// Create a new NODE to store this version of the world
//
m_currentNode = parent->Branch();
m_currentNode->ClearRanks();
m_currentNode->Add( head );
@ -1263,14 +1332,14 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveDraggingVia( VIA* aVia, const VECTOR2I& aWhere,
m_newHead = OPT_LINE();
m_draggedVia = NULL;
// Pop NODEs containing previous shoves which are no longer necessary
//
ITEM_SET headSet;
headSet.Add( *aVia );
// Pop NODEs containing previous shoves which are no longer necessary
//
NODE* parent = reduceSpringback( headSet, &aVia );
// Create a new NODE
// Create a new NODE to store this version of the world
//
m_currentNode = parent->Branch();
m_currentNode->ClearRanks();

View File

@ -94,6 +94,7 @@ VIA* VIA::Clone() const
v->m_rank = m_rank;
v->m_marker = m_marker;
v->m_viaType = m_viaType;
v->m_parent = m_parent;
return v;
}

View File

@ -66,7 +66,7 @@ public:
VIA( const VIA& aB ) :
ITEM( VIA_T )
ITEM( aB )
{
SetNet( aB.Net() );
SetLayers( aB.Layers() );