79 constexpr std::size_t prime = 19937;
81 return hash<int>()( k.
Netcode ) ^ ( hash<int>()( k.
Layer ) * prime );
95 virtual bool Run()
override;
97 virtual const wxString
GetName()
const override {
return wxT(
"copper width" ); };
123 std::set<VERTEX*> all_hits;
130 if( ( all_hits.empty() || all_hits.count( p ) == 0 ) && ( match =
getKink( p ) ) !=
nullptr )
132 if( !all_hits.count( match ) &&
m_hits.emplace( p->
i, match->
i ).second )
134 all_hits.emplace( p );
135 all_hits.emplace( match );
136 all_hits.emplace( p->
next );
137 all_hits.emplace( p->
prev );
138 all_hits.emplace( match->
next );
139 all_hits.emplace( match->
prev );
164 bool x_change =
false;
165 bool y_change =
false;
177 && checked < total_pts
178 && !( x_change && y_change ) )
196 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
198 if( !
same_point( p, aA ) && ( !x_change || !y_change ) )
209 && checked < total_pts
210 && !( x_change && y_change ) )
229 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
231 return (
same_point( p, aA ) || ( x_change && y_change ) );
247 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
250 while( p && p->
z <= maxZ )
256 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0
268 while( p && p->
z >= minZ )
274 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0
302 REPORT_AUX( wxT(
"Connection width violations ignored. Tests not run." ) );
306 if( !
reportPhase(
_(
"Checking nets for minimum connection width..." ) ) )
331 std::set<BOARD_ITEM*> Items;
335 std::unordered_map<NETCODE_LAYER_CACHE_KEY, ITEMS_POLY> dataset;
336 std::atomic<size_t> done( 1 );
339 [&](
const std::set<BOARD_ITEM*>& items,
PCB_LAYER_ID aLayer ) ->
size_t
347 ZONE* zone =
static_cast<ZONE*
>( item );
363 auto build_netlayer_polys =
364 [&](
int aNetcode,
const PCB_LAYER_ID aLayer ) ->
size_t
369 ITEMS_POLY& itemsPoly = dataset[ { aNetcode, aLayer } ];
374 itemsPoly.Poly.Fracture();
376 done.fetch_add( calc_effort( itemsPoly.Items, aLayer ) );
385 [&](
const ITEMS_POLY& aItemsPoly,
const PCB_LAYER_ID aLayer,
int aMinWidth ) ->
size_t
390 int testWidth = aMinWidth -
epsilon;
394 for(
int ii = 0; ii < aItemsPoly.Poly.OutlineCount(); ++ii )
399 auto& ret =
test.GetVertices();
401 for(
const std::pair<int, int>& pt : ret )
415 int dist = ( span.
A - span.
B ).EuclideanNorm();
417 std::vector<BOARD_ITEM*> contributingItems;
422 if( item->HitTest(
location, aMinWidth ) )
423 contributingItems.push_back( item );
431 auto obj_list = rtree->GetObjectsAt(
location, aLayer, aMinWidth );
433 if( !obj_list.empty() && zone->HitTestFilledArea( aLayer,
location, aMinWidth ) )
434 contributingItems.push_back( zone );
437 if( !contributingItems.empty() )
440 BOARD_ITEM* item2 = contributingItems.size() > 1 ? contributingItems[1]
443 item1, item2, aLayer );
450 msg =
formatMsg(
_(
"(%s minimum connection width %s; actual %s)" ),
457 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
461 drce->AddItem( item );
469 done.fetch_add( calc_effort( aItemsPoly.Items, aLayer ) );
479 dataset[ { zone->
GetNetCode(), layer } ].Items.emplace( zone );
486 if(
via->FlashLayer(
static_cast<int>( layer ) ) )
487 dataset[ {
via->GetNetCode(), layer } ].Items.emplace(
via );
489 else if( track->IsOnLayer( layer ) )
491 dataset[ { track->GetNetCode(), layer } ].Items.emplace( track );
497 for(
PAD*
pad : fp->Pads() )
499 if(
pad->FlashLayer(
static_cast<int>( layer ) ) )
500 dataset[ {
pad->GetNetCode(), layer } ].Items.emplace(
pad );
508 std::vector<std::future<size_t>> returns;
509 size_t total_effort = 0;
511 for(
const auto& [ netLayer, itemsPoly ] : dataset )
512 total_effort += calc_effort( itemsPoly.Items, netLayer.Layer );
514 total_effort += std::max( (
size_t) 1, total_effort ) * distinctMinWidths.size();
516 returns.reserve( dataset.size() );
518 for(
const auto& [ netLayer, itemsPoly ] : dataset )
520 returns.emplace_back(
tp.submit( build_netlayer_polys, netLayer.Netcode, netLayer.Layer ) );
523 for( std::future<size_t>& ret : returns )
525 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
527 while( status != std::future_status::ready )
530 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
535 returns.reserve( dataset.size() * distinctMinWidths.size() );
537 for(
const auto& [ netLayer, itemsPoly ] : dataset )
539 for(
int minWidth : distinctMinWidths )
544 returns.emplace_back(
tp.submit( min_checker, itemsPoly, netLayer.Layer, minWidth ) );
548 for( std::future<size_t>& ret : returns )
550 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
552 while( status != std::future_status::ready )
555 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
int GetDRCEpsilon() const
Return an epsilon which accounts for rounding errors, etc.
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.
std::vector< ZONE * > m_DRCCopperZones
int GetCopperLayerCount() const
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 ~DRC_TEST_PROVIDER_CONNECTION_WIDTH()=default
virtual const wxString GetName() const override
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
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...
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)
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual, EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
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)
constexpr int mmToIU(double mm) const
bool operator==(const NETCODE_LAYER_CACHE_KEY &other) const
std::size_t operator()(const NETCODE_LAYER_CACHE_KEY &k) const
const SHAPE_LINE_CHAIN chain
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::thread_pool thread_pool
@ PCB_ZONE_T
class ZONE, a copper pour area