Cache netclass clearances
Importing Altium boards can generate hundreds of netclasses. Our O(N) search was choking on the overload
This commit is contained in:
+2
-1
@@ -266,7 +266,7 @@ void BOARD::IncrementTimeStamp()
|
||||
if( !m_IntersectsAreaCache.empty() || !m_EnclosedByAreaCache.empty() || !m_IntersectsCourtyardCache.empty()
|
||||
|| !m_IntersectsFCourtyardCache.empty() || !m_IntersectsBCourtyardCache.empty()
|
||||
|| !m_LayerExpressionCache.empty() || !m_ZoneBBoxCache.empty() || m_CopperItemRTreeCache
|
||||
|| m_maxClearanceValue.has_value() || !m_itemByIdCache.empty() )
|
||||
|| m_maxClearanceValue.has_value() || !m_itemByIdCache.empty() || !m_ItemNetclassCache.empty() )
|
||||
{
|
||||
m_IntersectsAreaCache.clear();
|
||||
m_EnclosedByAreaCache.clear();
|
||||
@@ -274,6 +274,7 @@ void BOARD::IncrementTimeStamp()
|
||||
m_IntersectsFCourtyardCache.clear();
|
||||
m_IntersectsBCourtyardCache.clear();
|
||||
m_LayerExpressionCache.clear();
|
||||
m_ItemNetclassCache.clear();
|
||||
|
||||
m_ZoneBBoxCache.clear();
|
||||
|
||||
|
||||
@@ -1449,6 +1449,8 @@ public:
|
||||
mutable std::unordered_map<const ZONE*, BOX2I> m_ZoneBBoxCache;
|
||||
mutable std::optional<int> m_maxClearanceValue;
|
||||
|
||||
mutable std::unordered_map<const BOARD_ITEM*, wxString> m_ItemNetclassCache;
|
||||
|
||||
// ------------ DRC caches -------------
|
||||
std::vector<ZONE*> m_DRCZones;
|
||||
std::vector<ZONE*> m_DRCCopperZones;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <i18n_utility.h>
|
||||
#include <netinfo.h>
|
||||
#include <api/board/board_types.pb.h>
|
||||
#include <shared_mutex>
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
@@ -101,8 +102,13 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert )
|
||||
|
||||
// Invalidate clearance cache since net can affect clearance rules
|
||||
if( board )
|
||||
{
|
||||
board->InvalidateClearanceCache( m_Uuid );
|
||||
|
||||
std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
|
||||
board->m_ItemNetclassCache.erase( this );
|
||||
}
|
||||
|
||||
return ( m_netinfo != nullptr );
|
||||
}
|
||||
|
||||
|
||||
+102
-1
@@ -279,6 +279,7 @@ void DRC_ENGINE::loadImplicitRules()
|
||||
DRC_CONSTRAINT constraint( CLEARANCE_CONSTRAINT );
|
||||
constraint.Value().SetMin( nc->GetClearance() );
|
||||
netclassRule->AddConstraint( constraint );
|
||||
m_netclassClearances[nc->GetName()] = nc->GetClearance();
|
||||
}
|
||||
|
||||
if( nc->HasTrackWidth() )
|
||||
@@ -346,6 +347,8 @@ void DRC_ENGINE::loadImplicitRules()
|
||||
DRC_CONSTRAINT min_clearanceConstraint( CLEARANCE_CONSTRAINT );
|
||||
min_clearanceConstraint.Value().SetMin( nc->GetDiffPairGap() );
|
||||
netclassRule->AddConstraint( min_clearanceConstraint );
|
||||
|
||||
m_hasDiffPairClearanceOverrides = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,6 +728,23 @@ void DRC_ENGINE::compileRules()
|
||||
m_constraintMap[ constraint.m_Type ]->push_back( engineConstraint );
|
||||
}
|
||||
}
|
||||
|
||||
m_hasExplicitClearanceRules = false;
|
||||
m_explicitConstraints.clear();
|
||||
|
||||
for( auto& [constraintType, ruleList] : m_constraintMap )
|
||||
{
|
||||
for( DRC_ENGINE_CONSTRAINT* c : *ruleList )
|
||||
{
|
||||
if( c->parentRule && !c->parentRule->IsImplicit() )
|
||||
{
|
||||
m_explicitConstraints[constraintType].push_back( c );
|
||||
|
||||
if( constraintType == CLEARANCE_CONSTRAINT )
|
||||
m_hasExplicitClearanceRules = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -753,6 +773,10 @@ void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
|
||||
|
||||
m_constraintMap.clear();
|
||||
m_ownClearanceCache.clear();
|
||||
m_netclassClearances.clear();
|
||||
m_hasExplicitClearanceRules = false;
|
||||
m_hasDiffPairClearanceOverrides = false;
|
||||
m_explicitConstraints.clear();
|
||||
|
||||
m_board->IncrementTimeStamp(); // Clear board-level caches
|
||||
|
||||
@@ -1614,7 +1638,49 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
||||
}
|
||||
};
|
||||
|
||||
if( m_constraintMap.count( aConstraintType ) )
|
||||
// Fast-path for netclass clearance when no explicit or diff pair override rules exist
|
||||
if( aConstraintType == CLEARANCE_CONSTRAINT
|
||||
&& !m_hasExplicitClearanceRules
|
||||
&& !m_hasDiffPairClearanceOverrides
|
||||
&& !aReporter
|
||||
&& !a_is_non_copper
|
||||
&& ( !b || !b_is_non_copper ) )
|
||||
{
|
||||
int clearance = 0;
|
||||
|
||||
if( ac )
|
||||
{
|
||||
NETCLASS* ncA = ac->GetEffectiveNetClass();
|
||||
|
||||
if( ncA )
|
||||
{
|
||||
auto it = m_netclassClearances.find( ncA->GetName() );
|
||||
|
||||
if( it != m_netclassClearances.end() )
|
||||
clearance = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
if( bc )
|
||||
{
|
||||
NETCLASS* ncB = bc->GetEffectiveNetClass();
|
||||
|
||||
if( ncB )
|
||||
{
|
||||
auto it = m_netclassClearances.find( ncB->GetName() );
|
||||
|
||||
if( it != m_netclassClearances.end() )
|
||||
clearance = std::max( clearance, it->second );
|
||||
}
|
||||
}
|
||||
|
||||
if( clearance > 0 )
|
||||
{
|
||||
constraint.m_Value.SetMin( clearance );
|
||||
constraint.m_ImplicitMin = true;
|
||||
}
|
||||
}
|
||||
else if( m_constraintMap.count( aConstraintType ) )
|
||||
{
|
||||
std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
|
||||
|
||||
@@ -1852,6 +1918,41 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
||||
}
|
||||
|
||||
|
||||
DRC_CLEARANCE_BATCH DRC_ENGINE::EvalClearanceBatch( const BOARD_ITEM* a, const BOARD_ITEM* b,
|
||||
PCB_LAYER_ID aLayer )
|
||||
{
|
||||
DRC_CLEARANCE_BATCH result;
|
||||
DRC_CONSTRAINT c;
|
||||
|
||||
c = EvalRules( CLEARANCE_CONSTRAINT, a, b, aLayer );
|
||||
|
||||
if( c.m_Value.HasMin() )
|
||||
result.clearance = c.m_Value.Min();
|
||||
|
||||
c = EvalRules( HOLE_CLEARANCE_CONSTRAINT, a, b, aLayer );
|
||||
|
||||
if( c.m_Value.HasMin() )
|
||||
result.holeClearance = c.m_Value.Min();
|
||||
|
||||
c = EvalRules( HOLE_TO_HOLE_CONSTRAINT, a, b, aLayer );
|
||||
|
||||
if( c.m_Value.HasMin() )
|
||||
result.holeToHole = c.m_Value.Min();
|
||||
|
||||
c = EvalRules( EDGE_CLEARANCE_CONSTRAINT, a, b, aLayer );
|
||||
|
||||
if( c.m_Value.HasMin() )
|
||||
result.edgeClearance = c.m_Value.Min();
|
||||
|
||||
c = EvalRules( PHYSICAL_CLEARANCE_CONSTRAINT, a, b, aLayer );
|
||||
|
||||
if( c.m_Value.HasMin() )
|
||||
result.physicalClearance = c.m_Value.Min();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void DRC_ENGINE::ProcessAssertions( const BOARD_ITEM* a,
|
||||
std::function<void( const DRC_CONSTRAINT* )> aFailureHandler,
|
||||
REPORTER* aReporter )
|
||||
|
||||
@@ -103,6 +103,20 @@ typedef std::function<void( const std::shared_ptr<DRC_ITEM>& aItem,
|
||||
const VECTOR2I& aPos, int aLayer,
|
||||
const std::function<void( PCB_MARKER* )>& aPathGenerator )> DRC_VIOLATION_HANDLER;
|
||||
|
||||
|
||||
/**
|
||||
* Batch result for clearance-related constraints to reduce per-query overhead during PNS routing.
|
||||
*/
|
||||
struct DRC_CLEARANCE_BATCH
|
||||
{
|
||||
int clearance = 0;
|
||||
int holeClearance = 0;
|
||||
int holeToHole = 0;
|
||||
int edgeClearance = 0;
|
||||
int physicalClearance = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Design Rule Checker object that performs all the DRC tests.
|
||||
*
|
||||
@@ -196,6 +210,18 @@ public:
|
||||
DRC_CONSTRAINT EvalZoneConnection( const BOARD_ITEM* a, const BOARD_ITEM* b,
|
||||
PCB_LAYER_ID aLayer, REPORTER* aReporter = nullptr );
|
||||
|
||||
/**
|
||||
* Evaluate all clearance-related constraints in a single batch call.
|
||||
* This reduces per-call overhead during interactive PNS routing.
|
||||
*
|
||||
* @param a First board item
|
||||
* @param b Second board item (may be nullptr)
|
||||
* @param aLayer Layer to evaluate constraints on
|
||||
* @return DRC_CLEARANCE_BATCH containing all clearance constraint values
|
||||
*/
|
||||
DRC_CLEARANCE_BATCH EvalClearanceBatch( const BOARD_ITEM* a, const BOARD_ITEM* b,
|
||||
PCB_LAYER_ID aLayer );
|
||||
|
||||
/**
|
||||
* Get the cached own clearance for an item on a specific layer.
|
||||
*
|
||||
@@ -346,4 +372,9 @@ protected:
|
||||
// Cache for GetOwnClearance lookups to improve rendering performance.
|
||||
// Key is (UUID, layer), value is clearance in internal units.
|
||||
std::unordered_map<DRC_OWN_CLEARANCE_CACHE_KEY, int> m_ownClearanceCache;
|
||||
|
||||
std::unordered_map<wxString, int> m_netclassClearances; // netclass name -> clearance
|
||||
bool m_hasExplicitClearanceRules = false;
|
||||
bool m_hasDiffPairClearanceOverrides = false;
|
||||
std::map<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>> m_explicitConstraints;
|
||||
};
|
||||
|
||||
@@ -1351,12 +1351,34 @@ static void hasExactNetclassFunc( LIBEVAL::CONTEXT* aCtx, void* self )
|
||||
return 0.0;
|
||||
|
||||
BOARD_CONNECTED_ITEM* bcItem = static_cast<BOARD_CONNECTED_ITEM*>( item );
|
||||
NETCLASS* netclass = bcItem->GetEffectiveNetClass();
|
||||
BOARD* board = bcItem->GetBoard();
|
||||
wxString netclassName;
|
||||
|
||||
if( netclass && netclass->GetName() == arg->AsString() )
|
||||
return 1.0;
|
||||
if( board && ( item->GetFlags() & ROUTER_TRANSIENT ) == 0 )
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> readLock( board->m_CachesMutex );
|
||||
|
||||
return 0.0;
|
||||
auto it = board->m_ItemNetclassCache.find( item );
|
||||
|
||||
if( it != board->m_ItemNetclassCache.end() )
|
||||
netclassName = it->second;
|
||||
}
|
||||
|
||||
if( netclassName.empty() )
|
||||
{
|
||||
NETCLASS* netclass = bcItem->GetEffectiveNetClass();
|
||||
|
||||
if( netclass )
|
||||
netclassName = netclass->GetName();
|
||||
|
||||
if( board && !netclassName.empty() && ( item->GetFlags() & ROUTER_TRANSIENT ) == 0 )
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
|
||||
board->m_ItemNetclassCache[item] = netclassName;
|
||||
}
|
||||
}
|
||||
|
||||
return ( netclassName == arg->AsString() ) ? 1.0 : 0.0;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ HANDLE_EXCEPTIONS(BOARD::TracksInNetBetweenPoints)
|
||||
%ignore BOARD::m_LayerExpressionCache;
|
||||
%ignore BOARD::m_CopperZoneRTreeCache;
|
||||
%ignore BOARD::m_CopperItemRTreeCache;
|
||||
%ignore BOARD::m_ItemNetclassCache;
|
||||
%ignore BOARD::m_DRCZones;
|
||||
%ignore BOARD::m_DRCCopperZones;
|
||||
%ignore BOARD::m_DRCMaxClearance;
|
||||
|
||||
Reference in New Issue
Block a user