7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-19 14:11:41 +00:00

Speed up creepage

Make sure of sets where possible
Don't do checks in nested loops -- prune first
Thread when possible
Ensure we are updating the dialog as we go
Fix some coding convention issues

Fixes https://gitlab.com/kicad/code/kicad/-/issues/19488
This commit is contained in:
Seth Hillbrand 2025-01-11 13:16:19 -08:00
parent ae4ef7c062
commit 8ccf8c1138
4 changed files with 386 additions and 302 deletions

View File

@ -23,6 +23,7 @@
#include <drc/drc_creepage_utils.h>
#include <geometry/intersection.h>
#include <thread_pool.h>
extern bool segmentIntersectsArc( const VECTOR2I& p1, const VECTOR2I& p2, const VECTOR2I& center,
@ -467,7 +468,7 @@ std::vector<PATH_CONNECTION> BE_SHAPE_CIRCLE::Paths( const BE_SHAPE_CIRCLE& aS2,
}
void CreepageGraph::TransformCreepShapesToNodes( std::vector<CREEP_SHAPE*>& aShapes )
void CREEPAGE_GRAPH::TransformCreepShapesToNodes( std::vector<CREEP_SHAPE*>& aShapes )
{
for( CREEP_SHAPE* p1 : aShapes )
{
@ -476,15 +477,15 @@ void CreepageGraph::TransformCreepShapesToNodes( std::vector<CREEP_SHAPE*>& aSha
switch( p1->GetType() )
{
case CREEP_SHAPE::TYPE::POINT: AddNode( GraphNode::TYPE::POINT, p1, p1->GetPos() ); break;
case CREEP_SHAPE::TYPE::CIRCLE: AddNode( GraphNode::TYPE::CIRCLE, p1, p1->GetPos() ); break;
case CREEP_SHAPE::TYPE::ARC: AddNode( GraphNode::TYPE::ARC, p1, p1->GetPos() ); break;
case CREEP_SHAPE::TYPE::POINT: AddNode( GRAPH_NODE::TYPE::POINT, p1, p1->GetPos() ); break;
case CREEP_SHAPE::TYPE::CIRCLE: AddNode( GRAPH_NODE::TYPE::CIRCLE, p1, p1->GetPos() ); break;
case CREEP_SHAPE::TYPE::ARC: AddNode( GRAPH_NODE::TYPE::ARC, p1, p1->GetPos() ); break;
default: break;
}
}
}
void CreepageGraph::RemoveDuplicatedShapes()
void CREEPAGE_GRAPH::RemoveDuplicatedShapes()
{
// Sort the vector
sort( m_shapeCollection.begin(), m_shapeCollection.end(), compareShapes );
@ -514,7 +515,7 @@ void CreepageGraph::RemoveDuplicatedShapes()
std::swap( m_shapeCollection, newVector );
}
void CreepageGraph::TransformEdgeToCreepShapes()
void CREEPAGE_GRAPH::TransformEdgeToCreepShapes()
{
for( BOARD_ITEM* drawing : m_boardEdge )
{
@ -589,7 +590,7 @@ void CreepageGraph::TransformEdgeToCreepShapes()
}
std::vector<PCB_SHAPE> GraphConnection::GetShapes()
std::vector<PCB_SHAPE> GRAPH_CONNECTION::GetShapes()
{
std::vector<PCB_SHAPE> shapes = std::vector<PCB_SHAPE>();
int lineWidth = 0;
@ -600,12 +601,12 @@ std::vector<PCB_SHAPE> GraphConnection::GetShapes()
if( !n1 || !n2 )
return shapes;
if( n1->m_type == GraphNode::TYPE::VIRTUAL || n2->m_type == GraphNode::TYPE::VIRTUAL )
if( n1->m_type == GRAPH_NODE::TYPE::VIRTUAL || n2->m_type == GRAPH_NODE::TYPE::VIRTUAL )
{
return shapes;
}
if( !forceStraightLigne && n1->m_parent && ( n1->m_parent == n2->m_parent )
if( !m_forceStraightLine && n1->m_parent && ( n1->m_parent == n2->m_parent )
&& ( n1->m_parent->GetType() == CREEP_SHAPE::TYPE::CIRCLE ) )
{
VECTOR2I center = n1->m_parent->GetPos();
@ -633,7 +634,7 @@ std::vector<PCB_SHAPE> GraphConnection::GetShapes()
return shapes;
}
else if( !forceStraightLigne && n1->m_parent && ( n1->m_parent == n2->m_parent )
else if( !m_forceStraightLine && n1->m_parent && ( n1->m_parent == n2->m_parent )
&& n1->m_parent->GetType() == CREEP_SHAPE::TYPE::ARC )
{
BE_SHAPE_ARC* arc = dynamic_cast<BE_SHAPE_ARC*>( n1->m_parent );
@ -701,19 +702,19 @@ std::vector<PCB_SHAPE> GraphConnection::GetShapes()
return shapes;
}
void CREEP_SHAPE::ConnectChildren( std::shared_ptr<GraphNode>& a1, std::shared_ptr<GraphNode>&,
CreepageGraph& aG ) const
void CREEP_SHAPE::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>&,
CREEPAGE_GRAPH& aG ) const
{
}
void BE_SHAPE_POINT::ConnectChildren( std::shared_ptr<GraphNode>& a1, std::shared_ptr<GraphNode>&,
CreepageGraph& aG ) const
void BE_SHAPE_POINT::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>&,
CREEPAGE_GRAPH& aG ) const
{
}
void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GraphNode>& a1,
std::shared_ptr<GraphNode>& a2, CreepageGraph& aG,
void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1,
std::shared_ptr<GRAPH_NODE>& a2, CREEPAGE_GRAPH& aG,
double aNormalWeight ) const
{
EDA_ANGLE angle1 = EDA_ANGLE( a1->m_pos - m_pos );
@ -740,7 +741,7 @@ void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GraphNode>& a1,
skipPoint.y += m_radius * sin( pointAngle.AsRadians() );
std::shared_ptr<GraphNode> gnt = aG.AddNode( GraphNode::POINT, a1->m_parent, skipPoint );
std::shared_ptr<GRAPH_NODE> gnt = aG.AddNode( GRAPH_NODE::POINT, a1->m_parent, skipPoint );
PATH_CONNECTION pc;
@ -753,15 +754,15 @@ void BE_SHAPE_CIRCLE::ShortenChildDueToGV( std::shared_ptr<GraphNode>& a1,
pc.a2 = maxAngle == angle2 ? a2->m_pos : a1->m_pos;
pc.weight = aG.m_minGrooveWidth;
std::shared_ptr<GraphConnection> gc = aG.AddConnection( gnt, maxAngle == angle2 ? a2 : a1, pc );
std::shared_ptr<GRAPH_CONNECTION> gc = aG.AddConnection( gnt, maxAngle == angle2 ? a2 : a1, pc );
if( gc )
gc->forceStraightLigne = true;
gc->m_forceStraightLine = true;
return;
}
void BE_SHAPE_CIRCLE::ConnectChildren( std::shared_ptr<GraphNode>& a1,
std::shared_ptr<GraphNode>& a2, CreepageGraph& aG ) const
void BE_SHAPE_CIRCLE::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1,
std::shared_ptr<GRAPH_NODE>& a2, CREEPAGE_GRAPH& aG ) const
{
if( !a1 || !a2 )
return;
@ -797,8 +798,8 @@ void BE_SHAPE_CIRCLE::ConnectChildren( std::shared_ptr<GraphNode>& a1,
}
void BE_SHAPE_ARC::ConnectChildren( std::shared_ptr<GraphNode>& a1, std::shared_ptr<GraphNode>& a2,
CreepageGraph& aG ) const
void BE_SHAPE_ARC::ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
CREEPAGE_GRAPH& aG ) const
{
if( !a1 || !a2 )
return;
@ -828,7 +829,7 @@ void BE_SHAPE_ARC::ConnectChildren( std::shared_ptr<GraphNode>& a1, std::shared_
}
}
void CreepageGraph::SetTarget( double aTarget )
void CREEPAGE_GRAPH::SetTarget( double aTarget )
{
m_creepageTarget = aTarget;
m_creepageTargetSquared = aTarget * aTarget;
@ -2030,9 +2031,9 @@ std::vector<PATH_CONNECTION> GetPaths( CREEP_SHAPE* aS1, CREEP_SHAPE* aS2, doubl
return result;
}
double CreepageGraph::Solve(
std::shared_ptr<GraphNode>& aFrom, std::shared_ptr<GraphNode>& aTo,
std::vector<std::shared_ptr<GraphConnection>>& aResult ) // Change to vector of pointers
double CREEPAGE_GRAPH::Solve(
std::shared_ptr<GRAPH_NODE>& aFrom, std::shared_ptr<GRAPH_NODE>& aTo,
std::vector<std::shared_ptr<GRAPH_CONNECTION>>& aResult ) // Change to vector of pointers
{
if( !aFrom || !aTo )
return 0;
@ -2041,19 +2042,19 @@ double CreepageGraph::Solve(
return 0;
// Dijkstra's algorithm for shortest path
std::unordered_map<GraphNode*, double> distances;
std::unordered_map<GraphNode*, GraphNode*> previous;
std::unordered_map<GRAPH_NODE*, double> distances;
std::unordered_map<GRAPH_NODE*, GRAPH_NODE*> previous;
auto cmp = [&distances]( GraphNode* left, GraphNode* right )
auto cmp = [&distances]( GRAPH_NODE* left, GRAPH_NODE* right )
{
if( distances[left] == distances[right] )
return left > right; // Compare addresses to avoid ties.
return distances[left] > distances[right];
};
std::priority_queue<GraphNode*, std::vector<GraphNode*>, decltype( cmp )> pq( cmp );
std::priority_queue<GRAPH_NODE*, std::vector<GRAPH_NODE*>, decltype( cmp )> pq( cmp );
// Initialize distances to infinity for all nodes except the starting node
for( std::shared_ptr<GraphNode> node : m_nodes )
for( std::shared_ptr<GRAPH_NODE> node : m_nodes )
{
if( node != nullptr )
distances[node.get()] = std::numeric_limits<double>::infinity(); // Set to infinity
@ -2065,7 +2066,7 @@ double CreepageGraph::Solve(
// Dijkstra's main loop
while( !pq.empty() )
{
GraphNode* current = pq.top();
GRAPH_NODE* current = pq.top();
pq.pop();
if( current == aTo.get() )
@ -2074,9 +2075,9 @@ double CreepageGraph::Solve(
}
// Traverse neighbors
for( std::shared_ptr<GraphConnection> connection : current->m_connections )
for( std::shared_ptr<GRAPH_CONNECTION> connection : current->m_node_conns )
{
GraphNode* neighbor = ( connection->n1 ).get() == current ? ( connection->n2 ).get()
GRAPH_NODE* neighbor = ( connection->n1 ).get() == current ? ( connection->n2 ).get()
: ( connection->n1 ).get();
if( !neighbor )
@ -2103,17 +2104,18 @@ double CreepageGraph::Solve(
}
// Trace back the path from aTo to aFrom
GraphNode* step = aTo.get();
GRAPH_NODE* step = aTo.get();
while( step != aFrom.get() )
{
GraphNode* prevNode = previous[step];
for( std::shared_ptr<GraphConnection> connection : step->m_connections )
GRAPH_NODE* prevNode = previous[step];
for( std::shared_ptr<GRAPH_CONNECTION> node_conn : step->m_node_conns )
{
if( ( ( connection->n1 ).get() == prevNode && ( connection->n2 ).get() == step )
|| ( ( connection->n1 ).get() == step && ( connection->n2 ).get() == prevNode ) )
if( ( ( node_conn->n1 ).get() == prevNode && ( node_conn->n2 ).get() == step )
|| ( ( node_conn->n1 ).get() == step && ( node_conn->n2 ).get() == prevNode ) )
{
aResult.push_back( connection );
aResult.push_back( node_conn );
break;
}
}
@ -2123,7 +2125,7 @@ double CreepageGraph::Solve(
return pathWeight;
}
void CreepageGraph::Addshape( const SHAPE& aShape, std::shared_ptr<GraphNode>& aConnectTo,
void CREEPAGE_GRAPH::Addshape( const SHAPE& aShape, std::shared_ptr<GRAPH_NODE>& aConnectTo,
BOARD_ITEM* aParent )
{
CREEP_SHAPE* newshape = nullptr;
@ -2238,15 +2240,15 @@ void CreepageGraph::Addshape( const SHAPE& aShape, std::shared_ptr<GraphNode>& a
if( !newshape )
return;
std::shared_ptr<GraphNode> gnShape = nullptr;
std::shared_ptr<GRAPH_NODE> gnShape = nullptr;
newshape->SetParent( aParent );
switch( aShape.Type() )
{
case SH_SEGMENT: gnShape = AddNode( GraphNode::SEGMENT, newshape, newshape->GetPos() ); break;
case SH_CIRCLE: gnShape = AddNode( GraphNode::CIRCLE, newshape, newshape->GetPos() ); break;
case SH_ARC: gnShape = AddNode( GraphNode::ARC, newshape, newshape->GetPos() ); break;
case SH_SEGMENT: gnShape = AddNode( GRAPH_NODE::SEGMENT, newshape, newshape->GetPos() ); break;
case SH_CIRCLE: gnShape = AddNode( GRAPH_NODE::CIRCLE, newshape, newshape->GetPos() ); break;
case SH_ARC: gnShape = AddNode( GRAPH_NODE::ARC, newshape, newshape->GetPos() ); break;
default: break;
}
@ -2254,7 +2256,7 @@ void CreepageGraph::Addshape( const SHAPE& aShape, std::shared_ptr<GraphNode>& a
{
m_shapeCollection.push_back( newshape );
gnShape->m_net = aConnectTo->m_net;
std::shared_ptr<GraphConnection> gc = AddConnection( gnShape, aConnectTo );
std::shared_ptr<GRAPH_CONNECTION> gc = AddConnection( gnShape, aConnectTo );
if( gc )
gc->m_path.m_show = false;
@ -2266,113 +2268,121 @@ void CreepageGraph::Addshape( const SHAPE& aShape, std::shared_ptr<GraphNode>& a
}
}
void CreepageGraph::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer,
bool aGenerateBoardEdges )
void CREEPAGE_GRAPH::GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer, bool aClearance )
{
std::vector<std::shared_ptr<GraphNode>> nodes1 = m_nodes;
std::vector<std::shared_ptr<GraphNode>> nodes2 = m_nodes;
std::vector<std::shared_ptr<GRAPH_NODE>> nodes;
std::mutex nodes_lock;
thread_pool& tp = GetKiCadThreadPool();
std::copy_if( m_nodes.begin(), m_nodes.end(), std::back_inserter( nodes ),
[&]( std::shared_ptr<GRAPH_NODE> gn )
{
return !!gn && gn->m_parent && gn->m_connectDirectly
&& ( gn->m_type != GRAPH_NODE::TYPE::VIRTUAL );
} );
for( std::shared_ptr<GraphNode> gn1 : nodes1 )
auto processNodes = [&]( size_t i, size_t j ) -> bool
{
nodes2.erase( nodes2.begin() );
if( !gn1 )
continue;
if( !gn1->m_parent )
continue;
if( !gn1->m_connectDirectly )
continue;
if( gn1->m_type == GraphNode::TYPE::VIRTUAL )
continue;
for( std::shared_ptr<GraphNode> gn2 : nodes2 )
{
if( !gn2 )
continue;
if( !gn2->m_parent )
continue;
if( gn1->m_parent == gn2->m_parent )
continue;
if( !gn2->m_connectDirectly )
continue;
if( gn2->m_type == GraphNode::TYPE::VIRTUAL )
continue;
if( !aGenerateBoardEdges && !gn1->m_parent->IsConductive()
&& !gn2->m_parent->IsConductive() )
continue;
if( ( gn1->m_net == gn2->m_net ) && ( gn1->m_parent->IsConductive() )
&& ( gn2->m_parent->IsConductive() ) )
continue;
for( PATH_CONNECTION pc : GetPaths( gn1->m_parent, gn2->m_parent, aMaxWeight ) )
for( size_t ii = i; ii < j; ii++ )
{
std::vector<const BOARD_ITEM*> IgnoreForTest;
IgnoreForTest.push_back( gn1->m_parent->GetParent() );
IgnoreForTest.push_back( gn2->m_parent->GetParent() );
std::shared_ptr<GRAPH_NODE> gn1 = nodes[ii];
if( !pc.isValid( m_board, aLayer, m_boardEdge, IgnoreForTest, m_boardOutline,
{ false, true }, m_minGrooveWidth ) )
continue;
std::shared_ptr<GraphNode>* connect1 = &gn1;
std::shared_ptr<GraphNode>* connect2 = &gn2;
std::shared_ptr<GraphNode> gnt1 = nullptr;
std::shared_ptr<GraphNode> gnt2 = nullptr;
if ( gn1->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT )
for( size_t jj = ii + 1; jj < nodes.size(); jj++ )
{
gnt1 = AddNode( GraphNode::POINT, gn1->m_parent, pc.a1 );
gnt1->m_connectDirectly = false;
std::shared_ptr<GRAPH_NODE> gn2 = nodes[jj];
if( gn1->m_parent->IsConductive() )
if( gn1->m_parent->GetParent() == gn2->m_parent->GetParent() )
continue;
if( ( gn1->m_net == gn2->m_net ) && ( gn1->m_parent->IsConductive() )
&& ( gn2->m_parent->IsConductive() ) )
continue;
for( PATH_CONNECTION pc : GetPaths( gn1->m_parent, gn2->m_parent, aMaxWeight ) )
{
std::shared_ptr<GraphConnection> gc = AddConnection( gn1, gnt1 );
std::vector<const BOARD_ITEM*> IgnoreForTest;
IgnoreForTest.push_back( gn1->m_parent->GetParent() );
IgnoreForTest.push_back( gn2->m_parent->GetParent() );
if( gc )
gc->m_path.m_show = false;
if( !pc.isValid( m_board, aLayer, m_boardEdge, IgnoreForTest, m_boardOutline,
{ false, true }, m_minGrooveWidth ) )
continue;
std::shared_ptr<GRAPH_NODE>* connect1 = &gn1;
std::shared_ptr<GRAPH_NODE>* connect2 = &gn2;
std::shared_ptr<GRAPH_NODE> gnt1 = nullptr;
std::shared_ptr<GRAPH_NODE> gnt2 = nullptr;
std::lock_guard<std::mutex> lock( nodes_lock );
if( gn1->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT )
{
gnt1 = AddNode( GRAPH_NODE::POINT, gn1->m_parent, pc.a1 );
gnt1->m_connectDirectly = false;
if( gn1->m_parent->IsConductive() )
{
std::shared_ptr<GRAPH_CONNECTION> gc = AddConnection( gn1, gnt1 );
if( gc )
gc->m_path.m_show = false;
}
connect1 = &gnt1;
}
if( gn2->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT )
{
gnt2 = AddNode( GRAPH_NODE::POINT, gn2->m_parent, pc.a2 );
gnt2->m_connectDirectly = false;
if( gn2->m_parent->IsConductive() )
{
std::shared_ptr<GRAPH_CONNECTION> gc = AddConnection( gn2, gnt2 );
if( gc )
gc->m_path.m_show = false;
}
connect2 = &gnt2;
}
AddConnection( *connect1, *connect2, pc );
}
connect1 = &gnt1;
}
} // for jj
} // for ii
if( gn2->m_parent->GetType() != CREEP_SHAPE::TYPE::POINT )
return true;
};
// Running in the clearance test, we are already in a parallelized loop, so parallelizing again
// will run into deadlock as all threads start waiting
if( aClearance )
processNodes( 0, nodes.size() );
else
{
auto ret = tp.parallelize_loop( nodes.size(), processNodes );
for( size_t ii = 0; ii < ret.size(); ii++ )
{
std::future<bool>& r = ret[ii];
if( r.valid() )
{
std::future_status status = r.wait_for( std::chrono::seconds( 0 ) );
while( status != std::future_status::ready )
{
gnt2 = AddNode( GraphNode::POINT, gn2->m_parent, pc.a2 );
gnt2->m_connectDirectly = false;
if( gn2->m_parent->IsConductive() )
{
std::shared_ptr<GraphConnection> gc = AddConnection( gn2, gnt2 );
if( gc )
gc->m_path.m_show = false;
}
connect2 = &gnt2;
status = r.wait_for( std::chrono::milliseconds( 100 ) );
}
AddConnection( *connect1, *connect2, pc );
}
}
}
}
void CreepageGraph::Trim( double aWeightLimit )
void CREEPAGE_GRAPH::Trim( double aWeightLimit )
{
std::vector<std::shared_ptr<GraphConnection>> toRemove;
std::vector<std::shared_ptr<GRAPH_CONNECTION>> toRemove;
// Collect connections to remove
for( std::shared_ptr<GraphConnection>& gc : m_connections )
for( std::shared_ptr<GRAPH_CONNECTION>& gc : m_connections )
{
if( gc && ( gc->m_path.weight > aWeightLimit ) )
{
@ -2381,35 +2391,35 @@ void CreepageGraph::Trim( double aWeightLimit )
}
// Remove collected connections
for( const std::shared_ptr<GraphConnection>& gc : toRemove )
for( const std::shared_ptr<GRAPH_CONNECTION>& gc : toRemove )
{
RemoveConnection( gc );
}
}
void CreepageGraph::RemoveConnection( std::shared_ptr<GraphConnection> aGc, bool aDelete )
void CREEPAGE_GRAPH::RemoveConnection( std::shared_ptr<GRAPH_CONNECTION> aGc, bool aDelete )
{
if( !aGc )
return;
for( std::shared_ptr<GraphNode> gn : { aGc->n1, aGc->n2 } )
for( std::shared_ptr<GRAPH_NODE> gn : { aGc->n1, aGc->n2 } )
{
if( gn )
{
auto& nConns = gn->m_connections;
nConns.erase( std::remove( nConns.begin(), nConns.end(), aGc ), nConns.end() );
gn->m_node_conns.erase( aGc );
if( nConns.empty() && aDelete )
if( gn->m_node_conns.empty() && aDelete )
{
auto it = std::find_if( m_nodes.begin(), m_nodes.end(),
[&gn]( const std::shared_ptr<GraphNode> node )
[&gn]( const std::shared_ptr<GRAPH_NODE> node )
{
return node.get() == gn.get();
} );
if( it != m_nodes.end() )
{
m_nodes.erase( it );
}
m_nodeset.erase( gn );
}
}
}
@ -2423,30 +2433,32 @@ void CreepageGraph::RemoveConnection( std::shared_ptr<GraphConnection> aGc, bool
}
std::shared_ptr<GraphNode> CreepageGraph::AddNode( GraphNode::TYPE aType, CREEP_SHAPE* parent,
std::shared_ptr<GRAPH_NODE> CREEPAGE_GRAPH::AddNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* parent,
VECTOR2I pos )
{
std::shared_ptr<GraphNode> gn = FindNode( aType, parent, pos );
std::shared_ptr<GRAPH_NODE> gn = FindNode( aType, parent, pos );
if( gn )
return gn;
gn = std::make_shared<GraphNode>( aType, parent, pos );
gn = std::make_shared<GRAPH_NODE>( aType, parent, pos );
m_nodes.push_back( gn );
m_nodeset.insert( gn );
return gn;
}
std::shared_ptr<GraphNode> CreepageGraph::AddNodeVirtual()
std::shared_ptr<GRAPH_NODE> CREEPAGE_GRAPH::AddNodeVirtual()
{
//Virtual nodes are always unique, do not try to find them
std::shared_ptr<GraphNode> gn =
std::make_shared<GraphNode>( GraphNode::TYPE::VIRTUAL, nullptr );
std::shared_ptr<GRAPH_NODE> gn =
std::make_shared<GRAPH_NODE>( GRAPH_NODE::TYPE::VIRTUAL, nullptr );
m_nodes.push_back( gn );
m_nodeset.insert( gn );
return gn;
}
std::shared_ptr<GraphConnection> CreepageGraph::AddConnection( std::shared_ptr<GraphNode>& aN1,
std::shared_ptr<GraphNode>& aN2,
std::shared_ptr<GRAPH_CONNECTION> CREEPAGE_GRAPH::AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
std::shared_ptr<GRAPH_NODE>& aN2,
const PATH_CONNECTION& aPc )
{
if( !aN1 || !aN2 )
@ -2454,16 +2466,16 @@ std::shared_ptr<GraphConnection> CreepageGraph::AddConnection( std::shared_ptr<G
wxASSERT_MSG( ( aN1 != aN2 ), "Creepage: a connection connects a node to itself" );
std::shared_ptr<GraphConnection> gc = std::make_shared<GraphConnection>( aN1, aN2, aPc );
std::shared_ptr<GRAPH_CONNECTION> gc = std::make_shared<GRAPH_CONNECTION>( aN1, aN2, aPc );
m_connections.push_back( gc );
aN1->m_connections.push_back( gc );
aN2->m_connections.push_back( gc );
aN1->m_node_conns.insert( gc );
aN2->m_node_conns.insert( gc );
return gc;
}
std::shared_ptr<GraphConnection> CreepageGraph::AddConnection( std::shared_ptr<GraphNode>& aN1,
std::shared_ptr<GraphNode>& aN2 )
std::shared_ptr<GRAPH_CONNECTION> CREEPAGE_GRAPH::AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
std::shared_ptr<GRAPH_NODE>& aN2 )
{
if( !aN1 || !aN2 )
return nullptr;
@ -2476,24 +2488,22 @@ std::shared_ptr<GraphConnection> CreepageGraph::AddConnection( std::shared_ptr<G
return AddConnection( aN1, aN2, pc );
}
std::shared_ptr<GraphNode> CreepageGraph::FindNode( GraphNode::TYPE aType, CREEP_SHAPE* aParent,
std::shared_ptr<GRAPH_NODE> CREEPAGE_GRAPH::FindNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent,
VECTOR2I aPos )
{
for( std::shared_ptr<GraphNode> gn : m_nodes )
{
if( aPos == gn->m_pos && aParent == gn->m_parent && aType == gn->m_type )
{
return gn;
}
}
auto it = m_nodeset.find( std::make_shared<GRAPH_NODE>( aType, aParent, aPos ) );
if( it != m_nodeset.end() )
return *it;
return nullptr;
}
std::shared_ptr<GraphNode> CreepageGraph::AddNetElements( int aNetCode, PCB_LAYER_ID aLayer,
std::shared_ptr<GRAPH_NODE> CREEPAGE_GRAPH::AddNetElements( int aNetCode, PCB_LAYER_ID aLayer,
int aMaxCreepage )
{
std::shared_ptr<GraphNode> virtualNode = AddNodeVirtual();
std::shared_ptr<GRAPH_NODE> virtualNode = AddNodeVirtual();
virtualNode->m_net = aNetCode;
for( FOOTPRINT* footprint : m_board.Footprints() )

View File

@ -1,4 +1,3 @@
/*
* Copyright The KiCad Developers.
* Copyright (C) 2024 Fabien Corona f.corona<at>laposte.net
@ -25,6 +24,8 @@
#ifndef _DRC_CREEPAGE_UTILS_H
#define _DRC_CREEPAGE_UTILS_H
#include <unordered_set>
#include <common.h>
#include <macros.h>
#include <board_design_settings.h>
@ -141,9 +142,9 @@ struct PATH_CONNECTION
};
class GraphConnection;
class GraphNode;
class CreepageGraph;
class GRAPH_CONNECTION;
class GRAPH_NODE;
class CREEPAGE_GRAPH;
class CREEP_SHAPE;
class BE_SHAPE;
class BE_SHAPE_POINT;
@ -168,7 +169,14 @@ public:
CIRCLE,
ARC
};
CREEP_SHAPE() {};
CREEP_SHAPE()
{
m_conductive = false;
m_parent = nullptr;
m_pos = VECTOR2I( 0, 0 );
m_type = CREEP_SHAPE::TYPE::UNDEFINED;
};
virtual ~CREEP_SHAPE() {}
@ -183,8 +191,8 @@ public:
const BOARD_ITEM* GetParent() const { return m_parent; };
void SetParent( BOARD_ITEM* aParent ) { m_parent = aParent; };
virtual void ConnectChildren( std::shared_ptr<GraphNode>& a1, std::shared_ptr<GraphNode>& a2,
CreepageGraph& aG ) const;
virtual void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
CREEPAGE_GRAPH& aG ) const;
std::vector<PATH_CONNECTION> ReversePaths( const std::vector<PATH_CONNECTION>& aV ) const
{
@ -206,36 +214,42 @@ public:
std::vector<PATH_CONNECTION> a;
return a;
};
virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
std::vector<PATH_CONNECTION> a;
return a;
};
virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
std::vector<PATH_CONNECTION> a;
return a;
};
virtual std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
std::vector<PATH_CONNECTION> a;
return a;
};
virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
std::vector<PATH_CONNECTION> a;
return a;
};
virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
std::vector<PATH_CONNECTION> a;
return a;
};
virtual std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const
{
@ -248,10 +262,10 @@ public:
protected:
bool m_conductive = false;
BOARD_ITEM* m_parent = nullptr;
VECTOR2I m_pos = VECTOR2I( 0, 0 );
CREEP_SHAPE::TYPE m_type = CREEP_SHAPE::TYPE::UNDEFINED;
bool m_conductive;
BOARD_ITEM* m_parent;
VECTOR2I m_pos;
CREEP_SHAPE::TYPE m_type;
};
@ -346,7 +360,7 @@ public:
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
private:
protected:
VECTOR2I m_pos = VECTOR2I( 0, 0 );
double m_radius = 1;
};
@ -359,33 +373,36 @@ class CU_SHAPE_ARC : public CU_SHAPE_CIRCLE
{
public:
CU_SHAPE_ARC( VECTOR2I aPos, double aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
VECTOR2D aStartPoint, VECTOR2D aEndPoint ) : CU_SHAPE_CIRCLE( aPos, aRadius )
VECTOR2D aStartPoint, VECTOR2D aEndPoint ) :
CU_SHAPE_CIRCLE( aPos, aRadius ),
m_startAngle( aStartAngle ), m_endAngle( aEndAngle ),
m_startPoint( aStartPoint ), m_endPoint( aEndPoint )
{
m_pos = aPos;
m_type = CREEP_SHAPE::TYPE::ARC;
m_startAngle = aStartAngle;
m_endAngle = aEndAngle;
m_startPoint = aStartPoint;
m_endPoint = aEndPoint;
m_radius = aRadius;
m_width = 0;
}
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override
{
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
};
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override
{
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
};
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
@ -397,34 +414,36 @@ public:
VECTOR2I GetStartPoint() const override { return m_startPoint; }
VECTOR2I GetEndPoint() const override { return m_endPoint; }
EDA_ANGLE AngleBetweenStartAndEnd( const VECTOR2I aPoint ) const
{
EDA_ANGLE angle( aPoint - m_pos );
while( angle < GetStartAngle() )
angle += ANGLE_360;
while( angle > GetEndAngle() + ANGLE_360 )
angle -= ANGLE_360;
return angle;
}
double GetWidth() const { return m_width; };
void SetWidth( double aW ) { m_width = aW; };
private:
int m_width = 0;
VECTOR2I m_pos = VECTOR2I( 0, 0 );
double m_radius = 1;
EDA_ANGLE m_startAngle = EDA_ANGLE( 0 );
EDA_ANGLE m_endAngle = EDA_ANGLE( 180 );
VECTOR2I m_startPoint = VECTOR2I( 1, 0 );
VECTOR2I m_endPoint = VECTOR2I( -1, 0 );
int m_width;
EDA_ANGLE m_startAngle;
EDA_ANGLE m_endAngle;
VECTOR2I m_startPoint;
VECTOR2I m_endPoint;
};
/** @class Graphnode
*
* @brief a node in a @class CreepageGraph
*/
class GraphNode
class GRAPH_NODE
{
public:
enum TYPE
@ -437,48 +456,50 @@ public:
VIRTUAL
};
GraphNode( GraphNode::TYPE aType, CREEP_SHAPE* aParent, VECTOR2I aPos = VECTOR2I() )
GRAPH_NODE( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent, VECTOR2I aPos = VECTOR2I() )
: m_parent( aParent ), m_pos( aPos ), m_type( aType )
{
m_parent = aParent;
m_pos = aPos;
m_type = aType;
m_node_conns = {};
m_virtual = false;
m_connectDirectly = true;
m_connections = {};
m_net = -1;
};
~GraphNode() {};
~GRAPH_NODE() {};
CREEP_SHAPE* m_parent = nullptr;
std::vector<std::shared_ptr<GraphConnection>> m_connections = {};
VECTOR2I m_pos = VECTOR2I( 0, 0 );
CREEP_SHAPE* m_parent;
std::set<std::shared_ptr<GRAPH_CONNECTION>> m_node_conns;
VECTOR2I m_pos;
// Virtual nodes are connected with a 0 weight connection to equivalent net ( same net or netclass )
bool m_virtual = false;
bool m_connectDirectly = true;
int m_net = -1;
bool m_virtual ;
bool m_connectDirectly;
int m_net;
GraphNode::TYPE m_type;
GRAPH_NODE::TYPE m_type;
};
/** @class GraphConnection
*
* @brief a connection in a @class CreepageGraph
*/
class GraphConnection
class GRAPH_CONNECTION
{
public:
GraphConnection( std::shared_ptr<GraphNode>& aN1, std::shared_ptr<GraphNode>& aN2,
const PATH_CONNECTION& aPc ) : n1( aN1 ), n2( aN2 )
GRAPH_CONNECTION( std::shared_ptr<GRAPH_NODE>& aN1, std::shared_ptr<GRAPH_NODE>& aN2,
const PATH_CONNECTION& aPc ) : n1( aN1 ), n2( aN2 )
{
m_path = aPc;
m_forceStraightLine = false;
};
std::shared_ptr<GraphNode> n1 = nullptr;
std::shared_ptr<GraphNode> n2 = nullptr;
PATH_CONNECTION m_path;
std::vector<PCB_SHAPE> GetShapes();
bool forceStraightLigne = false;
std::shared_ptr<GRAPH_NODE> n1;
std::shared_ptr<GRAPH_NODE> n2;
PATH_CONNECTION m_path;
bool m_forceStraightLine;
};
@ -497,20 +518,25 @@ public:
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override
{
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
};
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override
{
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
}
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override
{
@ -518,8 +544,8 @@ public:
};
void ConnectChildren( std::shared_ptr<GraphNode>& a1, std::shared_ptr<GraphNode>& a2,
CreepageGraph& aG ) const override;
void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
CREEPAGE_GRAPH& aG ) const override;
};
/** @class BE_SHAPE_CIRCLE
@ -541,15 +567,19 @@ public:
{
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
};
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_ARC& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override;
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_SEGMENT& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override
{
return ReversePaths( aS2.Paths( *this, aMaxWeight, aMaxSquaredWeight ) );
};
std::vector<PATH_CONNECTION> Paths( const CU_SHAPE_CIRCLE& aS2, double aMaxWeight,
double aMaxSquaredWeight ) const override
{
@ -558,10 +588,12 @@ public:
int GetRadius() const override { return m_radius; }
void ConnectChildren( std::shared_ptr<GraphNode>& a1, std::shared_ptr<GraphNode>& a2,
CreepageGraph& aG ) const override;
void ShortenChildDueToGV( std::shared_ptr<GraphNode>& a1, std::shared_ptr<GraphNode>& a2,
CreepageGraph& aG, double aNormalWeight ) const;
void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
CREEPAGE_GRAPH& aG ) const override;
void ShortenChildDueToGV( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
CREEPAGE_GRAPH& aG, double aNormalWeight ) const;
protected:
@ -576,18 +608,16 @@ class BE_SHAPE_ARC : public BE_SHAPE_CIRCLE
{
public:
BE_SHAPE_ARC( VECTOR2I aPos, int aRadius, EDA_ANGLE aStartAngle, EDA_ANGLE aEndAngle,
VECTOR2D aStartPoint, VECTOR2D aEndPoint ) : BE_SHAPE_CIRCLE( aPos, aRadius )
VECTOR2D aStartPoint, VECTOR2D aEndPoint ) :
BE_SHAPE_CIRCLE( aPos, aRadius ),
m_startAngle( aStartAngle ), m_endAngle( aEndAngle ),
m_startPoint( aStartPoint ), m_endPoint( aEndPoint )
{
m_type = CREEP_SHAPE::TYPE::ARC;
m_startAngle = aStartAngle;
m_endAngle = aEndAngle;
m_startPoint = aStartPoint;
m_endPoint = aEndPoint;
m_radius = aRadius;
}
void ConnectChildren( std::shared_ptr<GraphNode>& a1, std::shared_ptr<GraphNode>& a2,
CreepageGraph& aG ) const override;
void ConnectChildren( std::shared_ptr<GRAPH_NODE>& a1, std::shared_ptr<GRAPH_NODE>& a2,
CREEPAGE_GRAPH& aG ) const override;
std::vector<PATH_CONNECTION> Paths( const BE_SHAPE_POINT& aS2, double aMaxWeight,
@ -642,7 +672,6 @@ public:
std::pair<bool, bool> IsThereATangentPassingThroughPoint( const BE_SHAPE_POINT aPoint ) const;
protected:
int m_radius;
EDA_ANGLE m_startAngle;
EDA_ANGLE m_endAngle;
VECTOR2I m_startPoint;
@ -654,16 +683,18 @@ protected:
*
* @brief A graph with nodes and connections for creepage calculation
*/
class CreepageGraph
class CREEPAGE_GRAPH
{
public:
CreepageGraph( BOARD& aBoard ) : m_board( aBoard )
CREEPAGE_GRAPH( BOARD& aBoard ) : m_board( aBoard )
{
m_boardOutline = nullptr;
m_minGrooveWidth = 0;
m_creepageTarget = -1;
m_creepageTargetSquared = -1;
};
~CreepageGraph()
~CREEPAGE_GRAPH()
{
for( CREEP_SHAPE* cs : m_shapeCollection )
if( cs )
@ -673,46 +704,73 @@ public:
}
};
BOARD& m_board;
std::vector<BOARD_ITEM*> m_boardEdge;
SHAPE_POLY_SET* m_boardOutline;
std::vector<std::shared_ptr<GraphNode>> m_nodes;
std::vector<std::shared_ptr<GraphConnection>> m_connections;
void TransformEdgeToCreepShapes();
void TransformCreepShapesToNodes( std::vector<CREEP_SHAPE*>& aShapes );
void TransformCreepShapesToNodes(std::vector<CREEP_SHAPE*>& aShapes);
void RemoveDuplicatedShapes();
// Add a node to the graph. If an equivalent node exists, returns the pointer of the existing node instead
std::shared_ptr<GraphNode> AddNode( GraphNode::TYPE aType, CREEP_SHAPE* aParent = nullptr,
std::shared_ptr<GRAPH_NODE> AddNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent = nullptr,
VECTOR2I aPos = VECTOR2I() );
std::shared_ptr<GraphNode> AddNodeVirtual();
std::shared_ptr<GraphConnection> AddConnection( std::shared_ptr<GraphNode>& aN1,
std::shared_ptr<GraphNode>& aN2,
std::shared_ptr<GRAPH_NODE> AddNodeVirtual();
std::shared_ptr<GRAPH_CONNECTION> AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
std::shared_ptr<GRAPH_NODE>& aN2,
const PATH_CONNECTION& aPc );
std::shared_ptr<GraphConnection> AddConnection( std::shared_ptr<GraphNode>& aN1,
std::shared_ptr<GraphNode>& aN2 );
std::shared_ptr<GraphNode> FindNode( GraphNode::TYPE aType, CREEP_SHAPE* aParent,
std::shared_ptr<GRAPH_CONNECTION> AddConnection( std::shared_ptr<GRAPH_NODE>& aN1,
std::shared_ptr<GRAPH_NODE>& aN2 );
std::shared_ptr<GRAPH_NODE> FindNode( GRAPH_NODE::TYPE aType, CREEP_SHAPE* aParent,
VECTOR2I aPos );
void RemoveConnection( std::shared_ptr<GraphConnection>, bool aDelete = false );
void RemoveConnection( std::shared_ptr<GRAPH_CONNECTION>, bool aDelete = false );
void Trim( double aWeightLimit );
void Addshape( const SHAPE& aShape, std::shared_ptr<GraphNode>& aConnectTo,
void Addshape( const SHAPE& aShape, std::shared_ptr<GRAPH_NODE>& aConnectTo,
BOARD_ITEM* aParent = nullptr );
double Solve( std::shared_ptr<GraphNode>& aFrom, std::shared_ptr<GraphNode>& aTo,
std::vector<std::shared_ptr<GraphConnection>>& aResult );
double Solve( std::shared_ptr<GRAPH_NODE>& aFrom, std::shared_ptr<GRAPH_NODE>& aTo,
std::vector<std::shared_ptr<GRAPH_CONNECTION>>& aResult );
void GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer, bool aGenerateBoardEdges = true );
std::shared_ptr<GraphNode> AddNetElements( int aNetCode, PCB_LAYER_ID aLayer,
void GeneratePaths( double aMaxWeight, PCB_LAYER_ID aLayer, bool aClearance );
std::shared_ptr<GRAPH_NODE> AddNetElements( int aNetCode, PCB_LAYER_ID aLayer,
int aMaxCreepage );
void SetTarget( double aTarget );
double GetTarget() { return m_creepageTarget; };
int m_minGrooveWidth = 0;
std::vector<CREEP_SHAPE*> m_shapeCollection;
struct GraphNodeHash
{
std::size_t operator()(const std::shared_ptr<GRAPH_NODE>& node) const
{
return hash_val(node->m_type, node->m_parent, node->m_pos.x, node->m_pos.y);
}
};
struct GraphNodeEqual
{
bool operator()(const std::shared_ptr<GRAPH_NODE>& lhs, const std::shared_ptr<GRAPH_NODE>& rhs) const
{
return lhs->m_type == rhs->m_type && lhs->m_parent == rhs->m_parent && lhs->m_pos == rhs->m_pos;
}
};
BOARD& m_board;
std::vector<BOARD_ITEM*> m_boardEdge;
SHAPE_POLY_SET* m_boardOutline;
std::vector<std::shared_ptr<GRAPH_NODE>> m_nodes;
std::vector<std::shared_ptr<GRAPH_CONNECTION>> m_connections;
std::vector<CREEP_SHAPE*> m_shapeCollection;
// This is a duplicate of m_nodes, but it is used to quickly find a node rather than iterating through m_nodes
std::unordered_set<std::shared_ptr<GRAPH_NODE>, GraphNodeHash, GraphNodeEqual> m_nodeset;
int m_minGrooveWidth;
private:
double m_creepageTarget;

View File

@ -92,9 +92,9 @@ void DRC_TEST_PROVIDER_CLEARANCE_BASE::ReportAndShowPathCuToCu(
std::shared_ptr<DRC_ITEM>& aDrce, const VECTOR2I& aMarkerPos, int aMarkerLayer,
const BOARD_ITEM* aItem1, const BOARD_ITEM* aItem2, PCB_LAYER_ID layer, int aDistance )
{
CreepageGraph graph( *m_board );
std::shared_ptr<GraphNode> NetA = graph.AddNodeVirtual();
std::shared_ptr<GraphNode> NetB = graph.AddNodeVirtual();
CREEPAGE_GRAPH graph( *m_board );
std::shared_ptr<GRAPH_NODE> NetA = graph.AddNodeVirtual();
std::shared_ptr<GRAPH_NODE> NetB = graph.AddNodeVirtual();
// They need to be different or the algorithm won't compute the path.
NetA->m_net = 1;
@ -103,12 +103,12 @@ void DRC_TEST_PROVIDER_CLEARANCE_BASE::ReportAndShowPathCuToCu(
graph.Addshape( *( aItem1->GetEffectiveShape( layer ) ), NetA, nullptr );
graph.Addshape( *( aItem2->GetEffectiveShape( layer ) ), NetB, nullptr );
graph.GeneratePaths( aDistance * 2, layer );
graph.GeneratePaths( aDistance * 2, layer, true );
double minValue = aDistance * 2;
GraphConnection* minGc = nullptr;
GRAPH_CONNECTION* minGc = nullptr;
for( std::shared_ptr<GraphConnection> gc : graph.m_connections )
for( std::shared_ptr<GRAPH_CONNECTION> gc : graph.m_connections )
{
if( ( gc->m_path.weight < minValue ) && ( gc->m_path.weight > 0 ) )
{
@ -119,7 +119,7 @@ void DRC_TEST_PROVIDER_CLEARANCE_BASE::ReportAndShowPathCuToCu(
if( minGc )
{
PATH_CONNECTION pc = minGc->m_path;
PATH_CONNECTION pc = minGc->m_path;
DRC_CUSTOM_MARKER_HANDLER handler =
GetGraphicsHandler( minGc->GetShapes(), pc.a1, pc.a2, aDistance );
reportViolation( aDrce, aMarkerPos, aMarkerLayer, &handler );

View File

@ -64,10 +64,12 @@ public:
private:
int testCreepage();
int testCreepage( CreepageGraph& aGraph, int aNetCodeA, int aNetCodeB, PCB_LAYER_ID aLayer );
int testCreepage( CREEPAGE_GRAPH& aGraph, int aNetCodeA, int aNetCodeB, PCB_LAYER_ID aLayer );
void CollectBoardEdges( std::vector<BOARD_ITEM*>& aVector );
void CollectNetCodes( std::vector<int>& aVector );
std::set<std::pair<const BOARD_ITEM*, const BOARD_ITEM*>> m_reportedPairs;
};
@ -75,8 +77,6 @@ bool DRC_TEST_PROVIDER_CREEPAGE::Run()
{
m_board = m_drcEngine->GetBoard();
//int errorMax = m_board->GetDesignSettings().m_MaxError;
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_CREEPAGE ) )
{
if( !reportPhase( _( "Checking creepage..." ) ) )
@ -88,13 +88,13 @@ bool DRC_TEST_PROVIDER_CREEPAGE::Run()
}
std::shared_ptr<GraphNode> FindInGraphNodes( std::shared_ptr<GraphNode> aNode,
std::vector<std::shared_ptr<GraphNode>>& aGraph )
std::shared_ptr<GRAPH_NODE> FindInGraphNodes( std::shared_ptr<GRAPH_NODE> aNode,
std::vector<std::shared_ptr<GRAPH_NODE>>& aGraph )
{
if( !aNode )
return nullptr;
for( std::shared_ptr<GraphNode> gn : aGraph )
for( std::shared_ptr<GRAPH_NODE> gn : aGraph )
{
if( aNode->m_pos == gn->m_pos )
{
@ -105,7 +105,7 @@ std::shared_ptr<GraphNode> FindInGraphNodes( std::shared_ptr<GraphNode>
}
int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CreepageGraph& aGraph, int aNetCodeA, int aNetCodeB,
int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CREEPAGE_GRAPH& aGraph, int aNetCodeA, int aNetCodeB,
PCB_LAYER_ID aLayer )
{
PCB_TRACK bci1( m_board );
@ -134,17 +134,23 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CreepageGraph& aGraph, int aNetCod
if ( netA->GetBoundingBox().Distance( netB->GetBoundingBox() ) > creepageValue )
return 0;
std::shared_ptr<GraphNode> NetA = aGraph.AddNetElements( aNetCodeA, aLayer, creepageValue );
std::shared_ptr<GraphNode> NetB = aGraph.AddNetElements( aNetCodeB, aLayer, creepageValue );
std::shared_ptr<GRAPH_NODE> NetA = aGraph.AddNetElements( aNetCodeA, aLayer, creepageValue );
std::shared_ptr<GRAPH_NODE> NetB = aGraph.AddNetElements( aNetCodeB, aLayer, creepageValue );
aGraph.GeneratePaths( creepageValue, aLayer );
aGraph.GeneratePaths( creepageValue, aLayer, false );
std::vector<std::shared_ptr<GraphNode>> nodes1 = aGraph.m_nodes;
std::vector<std::shared_ptr<GraphNode>> nodes2 = aGraph.m_nodes;
std::vector<std::shared_ptr<GRAPH_NODE>> temp_nodes;
alg::for_all_pairs( aGraph.m_nodes.begin(), aGraph.m_nodes.end(),
[&]( std::shared_ptr<GraphNode> aN1, std::shared_ptr<GraphNode> aN2 )
std::copy_if( aGraph.m_nodes.begin(), aGraph.m_nodes.end(), std::back_inserter( temp_nodes ),
[]( std::shared_ptr<GRAPH_NODE> aNode )
{
return !!aNode && aNode->m_parent && aNode->m_parent->IsConductive()
&& aNode->m_connectDirectly && aNode->m_type == GRAPH_NODE::POINT;
} );
alg::for_all_pairs( temp_nodes.begin(), temp_nodes.end(),
[&]( std::shared_ptr<GRAPH_NODE> aN1, std::shared_ptr<GRAPH_NODE> aN2 )
{
if( aN1 == aN2 )
return;
@ -167,21 +173,20 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CreepageGraph& aGraph, int aNetCod
// We are only looking for points on circles and arcs
if( aN1->m_type != GraphNode::POINT )
if( aN1->m_type != GRAPH_NODE::POINT )
return;
if( aN2->m_type != GraphNode::POINT )
if( aN2->m_type != GRAPH_NODE::POINT )
return;
aN1->m_parent->ConnectChildren( aN1, aN2, aGraph );
} );
std::vector<std::shared_ptr<GraphConnection>> shortestPath;
std::vector<std::shared_ptr<GRAPH_CONNECTION>> shortestPath;
shortestPath.clear();
double distance = aGraph.Solve( NetA, NetB, shortestPath );
if( ( shortestPath.size() > 0 ) && ( distance - creepageValue < 0 ) )
if( !shortestPath.empty() && ( shortestPath.size() >= 4 ) && ( distance - creepageValue < 0 ) )
{
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_CREEPAGE );
wxString msg = formatMsg( _( "(%s creepage %s; actual %s)" ), constraint.GetName(),
@ -189,22 +194,27 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CreepageGraph& aGraph, int aNetCod
drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
drce->SetViolatingRule( constraint.GetParentRule() );
if( shortestPath.size() >= 4 && shortestPath[1]->n1 && shortestPath[1]->n2 )
drce->SetItems( shortestPath[1]->n1->m_parent->GetParent(),
shortestPath[shortestPath.size() - 2]->n2->m_parent->GetParent() );
std::shared_ptr<GRAPH_CONNECTION> gc1 = shortestPath[1];
std::shared_ptr<GRAPH_CONNECTION> gc2 = shortestPath[shortestPath.size() - 2];
if( gc1->n1 && gc2->n2 )
{
const BOARD_ITEM* item1 = gc1->n1->m_parent->GetParent();
const BOARD_ITEM* item2 = gc2->n2->m_parent->GetParent();
if( m_reportedPairs.insert( std::make_pair( item1, item2 ) ).second )
drce->SetItems( item1, item2 );
else
return 1;
}
std::vector<PCB_SHAPE> shortestPathShapes1, shortestPathShapes2;
VECTOR2I startPoint = shortestPath[1]->m_path.a2;
VECTOR2I endPoint = shortestPath[shortestPath.size() - 2]->m_path.a2;
PCB_SHAPE s;
s.SetStart( startPoint );
s.SetEnd( endPoint );
VECTOR2I startPoint = gc1->m_path.a2;
VECTOR2I endPoint = gc2->m_path.a2;
std::vector<PCB_SHAPE> path;
for( std::shared_ptr<GraphConnection> gc : shortestPath )
for( std::shared_ptr<GRAPH_CONNECTION> gc : shortestPath )
{
if( !gc )
continue;
@ -217,11 +227,10 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage( CreepageGraph& aGraph, int aNetCod
}
}
DRC_CUSTOM_MARKER_HANDLER graphicsHandler =
GetGraphicsHandler( path, startPoint, endPoint, distance );
reportViolation( drce, shortestPath[1]->m_path.a2, aLayer, &graphicsHandler );
DRC_CUSTOM_MARKER_HANDLER handler = GetGraphicsHandler( path, startPoint, endPoint, distance );
reportViolation( drce, gc1->m_path.a2, aLayer, &handler );
}
shortestPath.clear();
return 1;
}
@ -336,7 +345,7 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage()
return -1;
const DRAWINGS drawings = m_board->Drawings();
CreepageGraph graph( *m_board );
CREEPAGE_GRAPH graph( *m_board );
if( ADVANCED_CFG::GetCfg().m_EnableCreepageSlot )
@ -355,23 +364,30 @@ int DRC_TEST_PROVIDER_CREEPAGE::testCreepage()
graph.RemoveDuplicatedShapes();
graph.TransformCreepShapesToNodes( graph.m_shapeCollection );
graph.GeneratePaths( maxConstraint, Edge_Cuts );
graph.GeneratePaths( maxConstraint, Edge_Cuts, false );
int beNodeSize = graph.m_nodes.size();
int beConnectionsSize = graph.m_connections.size();
int beNodeSize = graph.m_nodes.size();
int beConnectionsSize = graph.m_connections.size();
bool prevTestChangedGraph = false;
size_t current = 0;
size_t total =
( netcodes.size() * ( netcodes.size() - 1 ) ) / 2 * m_board->GetCopperLayerCount();
alg::for_all_pairs( netcodes.begin(), netcodes.end(),
[&]( int aNet1, int aNet2 )
{
if( aNet1 == aNet2 )
return;
for( PCB_LAYER_ID layer : LSET::AllCuMask().CuStack() )
for( auto it = m_board->GetLayerSet().copper_layers_begin();
it != m_board->GetLayerSet().copper_layers_end();
++it )
{
if( !m_board->IsLayerEnabled( layer ) )
continue;
PCB_LAYER_ID layer = *it;
reportProgress( current++, total );
if ( prevTestChangedGraph )
{