mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 18:23:15 +02:00
PNS: Support via stacks
This commit is contained in:
parent
be728f7800
commit
d0b2334ceb
@ -44,9 +44,9 @@
|
||||
* @return a SHAPE* object equivalent to object.
|
||||
*/
|
||||
template <class T>
|
||||
static const SHAPE* shapeFunctor( T aItem )
|
||||
static const SHAPE* shapeFunctor( T aItem, int aLayer )
|
||||
{
|
||||
return aItem->Shape();
|
||||
return aItem->Shape( aLayer );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,9 +59,9 @@ static const SHAPE* shapeFunctor( T aItem )
|
||||
* @return a BOX2I object containing the bounding box of the T object.
|
||||
*/
|
||||
template <class T>
|
||||
BOX2I boundingBox( T aObject )
|
||||
BOX2I boundingBox( T aObject, int aLayer )
|
||||
{
|
||||
BOX2I bbox = shapeFunctor( aObject )->BBox();
|
||||
BOX2I bbox = shapeFunctor( aObject, aLayer )->BBox();
|
||||
|
||||
return bbox;
|
||||
}
|
||||
@ -89,13 +89,14 @@ void acceptVisitor( T aObject, V aVisitor )
|
||||
*
|
||||
* @param aObject is a generic T object.
|
||||
* @param aAnotherObject is a generic U object.
|
||||
* @param aLayer is the layer to test
|
||||
* @param aMinDistance is the minimum collision distance.
|
||||
* @return true if object and anotherObject collide.
|
||||
*/
|
||||
template <class T, class U>
|
||||
bool collide( T aObject, U aAnotherObject, int aMinDistance )
|
||||
bool collide( T aObject, U aAnotherObject, int aLayer, int aMinDistance )
|
||||
{
|
||||
return shapeFunctor( aObject )->Collide( aAnotherObject, aMinDistance );
|
||||
return shapeFunctor( aObject, aLayer )->Collide( aAnotherObject, aMinDistance );
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
@ -197,7 +198,7 @@ class SHAPE_INDEX
|
||||
}
|
||||
};
|
||||
|
||||
SHAPE_INDEX();
|
||||
explicit SHAPE_INDEX( int aLayer );
|
||||
|
||||
~SHAPE_INDEX();
|
||||
|
||||
@ -281,6 +282,7 @@ class SHAPE_INDEX
|
||||
|
||||
private:
|
||||
RTree<T, int, 2, double>* m_tree;
|
||||
int m_shapeLayer;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -288,9 +290,10 @@ class SHAPE_INDEX
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
SHAPE_INDEX<T>::SHAPE_INDEX()
|
||||
SHAPE_INDEX<T>::SHAPE_INDEX( int aLayer )
|
||||
{
|
||||
this->m_tree = new RTree<T, int, 2, double>();
|
||||
this->m_shapeLayer = aLayer;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -311,7 +314,7 @@ void SHAPE_INDEX<T>::Add( T aShape, const BOX2I& aBbox )
|
||||
template <class T>
|
||||
void SHAPE_INDEX<T>::Add( T aShape )
|
||||
{
|
||||
BOX2I box = boundingBox( aShape );
|
||||
BOX2I box = boundingBox( aShape, this->m_shapeLayer );
|
||||
int min[2] = { box.GetX(), box.GetY() };
|
||||
int max[2] = { box.GetRight(), box.GetBottom() };
|
||||
|
||||
@ -321,7 +324,7 @@ void SHAPE_INDEX<T>::Add( T aShape )
|
||||
template <class T>
|
||||
void SHAPE_INDEX<T>::Remove( T aShape )
|
||||
{
|
||||
BOX2I box = boundingBox( aShape );
|
||||
BOX2I box = boundingBox( aShape, this->m_shapeLayer );
|
||||
int min[2] = { box.GetX(), box.GetY() };
|
||||
int max[2] = { box.GetRight(), box.GetBottom() };
|
||||
|
||||
@ -345,7 +348,7 @@ void SHAPE_INDEX<T>::Reindex()
|
||||
while( !iter.IsNull() )
|
||||
{
|
||||
T shape = *iter;
|
||||
BOX2I box = boundingBox( shape );
|
||||
BOX2I box = boundingBox( shape, this->m_shapeLayer );
|
||||
int min[2] = { box.GetX(), box.GetY() };
|
||||
int max[2] = { box.GetRight(), box.GetBottom() };
|
||||
newTree->Insert( min, max, shape );
|
||||
|
@ -35,7 +35,7 @@
|
||||
template <class T>
|
||||
const SHAPE* defaultShapeFunctor( const T aItem )
|
||||
{
|
||||
return aItem->Shape();
|
||||
return aItem->Shape( -1 );
|
||||
}
|
||||
|
||||
template <class T, const SHAPE* (ShapeFunctor) (const T) = defaultShapeFunctor<T> >
|
||||
|
@ -952,7 +952,7 @@ static PNS::LINKED_ITEM* pickSegment( PNS::ROUTER* aRouter, const VECTOR2I& aWhe
|
||||
if( aBaseline.PointCount() > 0 )
|
||||
{
|
||||
SEG::ecoord dcBaseline;
|
||||
VECTOR2I target = segm->Shape()->Centre();
|
||||
VECTOR2I target = segm->Shape( -1 )->Centre();
|
||||
|
||||
if( aBaseline.SegmentCount() > 0 )
|
||||
dcBaseline = aBaseline.SquaredDistance( target );
|
||||
|
@ -832,11 +832,15 @@ void PADSTACK::ForEachUniqueLayer( const std::function<void( PCB_LAYER_ID )>& aM
|
||||
break;
|
||||
|
||||
case MODE::CUSTOM:
|
||||
for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, MAX_CU_LAYERS ) )
|
||||
{
|
||||
int layerCount = m_parent ? m_parent->BoardCopperLayerCount() : MAX_CU_LAYERS;
|
||||
|
||||
for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, layerCount ) )
|
||||
aMethod( layer );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,8 +45,8 @@ ARC* ARC::Clone() const
|
||||
|
||||
OPT_BOX2I ARC::ChangedArea( const ARC* aOther ) const
|
||||
{
|
||||
BOX2I tmp = Shape()->BBox();
|
||||
tmp.Merge( aOther->Shape()->BBox() );
|
||||
BOX2I tmp = Shape( -1 )->BBox();
|
||||
tmp.Merge( aOther->Shape( -1 )->BBox() );
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
|
||||
ARC* Clone() const override;
|
||||
|
||||
const SHAPE* Shape() const override
|
||||
const SHAPE* Shape( int aLayer ) const override
|
||||
{
|
||||
return static_cast<const SHAPE*>( &m_arc );
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ bool COMPONENT_DRAGGER::Start( const VECTOR2I& aP, ITEM_SET& aPrimitives )
|
||||
{
|
||||
LINKED_ITEM* li = static_cast<LINKED_ITEM*>( extraJoint->LinkList().front() );
|
||||
|
||||
if( li->Collide( solid, m_world ) )
|
||||
if( li->Collide( solid, m_world, solid->Layer() ) )
|
||||
addLinked( solid, extraJoint, li, extraJoint->Pos() - solid->Pos() );
|
||||
}
|
||||
}
|
||||
|
@ -436,12 +436,13 @@ void DP_GATEWAYS::BuildFromPrimitivePair( const DP_PRIMITIVE_PAIR& aPair, bool a
|
||||
|
||||
const int pvMask = ITEM::SOLID_T | ITEM::VIA_T;
|
||||
|
||||
if( aPair.PrimP()->OfKind( pvMask ) && aPair.PrimN()->OfKind( pvMask ) )
|
||||
if( aPair.PrimP()->OfKind( pvMask ) && aPair.PrimN()->OfKind( pvMask ) )
|
||||
{
|
||||
p0_p = aPair.AnchorP();
|
||||
p0_n = aPair.AnchorN();
|
||||
|
||||
shP = aPair.PrimP()->Shape();
|
||||
// TODO(JE) padstacks
|
||||
shP = aPair.PrimP()->Shape( -1 );
|
||||
}
|
||||
else if( aPair.PrimP()->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T )
|
||||
&& aPair.PrimN()->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
|
||||
|
@ -413,8 +413,8 @@ public:
|
||||
|
||||
void SetViaDiameter( int aDiameter )
|
||||
{
|
||||
m_via_p.SetDiameter( aDiameter );
|
||||
m_via_n.SetDiameter( aDiameter );
|
||||
m_via_p.SetDiameter( VIA::ALL_LAYERS, aDiameter );
|
||||
m_via_n.SetDiameter( VIA::ALL_LAYERS, aDiameter );
|
||||
}
|
||||
|
||||
void SetViaDrill( int aDrill )
|
||||
|
@ -118,12 +118,12 @@ bool DIFF_PAIR_PLACER::propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNe
|
||||
|
||||
if( m_placingVia )
|
||||
{
|
||||
virtHead.SetDiameter( viaGap() + 2 * virtHead.Diameter() );
|
||||
virtHead.SetDiameter( 0, viaGap() + 2 * virtHead.Diameter( 0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
virtHead.SetLayer( m_currentLayer );
|
||||
virtHead.SetDiameter( m_sizes.DiffPairGap() + 2 * m_sizes.DiffPairWidth() );
|
||||
virtHead.SetDiameter( 0, m_sizes.DiffPairGap() + 2 * m_sizes.DiffPairWidth() );
|
||||
}
|
||||
|
||||
bool solidsOnly = true;
|
||||
@ -160,7 +160,8 @@ bool DIFF_PAIR_PLACER::propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNe
|
||||
|
||||
int clearance = m_currentNode->GetClearance( obs->m_item, &m_currentTrace.PLine(), false );
|
||||
|
||||
if( obs->m_item->Shape()->Collide( virtHead.Shape(), clearance, &force ) )
|
||||
// TODO(JE) padstacks - this won't work
|
||||
if( obs->m_item->Shape( 0 )->Collide( virtHead.Shape( 0 ), clearance, &force ) )
|
||||
{
|
||||
collided = true;
|
||||
totalForce += force;
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
|
||||
int Radius() const;
|
||||
|
||||
const SHAPE* Shape() const override { return m_holeShape; }
|
||||
const SHAPE* Shape( int aLayer ) const override { return m_holeShape; }
|
||||
|
||||
void SetParentPadVia( ITEM* aParent ) { m_parentPadVia = aParent; }
|
||||
ITEM* ParentPadVia() const override { return m_parentPadVia; }
|
||||
|
@ -31,10 +31,13 @@ void INDEX::Add( ITEM* aItem )
|
||||
assert( range.Start() != -1 && range.End() != -1 );
|
||||
|
||||
if( m_subIndices.size() <= static_cast<size_t>( range.End() ) )
|
||||
m_subIndices.resize( 2 * range.End() + 1 ); // +1 handles the 0 case
|
||||
{
|
||||
for( int i = 0; i <= range.End(); ++i )
|
||||
m_subIndices.emplace_back( std::make_unique<ITEM_SHAPE_INDEX>( i ) );
|
||||
}
|
||||
|
||||
for( int i = range.Start(); i <= range.End(); ++i )
|
||||
m_subIndices[i].Add( aItem );
|
||||
m_subIndices[i]->Add( aItem );
|
||||
|
||||
m_allItems.insert( aItem );
|
||||
NET_HANDLE net = aItem->Net();
|
||||
@ -53,7 +56,7 @@ void INDEX::Remove( ITEM* aItem )
|
||||
return;
|
||||
|
||||
for( int i = range.Start(); i <= range.End(); ++i )
|
||||
m_subIndices[i].Remove( aItem );
|
||||
m_subIndices[i]->Remove( aItem );
|
||||
|
||||
m_allItems.erase( aItem );
|
||||
NET_HANDLE net = aItem->Net();
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <geometry/shape_index.h>
|
||||
|
||||
#include "pns_item.h"
|
||||
#include "pns_node.h"
|
||||
|
||||
namespace PNS {
|
||||
|
||||
@ -122,7 +123,7 @@ private:
|
||||
int querySingle( std::size_t aIndex, const SHAPE* aShape, int aMinDistance, Visitor& aVisitor ) const;
|
||||
|
||||
private:
|
||||
std::deque<ITEM_SHAPE_INDEX> m_subIndices;
|
||||
std::deque<std::unique_ptr<ITEM_SHAPE_INDEX>> m_subIndices;
|
||||
std::map<NET_HANDLE, NET_ITEMS_LIST> m_netMap;
|
||||
ITEM_SET m_allItems;
|
||||
};
|
||||
@ -134,7 +135,8 @@ int INDEX::querySingle( std::size_t aIndex, const SHAPE* aShape, int aMinDistanc
|
||||
if( aIndex >= m_subIndices.size() )
|
||||
return 0;
|
||||
|
||||
return m_subIndices[aIndex].Query( aShape, aMinDistance, aVisitor);
|
||||
LAYER_CONTEXT_SETTER layerContext( aVisitor, aIndex );
|
||||
return m_subIndices[aIndex]->Query( aShape, aMinDistance, aVisitor);
|
||||
}
|
||||
|
||||
template<class Visitor>
|
||||
@ -147,7 +149,7 @@ int INDEX::Query( const ITEM* aItem, int aMinDistance, Visitor& aVisitor ) const
|
||||
const PNS_LAYER_RANGE& layers = aItem->Layers();
|
||||
|
||||
for( int i = layers.Start(); i <= layers.End(); ++i )
|
||||
total += querySingle( i, aItem->Shape(), aMinDistance, aVisitor );
|
||||
total += querySingle( i, aItem->Shape( i ), aMinDistance, aVisitor );
|
||||
|
||||
return total;
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ static bool shouldWeConsiderHoleCollisions( const ITEM* aItem, const ITEM* aHead
|
||||
{
|
||||
const ITEM* parentI = holeI->ParentPadVia();
|
||||
const ITEM* parentH = holeH->ParentPadVia();
|
||||
|
||||
if( !parentH || !parentI )
|
||||
return true;
|
||||
|
||||
@ -73,7 +74,7 @@ static bool shouldWeConsiderHoleCollisions( const ITEM* aItem, const ITEM* aHead
|
||||
// identical and belonging to the same net as non-colliding.
|
||||
|
||||
if( parentViaI && parentViaH && parentViaI->Pos() == parentViaH->Pos()
|
||||
&& parentViaI->Diameter() == parentViaH->Diameter()
|
||||
&& parentViaI->PadstackMatches( *parentViaH )
|
||||
&& parentViaI->Net() == parentViaH->Net()
|
||||
&& parentViaI->Drill() == parentViaH->Drill() )
|
||||
return false;
|
||||
@ -90,17 +91,32 @@ static bool shouldWeConsiderHoleCollisions( const ITEM* aItem, const ITEM* aHead
|
||||
}
|
||||
|
||||
|
||||
bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
|
||||
std::set<int> ITEM::RelevantShapeLayers( const ITEM* aOther ) const
|
||||
{
|
||||
std::vector<int> myLayers = UniqueShapeLayers();
|
||||
std::vector<int> otherLayers = aOther->UniqueShapeLayers();
|
||||
|
||||
if( !HasUniqueShapeLayers() && !aOther->HasUniqueShapeLayers() )
|
||||
return { -1 };
|
||||
|
||||
std::set<int> relevantLayers;
|
||||
|
||||
std::set_union( myLayers.begin(), myLayers.end(), otherLayers.begin(), otherLayers.end(),
|
||||
std::inserter( relevantLayers, relevantLayers.begin() ) );
|
||||
|
||||
return relevantLayers;
|
||||
}
|
||||
|
||||
|
||||
bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode, int aLayer,
|
||||
COLLISION_SEARCH_CONTEXT* aCtx ) const
|
||||
{
|
||||
// Note: if 'this' is a pad or a via then its hole is a separate PNS::ITEM in the node's
|
||||
// index and we don't need to deal with holeI here. The same is *not* true of the routing
|
||||
// "head", so we do need to handle holeH.
|
||||
|
||||
const SHAPE* shapeI = Shape();
|
||||
int lineWidthI = 0;
|
||||
|
||||
const SHAPE* shapeH = aHead->Shape();
|
||||
//const SHAPE* shapeH = aHead->Shape();
|
||||
const HOLE* holeH = aHead->Hole();
|
||||
int lineWidthH = 0;
|
||||
bool collisionsFound = false;
|
||||
@ -118,19 +134,19 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
|
||||
if( const auto line = dyn_cast<const LINE*>( this ) )
|
||||
{
|
||||
if( line->EndsWithVia() )
|
||||
collisionsFound |= line->Via().collideSimple( aHead, aNode, aCtx );
|
||||
collisionsFound |= line->Via().collideSimple( aHead, aNode, aLayer, aCtx );
|
||||
}
|
||||
|
||||
if( const auto line = dyn_cast<const LINE*>( aHead ) )
|
||||
{
|
||||
if( line->EndsWithVia() )
|
||||
collisionsFound |= line->Via().collideSimple( this, aNode, aCtx );
|
||||
collisionsFound |= line->Via().collideSimple( this, aNode, aLayer, aCtx );
|
||||
}
|
||||
|
||||
// And a special case for the "head" via's hole.
|
||||
if( holeH && shouldWeConsiderHoleCollisions( this, holeH ) )
|
||||
{
|
||||
if( Net() != holeH->Net() && collideSimple( holeH, aNode, aCtx ) )
|
||||
if( Net() != holeH->Net() && collideSimple( holeH, aNode, aLayer, aCtx ) )
|
||||
collisionsFound = true;
|
||||
}
|
||||
|
||||
@ -205,6 +221,9 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
|
||||
|
||||
bool checkNetTie = aNode->GetRuleResolver()->IsInNetTie( this );
|
||||
|
||||
const SHAPE* shapeI = Shape( aLayer );
|
||||
const SHAPE* shapeH = aHead->Shape( aLayer );
|
||||
|
||||
if( checkCastellation || checkNetTie )
|
||||
{
|
||||
// Slow method
|
||||
@ -270,9 +289,10 @@ bool ITEM::collideSimple( const ITEM* aHead, const NODE* aNode,
|
||||
}
|
||||
|
||||
|
||||
bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, COLLISION_SEARCH_CONTEXT *aCtx ) const
|
||||
bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, int aLayer,
|
||||
COLLISION_SEARCH_CONTEXT *aCtx ) const
|
||||
{
|
||||
if( collideSimple( aOther, aNode, aCtx ) )
|
||||
if( collideSimple( aOther, aNode, aLayer, aCtx ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -155,6 +155,8 @@ public:
|
||||
*
|
||||
* @param aClearance defines how far from the body of the item the hull should be,
|
||||
* @param aWalkaroundThickness is the width of the line that walks around this hull.
|
||||
* @param aLayer is the layer to build a hull for (the item may have different shapes on each
|
||||
* layer). If aLayer is -1, the hull will be a merged hull from all layers.
|
||||
*/
|
||||
virtual const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0,
|
||||
int aLayer = -1 ) const
|
||||
@ -217,17 +219,32 @@ public:
|
||||
* @param aOther is the item to check collision against.
|
||||
* @return true, if a collision was found.
|
||||
*/
|
||||
bool Collide( const ITEM* aHead, const NODE* aNode,
|
||||
bool Collide( const ITEM* aHead, const NODE* aNode, int aLayer,
|
||||
COLLISION_SEARCH_CONTEXT* aCtx = nullptr ) const;
|
||||
|
||||
/**
|
||||
* Return the geometrical shape of the item. Used for collision detection and spatial indexing.
|
||||
* @param aLayer is the layer to query shape for (items may have different shapes on different layers)
|
||||
*/
|
||||
virtual const SHAPE* Shape() const
|
||||
virtual const SHAPE* Shape( int aLayer ) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of layers that have unique (potentially different) shapes
|
||||
*/
|
||||
virtual std::vector<int> UniqueShapeLayers() const { return { -1 }; }
|
||||
|
||||
virtual bool HasUniqueShapeLayers() const { return false; }
|
||||
|
||||
/**
|
||||
* Returns the set of layers on which either this or the other item can have a unique shape.
|
||||
* Use this to loop over layers when hit-testing objects that can have different shapes on
|
||||
* each layer (currently only VIA)
|
||||
*/
|
||||
std::set<int> RelevantShapeLayers( const ITEM* aOther ) const;
|
||||
|
||||
virtual void Mark( int aMarker ) const { m_marker = aMarker; }
|
||||
virtual void Unmark( int aMarker = -1 ) const { m_marker &= ~aMarker; }
|
||||
virtual int Marker() const { return m_marker; }
|
||||
@ -279,7 +296,7 @@ public:
|
||||
virtual const NODE* OwningNode() const;
|
||||
|
||||
private:
|
||||
bool collideSimple( const ITEM* aHead, const NODE* aNode,
|
||||
bool collideSimple( const ITEM* aHead, const NODE* aNode, int aLayer,
|
||||
COLLISION_SEARCH_CONTEXT* aCtx ) const;
|
||||
|
||||
protected:
|
||||
|
@ -1129,7 +1129,7 @@ PNS_KICAD_IFACE::~PNS_KICAD_IFACE()
|
||||
std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
|
||||
{
|
||||
std::vector<std::unique_ptr<PNS::SOLID>> solids;
|
||||
PNS_LAYER_RANGE layers( 0, aPad->BoardCopperLayerCount() );
|
||||
PNS_LAYER_RANGE layers( 0, aPad->BoardCopperLayerCount() - 1 );
|
||||
LSEQ lmsk = aPad->GetLayerSet().CuStack();
|
||||
|
||||
// ignore non-copper pads except for those with holes
|
||||
@ -1174,14 +1174,14 @@ std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPa
|
||||
|
||||
if( aPad->Padstack().Mode() == PADSTACK::MODE::CUSTOM )
|
||||
{
|
||||
solid->SetLayers( GetPNSLayerFromBoardLayer( aLayer ) );
|
||||
solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
|
||||
}
|
||||
else if( aPad->Padstack().Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
|
||||
{
|
||||
if( aLayer == F_Cu || aLayer == B_Cu )
|
||||
solid->SetLayers( GetPNSLayerFromBoardLayer( aLayer ) );
|
||||
solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
|
||||
else
|
||||
solid->SetLayers( PNS_LAYER_RANGE( 1, aPad->BoardCopperLayerCount() - 1 ) );
|
||||
solid->SetLayers( PNS_LAYER_RANGE( 1, aPad->BoardCopperLayerCount() - 2 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1207,7 +1207,10 @@ std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPa
|
||||
solid->SetOffset( VECTOR2I( offset.x, offset.y ) );
|
||||
|
||||
if( aPad->GetDrillSize().x > 0 )
|
||||
{
|
||||
solid->SetHole( new PNS::HOLE( aPad->GetEffectiveHoleShape()->Clone() ) );
|
||||
solid->Hole()->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
|
||||
}
|
||||
|
||||
// We generate a single SOLID for a pad, so we have to treat it as ALWAYS_FLASHED and
|
||||
// then perform layer-specific flashing tests internally.
|
||||
@ -1285,41 +1288,81 @@ std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( PCB_ARC* aArc )
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::unique_ptr<PNS::VIA>> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
|
||||
std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
|
||||
{
|
||||
std::vector<std::unique_ptr<PNS::VIA>> vias;
|
||||
PCB_LAYER_ID top, bottom;
|
||||
aVia->LayerPair( &top, &bottom );
|
||||
|
||||
aVia->Padstack().ForEachUniqueLayer(
|
||||
/*
|
||||
* NOTE about PNS via padstacks:
|
||||
*
|
||||
* PNS::VIA has no knowledge about how many layers are in the board, and there is no fixed
|
||||
* reference to the "back layer" in the PNS. That means that there is no way for a VIA to know
|
||||
* the difference between its bottom layer and the bottom layer of the overall board (i.e. if
|
||||
* the via is a blind/buried via). For this reason, PNS::VIA::STACK_MODE::FRONT_INNER_BACK
|
||||
* cannot be used for blind/buried vias. This mode will always assume that the via's top layer
|
||||
* is the "front" layer and the via's bottom layer is the "back" layer, but from KiCad's point
|
||||
* of view, at least at the moment, front/inner/back padstack mode is board-scoped, not
|
||||
* via-scoped, so a buried via would only use the inner layer size even if its padstack mode is
|
||||
* set to PADSTACK::MODE::FRONT_INNER_BACK and different sizes are defined for front or back.
|
||||
* For this kind of via, the PNS VIA stack mode will be set to NORMAL because effectively it has
|
||||
* the same size on every layer it exists on.
|
||||
*/
|
||||
|
||||
auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
|
||||
SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ),
|
||||
0,
|
||||
aVia->GetDrillValue(),
|
||||
aVia->GetNet(),
|
||||
aVia->GetViaType() );
|
||||
|
||||
auto syncDiameter =
|
||||
[&]( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
|
||||
SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ),
|
||||
aVia->GetWidth( aLayer ),
|
||||
aVia->GetDrillValue(),
|
||||
aVia->GetNet(),
|
||||
aVia->GetViaType() );
|
||||
via->SetDiameter( GetPNSLayerFromBoardLayer( aLayer ), aVia->GetWidth( aLayer ) );
|
||||
};
|
||||
|
||||
via->SetParent( aVia );
|
||||
switch( aVia->Padstack().Mode() )
|
||||
{
|
||||
case PADSTACK::MODE::NORMAL:
|
||||
via->SetDiameter( 0, aVia->GetWidth( PADSTACK::ALL_LAYERS ) );
|
||||
break;
|
||||
|
||||
if( aVia->IsLocked() )
|
||||
via->Mark( PNS::MK_LOCKED );
|
||||
case PADSTACK::MODE::FRONT_INNER_BACK:
|
||||
if( aVia->GetViaType() == VIATYPE::BLIND_BURIED )
|
||||
{
|
||||
via->SetDiameter( 0, aVia->GetWidth( PADSTACK::INNER_LAYERS ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
via->SetStackMode( PNS::VIA::STACK_MODE::FRONT_INNER_BACK );
|
||||
aVia->Padstack().ForEachUniqueLayer( syncDiameter );
|
||||
}
|
||||
|
||||
if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
|
||||
{
|
||||
if( !generator->HasFlag( IN_EDIT ) )
|
||||
via->Mark( PNS::MK_LOCKED );
|
||||
}
|
||||
break;
|
||||
|
||||
via->SetIsFree( aVia->GetIsFree() );
|
||||
via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(),
|
||||
aVia->GetDrillValue() / 2,
|
||||
SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) ) );
|
||||
vias.emplace_back( std::move( via ) );
|
||||
} );
|
||||
case PADSTACK::MODE::CUSTOM:
|
||||
via->SetStackMode( PNS::VIA::STACK_MODE::CUSTOM );
|
||||
aVia->Padstack().ForEachUniqueLayer( syncDiameter );
|
||||
}
|
||||
|
||||
return vias;
|
||||
via->SetParent( aVia );
|
||||
|
||||
if( aVia->IsLocked() )
|
||||
via->Mark( PNS::MK_LOCKED );
|
||||
|
||||
if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
|
||||
{
|
||||
if( !generator->HasFlag( IN_EDIT ) )
|
||||
via->Mark( PNS::MK_LOCKED );
|
||||
}
|
||||
|
||||
via->SetIsFree( aVia->GetIsFree() );
|
||||
via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(),
|
||||
aVia->GetDrillValue() / 2,
|
||||
SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) ) );
|
||||
|
||||
return via;
|
||||
}
|
||||
|
||||
|
||||
@ -1432,7 +1475,7 @@ bool PNS_KICAD_IFACE_BASE::syncGraphicalItem( PNS::NODE* aWorld, PCB_SHAPE* aIte
|
||||
|
||||
if( aItem->GetLayer() == Edge_Cuts || aItem->GetLayer() == Margin )
|
||||
{
|
||||
solid->SetLayers( PNS_LAYER_RANGE( 0, m_board->GetCopperLayerCount() ) );
|
||||
solid->SetLayers( PNS_LAYER_RANGE( 0, m_board->GetCopperLayerCount() - 1 ) );
|
||||
solid->SetRoutable( false );
|
||||
}
|
||||
else
|
||||
@ -1707,9 +1750,7 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
|
||||
}
|
||||
else if( type == PCB_VIA_T )
|
||||
{
|
||||
std::vector<std::unique_ptr<PNS::VIA>> vias = syncVia( static_cast<PCB_VIA*>( t ) );
|
||||
|
||||
for( std::unique_ptr<PNS::VIA>& via : vias )
|
||||
if( std::unique_ptr<PNS::VIA> via = syncVia( static_cast<PCB_VIA*>( t ) ) )
|
||||
aWorld->Add( std::move( via ) );
|
||||
}
|
||||
}
|
||||
@ -1878,7 +1919,7 @@ void PNS_KICAD_IFACE::HideItem( PNS::ITEM* aItem )
|
||||
{
|
||||
if( td->IsTeardropArea()
|
||||
&& td->GetBoundingBox().Intersects( aItem->Parent()->GetBoundingBox() )
|
||||
&& td->Outline()->Collide( aItem->Shape() ) )
|
||||
&& td->Outline()->Collide( aItem->Shape( td->GetLayer() ) ) )
|
||||
{
|
||||
m_view->SetVisible( td, false );
|
||||
m_view->Update( td, KIGFX::APPEARANCE );
|
||||
@ -1928,7 +1969,7 @@ void PNS_KICAD_IFACE::modifyBoardItem( PNS::ITEM* aItem )
|
||||
{
|
||||
PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
|
||||
PCB_ARC* arc_board = static_cast<PCB_ARC*>( board_item );
|
||||
const SHAPE_ARC* arc_shape = static_cast<const SHAPE_ARC*>( arc->Shape() );
|
||||
const SHAPE_ARC* arc_shape = static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) );
|
||||
|
||||
m_commit->Modify( arc_board );
|
||||
|
||||
@ -1961,7 +2002,7 @@ void PNS_KICAD_IFACE::modifyBoardItem( PNS::ITEM* aItem )
|
||||
m_commit->Modify( via_board );
|
||||
|
||||
via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
|
||||
via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter() );
|
||||
via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter( 0 ) );
|
||||
via_board->SetDrill( via->Drill() );
|
||||
via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
|
||||
via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
|
||||
@ -2014,7 +2055,7 @@ BOARD_CONNECTED_ITEM* PNS_KICAD_IFACE::createBoardItem( PNS::ITEM* aItem )
|
||||
case PNS::ITEM::ARC_T:
|
||||
{
|
||||
PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
|
||||
PCB_ARC* new_arc = new PCB_ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape() ) );
|
||||
PCB_ARC* new_arc = new PCB_ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) ) );
|
||||
new_arc->SetWidth( arc->Width() );
|
||||
new_arc->SetLayer( GetBoardLayerFromPNSLayer( arc->Layers().Start() ) );
|
||||
new_arc->SetNet( net );
|
||||
@ -2041,7 +2082,7 @@ BOARD_CONNECTED_ITEM* PNS_KICAD_IFACE::createBoardItem( PNS::ITEM* aItem )
|
||||
PCB_VIA* via_board = new PCB_VIA( m_board );
|
||||
PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
|
||||
via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
|
||||
via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter() );
|
||||
via_board->SetWidth( PADSTACK::ALL_LAYERS, via->Diameter( 0 ) );
|
||||
via_board->SetDrill( via->Drill() );
|
||||
via_board->SetNet( net );
|
||||
via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
|
||||
|
@ -107,7 +107,7 @@ protected:
|
||||
std::vector<std::unique_ptr<PNS::SOLID>> syncPad( PAD* aPad );
|
||||
std::unique_ptr<PNS::SEGMENT> syncTrack( PCB_TRACK* aTrack );
|
||||
std::unique_ptr<PNS::ARC> syncArc( PCB_ARC* aArc );
|
||||
std::vector<std::unique_ptr<PNS::VIA>> syncVia( PCB_VIA* aVia );
|
||||
std::unique_ptr<PNS::VIA> syncVia( PCB_VIA* aVia );
|
||||
bool syncTextItem( PNS::NODE* aWorld, PCB_TEXT* aText, PCB_LAYER_ID aLayer );
|
||||
bool syncGraphicalItem( PNS::NODE* aWorld, PCB_SHAPE* aItem );
|
||||
bool syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline );
|
||||
|
@ -98,7 +98,8 @@ public:
|
||||
m_blockingObstacle( nullptr )
|
||||
{
|
||||
m_via = aVia;
|
||||
m_width = aVia->Diameter();
|
||||
// TODO(JE) Padstacks - does this matter?
|
||||
m_width = aVia->Diameter( aVia->Layers().Start() );
|
||||
m_net = aVia->Net();
|
||||
m_layers = aVia->Layers();
|
||||
m_rank = aVia->Rank();
|
||||
@ -130,7 +131,7 @@ public:
|
||||
}
|
||||
|
||||
///< Return the shape of the line.
|
||||
const SHAPE* Shape() const override { return &m_line; }
|
||||
const SHAPE* Shape( int aLayer ) const override { return &m_line; }
|
||||
|
||||
///< Modifiable accessor to the underlying shape.
|
||||
SHAPE_LINE_CHAIN& Line() { return m_line; }
|
||||
@ -197,7 +198,15 @@ public:
|
||||
VIA& Via() { return *m_via; }
|
||||
const VIA& Via() const { return *m_via; }
|
||||
|
||||
void SetViaDiameter( int aDiameter ) { assert(m_via); m_via->SetDiameter( aDiameter ); }
|
||||
void SetViaDiameter( int aDiameter )
|
||||
{
|
||||
wxCHECK( m_via, /* void */ );
|
||||
wxCHECK2_MSG( m_via->StackMode() == VIA::STACK_MODE::NORMAL,
|
||||
m_via->SetStackMode( VIA::STACK_MODE::NORMAL ),
|
||||
wxS( "Warning: converting a complex viastack to normal in PNS_LINE" ) );
|
||||
|
||||
m_via->SetDiameter( VIA::ALL_LAYERS, aDiameter );
|
||||
}
|
||||
void SetViaDrill( int aDrill ) { assert(m_via); m_via->SetDrill( aDrill ); }
|
||||
|
||||
virtual void Mark( int aMarker ) const override;
|
||||
|
@ -825,7 +825,7 @@ bool LINE_PLACER::rhMarkObstacles( const VECTOR2I& aP, LINE& aNewHead, LINE& aNe
|
||||
if( obs )
|
||||
{
|
||||
int clearance = m_currentNode->GetClearance( obs->m_item, &m_head, false );
|
||||
SHAPE_LINE_CHAIN hull = obs->m_item->Hull( clearance, m_head.Width() );
|
||||
SHAPE_LINE_CHAIN hull = obs->m_item->Hull( clearance, m_head.Width(), m_head.Layer() );
|
||||
VECTOR2I nearest;
|
||||
|
||||
DIRECTION_45::CORNER_MODE cornerMode = Settings().GetCornerMode();
|
||||
|
@ -302,7 +302,7 @@ bool clipToOtherLine( NODE* aNode, const LINE& aRef, LINE& aClipped )
|
||||
//PNS_DBG( dbg, 3int, pclip, WHITE, 500000, wxT(""));
|
||||
|
||||
|
||||
if( l.Collide( &aRef, aNode, &ctx ) )
|
||||
if( l.Collide( &aRef, aNode, l.Layer(), &ctx ) )
|
||||
{
|
||||
didClip = true;
|
||||
curL -= step;
|
||||
|
@ -241,7 +241,7 @@ struct NODE::DEFAULT_OBSTACLE_VISITOR : public OBSTACLE_VISITOR
|
||||
if( visit( aCandidate ) )
|
||||
return true;
|
||||
|
||||
if( !aCandidate->Collide( m_item, m_node, m_ctx ) )
|
||||
if( !aCandidate->Collide( m_item, m_node, m_layerContext.value_or( -1 ), m_ctx ) )
|
||||
return true;
|
||||
|
||||
if( m_ctx->options.m_limitCount > 0 && m_ctx->obstacles.size() >= m_ctx->options.m_limitCount )
|
||||
@ -363,7 +363,7 @@ NODE::OPT_OBSTACLE NODE::NearestObstacle( const LINE* aLine,
|
||||
{
|
||||
const VIA& via = aLine->Via();
|
||||
int viaClearance = GetClearance( obstacle.m_item, &via, aOpts.m_useClearanceEpsilon )
|
||||
+ via.Diameter() / 2;
|
||||
+ via.Diameter( aLine->Layer() ) / 2;
|
||||
|
||||
obstacleHull = obstacle.m_item->Hull( viaClearance, 0, layer );
|
||||
|
||||
@ -478,7 +478,8 @@ struct HIT_VISITOR : public OBSTACLE_VISITOR
|
||||
|
||||
int cl = 0;
|
||||
|
||||
if( aItem->Shape()->Collide( &cp, cl ) )
|
||||
// TODO(JE) padstacks -- this may not work
|
||||
if( aItem->Shape( -1 )->Collide( &cp, cl ) )
|
||||
m_items.Add( aItem );
|
||||
|
||||
return true;
|
||||
@ -1088,7 +1089,7 @@ const LINE NODE::AssembleLine( LINKED_ITEM* aSeg, int* aOriginSegmentIndex,
|
||||
if( li->Kind() == ITEM::ARC_T )
|
||||
{
|
||||
const ARC* arc = static_cast<const ARC*>( li );
|
||||
const SHAPE_ARC* sa = static_cast<const SHAPE_ARC*>( arc->Shape() );
|
||||
const SHAPE_ARC* sa = static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) );
|
||||
|
||||
int nSegs = line.PointCount();
|
||||
VECTOR2I last = nSegs ? line.CPoint( -1 ) : VECTOR2I();
|
||||
|
@ -117,6 +117,7 @@ struct COLLISION_SEARCH_OPTIONS
|
||||
int m_kindMask = -1;
|
||||
bool m_useClearanceEpsilon = true;
|
||||
std::function<bool(const ITEM*)> m_filter = nullptr;
|
||||
int m_layer = -1;
|
||||
};
|
||||
|
||||
|
||||
@ -182,6 +183,9 @@ public:
|
||||
|
||||
void SetWorld( const NODE* aNode, const NODE* aOverride = nullptr );
|
||||
|
||||
void SetLayerContext( int aLayer ) { m_layerContext = aLayer; }
|
||||
void ClearLayerContext() { m_layerContext = std::nullopt; }
|
||||
|
||||
virtual bool operator()( ITEM* aCandidate ) = 0;
|
||||
|
||||
protected:
|
||||
@ -192,6 +196,26 @@ protected:
|
||||
|
||||
const NODE* m_node; ///< node we are searching in (either root or a branch)
|
||||
const NODE* m_override; ///< node that overrides root entries
|
||||
std::optional<int> m_layerContext;
|
||||
};
|
||||
|
||||
|
||||
class LAYER_CONTEXT_SETTER
|
||||
{
|
||||
public:
|
||||
LAYER_CONTEXT_SETTER( OBSTACLE_VISITOR& aVisitor, int aLayer ) :
|
||||
m_visitor( aVisitor )
|
||||
{
|
||||
m_visitor.SetLayerContext( aLayer );
|
||||
}
|
||||
|
||||
~LAYER_CONTEXT_SETTER()
|
||||
{
|
||||
m_visitor.ClearLayerContext();
|
||||
}
|
||||
|
||||
private:
|
||||
OBSTACLE_VISITOR& m_visitor;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -141,7 +141,8 @@ struct OPTIMIZER::CACHE_VISITOR
|
||||
if( !( m_mask & aOtherItem->Kind() ) )
|
||||
return true;
|
||||
|
||||
if( !aOtherItem->Collide( m_ourItem, m_node ) )
|
||||
// TODO(JE) viastacks
|
||||
if( !aOtherItem->Collide( m_ourItem, m_node, m_ourItem->Layer() ) )
|
||||
return true;
|
||||
|
||||
m_collidingItem = aOtherItem;
|
||||
@ -789,7 +790,7 @@ OPTIMIZER::BREAKOUT_LIST OPTIMIZER::customBreakouts( int aWidth, const ITEM* aIt
|
||||
bool aPermitDiagonal ) const
|
||||
{
|
||||
BREAKOUT_LIST breakouts;
|
||||
const SHAPE_SIMPLE* convex = static_cast<const SHAPE_SIMPLE*>( aItem->Shape() );
|
||||
const SHAPE_SIMPLE* convex = static_cast<const SHAPE_SIMPLE*>( aItem->Shape( -1 ) );
|
||||
|
||||
BOX2I bbox = convex->BBox( 0 );
|
||||
VECTOR2I p0 = static_cast<const SOLID*>( aItem )->Pos();
|
||||
@ -896,12 +897,13 @@ OPTIMIZER::BREAKOUT_LIST OPTIMIZER::computeBreakouts( int aWidth, const ITEM* aI
|
||||
case ITEM::VIA_T:
|
||||
{
|
||||
const VIA* via = static_cast<const VIA*>( aItem );
|
||||
return circleBreakouts( aWidth, via->Shape(), aPermitDiagonal );
|
||||
// TODO(JE) padstacks -- computeBreakouts needs to have a layer argument
|
||||
return circleBreakouts( aWidth, via->Shape( 0 ), aPermitDiagonal );
|
||||
}
|
||||
|
||||
case ITEM::SOLID_T:
|
||||
{
|
||||
const SHAPE* shape = aItem->Shape();
|
||||
const SHAPE* shape = aItem->Shape( -1 );
|
||||
|
||||
switch( shape->Type() )
|
||||
{
|
||||
@ -982,7 +984,7 @@ int OPTIMIZER::smartPadsSingle( LINE* aLine, ITEM* aPad, bool aEnd, int aEndVert
|
||||
for( int p = 1; p <= p_end; p++ )
|
||||
{
|
||||
// If the line is contained inside the pad, don't optimize
|
||||
if( solid && solid->Shape() && !solid->Shape()->Collide(
|
||||
if( solid && solid->Shape( -1 ) && !solid->Shape( -1 )->Collide(
|
||||
SEG( line.CPoint( 0 ), line.CPoint( p ) ), aLine->Width() / 2 ) )
|
||||
{
|
||||
continue;
|
||||
@ -1198,7 +1200,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( refLine.Collide( &coupledLine, aNode ) )
|
||||
if( refLine.Collide( &coupledLine, aNode, refLine.Layer() ) )
|
||||
return false;
|
||||
|
||||
if( aNode->CheckColliding ( &refLine ) )
|
||||
|
@ -774,7 +774,7 @@ bool ROUTER::movePlacing( const VECTOR2I& aP, ITEM* aEndItem )
|
||||
if( via.HasHole() )
|
||||
{
|
||||
int holeClearance = GetRuleResolver()->Clearance( via.Hole(), nullptr );
|
||||
int annularWidth = std::max( 0, via.Diameter() - via.Drill() ) / 2;
|
||||
int annularWidth = std::max( 0, via.Diameter( l->Layer() ) - via.Drill() ) / 2;
|
||||
int excessHoleClearance = holeClearance - annularWidth;
|
||||
|
||||
if( excessHoleClearance > clearance )
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
|
||||
SEGMENT* Clone() const override;
|
||||
|
||||
const SHAPE* Shape() const override
|
||||
const SHAPE* Shape( int aLayer ) const override
|
||||
{
|
||||
return static_cast<const SHAPE*>( &m_seg );
|
||||
}
|
||||
|
@ -257,8 +257,8 @@ bool SHOVE::shoveLineFromLoneVia( const LINE& aCurLine, const LINE& aObstacleLin
|
||||
HOLE* viaHole = via.Hole();
|
||||
int holeClearance = getClearance( viaHole, &aObstacleLine );
|
||||
|
||||
if( holeClearance + via.Drill() / 2 > clearance + via.Diameter() / 2 )
|
||||
clearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
|
||||
if( holeClearance + via.Drill() / 2 > clearance + via.Diameter( aObstacleLine.Layer() ) / 2 )
|
||||
clearance = holeClearance + via.Drill() / 2 - via.Diameter( aObstacleLine.Layer() ) / 2;
|
||||
|
||||
SHAPE_LINE_CHAIN hull = aCurLine.Via().Hull( clearance, obstacleLineWidth, aCurLine.Layer() );
|
||||
SHAPE_LINE_CHAIN path_cw;
|
||||
@ -283,7 +283,7 @@ bool SHOVE::shoveLineFromLoneVia( const LINE& aCurLine, const LINE& aObstacleLin
|
||||
|
||||
aResultLine.SetShape( shortest );
|
||||
|
||||
if( aResultLine.Collide( &aCurLine, m_currentNode ) )
|
||||
if( aResultLine.Collide( &aCurLine, m_currentNode, aResultLine.Layer() ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -383,7 +383,7 @@ bool SHOVE::shoveLineToHullSet( const LINE& aCurLine, const LINE& aObstacleLine,
|
||||
continue;
|
||||
}
|
||||
|
||||
bool colliding = l.Collide( &aCurLine, m_currentNode );
|
||||
bool colliding = l.Collide( &aCurLine, m_currentNode, l.Layer() );
|
||||
|
||||
#if 0
|
||||
if(( aCurLine.Marker() & MK_HEAD ) && !colliding )
|
||||
@ -392,7 +392,7 @@ bool SHOVE::shoveLineToHullSet( const LINE& aCurLine, const LINE& aObstacleLine,
|
||||
|
||||
for( ITEM* item : jtStart->LinkList() )
|
||||
{
|
||||
if( item->Collide( &l, m_currentNode ) )
|
||||
if( item->Collide( &l, m_currentNode, l.Layer() ) )
|
||||
colliding = true;
|
||||
}
|
||||
}
|
||||
@ -494,11 +494,14 @@ bool SHOVE::ShoveObstacleLine( const LINE& aCurLine, const LINE& aObstacleLine,
|
||||
int viaClearance = getClearance( &via, &obstacleLine );
|
||||
HOLE* viaHole = via.Hole();
|
||||
int holeClearance = getClearance( viaHole, &obstacleLine );
|
||||
int layer = aObstacleLine.Layer();
|
||||
|
||||
if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
|
||||
viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
|
||||
if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter( layer ) / 2 )
|
||||
{
|
||||
viaClearance = holeClearance + via.Drill() / 2 - via.Diameter( layer ) / 2;
|
||||
}
|
||||
|
||||
hulls.push_back( aCurLine.Via().Hull( viaClearance, obstacleLineWidth ) );
|
||||
hulls.push_back( aCurLine.Via().Hull( viaClearance, obstacleLineWidth, layer ) );
|
||||
}
|
||||
|
||||
if (shoveLineToHullSet( aCurLine, obstacleLine, aResultLine, hulls ) )
|
||||
@ -688,7 +691,8 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle, OB
|
||||
}
|
||||
}
|
||||
|
||||
if( via && via->Collide( aObstacle, m_currentNode ) )
|
||||
// TODO(JE) viastacks -- can aObstacle be a via?
|
||||
if( via && via->Collide( aObstacle, m_currentNode, aObstacle->Layer() ) )
|
||||
return onCollidingVia( aObstacle, via, aObstacleInfo, aObstacle->Rank() - 1 );
|
||||
}
|
||||
|
||||
@ -757,7 +761,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle, OB
|
||||
{
|
||||
LINE lastLine = m_lineStack.front();
|
||||
|
||||
if( lastLine.Collide( &walkaroundLine, m_currentNode ) )
|
||||
if( lastLine.Collide( &walkaroundLine, m_currentNode, lastLine.Layer() ) )
|
||||
{
|
||||
LINE dummy( lastLine );
|
||||
|
||||
@ -1076,10 +1080,12 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia, OB
|
||||
if( aCurrent->OfKind( ITEM::LINE_T ) )
|
||||
{
|
||||
VIA vtmp ( *aObstacleVia );
|
||||
int layer = aCurrent->Layer();
|
||||
|
||||
if( aObstacleInfo.m_maxFanoutWidth > 0 && aObstacleInfo.m_maxFanoutWidth > aObstacleVia->Diameter() )
|
||||
if( aObstacleInfo.m_maxFanoutWidth > 0
|
||||
&& aObstacleInfo.m_maxFanoutWidth > aObstacleVia->Diameter( layer ) )
|
||||
{
|
||||
vtmp.SetDiameter( aObstacleInfo.m_maxFanoutWidth );
|
||||
vtmp.SetDiameter( layer, aObstacleInfo.m_maxFanoutWidth );
|
||||
}
|
||||
|
||||
LINE* currentLine = (LINE*) aCurrent;
|
||||
@ -1093,7 +1099,7 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia, OB
|
||||
|
||||
PNS_DBG( Dbg(), AddItem, vtmp.Clone(), LIGHTRED, 100000, wxT( "orig-via" ) );
|
||||
|
||||
lineCollision = vtmp.Shape()->Collide( currentLine->Shape(),
|
||||
lineCollision = vtmp.Shape( layer )->Collide( currentLine->Shape( -1 ),
|
||||
clearance + currentLine->Width() / 2,
|
||||
&mtvLine );
|
||||
|
||||
@ -1102,14 +1108,24 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingVia( ITEM* aCurrent, VIA* aObstacleVia, OB
|
||||
{
|
||||
const VIA& currentVia = currentLine->Via();
|
||||
int viaClearance = getClearance( ¤tVia, &vtmp );
|
||||
VECTOR2I layerMtv;
|
||||
|
||||
viaCollision = currentVia.Shape()->Collide( vtmp.Shape(), viaClearance, &mtvVia );
|
||||
for( int viaLayer : currentVia.RelevantShapeLayers( &vtmp ) )
|
||||
{
|
||||
viaCollision |= currentVia.Shape( viaLayer )->Collide( vtmp.Shape( viaLayer ),
|
||||
viaClearance,
|
||||
&layerMtv );
|
||||
|
||||
if( layerMtv.SquaredEuclideanNorm() > mtvVia.SquaredEuclideanNorm() )
|
||||
mtvVia = layerMtv;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( aCurrent->OfKind( ITEM::SOLID_T ) )
|
||||
{
|
||||
PNS_DBG( Dbg(), Message, wxT("collidee-is-solid" ) );
|
||||
solidCollision = aCurrent->Shape()->Collide( aObstacleVia->Shape(), clearance,
|
||||
// TODO(JE) if this case is real, handle via stacks
|
||||
solidCollision = aCurrent->Shape( -1 )->Collide( aObstacleVia->Shape( -1 ), clearance,
|
||||
&mtvSolid );
|
||||
//PNS_DBGN( Dbg(), EndGroup );
|
||||
|
||||
@ -1148,18 +1164,29 @@ SHOVE::SHOVE_STATUS SHOVE::onReverseCollidingVia( LINE& aCurrent, VIA* aObstacle
|
||||
auto p0 = aCurrent.Via().Pos();
|
||||
auto p1 = aObstacleVia->Pos();
|
||||
|
||||
int dist = (p0 - p1).EuclideanNorm() - aCurrent.Via().Diameter() / 2 - aObstacleVia->Diameter() / 2;
|
||||
int layer = aCurrent.Layer();
|
||||
int dist = (p0 - p1).EuclideanNorm() - aCurrent.Via().Diameter( layer ) / 2
|
||||
- aObstacleVia->Diameter( layer ) / 2;
|
||||
|
||||
int clearance = getClearance( &aCurrent.Via(), aObstacleVia );
|
||||
|
||||
SHAPE_LINE_CHAIN hull = aObstacleVia->Hull( clearance, aCurrent.Width(), aCurrent.Layer() );
|
||||
SHAPE_LINE_CHAIN hull = aObstacleVia->Hull( clearance, aCurrent.Width(), layer );
|
||||
|
||||
auto epInsideHull = hull.PointInside( p0 );
|
||||
|
||||
PNS_DBG( Dbg(), AddShape, &hull, LIGHTYELLOW, 100000, wxT( "obstacle-via-hull" ) );
|
||||
PNS_DBG( Dbg(), Message, wxString::Format("via2via coll check dist %d cl %d delta %d pi %d\n", dist, clearance, dist - clearance, epInsideHull ? 1 : 0) );
|
||||
|
||||
if( aCurrent.Via().Collide( aObstacleVia, m_currentNode ) )
|
||||
bool viaCollision = false;
|
||||
|
||||
for( int viaLayer : aCurrent.Via().RelevantShapeLayers( aObstacleVia ) )
|
||||
{
|
||||
viaCollision |=
|
||||
aCurrent.Via().Shape( viaLayer )->Collide( aObstacleVia->Shape( viaLayer ),
|
||||
clearance );
|
||||
}
|
||||
|
||||
if( viaCollision )
|
||||
{
|
||||
return onCollidingVia( &aCurrent, aObstacleVia, aObstacleInfo, aCurrent.Rank() - 1 );
|
||||
}
|
||||
@ -1346,6 +1373,8 @@ void SHOVE::popLineStack( )
|
||||
|
||||
bool SHOVE::fixupViaCollisions( const LINE* aCurrent, OBSTACLE& obs )
|
||||
{
|
||||
int layer = aCurrent->Layer();
|
||||
|
||||
// if the current obstacle is a via, consider also the lines connected to it
|
||||
// if their widths are larger or equal than the via diameter, the shove algorithm
|
||||
// will very likely fail in the subsequent iterations (as our base assumption is track
|
||||
@ -1376,11 +1405,11 @@ bool SHOVE::fixupViaCollisions( const LINE* aCurrent, OBSTACLE& obs )
|
||||
|
||||
obs.m_maxFanoutWidth = 0;
|
||||
|
||||
if( maxw > 0 && maxw >= v->Diameter() )
|
||||
if( maxw > 0 && maxw >= v->Diameter( layer ) )
|
||||
{
|
||||
obs.m_maxFanoutWidth = maxw + 1;
|
||||
PNS_DBG( Dbg(), Message,
|
||||
wxString::Format( "Fixup via: new-w %d via-w %d", maxw, v->Diameter() ) );
|
||||
wxString::Format( "Fixup via: new-w %d via-w %d", maxw, v->Diameter( layer ) ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1393,6 +1422,7 @@ bool SHOVE::fixupViaCollisions( const LINE* aCurrent, OBSTACLE& obs )
|
||||
return false;
|
||||
|
||||
const SEGMENT* s = static_cast<const SEGMENT*>( obs.m_item );
|
||||
int sl = s->Layer();
|
||||
|
||||
const JOINT* ja = m_currentNode->FindJoint( s->Seg().A, s );
|
||||
const JOINT* jb = m_currentNode->FindJoint( s->Seg().B, s );
|
||||
@ -1405,14 +1435,14 @@ bool SHOVE::fixupViaCollisions( const LINE* aCurrent, OBSTACLE& obs )
|
||||
|
||||
// via diameter is larger than the segment width - cool, the force propagation algo
|
||||
// will be able to deal with it, no need to intervene
|
||||
if( !v || v->Diameter() > s->Width() )
|
||||
if( !v || v->Diameter( sl ) > s->Width() )
|
||||
continue;
|
||||
|
||||
VIA vtest( *v );
|
||||
vtest.SetDiameter( s->Width() );
|
||||
vtest.SetDiameter( sl, s->Width() );
|
||||
|
||||
// enlarge the via to the width of the segment
|
||||
if( vtest.Collide( aCurrent, m_currentNode ) )
|
||||
if( vtest.Collide( aCurrent, m_currentNode, aCurrent->Layer() ) )
|
||||
{
|
||||
// if colliding, drop the segment in the shove iteration loop and force-propagate the via instead
|
||||
obs.m_item = v;
|
||||
@ -1475,7 +1505,7 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
||||
|
||||
if( nearest )
|
||||
{
|
||||
PNS_DBG( Dbg(), AddShape, nearest->m_item->Shape(), YELLOW, 10000,
|
||||
PNS_DBG( Dbg(), AddShape, nearest->m_item->Shape( currentLine.Layer() ), YELLOW, 10000,
|
||||
wxString::Format( "nearest %p %s rank %d",
|
||||
nearest->m_item,
|
||||
nearest->m_item->KindStr(),
|
||||
@ -1521,7 +1551,10 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
||||
{
|
||||
PNS_DBG( Dbg(), BeginGroup, wxString::Format( wxT( "iter %d: reverse-collide-via" ), aIter ), 0 );
|
||||
|
||||
if( currentLine.EndsWithVia() && nearest->m_item->Collide( ¤tLine.Via(), m_currentNode ) )
|
||||
// TODO(JE) viastacks -- via-via collisions here?
|
||||
if( currentLine.EndsWithVia()
|
||||
&& nearest->m_item->Collide( ¤tLine.Via(), m_currentNode,
|
||||
nearest->m_item->Layer() ) )
|
||||
{
|
||||
PNS_DBG( Dbg(), AddItem, nearest->m_item, YELLOW, 100000, wxT("v2v nearesti" ) );
|
||||
//PNS_DBG( Dbg(), AddItem, nearest->m_head,RED, 100000, wxString::Format("v2v nearesth force=%d,%d" ) );
|
||||
@ -1551,7 +1584,8 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
||||
|
||||
popLineStack();
|
||||
|
||||
if( currentLine.EndsWithVia() && currentLine.Via().Collide( (SEGMENT*) ni, m_currentNode ) )
|
||||
if( currentLine.EndsWithVia()
|
||||
&& currentLine.Via().Collide( (SEGMENT*) ni, m_currentNode, currentLine.Layer() ) )
|
||||
{
|
||||
VIA_HANDLE vh;
|
||||
vh.layers = currentLine.Via().Layers();
|
||||
|
@ -73,7 +73,7 @@ public:
|
||||
SetShape( aB.m_shape->Clone() );
|
||||
|
||||
if( aB.m_hole )
|
||||
SetHole( new PNS::HOLE( aB.m_hole->Shape()->Clone() ) );
|
||||
SetHole( new PNS::HOLE( aB.m_hole->Shape( -1 )->Clone() ) );
|
||||
|
||||
m_pos = aB.m_pos;
|
||||
m_padToDie = aB.m_padToDie;
|
||||
@ -89,7 +89,7 @@ public:
|
||||
|
||||
ITEM* Clone() const override;
|
||||
|
||||
const SHAPE* Shape() const override { return m_shape; }
|
||||
const SHAPE* Shape( int aLayer ) const override { return m_shape; }
|
||||
|
||||
|
||||
const SHAPE_LINE_CHAIN Hull( int aClearance = 0, int aWalkaroundThickness = 0,
|
||||
|
@ -167,7 +167,7 @@ ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, NET_HANDLE aNet, int aL
|
||||
{
|
||||
if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
|
||||
{
|
||||
SEG::ecoord d = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm();
|
||||
SEG::ecoord d = ( item->Shape( aLayer )->Centre() - aWhere ).SquaredEuclideanNorm();
|
||||
|
||||
if( d < dist[2] )
|
||||
{
|
||||
@ -203,7 +203,7 @@ ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, NET_HANDLE aNet, int aL
|
||||
else if( item->OfKind( ITEM::SOLID_T ) && item->IsFreePad() )
|
||||
{
|
||||
// Allow free pads only when already inside pad
|
||||
if( item->Shape()->Collide( aWhere ) )
|
||||
if( item->Shape( -1 )->Collide( aWhere ) )
|
||||
{
|
||||
prioritized[0] = item;
|
||||
dist[0] = 0;
|
||||
@ -500,7 +500,7 @@ const VECTOR2I TOOL_BASE::snapToItem( ITEM* aItem, const VECTOR2I& aP )
|
||||
else if( aItem->Kind() == ITEM::ARC_T )
|
||||
{
|
||||
ARC* arc = static_cast<ARC*>( li );
|
||||
return m_gridHelper->AlignToArc( aP, *static_cast<const SHAPE_ARC*>( arc->Shape() ) );
|
||||
return m_gridHelper->AlignToArc( aP, *static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) ) );
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -504,7 +504,7 @@ bool TOPOLOGY::AssembleDiffPair( ITEM* aStart, DIFF_PAIR& aPair )
|
||||
LINKED_ITEM* coupledItem = nullptr;
|
||||
SEG::ecoord minDist_sq = std::numeric_limits<SEG::ecoord>::max();
|
||||
SEG::ecoord minDistTarget_sq = std::numeric_limits<SEG::ecoord>::max();
|
||||
VECTOR2I targetPoint = aStart->Shape()->Centre();
|
||||
VECTOR2I targetPoint = aStart->Shape( -1 )->Centre();
|
||||
|
||||
auto findNItem = [&]( ITEM* p_item )
|
||||
{
|
||||
@ -552,7 +552,7 @@ bool TOPOLOGY::AssembleDiffPair( ITEM* aStart, DIFF_PAIR& aPair )
|
||||
|
||||
if( dist_sq <= minDist_sq )
|
||||
{
|
||||
SEG::ecoord distTarget_sq = n_item->Shape()->SquaredDistance( targetPoint );
|
||||
SEG::ecoord distTarget_sq = n_item->Shape( -1 )->SquaredDistance( targetPoint );
|
||||
if( distTarget_sq < minDistTarget_sq )
|
||||
{
|
||||
minDistTarget_sq = distTarget_sq;
|
||||
@ -634,7 +634,7 @@ const TOPOLOGY::CLUSTER TOPOLOGY::AssembleCluster( ITEM* aStart, int aLayer, dou
|
||||
|
||||
pending.push_back( aStart );
|
||||
|
||||
BOX2I clusterBBox = aStart->Shape()->BBox();
|
||||
BOX2I clusterBBox = aStart->Shape( aLayer )->BBox();
|
||||
int64_t initialArea = clusterBBox.GetArea();
|
||||
|
||||
while( !pending.empty() )
|
||||
@ -665,7 +665,7 @@ const TOPOLOGY::CLUSTER TOPOLOGY::AssembleCluster( ITEM* aStart, int aLayer, dou
|
||||
}
|
||||
else
|
||||
{
|
||||
clusterBBox.Merge( obs.m_item->Shape()->BBox() );
|
||||
clusterBBox.Merge( obs.m_item->Shape( aLayer )->BBox() );
|
||||
}
|
||||
|
||||
const int64_t currentArea = clusterBBox.GetArea();
|
||||
|
@ -30,25 +30,98 @@
|
||||
|
||||
namespace PNS {
|
||||
|
||||
int VIA::EffectiveLayer( int aLayer ) const
|
||||
{
|
||||
switch( m_stackMode )
|
||||
{
|
||||
default:
|
||||
case STACK_MODE::NORMAL:
|
||||
return ALL_LAYERS;
|
||||
|
||||
case STACK_MODE::FRONT_INNER_BACK:
|
||||
if( aLayer == m_layers.Start() || aLayer == m_layers.End() )
|
||||
return aLayer;
|
||||
|
||||
if( m_layers.Start() + 1 < m_layers.End() )
|
||||
return m_layers.Start() + 1;
|
||||
|
||||
return m_layers.Start();
|
||||
|
||||
case STACK_MODE::CUSTOM:
|
||||
return m_layers.Overlaps( aLayer ) ? aLayer : m_layers.Start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<int> VIA::UniqueShapeLayers() const
|
||||
{
|
||||
switch( m_stackMode )
|
||||
{
|
||||
default:
|
||||
case STACK_MODE::NORMAL:
|
||||
return { ALL_LAYERS };
|
||||
|
||||
case STACK_MODE::FRONT_INNER_BACK:
|
||||
return { 0, ALL_LAYERS, m_layers.End() };
|
||||
|
||||
case STACK_MODE::CUSTOM:
|
||||
std::vector<int> ret;
|
||||
|
||||
for( int l = m_layers.Start(); l <= m_layers.End(); l++ )
|
||||
ret.push_back( l );
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VIA::SetStackMode( STACK_MODE aStackMode )
|
||||
{
|
||||
m_stackMode = aStackMode;
|
||||
|
||||
wxASSERT_MSG( m_stackMode != STACK_MODE::FRONT_INNER_BACK || m_layers.Start() == 0,
|
||||
wxT( "Cannot use FRONT_INNER_BACK with blind/buried vias!" ) );
|
||||
|
||||
// In theory, it might be good to do some housekeeping on m_diameters and m_shapes here,
|
||||
// but it's not yet clear if the stack mode needs to be changed after initial creation.
|
||||
}
|
||||
|
||||
|
||||
bool VIA::PadstackMatches( const VIA& aOther ) const
|
||||
{
|
||||
std::vector<int> myLayers = UniqueShapeLayers();
|
||||
std::vector<int> otherLayers = aOther.UniqueShapeLayers();
|
||||
|
||||
if( !std::equal( myLayers.begin(), myLayers.end(), otherLayers.begin() ) )
|
||||
return false;
|
||||
|
||||
for( int i : myLayers )
|
||||
{
|
||||
if( Diameter( i ) != aOther.Diameter( i ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool VIA::PushoutForce( NODE* aNode, const ITEM* aOther, VECTOR2I& aForce )
|
||||
{
|
||||
int clearance = aNode->GetClearance( this, aOther, false );
|
||||
VECTOR2I elementForces[4], force;
|
||||
size_t nf = 0;
|
||||
VECTOR2I elementForce;
|
||||
|
||||
aOther->Shape()->Collide( Shape(), clearance, &elementForces[nf++] );
|
||||
|
||||
for( size_t i = 0; i < nf; i++ )
|
||||
for( int layer : RelevantShapeLayers( aOther ) )
|
||||
{
|
||||
if( elementForces[i].SquaredEuclideanNorm() > force.SquaredEuclideanNorm() )
|
||||
force = elementForces[i];
|
||||
aOther->Shape( layer )->Collide( Shape( layer ), clearance, &elementForce );
|
||||
|
||||
if( elementForce.SquaredEuclideanNorm() > aForce.SquaredEuclideanNorm() )
|
||||
aForce = elementForce;
|
||||
}
|
||||
|
||||
aForce = force;
|
||||
|
||||
return ( force != VECTOR2I( 0, 0 ) );
|
||||
return ( aForce != VECTOR2I( 0, 0 ) );
|
||||
}
|
||||
|
||||
|
||||
bool VIA::PushoutForce( NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForce,
|
||||
int aCollisionMask, int aMaxIterations )
|
||||
{
|
||||
@ -86,7 +159,8 @@ bool VIA::PushoutForce( NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForc
|
||||
break;
|
||||
}
|
||||
|
||||
const int threshold = Diameter() / 4; // another stupid heuristic.
|
||||
// TODO(JE) padstacks -- what is the correct logic here?
|
||||
const int threshold = Diameter( EffectiveLayer( 0 ) ) / 4; // another stupid heuristic.
|
||||
const int forceMag = force.EuclideanNorm();
|
||||
|
||||
// We've been through a lot of iterations already and our pushout force is still too big?
|
||||
@ -143,7 +217,7 @@ bool VIA::PushoutForce( NODE* aNode, const VECTOR2I& aDirection, VECTOR2I& aForc
|
||||
const SHAPE_LINE_CHAIN VIA::Hull( int aClearance, int aWalkaroundThickness, int aLayer ) const
|
||||
{
|
||||
int cl = ( aClearance + aWalkaroundThickness / 2 );
|
||||
int width = m_diameter;
|
||||
int width = Diameter( aLayer );
|
||||
|
||||
if( m_hole && !ROUTER::GetInstance()->GetInterface()->IsFlashedOnLayer( this, aLayer ) )
|
||||
width = m_hole->Radius() * 2;
|
||||
@ -163,9 +237,13 @@ VIA* VIA::Clone() const
|
||||
v->SetNet( Net() );
|
||||
v->SetLayers( Layers() );
|
||||
v->m_pos = m_pos;
|
||||
v->m_diameter = m_diameter;
|
||||
v->m_stackMode = m_stackMode;
|
||||
v->m_diameters = m_diameters;
|
||||
v->m_drill = m_drill;
|
||||
v->m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 );
|
||||
|
||||
for( const auto& [layer, shape] : m_shapes )
|
||||
v->m_shapes[layer] = SHAPE_CIRCLE( m_pos, shape.GetRadius() );
|
||||
|
||||
v->SetHole( HOLE::MakeCircularHole( m_pos, m_drill / 2, m_layers ) );
|
||||
v->m_rank = m_rank;
|
||||
v->m_marker = m_marker;
|
||||
@ -182,8 +260,14 @@ OPT_BOX2I VIA::ChangedArea( const VIA* aOther ) const
|
||||
{
|
||||
if( aOther->Pos() != Pos() )
|
||||
{
|
||||
BOX2I tmp = Shape()->BBox();
|
||||
tmp.Merge( aOther->Shape()->BBox() );
|
||||
BOX2I tmp;
|
||||
|
||||
for( int layer : UniqueShapeLayers() )
|
||||
tmp.Merge( Shape( layer )->BBox() );
|
||||
|
||||
for( int layer : aOther->UniqueShapeLayers() )
|
||||
tmp.Merge( aOther->Shape( layer )->BBox() );
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@ -206,7 +290,8 @@ const std::string VIA::Format( ) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << ITEM::Format() << " drill " << m_drill << " ";
|
||||
ss << m_shape.Format( false );
|
||||
// TODO(JE) padstacks
|
||||
ss << Shape( 0 )->Format( false );
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#ifndef __PNS_VIA_H
|
||||
#define __PNS_VIA_H
|
||||
|
||||
#include <geometry/shape_index.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_circle.h>
|
||||
#include <math/box2.h>
|
||||
@ -47,7 +48,7 @@ struct VIA_HANDLE
|
||||
pos( aPos ),
|
||||
layers (aLayers),
|
||||
net (aNet ) {};
|
||||
|
||||
|
||||
bool valid = false;
|
||||
VECTOR2I pos;
|
||||
PNS_LAYER_RANGE layers;
|
||||
@ -57,11 +58,30 @@ struct VIA_HANDLE
|
||||
class VIA : public LINKED_ITEM
|
||||
{
|
||||
public:
|
||||
enum class STACK_MODE
|
||||
{
|
||||
// The via is the same size on every layer
|
||||
NORMAL,
|
||||
|
||||
// The via can have three different sizes -- note that in this context, front means
|
||||
// m_layers.Start() and back means m_layers.End(), which does not align with KiCad in the
|
||||
// case of blind/buried vias. Using this STACK_MODE only makes sense for vias that extend
|
||||
// through the whole PCB
|
||||
FRONT_INNER_BACK,
|
||||
|
||||
// The via can have a different size on each layer
|
||||
CUSTOM
|
||||
};
|
||||
|
||||
static constexpr int ALL_LAYERS = 0;
|
||||
static constexpr int INNER_LAYERS = 1;
|
||||
|
||||
VIA() :
|
||||
LINKED_ITEM( VIA_T ),
|
||||
m_hole( nullptr )
|
||||
{
|
||||
m_diameter = 2; // Dummy value
|
||||
m_stackMode = STACK_MODE::NORMAL;
|
||||
m_diameters[0] = 2; // Dummy value
|
||||
m_drill = 1; // Dummy value
|
||||
m_viaType = VIATYPE::THROUGH;
|
||||
m_isFree = false;
|
||||
@ -77,9 +97,10 @@ public:
|
||||
SetNet( aNet );
|
||||
SetLayers( aLayers );
|
||||
m_pos = aPos;
|
||||
m_diameter = aDiameter;
|
||||
m_stackMode = STACK_MODE::NORMAL;
|
||||
m_diameters[0] = aDiameter;
|
||||
m_drill = aDrill;
|
||||
m_shape = SHAPE_CIRCLE( aPos, aDiameter / 2 );
|
||||
m_shapes[0] = SHAPE_CIRCLE( aPos, aDiameter / 2 );
|
||||
SetHole( HOLE::MakeCircularHole( m_pos, aDrill / 2, PNS_LAYER_RANGE() ) );
|
||||
m_viaType = aViaType;
|
||||
m_isFree = false;
|
||||
@ -93,8 +114,12 @@ public:
|
||||
SetNet( aB.Net() );
|
||||
SetLayers( aB.Layers() );
|
||||
m_pos = aB.m_pos;
|
||||
m_diameter = aB.m_diameter;
|
||||
m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 );
|
||||
m_stackMode = aB.m_stackMode;
|
||||
m_diameters = aB.m_diameters;
|
||||
|
||||
for( const auto& [layer, shape] : aB.m_shapes )
|
||||
m_shapes[layer] = SHAPE_CIRCLE( m_pos, shape.GetRadius() );
|
||||
|
||||
m_drill = aB.m_drill;
|
||||
SetHole( HOLE::MakeCircularHole( m_pos, m_drill / 2, PNS_LAYER_RANGE() ) );
|
||||
m_marker = aB.m_marker;
|
||||
@ -115,8 +140,12 @@ public:
|
||||
SetNet( aB.Net() );
|
||||
SetLayers( aB.Layers() );
|
||||
m_pos = aB.m_pos;
|
||||
m_diameter = aB.m_diameter;
|
||||
m_shape = SHAPE_CIRCLE( m_pos, m_diameter / 2 );
|
||||
m_stackMode = aB.m_stackMode;
|
||||
m_diameters = aB.m_diameters;
|
||||
|
||||
for( const auto& [layer, shape] : aB.m_shapes )
|
||||
m_shapes[layer] = SHAPE_CIRCLE( m_pos, shape.GetRadius() );
|
||||
|
||||
m_drill = aB.m_drill;
|
||||
SetHole( HOLE::MakeCircularHole( m_pos, m_drill / 2, PNS_LAYER_RANGE() ) );
|
||||
m_marker = aB.m_marker;
|
||||
@ -133,12 +162,24 @@ public:
|
||||
return aItem && VIA_T == aItem->Kind();
|
||||
}
|
||||
|
||||
STACK_MODE StackMode() const { return m_stackMode; }
|
||||
|
||||
void SetStackMode( STACK_MODE aStackMode );
|
||||
|
||||
int EffectiveLayer( int aLayer ) const;
|
||||
|
||||
std::vector<int> UniqueShapeLayers() const override;
|
||||
|
||||
bool HasUniqueShapeLayers() const override { return true; }
|
||||
|
||||
const VECTOR2I& Pos() const { return m_pos; }
|
||||
|
||||
void SetPos( const VECTOR2I& aPos )
|
||||
{
|
||||
m_pos = aPos;
|
||||
m_shape.SetCenter( aPos );
|
||||
|
||||
for( auto& [layer, shape] : m_shapes )
|
||||
shape.SetCenter( aPos );
|
||||
|
||||
if( m_hole )
|
||||
m_hole->SetCenter( aPos );
|
||||
@ -147,14 +188,26 @@ public:
|
||||
VIATYPE ViaType() const { return m_viaType; }
|
||||
void SetViaType( VIATYPE aViaType ) { m_viaType = aViaType; }
|
||||
|
||||
int Diameter() const { return m_diameter; }
|
||||
|
||||
void SetDiameter( int aDiameter )
|
||||
int Diameter( int aLayer ) const
|
||||
{
|
||||
m_diameter = aDiameter;
|
||||
m_shape.SetRadius( m_diameter / 2 );
|
||||
int layer = EffectiveLayer( aLayer );
|
||||
wxCHECK( m_diameters.contains( layer ), m_diameters.begin()->second );
|
||||
return m_diameters.at( layer );
|
||||
}
|
||||
|
||||
void SetDiameter( int aLayer, int aDiameter )
|
||||
{
|
||||
int layer = EffectiveLayer( aLayer );
|
||||
m_diameters[layer] = aDiameter;
|
||||
|
||||
if( !m_shapes.contains( layer ) )
|
||||
m_shapes[layer] = SHAPE_CIRCLE( m_pos, aDiameter / 2 );
|
||||
else
|
||||
m_shapes[layer].SetRadius( aDiameter / 2 );
|
||||
}
|
||||
|
||||
bool PadstackMatches( const VIA& aOther ) const;
|
||||
|
||||
int Drill() const { return m_drill; }
|
||||
|
||||
void SetDrill( int aDrill )
|
||||
@ -173,7 +226,12 @@ public:
|
||||
|
||||
bool PushoutForce( NODE* aNode, const ITEM* aOther, VECTOR2I& aForce );
|
||||
|
||||
const SHAPE* Shape() const override { return &m_shape; }
|
||||
const SHAPE* Shape( int aLayer ) const override
|
||||
{
|
||||
int layer = EffectiveLayer( aLayer );
|
||||
wxCHECK( m_shapes.contains( layer ), nullptr );
|
||||
return &m_shapes.at( layer );
|
||||
}
|
||||
|
||||
VIA* Clone() const override;
|
||||
|
||||
@ -212,10 +270,14 @@ public:
|
||||
virtual const std::string Format() const override;
|
||||
|
||||
private:
|
||||
int m_diameter;
|
||||
STACK_MODE m_stackMode;
|
||||
|
||||
/// May contain 1..n diameters depending on m_stackMode
|
||||
std::map<int, int> m_diameters;
|
||||
std::map<int, SHAPE_CIRCLE> m_shapes;
|
||||
|
||||
int m_drill;
|
||||
VECTOR2I m_pos;
|
||||
SHAPE_CIRCLE m_shape;
|
||||
VIATYPE m_viaType;
|
||||
bool m_isFree;
|
||||
HOLE* m_hole;
|
||||
|
@ -212,7 +212,7 @@ bool WALKAROUND::singleStep()
|
||||
std::optional<LINE> shortest;
|
||||
std::optional<LINE> shortest_alt;
|
||||
|
||||
|
||||
|
||||
if( st_cw && st_ccw )
|
||||
{
|
||||
if( !cw_coll && !ccw_coll || ( cw_coll && ccw_coll) )
|
||||
@ -232,7 +232,7 @@ bool WALKAROUND::singleStep()
|
||||
shortest = path_cw;
|
||||
else if( !ccw_coll )
|
||||
shortest = path_ccw;
|
||||
|
||||
|
||||
}
|
||||
else if( st_ccw )
|
||||
shortest = path_ccw;
|
||||
@ -245,7 +245,7 @@ bool WALKAROUND::singleStep()
|
||||
{
|
||||
for( auto& item : m_lastShortestCluster->m_items )
|
||||
{
|
||||
if( shortest->Collide( item, m_world) )
|
||||
if( shortest->Collide( item, m_world, shortest->Layer() ) )
|
||||
{
|
||||
anyColliding = true;
|
||||
break;
|
||||
@ -357,7 +357,7 @@ const WALKAROUND::RESULT WALKAROUND::Route( const LINE& aInitialPath )
|
||||
if( ln.PointCount() > 0 && ln.CPoint( -1 ) != aInitialPath.CPoint( -1 ) )
|
||||
{
|
||||
st = ST_ALMOST_DONE;
|
||||
|
||||
|
||||
}
|
||||
PNS_DBG( Dbg(), Message, wxString::Format( "stat=%d", st ) );
|
||||
|
||||
|
@ -58,10 +58,11 @@ ROUTER_PREVIEW_ITEM::ROUTER_PREVIEW_ITEM( const PNS::ITEM* aItem, PNS::ROUTER_IF
|
||||
}
|
||||
else if( aItem )
|
||||
{
|
||||
m_shape = aItem->Shape()->Clone();
|
||||
// TODO(JE) padstacks -- need to know the layer here
|
||||
m_shape = aItem->Shape( -1 )->Clone();
|
||||
|
||||
if( aItem->Hole() )
|
||||
m_hole = aItem->Hole()->Shape()->Clone();
|
||||
m_hole = aItem->Hole()->Shape( -1 )->Clone();
|
||||
}
|
||||
|
||||
m_clearance = -1;
|
||||
@ -149,6 +150,7 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS::ITEM* aItem )
|
||||
break;
|
||||
|
||||
case PNS::ITEM::VIA_T:
|
||||
{
|
||||
m_originLayer = m_layer = LAYER_VIAS;
|
||||
m_type = PR_SHAPE;
|
||||
m_width = 0;
|
||||
@ -158,16 +160,30 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS::ITEM* aItem )
|
||||
delete m_shape;
|
||||
m_shape = nullptr;
|
||||
|
||||
if( aItem->Shape() )
|
||||
m_shape = aItem->Shape()->Clone();
|
||||
auto via = static_cast<const PNS::VIA*>( aItem );
|
||||
int shapeLayer = -1;
|
||||
int largestDiameter = 0;
|
||||
|
||||
for( int layer : via->UniqueShapeLayers() )
|
||||
{
|
||||
if( via->Diameter( layer ) > largestDiameter )
|
||||
{
|
||||
largestDiameter = via->Diameter( layer );
|
||||
shapeLayer = layer;
|
||||
}
|
||||
}
|
||||
|
||||
if( aItem->Shape( shapeLayer ) )
|
||||
m_shape = aItem->Shape( shapeLayer )->Clone();
|
||||
|
||||
delete m_hole;
|
||||
m_hole = nullptr;
|
||||
|
||||
if( aItem->Hole() )
|
||||
m_hole = aItem->Hole()->Shape()->Clone();
|
||||
m_hole = aItem->Hole()->Shape( -1 )->Clone();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PNS::ITEM::SOLID_T:
|
||||
m_type = PR_SHAPE;
|
||||
|
@ -2240,9 +2240,11 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent )
|
||||
|
||||
if( itemsToDrag.Count() >= 1 )
|
||||
{
|
||||
int layer = m_iface->GetPNSLayerFromBoardLayer( m_originalActiveLayer );
|
||||
|
||||
for( PNS::ITEM* pitem : itemsToDrag.Items() )
|
||||
{
|
||||
if( pitem->Shape()->Collide( p0, 0 ) )
|
||||
if( pitem->Shape( layer )->Collide( p0, 0 ) )
|
||||
{
|
||||
p = snapToItem( pitem, p0 );
|
||||
m_startItem = pitem;
|
||||
|
1
thirdparty/rtree/geometry/rtree.h
vendored
1
thirdparty/rtree/geometry/rtree.h
vendored
@ -50,6 +50,7 @@
|
||||
|
||||
// NOTE These next few lines may be win32 specific, you may need to modify them to compile on other platform
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
Loading…
x
Reference in New Issue
Block a user