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:
parent
a7c41f0c34
commit
79934a327e
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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( ¤tLine->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( ¤tLine.Via(), revVia ) )
|
||||
if( currentLine.EndsWithVia()
|
||||
&& m_currentNode->CheckColliding( ¤tLine.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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
|
||||
|
||||
VIA( const VIA& aB ) :
|
||||
ITEM( VIA_T )
|
||||
ITEM( aB )
|
||||
{
|
||||
SetNet( aB.Net() );
|
||||
SetLayers( aB.Layers() );
|
||||
|
|
Loading…
Reference in New Issue