75 constexpr std::size_t prime = 19937;
77 return hash<int>()( k.
Netcode ) ^ ( hash<int>()( k.
Layer ) * prime );
91 virtual bool Run()
override;
93 virtual const wxString
GetName()
const override {
return wxT(
"copper width" ); };
119 std::set<VERTEX*> all_hits;
126 if( ( all_hits.empty() || all_hits.count( p ) == 0 ) && ( match =
getKink( p ) ) !=
nullptr )
128 if( !all_hits.count( match ) &&
m_hits.emplace( p->
i, match->
i ).second )
130 all_hits.emplace( p );
131 all_hits.emplace( match );
132 all_hits.emplace( p->
next );
133 all_hits.emplace( p->
prev );
134 all_hits.emplace( match->
next );
135 all_hits.emplace( match->
prev );
160 bool x_change =
false;
161 bool y_change =
false;
173 && checked < total_pts
174 && !( x_change && y_change ) )
192 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
194 if( !
same_point( p, aA ) && ( !x_change || !y_change ) )
205 && checked < total_pts
206 && !( x_change && y_change ) )
225 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
227 return (
same_point( p, aA ) || ( x_change && y_change ) );
243 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
246 while( p && p->
z <= maxZ )
252 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0
264 while( p && p->
z >= minZ )
270 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0
290 return wxString::Format( wxT(
"(%s)" ),
m_drcEngine->GetBoard()->GetLayerName( aLayer ) );
298 REPORT_AUX( wxT(
"Connection width violations ignored. Tests not run." ) );
302 if( !
reportPhase(
_(
"Checking nets for minimum connection width..." ) ) )
327 std::set<BOARD_ITEM*> Items;
331 std::unordered_map<NETCODE_LAYER_CACHE_KEY, ITEMS_POLY> dataset;
332 std::atomic<size_t> done( 1 );
335 [&](
const std::set<BOARD_ITEM*>& items,
PCB_LAYER_ID aLayer ) ->
size_t
343 ZONE* zone =
static_cast<ZONE*
>( item );
359 auto build_netlayer_polys =
360 [&](
int aNetcode,
const PCB_LAYER_ID aLayer ) ->
size_t
365 ITEMS_POLY& itemsPoly = dataset[ { aNetcode, aLayer } ];
370 itemsPoly.Poly.Fracture();
372 done.fetch_add( calc_effort( itemsPoly.Items, aLayer ) );
381 [&](
const ITEMS_POLY& aItemsPoly,
const PCB_LAYER_ID aLayer,
int aMinWidth ) ->
size_t
386 int testWidth = aMinWidth -
epsilon;
390 for(
int ii = 0; ii < aItemsPoly.Poly.OutlineCount(); ++ii )
395 auto& ret =
test.GetVertices();
397 for(
const std::pair<int, int>& pt : ret )
409 SEG span(
chain.CPoint( pt.first ),
chain.CPoint( pt.second ) );
411 int dist = ( span.
A - span.
B ).EuclideanNorm();
413 std::vector<BOARD_ITEM*> contributingItems;
418 if( item->HitTest(
location, aMinWidth ) )
419 contributingItems.push_back( item );
427 auto obj_list = rtree->GetObjectsAt(
location, aLayer, aMinWidth );
429 if( !obj_list.empty() && zone->HitTestFilledArea( aLayer,
location, aMinWidth ) )
430 contributingItems.push_back( zone );
433 if( !contributingItems.empty() )
436 BOARD_ITEM* item2 = contributingItems.size() > 1 ? contributingItems[1]
439 item1, item2, aLayer );
446 msg =
formatMsg(
_(
"(%s minimum connection width %s; actual %s)" ),
453 drcItem->SetErrorDetail( msg );
457 drcItem->AddItem( item );
465 done.fetch_add( calc_effort( aItemsPoly.Items, aLayer ) );
475 dataset[ { zone->
GetNetCode(), layer } ].Items.emplace( zone );
482 if(
via->FlashLayer(
static_cast<int>( layer ) ) )
483 dataset[ {
via->GetNetCode(), layer } ].Items.emplace(
via );
485 else if( track->IsOnLayer( layer ) )
487 dataset[ { track->GetNetCode(), layer } ].Items.emplace( track );
493 for(
PAD*
pad : fp->Pads() )
495 if(
pad->FlashLayer(
static_cast<int>( layer ) ) )
496 dataset[ {
pad->GetNetCode(), layer } ].Items.emplace(
pad );
504 size_t total_effort = 0;
506 for(
const auto& [ netLayer, itemsPoly ] : dataset )
507 total_effort += calc_effort( itemsPoly.Items, netLayer.Layer );
509 total_effort += std::max( (
size_t) 1, total_effort ) * distinctMinWidths.size();
511 std::vector<std::future<size_t>> returns;
512 returns.reserve( dataset.size() );
514 for(
const auto& [ netLayer, itemsPoly ] : dataset )
516 int netcode = netLayer.Netcode;
518 returns.emplace_back(
tp.submit_task(
519 [&, netcode, layer]()
521 return build_netlayer_polys( netcode, layer );
525 for(
auto& ret : returns )
527 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
529 while( status != std::future_status::ready )
532 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
537 returns.reserve( dataset.size() * distinctMinWidths.size() );
539 for(
const auto& [ netLayer, itemsPoly ] : dataset )
541 for(
int minWidth : distinctMinWidths )
546 returns.emplace_back(
tp.submit_task(
547 [min_checker, &itemsPoly, &netLayer, minWidth]()
549 return min_checker( itemsPoly, netLayer.Layer, minWidth );
554 for(
auto& ret : returns )
556 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
558 while( status != std::future_status::ready )
561 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
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
MINOPTMAX< int > & Value()
DRC_RULE * GetParentRule() const
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
std::unordered_set< BOARD_ITEM * > GetObjectsAt(const VECTOR2I &aPt, PCB_LAYER_ID aLayer, int aClearance=0)
Gets the BOARD_ITEMs that overlap the specified point/layer.
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)
virtual bool reportPhase(const wxString &aStageName)
void reportTwoPointGeometry(std::shared_ptr< DRC_ITEM > &aDrcItem, const VECTOR2I &aMarkerPos, const VECTOR2I &ptA, const VECTOR2I &ptB, PCB_LAYER_ID aLayer)
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(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
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 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.
int FullPointCount() const
Return the number of points in the shape poly set.
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_SET(int aSimplificationLevel)
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:
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
const SHAPE_LINE_CHAIN chain
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
@ PCB_ZONE_T
class ZONE, a copper pour area
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D