79 constexpr std::size_t prime = 19937;
81 return hash<int>()( k.
Netcode ) ^ ( hash<int>()( k.
Layer ) * prime );
98 virtual bool Run()
override;
100 virtual const wxString
GetName()
const override
102 return wxT(
"copper width" );
107 return wxT(
"Checks copper nets for connections less than a specified minimum" );
135 std::set<VERTEX*> all_hits;
142 if( ( all_hits.empty() || all_hits.count( p ) == 0 ) && ( match =
getKink( p ) ) !=
nullptr )
144 if( !all_hits.count( match ) &&
m_hits.emplace( p->
i, match->
i ).second )
146 all_hits.emplace( p );
147 all_hits.emplace( match );
148 all_hits.emplace( p->
next );
149 all_hits.emplace( p->
prev );
150 all_hits.emplace( match->
next );
151 all_hits.emplace( match->
prev );
177 bool x_change =
false;
178 bool y_change =
false;
190 && checked < total_pts
191 && !( x_change && y_change ) )
209 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
211 if( !
same_point( p, aA ) && ( !x_change || !y_change ) )
222 && checked < total_pts
223 && !( x_change && y_change ) )
242 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
244 return (
same_point( p, aA ) || ( x_change && y_change ) );
261 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
264 while( p && p->
z <= maxZ )
270 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0
282 while( p && p->
z >= minZ )
288 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0
317 if( !
reportPhase(
_(
"Checking nets for minimum connection width..." ) ) )
321 LSEQ copperLayers = copperLayerSet.
Seq();
333 std::set<int> distinctMinWidths
341 std::set<BOARD_ITEM*> Items;
345 std::unordered_map<NETCODE_LAYER_CACHE_KEY, ITEMS_POLY> dataset;
346 std::atomic<size_t> done( 1 );
349 [&](
const std::set<BOARD_ITEM*>& items,
PCB_LAYER_ID aLayer ) ->
size_t
357 ZONE* zone =
static_cast<ZONE*
>( item );
373 auto build_netlayer_polys =
374 [&](
int aNetcode,
const PCB_LAYER_ID aLayer ) ->
size_t
379 ITEMS_POLY& itemsPoly = dataset[ { aNetcode, aLayer } ];
387 itemsPoly.Poly.Fracture();
389 done.fetch_add( calc_effort( itemsPoly.Items, aLayer ) );
398 [&](
const ITEMS_POLY& aItemsPoly,
const PCB_LAYER_ID aLayer,
int aMinWidth ) ->
size_t
403 int testWidth = aMinWidth -
epsilon;
407 for(
int ii = 0; ii < aItemsPoly.Poly.OutlineCount(); ++ii )
411 test.FindPairs( chain );
412 auto& ret =
test.GetVertices();
414 for(
const std::pair<int, int>& pt : ret )
428 int dist = ( span.
A - span.
B ).EuclideanNorm();
430 std::vector<BOARD_ITEM*> contributingItems;
436 if( item->HitTest( location, aMinWidth ) )
437 contributingItems.push_back( item );
445 auto obj_list = rtree->GetObjectsAt( location, aLayer, aMinWidth );
447 if( !obj_list.empty() && zone->HitTestFilledArea( aLayer, location, aMinWidth ) )
449 contributingItems.push_back( zone );
453 if( !contributingItems.empty() )
456 BOARD_ITEM* item2 = contributingItems.size() > 1 ? contributingItems[1]
459 item1, item2, aLayer );
466 msg =
formatMsg(
_(
"(%s minimum connection width %s; actual %s)" ),
473 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
477 drce->AddItem( item );
485 done.fetch_add( calc_effort( aItemsPoly.Items, aLayer ) );
495 dataset[ { zone->
GetNetCode(), layer } ].Items.emplace( zone );
502 if(
via->FlashLayer(
static_cast<int>( layer ) ) )
503 dataset[ {
via->GetNetCode(), layer } ].Items.emplace(
via );
505 else if( track->IsOnLayer( layer ) )
507 dataset[ { track->GetNetCode(), layer } ].Items.emplace( track );
513 for(
PAD*
pad : fp->Pads() )
515 if(
pad->FlashLayer(
static_cast<int>( layer ) ) )
516 dataset[ {
pad->GetNetCode(), layer } ].Items.emplace(
pad );
524 std::vector<std::future<size_t>> returns;
525 size_t total_effort = 0;
527 for(
const auto& [ netLayer, itemsPoly ] : dataset )
528 total_effort += calc_effort( itemsPoly.Items, netLayer.Layer );
530 total_effort += std::max( (
size_t) 1, total_effort ) * distinctMinWidths.size();
532 returns.reserve( dataset.size() );
534 for(
const auto& [ netLayer, itemsPoly ] : dataset )
536 returns.emplace_back(
tp.submit( build_netlayer_polys, netLayer.Netcode, netLayer.Layer ) );
539 for( std::future<size_t>& ret : returns )
541 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
543 while( status != std::future_status::ready )
546 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
551 returns.reserve( dataset.size() * distinctMinWidths.size() );
553 for(
const auto& [ netLayer, itemsPoly ] : dataset )
555 for(
int minWidth : distinctMinWidths )
560 returns.emplace_back(
tp.submit( min_checker, itemsPoly, netLayer.Layer, minWidth ) );
564 for( std::future<size_t>& ret : returns )
566 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
568 while( status != std::future_status::ready )
571 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
constexpr int ARC_HIGH_DEF
int GetDRCEpsilon() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
Information pertinent to a Pcbnew printed circuit board.
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
std::vector< ZONE * > m_DRCCopperZones
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
std::shared_ptr< DRC_RTREE > m_CopperItemRTreeCache
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
MINOPTMAX< int > & Value()
DRC_RULE * GetParentRule() const
std::set< int > QueryDistinctConstraints(DRC_CONSTRAINT_T aConstraintId)
bool IsErrorLimitExceeded(int error_code)
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
virtual const wxString GetDescription() const override
virtual const wxString GetName() const override
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual ~DRC_TEST_PROVIDER_CONNECTION_WIDTH()
DRC_TEST_PROVIDER_CONNECTION_WIDTH()
wxString layerDesc(PCB_LAYER_ID aLayer)
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out DRC_ITEM and posi...
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual)
virtual bool reportPhase(const wxString &aStageName)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER *aCustomHandler=nullptr)
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool isSubstantial(const VERTEX *aA, const VERTEX *aB) const
Checks to see if there is a "substantial" protrusion in each polygon produced by the cut from aA to a...
VERTEX * getKink(VERTEX *aPt) const
bool FindPairs(const SHAPE_LINE_CHAIN &aPoly)
std::set< std::pair< int, int > > & GetVertices()
std::set< std::pair< int, int > > m_hits
VECTOR2I::extended_type ecoord
static SEG::ecoord Square(int a)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a set of closed polygons.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
std::deque< VERTEX > m_vertices
VERTEX * createList(const SHAPE_LINE_CHAIN &points, VERTEX *aTail=nullptr, void *aUserData=nullptr)
Create a list of vertices from a line chain.
bool locallyInside(const VERTEX *a, const VERTEX *b) const
Check whether the segment from vertex a -> vertex b is inside the polygon around the immediate area o...
VERTEX * getPrevOutlineVertex(const VERTEX *aPt) const
Get the previous vertex in the outline, avoiding steiner points and points that overlap with splits.
VERTEX * getNextOutlineVertex(const VERTEX *aPt) const
Get the next vertex in the outline, avoiding steiner points and points that overlap with splits.
uint32_t zOrder(const double aX, const double aY) const
Note that while the inputs are doubles, these are scaled by the size of the bounding box to fit into ...
bool same_point(const VERTEX *aA, const VERTEX *aB) const
Check if two vertices are at the same point.
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
@ CONNECTION_WIDTH_CONSTRAINT
PCB_LAYER_ID
A quick note on layer IDs:
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
bool operator==(const NETCODE_LAYER_CACHE_KEY &other) const
std::size_t operator()(const NETCODE_LAYER_CACHE_KEY &k) const
BS::thread_pool thread_pool
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
@ PCB_ZONE_T
class ZONE, a copper pour area