Implement hole clearance and hole-to-hole clearance in router.
Fixes https://gitlab.com/kicad/code/kicad/issues/6882
This commit is contained in:
parent
5d8e6020d1
commit
ecc0e861d3
|
@ -100,7 +100,7 @@ bool COMPONENT_DRAGGER::Start( const VECTOR2I& aP, ITEM_SET& aPrimitives )
|
|||
{
|
||||
LINKED_ITEM* li = static_cast<LINKED_ITEM*>( extraJoint->LinkList()[0].item );
|
||||
|
||||
if( li->Collide( solid, 0, false, nullptr, nullptr, false ) )
|
||||
if( li->Collide( solid, 0, m_world ) )
|
||||
addLinked( solid, li, extraJoint->Pos() - solid->Pos() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,28 +33,7 @@ void INDEX::Add( ITEM* aItem )
|
|||
m_subIndices.resize( 2 * range.End() + 1 ); // +1 handles the 0 case
|
||||
|
||||
for( int i = range.Start(); i <= range.End(); ++i )
|
||||
{
|
||||
if( !ROUTER::GetInstance()->GetInterface()->IsOnLayer( aItem, i ) )
|
||||
{
|
||||
if( aItem->AlternateShape() )
|
||||
{
|
||||
m_subIndices[i].Add( aItem, aItem->AlternateShape()->BBox() );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogError( "Missing expected Alternate shape for %s at %d %d",
|
||||
aItem->Parent()->GetClass(),
|
||||
aItem->Anchor( 0 ).x,
|
||||
aItem->Anchor( 0 ).y );
|
||||
m_subIndices[i].Add( aItem );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_subIndices[i].Add( aItem );
|
||||
}
|
||||
}
|
||||
m_subIndices[i].Add( aItem );
|
||||
|
||||
m_allItems.insert( aItem );
|
||||
int net = aItem->Net();
|
||||
|
|
|
@ -28,12 +28,23 @@ typedef VECTOR2I::extended_type ecoord;
|
|||
|
||||
namespace PNS {
|
||||
|
||||
bool ITEM::collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
|
||||
const NODE* aParentNode, bool aDifferentNetsOnly ) const
|
||||
bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly ) const
|
||||
{
|
||||
const ROUTER_IFACE* iface = ROUTER::GetInstance()->GetInterface();
|
||||
const SHAPE* shapeA = Shape();
|
||||
const SHAPE* holeA = Hole();
|
||||
int lineWidthA = 0;
|
||||
const SHAPE* shapeB = aOther->Shape();
|
||||
const SHAPE* holeB = aOther->Hole();
|
||||
int lineWidthB = 0;
|
||||
|
||||
// Sadly collision routines ignore SHAPE_POLY_LINE widths so we have to pass them in as part
|
||||
// of the clearance value.
|
||||
if( m_kind == LINE_T )
|
||||
lineWidthA = static_cast<const LINE*>( this )->Width() / 2;
|
||||
|
||||
if( aOther->m_kind == LINE_T )
|
||||
lineWidthB = static_cast<const LINE*>( aOther )->Width() / 2;
|
||||
|
||||
// same nets? no collision!
|
||||
if( aDifferentNetsOnly && m_net == aOther->m_net && m_net >= 0 && aOther->m_net >= 0 )
|
||||
|
@ -43,62 +54,69 @@ bool ITEM::collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VEC
|
|||
if( !m_layers.Overlaps( aOther->m_layers ) )
|
||||
return false;
|
||||
|
||||
if( !aOther->Layers().IsMultilayer() && !iface->IsOnLayer( this, aOther->Layer() ) )
|
||||
if( holeA || holeB )
|
||||
{
|
||||
if( !AlternateShape() )
|
||||
int holeClearance = aNode->GetHoleClearance( this, aOther );
|
||||
|
||||
if( holeA && holeA->Collide( shapeB, holeClearance + lineWidthB ) )
|
||||
{
|
||||
wxLogError( "Missing expected Alternate shape for %s at %d %d",
|
||||
m_parent->GetClass(),
|
||||
Anchor( 0 ).x,
|
||||
Anchor( 0 ).y );
|
||||
Mark( MK_HOLE );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
if( holeB && holeB->Collide( shapeA, holeClearance + lineWidthA ) )
|
||||
{
|
||||
shapeA = AlternateShape();
|
||||
Mark( MK_ALT_SHAPE );
|
||||
aOther->Mark( MK_HOLE );
|
||||
return true;
|
||||
}
|
||||
|
||||
if( holeA && holeB )
|
||||
{
|
||||
int holeToHoleClearance = aNode->GetHoleToHoleClearance( this, aOther );
|
||||
|
||||
if( holeA->Collide( holeB, holeToHoleClearance ) )
|
||||
{
|
||||
Mark( MK_HOLE );
|
||||
aOther->Mark( MK_HOLE );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !Layers().IsMultilayer() && !iface->IsOnLayer( aOther, Layer() ) )
|
||||
{
|
||||
if( !aOther->AlternateShape() )
|
||||
{
|
||||
wxLogError( "Missing expected Alternate shape for %s at %d %d",
|
||||
aOther->Parent()->GetClass(),
|
||||
aOther->Anchor( 0 ).x,
|
||||
aOther->Anchor( 0 ).y );
|
||||
}
|
||||
else
|
||||
{
|
||||
shapeB = aOther->AlternateShape();
|
||||
aOther->Mark( MK_ALT_SHAPE );
|
||||
}
|
||||
}
|
||||
if( !aOther->Layers().IsMultilayer() && !iface->IsFlashedOnLayer( this, aOther->Layer()) )
|
||||
return false;
|
||||
|
||||
if( aNeedMTV )
|
||||
return shapeA->Collide( shapeB, aClearance, aMTV );
|
||||
else
|
||||
return shapeA->Collide( shapeB, aClearance );
|
||||
if( !Layers().IsMultilayer() && !iface->IsFlashedOnLayer( aOther, Layer()) )
|
||||
return false;
|
||||
|
||||
int clearance = aNode->GetClearance( this, aOther );
|
||||
return shapeA->Collide( shapeB, clearance + lineWidthA + lineWidthB );
|
||||
}
|
||||
|
||||
|
||||
bool ITEM::Collide( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
|
||||
const NODE* aParentNode, bool aDifferentNetsOnly ) const
|
||||
bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly ) const
|
||||
{
|
||||
if( collideSimple( aOther, aClearance, aNeedMTV, aMTV, aParentNode, aDifferentNetsOnly ) )
|
||||
if( collideSimple( aOther, aNode, aDifferentNetsOnly ) )
|
||||
return true;
|
||||
|
||||
// special case for "head" line with a via attached at the end.
|
||||
// Special cases for "head" lines with vias attached at the end. Note that this does not
|
||||
// support head-line-via to head-line-via collisions, but you can't route two independant
|
||||
// tracks at once so it shouldn't come up.
|
||||
|
||||
if( m_kind == LINE_T )
|
||||
{
|
||||
const LINE* line = static_cast<const LINE*>( this );
|
||||
|
||||
if( line->EndsWithVia() && line->Via().collideSimple( aOther, aNode, aDifferentNetsOnly ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
if( aOther->m_kind == LINE_T )
|
||||
{
|
||||
const LINE* line = static_cast<const LINE*>( aOther );
|
||||
int clearance = aClearance - line->Width() / 2;
|
||||
|
||||
if( line->EndsWithVia() )
|
||||
{
|
||||
return collideSimple( &line->Via(), clearance, aNeedMTV, aMTV, aParentNode,
|
||||
aDifferentNetsOnly );
|
||||
}
|
||||
if( line->EndsWithVia() && line->Via().collideSimple( this, aNode, aDifferentNetsOnly ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -109,14 +127,14 @@ std::string ITEM::KindStr() const
|
|||
{
|
||||
switch( m_kind )
|
||||
{
|
||||
case ARC_T: return "arc";
|
||||
case LINE_T: return "line";
|
||||
case SEGMENT_T: return "segment";
|
||||
case VIA_T: return "via";
|
||||
case JOINT_T: return "joint";
|
||||
case SOLID_T: return "solid";
|
||||
case DIFF_PAIR_T: return "diff-pair";
|
||||
default: return "unknown";
|
||||
case ARC_T: return "arc";
|
||||
case LINE_T: return "line";
|
||||
case SEGMENT_T: return "segment";
|
||||
case VIA_T: return "via";
|
||||
case JOINT_T: return "joint";
|
||||
case SOLID_T: return "solid";
|
||||
case DIFF_PAIR_T: return "diff-pair";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,7 @@ enum LineMarker {
|
|||
MK_VIOLATION = ( 1 << 3 ),
|
||||
MK_LOCKED = ( 1 << 4 ),
|
||||
MK_DP_COUPLED = ( 1 << 5 ),
|
||||
MK_ALT_SHAPE = ( 1 << 6 ) // For instance, a simple annular ring when the pad has
|
||||
// been dropped from a layer.
|
||||
MK_HOLE = ( 1 << 6 )
|
||||
};
|
||||
|
||||
|
||||
|
@ -117,6 +116,11 @@ public:
|
|||
return SHAPE_LINE_CHAIN();
|
||||
}
|
||||
|
||||
virtual const SHAPE_LINE_CHAIN HoleHull( int aClearance, int aWalkaroundThickness, int aLayer ) const
|
||||
{
|
||||
return SHAPE_LINE_CHAIN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function Kind()
|
||||
*
|
||||
|
@ -199,13 +203,9 @@ public:
|
|||
* Optionally returns a minimum translation vector for force propagation algorithm.
|
||||
*
|
||||
* @param aOther item to check collision against
|
||||
* @param aClearance desired clearance
|
||||
* @param aNeedMTV when true, the minimum translation vector is calculated
|
||||
* @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,
|
||||
const NODE* aParentNode, bool aDifferentNetsOnly = true ) const;
|
||||
bool Collide( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly = true ) const;
|
||||
|
||||
/**
|
||||
* Function Shape()
|
||||
|
@ -215,12 +215,12 @@ public:
|
|||
*/
|
||||
virtual const SHAPE* Shape() const
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual const SHAPE* AlternateShape() const
|
||||
virtual const SHAPE* Hole() const
|
||||
{
|
||||
return Shape();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void Mark( int aMarker ) const { m_marker = aMarker; }
|
||||
|
@ -249,8 +249,7 @@ public:
|
|||
bool IsRoutable() const { return m_routable; }
|
||||
|
||||
private:
|
||||
bool collideSimple( const ITEM* aOther, int aClearance, bool aNeedMTV, VECTOR2I* aMTV,
|
||||
const NODE* aParentNode, bool aDifferentNetsOnly ) const;
|
||||
bool collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly ) const;
|
||||
|
||||
protected:
|
||||
PnsKind m_kind;
|
||||
|
|
|
@ -73,10 +73,10 @@ public:
|
|||
PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER_IFACE* aRouterIface );
|
||||
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 ) override;
|
||||
virtual int HoleClearance( const PNS::ITEM* aA, const PNS::ITEM* aB ) override;
|
||||
virtual int HoleToHoleClearance( const PNS::ITEM* aA, const PNS::ITEM* aB ) override;
|
||||
|
||||
virtual int DpCoupledNet( int aNet ) override;
|
||||
virtual int DpNetPolarity( int aNet ) override;
|
||||
virtual bool DpNetPair( const PNS::ITEM* aItem, int& aNetP, int& aNetN ) override;
|
||||
|
@ -97,6 +97,8 @@ private:
|
|||
VIA m_dummyVia;
|
||||
|
||||
std::map<std::pair<const PNS::ITEM*, const PNS::ITEM*>, int> m_clearanceCache;
|
||||
std::map<std::pair<const PNS::ITEM*, const PNS::ITEM*>, int> m_holeClearanceCache;
|
||||
std::map<std::pair<const PNS::ITEM*, const PNS::ITEM*>, int> m_holeToHoleClearanceCache;
|
||||
};
|
||||
|
||||
|
||||
|
@ -137,44 +139,6 @@ int PNS_PCBNEW_RULE_RESOLVER::holeRadius( const PNS::ITEM* aItem ) const
|
|||
}
|
||||
|
||||
|
||||
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 == 0 || 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 PNS_PCBNEW_RULE_RESOLVER::IsDiffPair( const PNS::ITEM* aA, const PNS::ITEM* aB )
|
||||
{
|
||||
int net_p, net_n;
|
||||
|
@ -191,6 +155,11 @@ bool PNS_PCBNEW_RULE_RESOLVER::IsDiffPair( const PNS::ITEM* aA, const PNS::ITEM*
|
|||
}
|
||||
|
||||
|
||||
bool isEdge( const PNS::ITEM* aItem )
|
||||
{
|
||||
return aItem->Layer() == Edge_Cuts || aItem->Layer() == Margin;
|
||||
}
|
||||
|
||||
|
||||
bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
|
||||
const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
|
||||
|
@ -205,13 +174,16 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
|
|||
|
||||
switch ( aType )
|
||||
{
|
||||
case PNS::CONSTRAINT_TYPE::CT_CLEARANCE: hostType = CLEARANCE_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_WIDTH: hostType = TRACK_WIDTH_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP: hostType = DIFF_PAIR_GAP_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_LENGTH: hostType = LENGTH_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER: hostType = VIA_DIAMETER_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_VIA_HOLE: hostType = HOLE_SIZE_CONSTRAINT; break;
|
||||
default: return false; // should not happen
|
||||
case PNS::CONSTRAINT_TYPE::CT_CLEARANCE: hostType = CLEARANCE_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_WIDTH: hostType = TRACK_WIDTH_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP: hostType = DIFF_PAIR_GAP_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_LENGTH: hostType = LENGTH_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER: hostType = VIA_DIAMETER_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_VIA_HOLE: hostType = HOLE_SIZE_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE: hostType = HOLE_CLEARANCE_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE: hostType = EDGE_CLEARANCE_CONSTRAINT; break;
|
||||
case PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE: hostType = HOLE_TO_HOLE_CONSTRAINT; break;
|
||||
default: return false; // should not happen
|
||||
}
|
||||
|
||||
BOARD_ITEM* parentA = aItemA ? aItemA->Parent() : nullptr;
|
||||
|
@ -271,6 +243,9 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
|
|||
case PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP:
|
||||
case PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER:
|
||||
case PNS::CONSTRAINT_TYPE::CT_VIA_HOLE:
|
||||
case PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE:
|
||||
case PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE:
|
||||
case PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE:
|
||||
aConstraint->m_Value = hostConstraint.GetValue();
|
||||
aConstraint->m_RuleName = hostConstraint.GetName();
|
||||
aConstraint->m_Type = aType;
|
||||
|
@ -291,7 +266,6 @@ int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* a
|
|||
return it->second;
|
||||
|
||||
PNS::CONSTRAINT constraint;
|
||||
bool ok = false;
|
||||
int rv = 0;
|
||||
|
||||
if( aB && IsDiffPair( aA, aB ) )
|
||||
|
@ -301,26 +275,72 @@ int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* a
|
|||
&constraint ) )
|
||||
{
|
||||
rv = constraint.m_Value.Opt();
|
||||
ok = true;
|
||||
m_clearanceCache[ key ] = rv;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if( !ok )
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, aA->Layer(),
|
||||
&constraint ) )
|
||||
{
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, aA->Layer(),
|
||||
rv = constraint.m_Value.Min();
|
||||
}
|
||||
|
||||
if( isEdge( aA ) || ( aB && isEdge( aB ) ) )
|
||||
{
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, aA->Layer(),
|
||||
&constraint ) )
|
||||
{
|
||||
rv = constraint.m_Value.Min();
|
||||
ok = true;
|
||||
if( constraint.m_Value.Min() > rv )
|
||||
rv = constraint.m_Value.Min();
|
||||
}
|
||||
}
|
||||
|
||||
// still no valid clearance rule? fall back to global minimum.
|
||||
if( !ok )
|
||||
rv = m_board->GetDesignSettings().m_MinClearance;
|
||||
|
||||
m_clearanceCache[ key ] = rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int PNS_PCBNEW_RULE_RESOLVER::HoleClearance( const PNS::ITEM* aA, const PNS::ITEM* aB )
|
||||
{
|
||||
std::pair<const PNS::ITEM*, const PNS::ITEM*> key( aA, aB );
|
||||
auto it = m_holeClearanceCache.find( key );
|
||||
|
||||
if( it != m_holeClearanceCache.end() )
|
||||
return it->second;
|
||||
|
||||
PNS::CONSTRAINT constraint;
|
||||
int rv = 0;
|
||||
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE, aA, aB, aA->Layer(),
|
||||
&constraint ) )
|
||||
{
|
||||
rv = constraint.m_Value.Min();
|
||||
}
|
||||
|
||||
m_holeClearanceCache[ key ] = rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int PNS_PCBNEW_RULE_RESOLVER::HoleToHoleClearance( const PNS::ITEM* aA, const PNS::ITEM* aB )
|
||||
{
|
||||
std::pair<const PNS::ITEM*, const PNS::ITEM*> key( aA, aB );
|
||||
auto it = m_holeToHoleClearanceCache.find( key );
|
||||
|
||||
if( it != m_holeToHoleClearanceCache.end() )
|
||||
return it->second;
|
||||
|
||||
PNS::CONSTRAINT constraint;
|
||||
int rv = 0;
|
||||
|
||||
if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, aA, aB, aA->Layer(),
|
||||
&constraint ) )
|
||||
{
|
||||
rv = constraint.m_Value.Min();
|
||||
}
|
||||
|
||||
m_holeToHoleClearanceCache[ key ] = rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -821,7 +841,7 @@ std::unique_ptr<PNS::SOLID> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
|
|||
slot->SetWidth( slot->GetWidth() + bds.GetHolePlatingThickness() * 2 );
|
||||
}
|
||||
|
||||
solid->SetAlternateShape( slot );
|
||||
solid->SetHole( slot );
|
||||
}
|
||||
|
||||
if( aPad->GetAttribute() == PAD_ATTRIB_NPTH )
|
||||
|
@ -923,6 +943,10 @@ std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( VIA* aVia )
|
|||
|
||||
via->SetIsFree( aVia->GetIsFree() );
|
||||
|
||||
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||
via->SetHole( SHAPE_CIRCLE( aVia->GetPosition(),
|
||||
aVia->GetDrill() / 2 + bds.GetHolePlatingThickness() ) );
|
||||
|
||||
return via;
|
||||
}
|
||||
|
||||
|
@ -1107,7 +1131,7 @@ bool PNS_KICAD_IFACE::IsAnyLayerVisible( const LAYER_RANGE& aLayer ) const
|
|||
}
|
||||
|
||||
|
||||
bool PNS_KICAD_IFACE::IsOnLayer( const PNS::ITEM* aItem, int aLayer ) const
|
||||
bool PNS_KICAD_IFACE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const
|
||||
{
|
||||
/// Default is all layers
|
||||
if( aLayer < 0 )
|
||||
|
@ -1170,7 +1194,7 @@ bool PNS_KICAD_IFACE::IsItemVisible( const PNS::ITEM* aItem ) const
|
|||
|
||||
void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
|
||||
{
|
||||
int worstPadClearance = 0;
|
||||
int worstClearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
|
||||
|
||||
m_world = aWorld;
|
||||
|
||||
|
@ -1210,7 +1234,7 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
|
|||
if( std::unique_ptr<PNS::SOLID> solid = syncPad( pad ) )
|
||||
aWorld->Add( std::move( solid ) );
|
||||
|
||||
worstPadClearance = std::max( worstPadClearance, pad->GetLocalClearance() );
|
||||
worstClearance = std::max( worstClearance, pad->GetLocalClearance() );
|
||||
}
|
||||
|
||||
syncTextItem( aWorld, &footprint->Reference(), footprint->Reference().GetLayer() );
|
||||
|
@ -1256,15 +1280,13 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
|
|||
}
|
||||
}
|
||||
|
||||
int worstRuleClearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
|
||||
|
||||
// NB: if this were ever to become a long-lived object we would need to dirty its
|
||||
// clearance cache here....
|
||||
delete m_ruleResolver;
|
||||
m_ruleResolver = new PNS_PCBNEW_RULE_RESOLVER( m_board, this );
|
||||
|
||||
aWorld->SetRuleResolver( m_ruleResolver );
|
||||
aWorld->SetMaxClearance( 4 * std::max(worstPadClearance, worstRuleClearance ) );
|
||||
aWorld->SetMaxClearance( 4 * worstClearance );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
void SetBoard( BOARD* aBoard );
|
||||
void SyncWorld( PNS::NODE* aWorld ) override;
|
||||
bool IsAnyLayerVisible( const LAYER_RANGE& aLayer ) const override { return true; };
|
||||
bool IsOnLayer( const PNS::ITEM* aItem, int aLayer ) const override { return true; };
|
||||
bool IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const override { return true; };
|
||||
bool IsItemVisible( const PNS::ITEM* aItem ) const override { return true; }
|
||||
void HideItem( PNS::ITEM* aItem ) override {}
|
||||
void DisplayItem( const PNS::ITEM* aItem, int aColor = 0, int aClearance = 0,
|
||||
|
@ -115,7 +115,7 @@ public:
|
|||
void EraseView() override;
|
||||
bool IsAnyLayerVisible( const LAYER_RANGE& aLayer ) const override;
|
||||
bool IsItemVisible( const PNS::ITEM* aItem ) const override;
|
||||
bool IsOnLayer( const PNS::ITEM* aItem, int aLayer ) const override;
|
||||
bool IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const override;
|
||||
void HideItem( PNS::ITEM* aItem ) override;
|
||||
void DisplayItem( const PNS::ITEM* aItem, int aColor = 0, int aClearance = 0,
|
||||
bool aEdit = false ) override;
|
||||
|
|
|
@ -478,55 +478,17 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead )
|
|||
|
||||
bool LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, LINE& aNewHead )
|
||||
{
|
||||
LINE newHead( m_head );
|
||||
LINE bestHead( m_head );
|
||||
bool hasBest = false;
|
||||
buildInitialLine( aP, m_head );
|
||||
|
||||
buildInitialLine( aP, newHead );
|
||||
|
||||
NODE::OBSTACLES obstacles;
|
||||
|
||||
m_currentNode->QueryColliding( &newHead, obstacles );
|
||||
|
||||
// If we are allowing DRC violations, we don't push back to the hull
|
||||
// If we are enforcing DRC violations, push back to the hull
|
||||
if( !Settings().CanViolateDRC() )
|
||||
{
|
||||
int layer = m_head.Layer();
|
||||
int lineWidth = m_placingVia ? m_head.Via().Diameter() : m_head.Width();
|
||||
int clearance;
|
||||
NODE::OPT_OBSTACLE obs = m_currentNode->NearestObstacle( &m_head );
|
||||
|
||||
for( OBSTACLE& obs : obstacles )
|
||||
{
|
||||
if( m_placingVia )
|
||||
clearance = m_currentNode->GetClearance( obs.m_item, &m_head.Via() );
|
||||
else
|
||||
clearance = m_currentNode->GetClearance( obs.m_item, &m_head );
|
||||
|
||||
const SHAPE_LINE_CHAIN hull = obs.m_item->Hull( clearance, lineWidth, layer );
|
||||
VECTOR2I nearest = hull.NearestPoint( aP );
|
||||
|
||||
Dbg()->AddLine( hull, 2, 10000 );
|
||||
|
||||
if( ( nearest - aP ).EuclideanNorm() < lineWidth + clearance )
|
||||
{
|
||||
buildInitialLine( nearest, newHead );
|
||||
|
||||
// We want the shortest line here to ensure we don't break a clearance
|
||||
// rule on larger, overlapping items (e.g. vias)
|
||||
if( !hasBest || newHead.CLine().Length() < bestHead.CLine().Length() )
|
||||
{
|
||||
bestHead = newHead;
|
||||
hasBest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( obs && obs->m_distFirst != INT_MAX )
|
||||
buildInitialLine( obs->m_ipFirst, m_head );
|
||||
}
|
||||
|
||||
if( hasBest )
|
||||
m_head = bestHead;
|
||||
else
|
||||
m_head = newHead;
|
||||
|
||||
aNewHead = m_head;
|
||||
|
||||
return static_cast<bool>( m_currentNode->CheckColliding( &m_head ) );
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include "pns_solid.h"
|
||||
#include "pns_joint.h"
|
||||
#include "pns_index.h"
|
||||
#include "pns_debug_decorator.h"
|
||||
#include "pns_router.h"
|
||||
|
||||
|
||||
namespace PNS {
|
||||
|
@ -103,6 +105,24 @@ int NODE::GetClearance( const ITEM* aA, const ITEM* aB ) const
|
|||
}
|
||||
|
||||
|
||||
int NODE::GetHoleClearance( const ITEM* aA, const ITEM* aB ) const
|
||||
{
|
||||
if( !m_ruleResolver )
|
||||
return 0;
|
||||
|
||||
return m_ruleResolver->HoleClearance( aA, aB );
|
||||
}
|
||||
|
||||
|
||||
int NODE::GetHoleToHoleClearance( const ITEM* aA, const ITEM* aB ) const
|
||||
{
|
||||
if( !m_ruleResolver )
|
||||
return 0;
|
||||
|
||||
return m_ruleResolver->HoleToHoleClearance( aA, aB );
|
||||
}
|
||||
|
||||
|
||||
NODE* NODE::Branch()
|
||||
{
|
||||
NODE* child = new NODE;
|
||||
|
@ -194,8 +214,6 @@ struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
|
|||
|
||||
bool m_differentNetsOnly;
|
||||
|
||||
int m_forceClearance;
|
||||
|
||||
DEFAULT_OBSTACLE_VISITOR( NODE::OBSTACLES& aTab, const ITEM* aItem, int aKindMask, bool aDifferentNetsOnly ) :
|
||||
OBSTACLE_VISITOR( aItem ),
|
||||
m_tab( aTab ),
|
||||
|
@ -203,8 +221,7 @@ struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
|
|||
m_limitCount( -1 ),
|
||||
m_matchCount( 0 ),
|
||||
m_extraClearance( 0 ),
|
||||
m_differentNetsOnly( aDifferentNetsOnly ),
|
||||
m_forceClearance( -1 )
|
||||
m_differentNetsOnly( aDifferentNetsOnly )
|
||||
{
|
||||
if( aItem && aItem->Kind() == ITEM::LINE_T )
|
||||
{
|
||||
|
@ -229,18 +246,7 @@ struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
|
|||
if( visit( aCandidate ) )
|
||||
return true;
|
||||
|
||||
int clearance = m_extraClearance + m_node->GetClearance( aCandidate, m_item );
|
||||
|
||||
if( aCandidate->Kind() == ITEM::LINE_T ) // this should never happen.
|
||||
{
|
||||
assert( false );
|
||||
clearance += static_cast<LINE*>( aCandidate )->Width() / 2;
|
||||
}
|
||||
|
||||
if( m_forceClearance >= 0 )
|
||||
clearance = m_forceClearance;
|
||||
|
||||
if( !aCandidate->Collide( m_item, clearance, false, nullptr, m_node, m_differentNetsOnly ) )
|
||||
if( !aCandidate->Collide( m_item, m_node, m_differentNetsOnly ) )
|
||||
return true;
|
||||
|
||||
OBSTACLE obs;
|
||||
|
@ -259,24 +265,8 @@ struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
|
|||
};
|
||||
|
||||
|
||||
int NODE::QueryColliding( const ITEM* aItem, OBSTACLE_VISITOR& aVisitor )
|
||||
{
|
||||
aVisitor.SetWorld( this, NULL );
|
||||
m_index->Query( aItem, m_maxClearance, aVisitor );
|
||||
|
||||
// if we haven't found enough items, look in the root branch as well.
|
||||
if( !isRoot() )
|
||||
{
|
||||
aVisitor.SetWorld( m_root, this );
|
||||
m_root->m_index->Query( aItem, m_maxClearance, aVisitor );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int NODE::QueryColliding( const ITEM* aItem, NODE::OBSTACLES& aObstacles, int aKindMask,
|
||||
int aLimitCount, bool aDifferentNetsOnly, int aForceClearance )
|
||||
int aLimitCount, bool aDifferentNetsOnly )
|
||||
{
|
||||
DEFAULT_OBSTACLE_VISITOR visitor( aObstacles, aItem, aKindMask, aDifferentNetsOnly );
|
||||
|
||||
|
@ -286,7 +276,7 @@ int NODE::QueryColliding( const ITEM* aItem, NODE::OBSTACLES& aObstacles, int aK
|
|||
|
||||
visitor.SetCountLimit( aLimitCount );
|
||||
visitor.SetWorld( this, NULL );
|
||||
visitor.m_forceClearance = aForceClearance;
|
||||
|
||||
// first, look for colliding items in the local index
|
||||
m_index->Query( aItem, m_maxClearance, visitor );
|
||||
|
||||
|
@ -304,105 +294,131 @@ int NODE::QueryColliding( const ITEM* aItem, NODE::OBSTACLES& aObstacles, int aK
|
|||
NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine, int aKindMask,
|
||||
const std::set<ITEM*>* aRestrictedSet )
|
||||
{
|
||||
OBSTACLES obs_list;
|
||||
bool found_isects = false;
|
||||
OBSTACLES obstacleList;
|
||||
obstacleList.reserve( 100 );
|
||||
|
||||
const SHAPE_LINE_CHAIN& line = aLine->CLine();
|
||||
|
||||
obs_list.reserve( 100 );
|
||||
|
||||
int n = 0;
|
||||
|
||||
for( int i = 0; i < line.SegmentCount(); i++ )
|
||||
for( int i = 0; i < aLine->CLine().SegmentCount(); i++ )
|
||||
{
|
||||
const SEGMENT s( *aLine, line.CSegment( i ) );
|
||||
n += QueryColliding( &s, obs_list, aKindMask );
|
||||
const SEGMENT s( *aLine, aLine->CLine().CSegment( i ) );
|
||||
QueryColliding( &s, obstacleList, aKindMask );
|
||||
}
|
||||
|
||||
if( aLine->EndsWithVia() )
|
||||
n += QueryColliding( &aLine->Via(), obs_list, aKindMask );
|
||||
QueryColliding( &aLine->Via(), obstacleList, aKindMask );
|
||||
|
||||
if( !n )
|
||||
if( obstacleList.empty() )
|
||||
return OPT_OBSTACLE();
|
||||
|
||||
OBSTACLE nearest;
|
||||
nearest.m_item = NULL;
|
||||
nearest.m_distFirst = INT_MAX;
|
||||
|
||||
for( const OBSTACLE& obs : obs_list )
|
||||
{
|
||||
VECTOR2I ip_last;
|
||||
int dist_max = INT_MIN;
|
||||
auto updateNearest =
|
||||
[&]( int dist, VECTOR2I pt, ITEM* item, const SHAPE_LINE_CHAIN& hull )
|
||||
{
|
||||
if( dist < nearest.m_distFirst )
|
||||
{
|
||||
nearest.m_distFirst = dist;
|
||||
nearest.m_ipFirst = pt;
|
||||
nearest.m_item = item;
|
||||
nearest.m_hull = hull;
|
||||
}
|
||||
};
|
||||
|
||||
if( aRestrictedSet && aRestrictedSet->find( obs.m_item ) == aRestrictedSet->end() )
|
||||
for( const OBSTACLE& obstacle : obstacleList )
|
||||
{
|
||||
if( aRestrictedSet && aRestrictedSet->find( obstacle.m_item ) == aRestrictedSet->end() )
|
||||
continue;
|
||||
|
||||
std::vector<SHAPE_LINE_CHAIN::INTERSECTION> isect_list;
|
||||
std::vector<SHAPE_LINE_CHAIN::INTERSECTION> intersectingPts;
|
||||
|
||||
int clearance = GetClearance( obs.m_item, aLine );
|
||||
int clearance = GetClearance( obstacle.m_item, aLine ) + aLine->Width() / 2;
|
||||
SHAPE_LINE_CHAIN obstacleHull = obstacle.m_item->Hull( clearance, 0, aLine->Layer() );
|
||||
|
||||
SHAPE_LINE_CHAIN obsHull = obs.m_item->Hull( clearance, aLine->Width(), aLine->Layer() );
|
||||
ROUTER::GetInstance()->GetInterface()->GetDebugDecorator()->AddLine( obstacleHull, 2, 1000 );
|
||||
|
||||
if( aLine->EndsWithVia() )
|
||||
{
|
||||
clearance = GetClearance( obs.m_item, &aLine->Via() );
|
||||
const VIA& via = aLine->Via();
|
||||
int viaClearance = GetClearance( obstacle.m_item, &via );
|
||||
int holeClearance = GetHoleClearance( obstacle.m_item, &via );
|
||||
|
||||
SHAPE_LINE_CHAIN viaHull = aLine->Via().Hull( clearance, aLine->Width() );
|
||||
if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
|
||||
viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
|
||||
|
||||
viaHull.Intersect( obsHull, isect_list );
|
||||
// ObstacleHull has line clearance and 1/2 line width already built in. So
|
||||
// viaHull's clearance needs to be only that portion of the via clearance that
|
||||
// is *in excess* of the line clearance.
|
||||
viaClearance = std::max( 0, viaClearance - clearance );
|
||||
|
||||
for( const SHAPE_LINE_CHAIN::INTERSECTION& isect : isect_list )
|
||||
SHAPE_LINE_CHAIN viaHull = via.Hull( viaClearance, 0 );
|
||||
|
||||
obstacleHull.Intersect( viaHull, intersectingPts );
|
||||
|
||||
for( const SHAPE_LINE_CHAIN::INTERSECTION& ip : intersectingPts )
|
||||
{
|
||||
int dist = aLine->CLine().Length() +
|
||||
( isect.p - aLine->Via().Pos() ).EuclideanNorm();
|
||||
|
||||
if( dist < nearest.m_distFirst )
|
||||
{
|
||||
found_isects = true;
|
||||
nearest.m_distFirst = dist;
|
||||
nearest.m_ipFirst = isect.p;
|
||||
nearest.m_item = obs.m_item;
|
||||
nearest.m_hull = obsHull;
|
||||
}
|
||||
|
||||
if( dist > dist_max )
|
||||
{
|
||||
dist_max = dist;
|
||||
ip_last = isect.p;
|
||||
}
|
||||
int dist = aLine->CLine().Length() + ( ip.p - via.Pos() ).EuclideanNorm();
|
||||
updateNearest( dist, ip.p, obstacle.m_item, obstacleHull );
|
||||
}
|
||||
}
|
||||
|
||||
isect_list.clear();
|
||||
intersectingPts.clear();
|
||||
obstacleHull.Intersect( aLine->CLine(), intersectingPts );
|
||||
|
||||
obsHull.Intersect( aLine->CLine(), isect_list );
|
||||
|
||||
for( const SHAPE_LINE_CHAIN::INTERSECTION& isect : isect_list )
|
||||
for( const SHAPE_LINE_CHAIN::INTERSECTION& ip : intersectingPts )
|
||||
{
|
||||
int dist = aLine->CLine().PathLength( isect.p );
|
||||
|
||||
if( dist < nearest.m_distFirst )
|
||||
{
|
||||
found_isects = true;
|
||||
nearest.m_distFirst = dist;
|
||||
nearest.m_ipFirst = isect.p;
|
||||
nearest.m_item = obs.m_item;
|
||||
nearest.m_hull = obsHull;
|
||||
}
|
||||
|
||||
if( dist > dist_max )
|
||||
{
|
||||
dist_max = dist;
|
||||
ip_last = isect.p;
|
||||
}
|
||||
int dist = aLine->CLine().PathLength( ip.p );
|
||||
updateNearest( dist, ip.p, obstacle.m_item, obstacleHull );
|
||||
}
|
||||
|
||||
nearest.m_ipLast = ip_last;
|
||||
nearest.m_distLast = dist_max;
|
||||
if( obstacle.m_item->Hole() )
|
||||
{
|
||||
clearance = GetHoleClearance( obstacle.m_item, aLine ) + aLine->Width() / 2;
|
||||
obstacleHull = obstacle.m_item->HoleHull( clearance, 0, aLine->Layer() );
|
||||
|
||||
ROUTER::GetInstance()->GetInterface()->GetDebugDecorator()->AddLine( obstacleHull, 3, 1000 );
|
||||
|
||||
if( aLine->EndsWithVia() )
|
||||
{
|
||||
const VIA& via = aLine->Via();
|
||||
int viaClearance = GetClearance( obstacle.m_item, &via );
|
||||
int holeClearance = GetHoleClearance( obstacle.m_item, &via );
|
||||
int holeToHole = GetHoleToHoleClearance( obstacle.m_item, &via );
|
||||
|
||||
if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
|
||||
viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
|
||||
|
||||
if( holeToHole + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
|
||||
viaClearance = holeToHole + via.Drill() / 2 - via.Diameter() / 2;
|
||||
|
||||
// ObsHull has line clearance and 1/2 line width already built in. So viaHull's
|
||||
// clearance needs to be just that which is *in excess* of clearance.
|
||||
viaClearance = std::max( 0, viaClearance - clearance );
|
||||
|
||||
SHAPE_LINE_CHAIN viaHull = via.Hull( viaClearance, 0 );
|
||||
|
||||
obstacleHull.Intersect( viaHull, intersectingPts );
|
||||
|
||||
for( const SHAPE_LINE_CHAIN::INTERSECTION& ip : intersectingPts )
|
||||
{
|
||||
int dist = aLine->CLine().Length() + ( ip.p - via.Pos() ).EuclideanNorm();
|
||||
updateNearest( dist, ip.p, obstacle.m_item, obstacleHull );
|
||||
}
|
||||
}
|
||||
|
||||
intersectingPts.clear();
|
||||
obstacleHull.Intersect( aLine->CLine(), intersectingPts );
|
||||
|
||||
for( const SHAPE_LINE_CHAIN::INTERSECTION& ip : intersectingPts )
|
||||
{
|
||||
int dist = aLine->CLine().PathLength( ip.p );
|
||||
updateNearest( dist, ip.p, obstacle.m_item, obstacleHull );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !found_isects )
|
||||
nearest.m_item = obs_list[0].m_item;
|
||||
if( nearest.m_distFirst == INT_MAX )
|
||||
nearest.m_item = obstacleList[0].m_item;
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
@ -458,25 +474,6 @@ NODE::OPT_OBSTACLE NODE::CheckColliding( const ITEM* aItemA, int aKindMask )
|
|||
}
|
||||
|
||||
|
||||
bool NODE::CheckColliding( const ITEM* aItemA, const ITEM* aItemB, int aKindMask, int aForceClearance )
|
||||
{
|
||||
assert( aItemB );
|
||||
int clearance;
|
||||
if( aForceClearance >= 0 )
|
||||
clearance = aForceClearance;
|
||||
else
|
||||
clearance = GetClearance( aItemA, aItemB );
|
||||
|
||||
// fixme: refactor
|
||||
if( aItemA->Kind() == ITEM::LINE_T )
|
||||
clearance += static_cast<const LINE*>( aItemA )->Width() / 2;
|
||||
if( aItemB->Kind() == ITEM::LINE_T )
|
||||
clearance += static_cast<const LINE*>( aItemB )->Width() / 2;
|
||||
|
||||
return aItemA->Collide( aItemB, clearance, false, nullptr, this );
|
||||
}
|
||||
|
||||
|
||||
struct HIT_VISITOR : public OBSTACLE_VISITOR
|
||||
{
|
||||
ITEM_SET& m_items;
|
||||
|
|
|
@ -64,7 +64,8 @@ enum class CONSTRAINT_TYPE
|
|||
CT_VIA_DIAMETER = 5,
|
||||
CT_VIA_HOLE = 6,
|
||||
CT_HOLE_CLEARANCE = 7,
|
||||
CT_EDGE_CLEARANCE = 8
|
||||
CT_EDGE_CLEARANCE = 8,
|
||||
CT_HOLE_TO_HOLE = 9
|
||||
};
|
||||
|
||||
struct CONSTRAINT
|
||||
|
@ -82,10 +83,10 @@ 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 ) = 0;
|
||||
virtual int HoleClearance( const ITEM* aA, const ITEM* aB ) = 0;
|
||||
virtual int HoleToHoleClearance( const ITEM* aA, const ITEM* aB ) = 0;
|
||||
|
||||
virtual int DpCoupledNet( int aNet ) = 0;
|
||||
virtual int DpNetPolarity( int aNet ) = 0;
|
||||
virtual bool DpNetPair( const ITEM* aItem, int& aNetP, int& aNetN ) = 0;
|
||||
|
@ -114,12 +115,11 @@ struct OBSTACLE
|
|||
///> Hull of the colliding m_item
|
||||
SHAPE_LINE_CHAIN m_hull;
|
||||
|
||||
///> First and last intersection point between the head item and the hull
|
||||
///> of the colliding m_item
|
||||
VECTOR2I m_ipFirst, m_ipLast;
|
||||
///> First intersection point between the head item and the hull of the colliding m_item
|
||||
VECTOR2I m_ipFirst;
|
||||
|
||||
///> ... and the distance thereof
|
||||
int m_distFirst, m_distLast;
|
||||
int m_distFirst;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -180,6 +180,8 @@ public:
|
|||
|
||||
///> Returns the expected clearance between items a and b.
|
||||
int GetClearance( const ITEM* aA, const ITEM* aB ) const;
|
||||
int GetHoleClearance( const ITEM* aA, const ITEM* aB ) const;
|
||||
int GetHoleToHoleClearance( const ITEM* aA, const ITEM* aB ) const;
|
||||
|
||||
///> Returns the pre-set worst case clearance between any pair of items
|
||||
int GetMaxClearance() const
|
||||
|
@ -230,16 +232,13 @@ public:
|
|||
OBSTACLES& aObstacles,
|
||||
int aKindMask = ITEM::ANY_T,
|
||||
int aLimitCount = -1,
|
||||
bool aDifferentNetsOnly = true,
|
||||
int aForceClearance = -1 );
|
||||
bool aDifferentNetsOnly = true );
|
||||
|
||||
int QueryJoints( const BOX2I& aBox,
|
||||
std::vector<JOINT*>& aJoints,
|
||||
LAYER_RANGE aLayerMask = LAYER_RANGE::All(),
|
||||
int aKindMask = ITEM::ANY_T );
|
||||
|
||||
int QueryColliding( const ITEM* aItem, OBSTACLE_VISITOR& aVisitor );
|
||||
|
||||
/**
|
||||
* Function NearestObstacle()
|
||||
*
|
||||
|
@ -278,22 +277,6 @@ public:
|
|||
OPT_OBSTACLE CheckColliding( const ITEM_SET& aSet,
|
||||
int aKindMask = ITEM::ANY_T );
|
||||
|
||||
|
||||
/**
|
||||
* Function CheckColliding()
|
||||
*
|
||||
* Checks if 2 items collide.
|
||||
* and if found, returns the obstacle.
|
||||
* @param aItemA first item to find collisions with
|
||||
* @param aItemB second item to find collisions with
|
||||
* @param aKindMask mask of obstacle types to take into account
|
||||
* @return the obstacle, if found, otherwise empty.
|
||||
*/
|
||||
bool CheckColliding( const ITEM* aItemA,
|
||||
const ITEM* aItemB,
|
||||
int aKindMask = ITEM::ANY_T,
|
||||
int aForceClearance = -1 );
|
||||
|
||||
/**
|
||||
* Function HitTest()
|
||||
*
|
||||
|
@ -439,7 +422,7 @@ public:
|
|||
|
||||
void AllItemsInNet( int aNet, std::set<ITEM*>& aItems, int aKindMask = -1 );
|
||||
|
||||
void ClearRanks( int aMarkerMask = MK_HEAD | MK_VIOLATION | MK_ALT_SHAPE );
|
||||
void ClearRanks( int aMarkerMask = MK_HEAD | MK_VIOLATION | MK_HOLE );
|
||||
|
||||
void RemoveByMarker( int aMarker );
|
||||
|
||||
|
|
|
@ -158,9 +158,7 @@ struct OPTIMIZER::CACHE_VISITOR
|
|||
if( !( m_mask & aOtherItem->Kind() ) )
|
||||
return true;
|
||||
|
||||
int clearance = m_node->GetClearance( aOtherItem, m_ourItem );
|
||||
|
||||
if( !aOtherItem->Collide( m_ourItem, clearance, false, nullptr, m_node ) )
|
||||
if( !aOtherItem->Collide( m_ourItem, m_node ) )
|
||||
return true;
|
||||
|
||||
m_collidingItem = aOtherItem;
|
||||
|
@ -1156,7 +1154,7 @@ bool verifyDpBypass( NODE* aNode, DIFF_PAIR* aPair, bool aRefIsP, const SHAPE_LI
|
|||
LINE refLine ( aRefIsP ? aPair->PLine() : aPair->NLine(), aNewRef );
|
||||
LINE coupledLine ( aRefIsP ? aPair->NLine() : aPair->PLine(), aNewCoupled );
|
||||
|
||||
if( aNode->CheckColliding( &refLine, &coupledLine, ITEM::ANY_T, aPair->Gap() - 10 ) )
|
||||
if( refLine.Collide( &coupledLine, aNode ) )
|
||||
return false;
|
||||
|
||||
if( aNode->CheckColliding ( &refLine ) )
|
||||
|
|
|
@ -308,7 +308,13 @@ void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR&
|
|||
|
||||
for( OBSTACLE& obs : obstacles )
|
||||
{
|
||||
int clearance = aNode->GetClearance( item, obs.m_item );
|
||||
int clearance;
|
||||
|
||||
if( ( obs.m_item->Marker() & MK_HOLE ) > 0 )
|
||||
clearance = aNode->GetHoleClearance( item, obs.m_item );
|
||||
else
|
||||
clearance = aNode->GetClearance( item, obs.m_item );
|
||||
|
||||
std::unique_ptr<ITEM> tmp( obs.m_item->Clone() );
|
||||
tmp->Mark( tmp->Marker() | MK_VIOLATION );
|
||||
m_iface->DisplayItem( tmp.get(), -1, clearance );
|
||||
|
@ -370,7 +376,16 @@ void ROUTER::movePlacing( const VECTOR2I& aP, ITEM* aEndItem )
|
|||
m_iface->DisplayItem( l, -1, clearance );
|
||||
|
||||
if( l->EndsWithVia() )
|
||||
m_iface->DisplayItem( &l->Via(), -1, clearance );
|
||||
{
|
||||
const VIA& via = l->Via();
|
||||
int viaClearance = GetRuleResolver()->Clearance( &via, nullptr );
|
||||
int holeClearance = GetRuleResolver()->HoleClearance( &via, nullptr );
|
||||
|
||||
if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
|
||||
viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
|
||||
|
||||
m_iface->DisplayItem( &l->Via(), -1, viaClearance );
|
||||
}
|
||||
}
|
||||
|
||||
//ITEM_SET tmp( ¤t );
|
||||
|
|
|
@ -100,7 +100,7 @@ enum DRAG_MODE
|
|||
virtual void RemoveItem( ITEM* aItem ) = 0;
|
||||
virtual bool IsAnyLayerVisible( const LAYER_RANGE& aLayer ) const = 0;
|
||||
virtual bool IsItemVisible( const PNS::ITEM* aItem ) const = 0;
|
||||
virtual bool IsOnLayer( const PNS::ITEM* aItem, int aLayer ) const = 0;
|
||||
virtual bool IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const = 0;
|
||||
virtual void DisplayItem( const ITEM* aItem, int aColor = -1, int aClearance = -1,
|
||||
bool aEdit = false ) = 0;
|
||||
virtual void DisplayRatline( const SHAPE_LINE_CHAIN& aRatline, int aColor = -1 ) = 0;
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <cassert>
|
||||
#include <math/box2.h>
|
||||
|
||||
#include <geometry/shape_compound.h>
|
||||
|
||||
#include "pns_arc.h"
|
||||
#include "pns_line.h"
|
||||
#include "pns_node.h"
|
||||
|
@ -72,6 +74,14 @@ int SHOVE::getClearance( const ITEM* aA, const ITEM* aB ) const
|
|||
return m_currentNode->GetClearance( aA, aB );
|
||||
}
|
||||
|
||||
int SHOVE::getHoleClearance( const ITEM* aA, const ITEM* aB ) const
|
||||
{
|
||||
if( m_forceClearance >= 0 )
|
||||
return m_forceClearance;
|
||||
|
||||
return m_currentNode->GetHoleClearance( aA, aB );
|
||||
}
|
||||
|
||||
|
||||
void SHOVE::sanityCheck( LINE* aOld, LINE* aNew )
|
||||
{
|
||||
|
@ -129,6 +139,11 @@ bool SHOVE::checkBumpDirection( const LINE& aCurrent, const LINE& aObstacle, con
|
|||
SHOVE::SHOVE_STATUS SHOVE::walkaroundLoneVia( LINE& aCurrent, LINE& aObstacle, LINE& aShoved )
|
||||
{
|
||||
int clearance = getClearance( &aCurrent, &aObstacle );
|
||||
int holeClearance = getHoleClearance( &aCurrent.Via(), &aObstacle );
|
||||
|
||||
if( holeClearance + aCurrent.Via().Drill() / 2 > clearance + aCurrent.Via().Diameter() / 2 )
|
||||
clearance = holeClearance + aCurrent.Via().Drill() / 2 - aCurrent.Via().Diameter() / 2;
|
||||
|
||||
const SHAPE_LINE_CHAIN hull = aCurrent.Via().Hull( clearance, aObstacle.Width(), aCurrent.Layer() );
|
||||
SHAPE_LINE_CHAIN path_cw;
|
||||
SHAPE_LINE_CHAIN path_ccw;
|
||||
|
@ -152,7 +167,7 @@ SHOVE::SHOVE_STATUS SHOVE::walkaroundLoneVia( LINE& aCurrent, LINE& aObstacle, L
|
|||
|
||||
aShoved.SetShape( shortest );
|
||||
|
||||
if( m_currentNode->CheckColliding( &aShoved, &aCurrent ) )
|
||||
if( aShoved.Collide( &aCurrent, m_currentNode ) )
|
||||
return SH_INCOMPLETE;
|
||||
|
||||
return SH_OK;
|
||||
|
@ -234,7 +249,7 @@ SHOVE::SHOVE_STATUS SHOVE::processHullSet( LINE& aCurrent, LINE& aObstacle,
|
|||
continue;
|
||||
}
|
||||
|
||||
bool colliding = m_currentNode->CheckColliding( &l, &aCurrent, ITEM::ANY_T, m_forceClearance );
|
||||
bool colliding = l.Collide( &aCurrent, m_currentNode );
|
||||
|
||||
#ifdef DEBUG
|
||||
char str[128];
|
||||
|
@ -248,7 +263,7 @@ SHOVE::SHOVE_STATUS SHOVE::processHullSet( LINE& aCurrent, LINE& aObstacle,
|
|||
|
||||
for( ITEM* item : jtStart->LinkList() )
|
||||
{
|
||||
if( m_currentNode->CheckColliding( item, &l ) )
|
||||
if( item->Collide( &l, m_currentNode ) )
|
||||
colliding = true;
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +336,16 @@ SHOVE::SHOVE_STATUS SHOVE::ProcessSingleLine( LINE& aCurrent, LINE& aObstacle, L
|
|||
}
|
||||
|
||||
if( viaOnEnd )
|
||||
hulls.push_back( aCurrent.Via().Hull( clearance, w ) );
|
||||
{
|
||||
const VIA& via = aCurrent.Via();
|
||||
int viaClearance = getClearance( &via, &aObstacle );
|
||||
int holeClearance = getHoleClearance( &via, &aObstacle );
|
||||
|
||||
if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
|
||||
viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
|
||||
|
||||
hulls.push_back( aCurrent.Via().Hull( viaClearance, w ) );
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
char str[128];
|
||||
|
@ -530,7 +554,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle )
|
|||
}
|
||||
}
|
||||
|
||||
if( via && m_currentNode->CheckColliding( via, aObstacle ) )
|
||||
if( via && via->Collide( aObstacle, m_currentNode ) )
|
||||
return onCollidingVia( aObstacle, via );
|
||||
}
|
||||
|
||||
|
@ -598,7 +622,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle )
|
|||
{
|
||||
LINE lastLine = m_lineStack.front();
|
||||
|
||||
if( m_currentNode->CheckColliding( &lastLine, &walkaroundLine ) )
|
||||
if( lastLine.Collide( &walkaroundLine, m_currentNode ) )
|
||||
{
|
||||
LINE dummy( lastLine );
|
||||
|
||||
|
@ -834,73 +858,51 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in
|
|||
*/
|
||||
SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia )
|
||||
{
|
||||
int clearance = getClearance( aCurrent, aObstacleVia ) + PNS_HULL_MARGIN;
|
||||
int clearance = getClearance( aCurrent, aObstacleVia );
|
||||
LINE_PAIR_VEC draggedLines;
|
||||
bool lineCollision = false;
|
||||
bool viaCollision = false;
|
||||
bool holeCollision = false;
|
||||
LINE* currentLine = NULL;
|
||||
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)
|
||||
VECTOR2I mtv;
|
||||
int rank = -1;
|
||||
|
||||
SHAPE_COMPOUND shape;
|
||||
|
||||
if( aCurrent->OfKind( ITEM::LINE_T ) )
|
||||
{
|
||||
LINE* currentLine = (LINE*) aCurrent;
|
||||
|
||||
#if 0
|
||||
m_logger.NewGroup( "push-via-by-line", m_iter );
|
||||
m_logger.Log( aCurrent, 4, "current" );
|
||||
m_logger.NewGroup( "push-via-by-line", m_iter );
|
||||
m_logger.Log( currentLine, 4, "current" );
|
||||
#endif
|
||||
|
||||
currentLine = (LINE*) aCurrent;
|
||||
lineCollision = aObstacleVia->Shape()->Collide( currentLine->Shape(),
|
||||
clearance + currentLine->Width() / 2,
|
||||
&mtvLine );
|
||||
shape.AddShape( currentLine->Shape()->Clone() );
|
||||
|
||||
// SHAPE_LINE_CHAIN collisions don't currently pay any attention to the line-chain's
|
||||
// width, so we have to add it to the clearance.
|
||||
clearance += currentLine->Width() / 2;
|
||||
|
||||
// Add a second shape for the via (if any)
|
||||
if( currentLine->EndsWithVia() )
|
||||
{
|
||||
int currentNet = currentLine->Net();
|
||||
int obstacleNet = aObstacleVia->Net();
|
||||
const VIA& currentVia = currentLine->Via();
|
||||
int viaClearance = getClearance( ¤tVia, aObstacleVia );
|
||||
int holeClearance = getHoleClearance( ¤tVia, aObstacleVia );
|
||||
int effectiveRadius = std::max( currentVia.Diameter() / 2 + viaClearance,
|
||||
currentVia.Drill() / 2 + holeClearance );
|
||||
|
||||
if( currentNet != obstacleNet && currentNet >= 0 && obstacleNet >= 0 )
|
||||
{
|
||||
viaCollision = currentLine->Via().Shape()->Collide( aObstacleVia->Shape(),
|
||||
clearance, &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.
|
||||
|
||||
// temporarily removed hole-to-hole collision check due to conflicts with the
|
||||
// springback algorithm...
|
||||
// we need to figure out a better solution here - TW
|
||||
holeCollision = false; //rr->CollideHoles( ¤tLine->Via(), aObstacleVia, true, &mtvHoles );
|
||||
// Since we have to run the collision with the line's clearance + 1/2 its width (as
|
||||
// it's the only way to take the SHAPE_LINE_CHAIN's width into account), we need to
|
||||
// subtract that clearance back out of the via's effective radius.
|
||||
shape.AddShape( new SHAPE_CIRCLE( currentVia.Pos(), effectiveRadius - clearance ) );
|
||||
}
|
||||
|
||||
// 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( lineMTVLength >= viaMTVLength && lineMTVLength >= holeMTVLength )
|
||||
mtv = mtvLine;
|
||||
else if( viaMTVLength >= lineMTVLength && viaMTVLength >= holeMTVLength )
|
||||
mtv = mtvVia;
|
||||
else
|
||||
mtv = mtvHoles;
|
||||
|
||||
rank = currentLine->Rank();
|
||||
}
|
||||
else if( aCurrent->OfKind( ITEM::SOLID_T ) )
|
||||
{
|
||||
aObstacleVia->Shape()->Collide( aCurrent->Shape(), clearance, &mtvSolid );
|
||||
mtv = -mtvSolid;
|
||||
rank = aCurrent->Rank() + 10000;
|
||||
shape.AddShape( aCurrent->Shape()->Clone() );
|
||||
}
|
||||
|
||||
aObstacleVia->Shape()->Collide( &shape, clearance + PNS_HULL_MARGIN, &mtv );
|
||||
rank = aCurrent->Rank() + 10000;
|
||||
|
||||
return pushOrShoveVia( aObstacleVia, mtv, rank );
|
||||
}
|
||||
|
||||
|
@ -1111,8 +1113,7 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
|||
{
|
||||
wxLogTrace( "PNS", "iter %d: reverse-collide-via", aIter );
|
||||
|
||||
if( currentLine.EndsWithVia()
|
||||
&& m_currentNode->CheckColliding( ¤tLine.Via(), (VIA*) ni ) )
|
||||
if( currentLine.EndsWithVia() )
|
||||
{
|
||||
st = SH_INCOMPLETE;
|
||||
}
|
||||
|
|
|
@ -153,6 +153,7 @@ private:
|
|||
SHOVE_STATUS shoveMainLoop();
|
||||
|
||||
int getClearance( const ITEM* aA, const ITEM* aB ) const;
|
||||
int getHoleClearance( const ITEM* aA, const ITEM* aB ) const;
|
||||
|
||||
std::vector<SPRINGBACK_TAG> m_nodeStack;
|
||||
std::vector<LINE> m_lineStack;
|
||||
|
|
|
@ -79,21 +79,16 @@ static const SHAPE_LINE_CHAIN buildHullForPrimitiveShape( const SHAPE* aShape, i
|
|||
|
||||
const SHAPE_LINE_CHAIN SOLID::Hull( int aClearance, int aWalkaroundThickness, int aLayer ) const
|
||||
{
|
||||
SHAPE* shape = m_shape;
|
||||
if( !ROUTER::GetInstance()->GetInterface()->IsFlashedOnLayer( this, aLayer ) )
|
||||
return HoleHull( aClearance, aWalkaroundThickness, aLayer );
|
||||
|
||||
if( !ROUTER::GetInstance()->GetInterface()->IsOnLayer( this, aLayer ) )
|
||||
if( !m_shape )
|
||||
return SHAPE_LINE_CHAIN();
|
||||
|
||||
if( m_shape->Type() == SH_COMPOUND )
|
||||
{
|
||||
/// The alternate shape is defined for THT pads. If we don't have an alternate shape
|
||||
/// then the solid shape does not exist on this layer
|
||||
if( !m_alternateShape )
|
||||
return SHAPE_LINE_CHAIN();
|
||||
SHAPE_COMPOUND* cmpnd = static_cast<SHAPE_COMPOUND*>( m_shape );
|
||||
|
||||
shape = m_alternateShape;
|
||||
}
|
||||
|
||||
if( shape->Type() == SH_COMPOUND )
|
||||
{
|
||||
auto cmpnd = static_cast<SHAPE_COMPOUND*>( shape );
|
||||
if ( cmpnd->Shapes().size() == 1 )
|
||||
{
|
||||
return buildHullForPrimitiveShape( cmpnd->Shapes()[0], aClearance, aWalkaroundThickness );
|
||||
|
@ -107,10 +102,35 @@ const SHAPE_LINE_CHAIN SOLID::Hull( int aClearance, int aWalkaroundThickness, in
|
|||
}
|
||||
else
|
||||
{
|
||||
return buildHullForPrimitiveShape( shape, aClearance, aWalkaroundThickness );
|
||||
return buildHullForPrimitiveShape( m_shape, aClearance, aWalkaroundThickness );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const SHAPE_LINE_CHAIN SOLID::HoleHull( int aClearance, int aWalkaroundThickness, int aLayer ) const
|
||||
{
|
||||
if( !m_hole )
|
||||
return SHAPE_LINE_CHAIN();
|
||||
|
||||
if( m_hole->Type() == SH_COMPOUND )
|
||||
{
|
||||
SHAPE_COMPOUND* cmpnd = static_cast<SHAPE_COMPOUND*>( m_hole );
|
||||
|
||||
if ( cmpnd->Shapes().size() == 1 )
|
||||
{
|
||||
return buildHullForPrimitiveShape( cmpnd->Shapes()[0], aClearance, aWalkaroundThickness );
|
||||
}
|
||||
else
|
||||
{
|
||||
// fixme - shouldn't happen but one day we should move TransformShapeWithClearanceToPolygon()
|
||||
// to the Geometry Library
|
||||
return SHAPE_LINE_CHAIN();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return buildHullForPrimitiveShape( m_hole, aClearance, aWalkaroundThickness );
|
||||
}
|
||||
|
||||
return SHAPE_LINE_CHAIN();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
SOLID() :
|
||||
ITEM( SOLID_T ),
|
||||
m_shape( NULL ),
|
||||
m_alternateShape( NULL )
|
||||
m_hole( NULL )
|
||||
{
|
||||
m_movable = false;
|
||||
m_padToDie = 0;
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
~SOLID()
|
||||
{
|
||||
delete m_shape;
|
||||
delete m_alternateShape;
|
||||
delete m_hole;
|
||||
}
|
||||
|
||||
SOLID( const SOLID& aSolid ) :
|
||||
|
@ -59,10 +59,10 @@ public:
|
|||
else
|
||||
m_shape = nullptr;
|
||||
|
||||
if( aSolid.m_alternateShape )
|
||||
m_alternateShape = aSolid.m_alternateShape->Clone();
|
||||
if( aSolid.m_hole )
|
||||
m_hole = aSolid.m_hole->Clone();
|
||||
else
|
||||
m_alternateShape = nullptr;
|
||||
m_hole = nullptr;
|
||||
|
||||
m_pos = aSolid.m_pos;
|
||||
m_padToDie = aSolid.m_padToDie;
|
||||
|
@ -77,21 +77,24 @@ public:
|
|||
|
||||
const SHAPE* Shape() const override { return m_shape; }
|
||||
|
||||
const SHAPE* AlternateShape() const override { return m_alternateShape; }
|
||||
const SHAPE* Hole() const override { return m_hole; }
|
||||
|
||||
const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0,
|
||||
int aLayer = -1 ) const override;
|
||||
|
||||
const SHAPE_LINE_CHAIN HoleHull( int aClearance, int aWalkaroundThickness,
|
||||
int aLayer ) const override;
|
||||
|
||||
void SetShape( SHAPE* shape )
|
||||
{
|
||||
delete m_shape;
|
||||
m_shape = shape;
|
||||
}
|
||||
|
||||
void SetAlternateShape( SHAPE* shape )
|
||||
void SetHole( SHAPE* shape )
|
||||
{
|
||||
delete m_alternateShape;
|
||||
m_alternateShape = shape;
|
||||
delete m_hole;
|
||||
m_hole = shape;
|
||||
}
|
||||
|
||||
const VECTOR2I& Pos() const { return m_pos; }
|
||||
|
@ -119,7 +122,7 @@ public:
|
|||
private:
|
||||
VECTOR2I m_pos;
|
||||
SHAPE* m_shape;
|
||||
SHAPE* m_alternateShape;
|
||||
SHAPE* m_hole;
|
||||
VECTOR2I m_offset;
|
||||
int m_padToDie;
|
||||
double m_orientation; // in 1/10 degrees, matching PAD
|
||||
|
|
|
@ -112,12 +112,21 @@ const SHAPE_LINE_CHAIN ArcHull( const SHAPE_ARC& aSeg, int aClearance,
|
|||
const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance,
|
||||
int aWalkaroundThickness )
|
||||
{
|
||||
int d = aSeg.GetWidth() / 2 + aClearance + aWalkaroundThickness / 2 + HULL_MARGIN;
|
||||
int cl = aClearance + aWalkaroundThickness / 2 + HULL_MARGIN;
|
||||
int d = aSeg.GetWidth() / 2 + cl;
|
||||
int x = (int)( 2.0 / ( 1.0 + M_SQRT2 ) * d );
|
||||
|
||||
const VECTOR2I a = aSeg.GetSeg().A;
|
||||
const VECTOR2I b = aSeg.GetSeg().B;
|
||||
|
||||
if( a == b )
|
||||
{
|
||||
return OctagonalHull( a - VECTOR2I( aSeg.GetWidth() / 2, aSeg.GetWidth() / 2 ),
|
||||
VECTOR2I( aSeg.GetWidth(), aSeg.GetWidth() ),
|
||||
cl + 1,
|
||||
0.52 * d );
|
||||
}
|
||||
|
||||
VECTOR2I dir = b - a;
|
||||
VECTOR2I p0 = dir.Perpendicular().Resize( d );
|
||||
VECTOR2I ds = dir.Perpendicular().Resize( x / 2 );
|
||||
|
|
|
@ -76,7 +76,7 @@ const SHAPE_LINE_CHAIN VIA::Hull( int aClearance, int aWalkaroundThickness, int
|
|||
int cl = ( aClearance + aWalkaroundThickness / 2 );
|
||||
int width = m_diameter;
|
||||
|
||||
if( !ROUTER::GetInstance()->GetInterface()->IsOnLayer( this, aLayer ) )
|
||||
if( !ROUTER::GetInstance()->GetInterface()->IsFlashedOnLayer( this, aLayer ) )
|
||||
width = m_drill;
|
||||
|
||||
return OctagonalHull( m_pos -
|
||||
|
|
|
@ -67,7 +67,7 @@ public:
|
|||
m_diameter = aDiameter;
|
||||
m_drill = aDrill;
|
||||
m_shape = SHAPE_CIRCLE( aPos, aDiameter / 2 );
|
||||
m_alternateShape = SHAPE_CIRCLE( m_pos, aDrill / 2 );
|
||||
m_hole = SHAPE_CIRCLE( m_pos, aDrill / 2 );
|
||||
m_viaType = aViaType;
|
||||
m_isFree = false;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ public:
|
|||
m_pos = aB.m_pos;
|
||||
m_diameter = aB.m_diameter;
|
||||
m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 );
|
||||
m_alternateShape = SHAPE_CIRCLE( m_pos, aB.m_drill / 2 );
|
||||
m_hole = SHAPE_CIRCLE( m_pos, aB.m_drill / 2 );
|
||||
m_marker = aB.m_marker;
|
||||
m_rank = aB.m_rank;
|
||||
m_drill = aB.m_drill;
|
||||
|
@ -151,9 +151,14 @@ public:
|
|||
return &m_shape;
|
||||
}
|
||||
|
||||
const SHAPE* AlternateShape() const override
|
||||
const SHAPE_CIRCLE* Hole() const override
|
||||
{
|
||||
return &m_alternateShape;
|
||||
return &m_hole;
|
||||
}
|
||||
|
||||
void SetHole( const SHAPE_CIRCLE& aHole )
|
||||
{
|
||||
m_hole = aHole;
|
||||
}
|
||||
|
||||
VIA* Clone() const override;
|
||||
|
@ -179,7 +184,7 @@ private:
|
|||
int m_drill;
|
||||
VECTOR2I m_pos;
|
||||
SHAPE_CIRCLE m_shape;
|
||||
SHAPE_CIRCLE m_alternateShape;
|
||||
SHAPE_CIRCLE m_hole;
|
||||
VIATYPE m_viaType;
|
||||
bool m_isFree;
|
||||
};
|
||||
|
|
|
@ -86,8 +86,8 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS::ITEM* aItem )
|
|||
m_color.a = 0.8;
|
||||
m_depth = BaseOverlayDepth - aItem->Layers().Start();
|
||||
|
||||
if( ( aItem->Marker() & PNS::MK_ALT_SHAPE ) && aItem->AlternateShape() )
|
||||
m_shape = aItem->AlternateShape()->Clone();
|
||||
if(( aItem->Marker() & PNS::MK_HOLE ) && aItem->Hole() )
|
||||
m_shape = aItem->Hole()->Clone();
|
||||
else
|
||||
m_shape = aItem->Shape()->Clone();
|
||||
|
||||
|
|
Loading…
Reference in New Issue