7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-20 00:21:31 +00:00

PNS: Support via stacks

This commit is contained in:
Jon Evans 2024-10-19 19:37:07 -04:00
parent be728f7800
commit d0b2334ceb
35 changed files with 507 additions and 179 deletions

View File

@ -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 );

View File

@ -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> >

View File

@ -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 );

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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 );
}

View File

@ -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() );
}
}

View File

@ -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 ) )

View File

@ -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 )

View File

@ -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;

View File

@ -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; }

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -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:

View File

@ -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()

View File

@ -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 );

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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;
};
/**

View File

@ -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 ) )

View File

@ -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 )

View File

@ -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 );
}

Some files were not shown because too many files have changed in this diff Show More