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
|
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013-2014 CERN
|
* 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>
|
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <class_board.h>
|
#include "pns_node.h"
|
||||||
#include <class_board_item.h>
|
|
||||||
#include <class_pad.h>
|
|
||||||
#include <class_track.h> // For ::VIA
|
|
||||||
#include <pad_shapes.h>
|
|
||||||
|
|
||||||
#include "pns_item.h"
|
#include "pns_item.h"
|
||||||
#include "pns_line.h"
|
#include "pns_line.h"
|
||||||
|
|
||||||
|
@ -32,72 +27,12 @@ typedef VECTOR2I::extended_type ecoord;
|
||||||
|
|
||||||
namespace PNS {
|
namespace PNS {
|
||||||
|
|
||||||
static int holeRadius( BOARD_ITEM* aItem )
|
bool ITEM::collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
|
||||||
{
|
const NODE* aParentNode, bool aDifferentNetsOnly ) const
|
||||||
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
|
|
||||||
{
|
{
|
||||||
// hole-to-hole is a mechanical constraint (broken drill bits) not an electrical one, so
|
// hole-to-hole is a mechanical constraint (broken drill bits) not an electrical one, so
|
||||||
// it must be checked before checking aDifferentNetsOnly
|
// it must be checked before checking aDifferentNetsOnly
|
||||||
if( CollideHoles( aOther, aNeedMTV, aMTV ) )
|
if( aParentNode->GetRuleResolver()->CollideHoles( this, aOther, aNeedMTV, aMTV ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// same nets? no collision!
|
// 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 ) )
|
if( !m_layers.Overlaps( aOther->m_layers ) )
|
||||||
return false;
|
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 ITEM::Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
|
||||||
bool aDifferentNetsOnly ) const
|
const NODE* aParentNode, bool aDifferentNetsOnly ) const
|
||||||
{
|
{
|
||||||
if( collideSimple( aOther, aClearance, aNeedMTV, aMTV, aDifferentNetsOnly ) )
|
if( collideSimple( aOther, aClearance, aNeedMTV, aMTV, aParentNode, aDifferentNetsOnly ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// special case for "head" line with a via attached at the end.
|
// 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;
|
int clearance = aClearance - line->Width() / 2;
|
||||||
|
|
||||||
if( line->EndsWithVia() )
|
if( line->EndsWithVia() )
|
||||||
return collideSimple( &line->Via(), clearance, aNeedMTV, aMTV, aDifferentNetsOnly );
|
{
|
||||||
|
return collideSimple( &line->Via(), clearance, aNeedMTV, aMTV, aParentNode,
|
||||||
|
aDifferentNetsOnly );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -201,26 +201,8 @@ public:
|
||||||
* @param aMTV the minimum translation vector
|
* @param aMTV the minimum translation vector
|
||||||
* @return true, if a collision was found.
|
* @return true, if a collision was found.
|
||||||
*/
|
*/
|
||||||
virtual bool Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I& aMTV,
|
virtual bool Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
|
||||||
bool aDifferentNetsOnly = true ) const;
|
const NODE* aParentNode, 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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Shape()
|
* Function Shape()
|
||||||
|
@ -259,8 +241,8 @@ public:
|
||||||
bool IsRoutable() const { return m_routable; }
|
bool IsRoutable() const { return m_routable; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV,
|
bool collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
|
||||||
VECTOR2I& aMTV, bool aDifferentNetsOnly ) const;
|
const NODE* aParentNode, bool aDifferentNetsOnly ) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PnsKind m_kind;
|
PnsKind m_kind;
|
||||||
|
|
|
@ -60,17 +60,23 @@
|
||||||
#include "pns_debug_decorator.h"
|
#include "pns_debug_decorator.h"
|
||||||
#include "router_preview_item.h"
|
#include "router_preview_item.h"
|
||||||
|
|
||||||
|
typedef VECTOR2I::extended_type ecoord;
|
||||||
|
|
||||||
class PNS_PCBNEW_RULE_RESOLVER : public PNS::RULE_RESOLVER
|
class PNS_PCBNEW_RULE_RESOLVER : public PNS::RULE_RESOLVER
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER* aRouter );
|
PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER* aRouter );
|
||||||
virtual ~PNS_PCBNEW_RULE_RESOLVER();
|
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( const PNS::ITEM* aA, const PNS::ITEM* aB ) const override;
|
||||||
virtual int Clearance( int aNetCode ) const override;
|
virtual int Clearance( int aNetCode ) const override;
|
||||||
virtual int DpCoupledNet( int aNet ) override;
|
virtual int DpCoupledNet( int aNet ) override;
|
||||||
virtual int DpNetPolarity( int aNet ) override;
|
virtual int DpNetPolarity( int aNet ) override;
|
||||||
virtual bool DpNetPair( PNS::ITEM* aItem, int& aNetP, int& aNetN ) override;
|
virtual bool DpNetPair( PNS::ITEM* aItem, int& aNetP, int& aNetN ) override;
|
||||||
|
|
||||||
virtual wxString NetName( int aNet ) override;
|
virtual wxString NetName( int aNet ) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -81,6 +87,7 @@ private:
|
||||||
int clearance;
|
int clearance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int holeRadius( const PNS::ITEM* aItem ) const;
|
||||||
int localPadClearance( const PNS::ITEM* aItem ) const;
|
int localPadClearance( const PNS::ITEM* aItem ) const;
|
||||||
int matchDpSuffix( const wxString& aNetName, wxString& aComplementNet, wxString& aBaseDpName );
|
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
|
int PNS_PCBNEW_RULE_RESOLVER::localPadClearance( const PNS::ITEM* aItem ) const
|
||||||
{
|
{
|
||||||
if( !aItem->Parent() || aItem->Parent()->Type() != PCB_PAD_T )
|
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 )
|
if( m_forceClearance >= 0 )
|
||||||
clearance = m_forceClearance;
|
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;
|
return true;
|
||||||
|
|
||||||
OBSTACLE obs;
|
OBSTACLE obs;
|
||||||
|
@ -269,8 +269,8 @@ int NODE::QueryColliding( const ITEM* aItem, OBSTACLE_VISITOR& aVisitor )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int NODE::QueryColliding( const ITEM* aItem,
|
int NODE::QueryColliding( const ITEM* aItem, NODE::OBSTACLES& aObstacles, int aKindMask,
|
||||||
NODE::OBSTACLES& aObstacles, int aKindMask, int aLimitCount, bool aDifferentNetsOnly, int aForceClearance )
|
int aLimitCount, bool aDifferentNetsOnly, int aForceClearance )
|
||||||
{
|
{
|
||||||
DEFAULT_OBSTACLE_VISITOR visitor( aObstacles, aItem, aKindMask, aDifferentNetsOnly );
|
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 )
|
if( aItemB->Kind() == ITEM::LINE_T )
|
||||||
clearance += static_cast<const LINE*>( aItemB )->Width() / 2;
|
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() )
|
switch( aItem->Kind() )
|
||||||
{
|
{
|
||||||
case ITEM::SOLID_T:
|
case ITEM::SOLID_T: Add( ItemCast<SOLID>( std::move( aItem ) ) ); break;
|
||||||
Add( ItemCast<SOLID>( std::move( aItem ) ) );
|
case ITEM::SEGMENT_T: Add( ItemCast<SEGMENT>( std::move( aItem ) ), aAllowRedundant ); break;
|
||||||
break;
|
case ITEM::VIA_T: Add( ItemCast<VIA>( std::move( aItem ) ) ); break;
|
||||||
|
|
||||||
case ITEM::SEGMENT_T:
|
|
||||||
Add( ItemCast<SEGMENT>( std::move( aItem ) ), aAllowRedundant );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ITEM::LINE_T:
|
case ITEM::LINE_T:
|
||||||
assert( false );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ITEM::VIA_T:
|
|
||||||
Add( ItemCast<VIA>( std::move( aItem ) ) );
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert( false );
|
assert( false );
|
||||||
}
|
}
|
||||||
|
@ -660,7 +649,8 @@ void NODE::removeSegmentIndex( SEGMENT* aSeg )
|
||||||
void NODE::removeViaIndex( VIA* aVia )
|
void NODE::removeViaIndex( VIA* aVia )
|
||||||
{
|
{
|
||||||
// We have to split a single joint (associated with a via, binding together multiple layers)
|
// 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;
|
JOINT::HASH_TAG tag;
|
||||||
|
|
||||||
|
@ -1258,36 +1248,18 @@ void NODE::ClearRanks( int aMarkerMask )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int NODE::FindByMarker( int aMarker, ITEM_SET& aItems )
|
void NODE::RemoveByMarker( int aMarker )
|
||||||
{
|
|
||||||
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 )
|
|
||||||
{
|
{
|
||||||
std::list<ITEM*> garbage;
|
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 )
|
if( item->Marker() & aMarker )
|
||||||
{
|
garbage.push_back( item );
|
||||||
garbage.push_back( *i );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for( std::list<ITEM*>::const_iterator i = garbage.begin(), end = garbage.end(); i != end; ++i )
|
for( ITEM* item : garbage )
|
||||||
{
|
Remove( item );
|
||||||
Remove( *i );
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SEGMENT* NODE::findRedundantSegment( const VECTOR2I& A, const VECTOR2I& B, const LAYER_RANGE& lr,
|
SEGMENT* NODE::findRedundantSegment( const VECTOR2I& A, const VECTOR2I& B, const LAYER_RANGE& lr,
|
||||||
|
|
|
@ -58,11 +58,15 @@ class RULE_RESOLVER
|
||||||
public:
|
public:
|
||||||
virtual ~RULE_RESOLVER() {}
|
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( const ITEM* aA, const ITEM* aB ) const = 0;
|
||||||
virtual int Clearance( int aNetCode ) const = 0;
|
virtual int Clearance( int aNetCode ) const = 0;
|
||||||
virtual int DpCoupledNet( int aNet ) = 0;
|
virtual int DpCoupledNet( int aNet ) = 0;
|
||||||
virtual int DpNetPolarity( int aNet ) = 0;
|
virtual int DpNetPolarity( int aNet ) = 0;
|
||||||
virtual bool DpNetPair( ITEM* aItem, int& aNetP, int& aNetN ) = 0;
|
virtual bool DpNetPair( ITEM* aItem, int& aNetP, int& aNetN ) = 0;
|
||||||
|
|
||||||
virtual wxString NetName( int aNet ) = 0;
|
virtual wxString NetName( int aNet ) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -164,7 +168,7 @@ public:
|
||||||
m_ruleResolver = aFunc;
|
m_ruleResolver = aFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
RULE_RESOLVER* GetRuleResolver()
|
RULE_RESOLVER* GetRuleResolver() const
|
||||||
{
|
{
|
||||||
return m_ruleResolver;
|
return m_ruleResolver;
|
||||||
}
|
}
|
||||||
|
@ -401,8 +405,7 @@ public:
|
||||||
|
|
||||||
void ClearRanks( int aMarkerMask = MK_HEAD | MK_VIOLATION );
|
void ClearRanks( int aMarkerMask = MK_HEAD | MK_VIOLATION );
|
||||||
|
|
||||||
int FindByMarker( int aMarker, ITEM_SET& aItems );
|
void RemoveByMarker( int aMarker );
|
||||||
int RemoveByMarker( int aMarker );
|
|
||||||
|
|
||||||
ITEM* FindItemByParent( const BOARD_CONNECTED_ITEM* aParent );
|
ITEM* FindItemByParent( const BOARD_CONNECTED_ITEM* aParent );
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ struct OPTIMIZER::CACHE_VISITOR
|
||||||
|
|
||||||
int clearance = m_node->GetClearance( aOtherItem, m_ourItem );
|
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;
|
return true;
|
||||||
|
|
||||||
m_collidingItem = aOtherItem;
|
m_collidingItem = aOtherItem;
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
|
|
||||||
#include "time_limit.h"
|
#include "time_limit.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef VECTOR2I::extended_type ecoord;
|
||||||
|
|
||||||
namespace PNS {
|
namespace PNS {
|
||||||
|
|
||||||
void SHOVE::replaceItems( ITEM* aOld, std::unique_ptr< ITEM > aNew )
|
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,
|
SHOVE::SHOVE_STATUS SHOVE::processHullSet( LINE& aCurrent, LINE& aObstacle,
|
||||||
LINE& aShoved, const HULL_SET& aHulls )
|
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 )
|
SHOVE::SHOVE_STATUS SHOVE::ProcessSingleLine( LINE& aCurrent, LINE& aObstacle, LINE& aShoved )
|
||||||
{
|
{
|
||||||
aShoved.ClearSegmentLinks();
|
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 )
|
SHOVE::SHOVE_STATUS SHOVE::onCollidingSegment( LINE& aCurrent, SEGMENT* aObstacleSeg )
|
||||||
{
|
{
|
||||||
int segIndex;
|
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 )
|
SHOVE::SHOVE_STATUS SHOVE::onCollidingLine( LINE& aCurrent, LINE& aObstacle )
|
||||||
{
|
{
|
||||||
LINE shovedLine( aObstacle );
|
LINE shovedLine( aObstacle );
|
||||||
|
@ -401,6 +416,10 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingLine( LINE& aCurrent, LINE& aObstacle )
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO describe....
|
||||||
|
*/
|
||||||
SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle )
|
SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle )
|
||||||
{
|
{
|
||||||
WALKAROUND walkaround( m_currentNode, Router() );
|
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 )
|
SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, int aCurrentRank )
|
||||||
{
|
{
|
||||||
LINE_PAIR_VEC draggedLines;
|
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" );
|
m_logger.Log( pushedVia.get(), 1, "pushed-via" );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( aVia->Marker() & MK_HEAD )
|
if( aVia->Marker() & MK_HEAD ) // push
|
||||||
|
{
|
||||||
m_draggedVia = pushedVia.get();
|
m_draggedVia = pushedVia.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // shove
|
||||||
|
if( jt->IsStitchingVia() )
|
||||||
|
pushLineStack( LINE( *pushedVia ) );
|
||||||
|
}
|
||||||
|
|
||||||
replaceItems( aVia, std::move( 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 )
|
SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
|
||||||
{
|
{
|
||||||
|
RULE_RESOLVER* rr = m_currentNode->GetRuleResolver();
|
||||||
int clearance = getClearance( aCurrent, aObstacleVia ) ;
|
int clearance = getClearance( aCurrent, aObstacleVia ) ;
|
||||||
LINE_PAIR_VEC draggedLines;
|
LINE_PAIR_VEC draggedLines;
|
||||||
bool lineCollision = false;
|
bool lineCollision = false;
|
||||||
bool viaCollision = false;
|
bool viaCollision = false;
|
||||||
|
bool holeCollision = false;
|
||||||
LINE* currentLine = NULL;
|
LINE* currentLine = NULL;
|
||||||
VECTOR2I mtvLine;
|
VECTOR2I mtvLine; // Minimum translation vector to correct line collisions
|
||||||
VECTOR2I mtvVia;
|
VECTOR2I mtvVia; // MTV to correct via collisions
|
||||||
VECTOR2I mtvSolid;
|
VECTOR2I mtvHoles; // MTV to correct hole collisions
|
||||||
VECTOR2I mtv;
|
VECTOR2I mtvSolid; // MTV to correct solid collisions
|
||||||
|
VECTOR2I mtv; // Union of relevant MTVs (will correct all collisions)
|
||||||
int rank = -1;
|
int rank = -1;
|
||||||
|
|
||||||
if( aCurrent->OfKind( ITEM::LINE_T ) )
|
if( aCurrent->OfKind( ITEM::LINE_T ) )
|
||||||
|
@ -728,19 +765,32 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
|
||||||
|
|
||||||
if( currentLine->EndsWithVia() )
|
if( currentLine->EndsWithVia() )
|
||||||
{
|
{
|
||||||
viaCollision = CollideShapes( currentLine->Via().Shape(), aObstacleVia->Shape(),
|
int currentNet = currentLine->Net();
|
||||||
clearance + PNS_HULL_MARGIN, true, mtvVia );
|
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 )
|
// These aren't /actually/ lengths as we don't bother to do the square-root part,
|
||||||
return SH_OK;
|
// 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 )
|
if( lineMTVLength >= viaMTVLength && lineMTVLength >= holeMTVLength )
|
||||||
mtv = mtvVia.EuclideanNorm() > mtvLine.EuclideanNorm() ? mtvVia : mtvLine;
|
|
||||||
else if( lineCollision )
|
|
||||||
mtv = mtvLine;
|
mtv = mtvLine;
|
||||||
else
|
else if( viaMTVLength >= lineMTVLength && viaMTVLength >= holeMTVLength )
|
||||||
mtv = mtvVia;
|
mtv = mtvVia;
|
||||||
|
else
|
||||||
|
mtv = mtvHoles;
|
||||||
|
|
||||||
rank = currentLine->Rank();
|
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 )
|
SHOVE::SHOVE_STATUS SHOVE::onReverseCollidingVia( LINE& aCurrent, VIA* aObstacleVia )
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
@ -918,6 +971,9 @@ void SHOVE::popLineStack( )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolve the next collision.
|
||||||
|
*/
|
||||||
SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
||||||
{
|
{
|
||||||
LINE currentLine = m_lineStack.back();
|
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() )
|
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() )
|
switch( ni->Kind() )
|
||||||
{
|
{
|
||||||
case ITEM::VIA_T:
|
case ITEM::VIA_T:
|
||||||
{
|
{
|
||||||
VIA* revVia = (VIA*) ni;
|
|
||||||
wxLogTrace( "PNS", "iter %d: reverse-collide-via", aIter );
|
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;
|
st = SH_INCOMPLETE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
st = onReverseCollidingVia( currentLine, revVia );
|
st = onReverseCollidingVia( currentLine, (VIA*) ni );
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -965,9 +1023,8 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
||||||
|
|
||||||
case ITEM::SEGMENT_T:
|
case ITEM::SEGMENT_T:
|
||||||
{
|
{
|
||||||
SEGMENT* seg = (SEGMENT*) ni;
|
|
||||||
wxLogTrace( "PNS", "iter %d: reverse-collide-segment ", aIter );
|
wxLogTrace( "PNS", "iter %d: reverse-collide-segment ", aIter );
|
||||||
LINE revLine = assembleLine( seg );
|
LINE revLine = assembleLine( (SEGMENT*) ni );
|
||||||
|
|
||||||
popLineStack();
|
popLineStack();
|
||||||
st = onCollidingLine( revLine, currentLine );
|
st = onCollidingLine( revLine, currentLine );
|
||||||
|
@ -982,7 +1039,9 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // "forward" collisions
|
{
|
||||||
|
// Collision with a lower-ranking object or a solid
|
||||||
|
//
|
||||||
switch( ni->Kind() )
|
switch( ni->Kind() )
|
||||||
{
|
{
|
||||||
case ITEM::SEGMENT_T:
|
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::SHOVE_STATUS SHOVE::shoveMainLoop()
|
||||||
{
|
{
|
||||||
SHOVE_STATUS st = SH_OK;
|
SHOVE_STATUS st = SH_OK;
|
||||||
|
@ -1093,11 +1158,15 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveLines( const LINE& aCurrentHead )
|
||||||
m_newHead = OPT_LINE();
|
m_newHead = OPT_LINE();
|
||||||
m_logger.Clear();
|
m_logger.Clear();
|
||||||
|
|
||||||
|
// Pop NODEs containing previous shoves which are no longer necessary
|
||||||
|
//
|
||||||
ITEM_SET headSet;
|
ITEM_SET headSet;
|
||||||
headSet.Add( aCurrentHead );
|
headSet.Add( aCurrentHead );
|
||||||
|
|
||||||
NODE* parent = reduceSpringback( headSet, nullptr );
|
NODE* parent = reduceSpringback( headSet, nullptr );
|
||||||
|
|
||||||
|
// Create a new NODE to store this version of the world
|
||||||
|
//
|
||||||
m_currentNode = parent->Branch();
|
m_currentNode = parent->Branch();
|
||||||
m_currentNode->ClearRanks();
|
m_currentNode->ClearRanks();
|
||||||
m_currentNode->Add( head );
|
m_currentNode->Add( head );
|
||||||
|
@ -1263,14 +1332,14 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveDraggingVia( VIA* aVia, const VECTOR2I& aWhere,
|
||||||
m_newHead = OPT_LINE();
|
m_newHead = OPT_LINE();
|
||||||
m_draggedVia = NULL;
|
m_draggedVia = NULL;
|
||||||
|
|
||||||
|
// Pop NODEs containing previous shoves which are no longer necessary
|
||||||
|
//
|
||||||
ITEM_SET headSet;
|
ITEM_SET headSet;
|
||||||
headSet.Add( *aVia );
|
headSet.Add( *aVia );
|
||||||
|
|
||||||
// Pop NODEs containing previous shoves which are no longer necessary
|
|
||||||
//
|
|
||||||
NODE* parent = reduceSpringback( headSet, &aVia );
|
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 = parent->Branch();
|
||||||
m_currentNode->ClearRanks();
|
m_currentNode->ClearRanks();
|
||||||
|
|
|
@ -94,6 +94,7 @@ VIA* VIA::Clone() const
|
||||||
v->m_rank = m_rank;
|
v->m_rank = m_rank;
|
||||||
v->m_marker = m_marker;
|
v->m_marker = m_marker;
|
||||||
v->m_viaType = m_viaType;
|
v->m_viaType = m_viaType;
|
||||||
|
v->m_parent = m_parent;
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
VIA( const VIA& aB ) :
|
VIA( const VIA& aB ) :
|
||||||
ITEM( VIA_T )
|
ITEM( aB )
|
||||||
{
|
{
|
||||||
SetNet( aB.Net() );
|
SetNet( aB.Net() );
|
||||||
SetLayers( aB.Layers() );
|
SetLayers( aB.Layers() );
|
||||||
|
|
Loading…
Reference in New Issue