78 constexpr std::size_t prime = 19937;
80 return hash<int>()( k.
Netcode ) ^ ( hash<int>()( k.
Layer ) * prime );
97 virtual bool Run()
override;
99 virtual const wxString
GetName()
const override
101 return wxT(
"copper width" );
106 return wxT(
"Checks copper nets for connections less than a specified minimum" );
133 std::set<Vertex*> all_hits;
140 if( ( all_hits.empty() || all_hits.count( p ) == 0 ) && ( match =
getKink( p ) ) !=
nullptr )
142 if( !all_hits.count( match ) &&
m_hits.emplace( p->
i, match->
i ).second )
144 all_hits.emplace( p );
145 all_hits.emplace( match );
146 all_hits.emplace( p->
next );
147 all_hits.emplace( p->
prev );
148 all_hits.emplace( match->
next );
149 all_hits.emplace( match->
prev );
181 return this->
x == rhs.
x && this->
y == rhs.
y;
246 std::deque<Vertex*> queue;
248 queue.push_back(
this );
251 queue.push_back( p );
253 std::sort( queue.begin(), queue.end(), [](
const Vertex* a,
const Vertex* b )
267 Vertex* prev_elem =
nullptr;
269 for(
Vertex* elem : queue )
272 prev_elem->
nextZ = elem;
274 elem->
prevZ = prev_elem;
278 prev_elem->
nextZ =
nullptr;
303 int32_t
zOrder(
const double aX,
const double aY )
const
308 x = ( x | ( x << 8 ) ) & 0x00FF00FF;
309 x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
310 x = ( x | ( x << 2 ) ) & 0x33333333;
311 x = ( x | ( x << 1 ) ) & 0x55555555;
313 y = ( y | ( y << 8 ) ) & 0x00FF00FF;
314 y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
315 y = ( y | ( y << 2 ) ) & 0x33333333;
316 y = ( y | ( y << 1 ) ) & 0x55555555;
318 return x | ( y << 1 );
323 return aA && aB && aA->
x == aB->
x && aA->
y == aB->
y;
339 && aPt->
y == aPt->
next->
y )
345 && aPt->
y == aPt->
next->
y )
366 && aPt->
y == aPt->
prev->
y)
372 && aPt->
y == aPt->
prev->
y )
391 bool x_change =
false;
392 bool y_change =
false;
402 while( !
same_point( p, aB ) && checked < total_pts && !( x_change && y_change ) )
421 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
423 if( !x_change || !y_change )
432 while( !
same_point( p, aB ) && checked < total_pts && !( x_change && y_change ) )
451 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
453 return ( x_change && y_change );
465 for(
int i = 0; i < points.
PointCount(); i++ )
470 sum += ( ( p2.
x - p1.
x ) * ( p2.
y + p1.
y ) );
475 for(
int i = points.
PointCount() - 1; i >= 0; i--)
480 for(
int i = 0; i < points.
PointCount(); i++ )
484 if( tail && ( *tail == *tail->
next ) )
510 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
513 while( p && p->
z <= maxZ )
519 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0.0
531 while( p && p->
z >= minZ )
537 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0.0
555 return ( q->
y - p->
y ) * ( r->
x - q->
x ) - ( q->
x - p->
x ) * ( r->
y - q->
y );
573 if(
area( ap, a, an ) < 0 )
574 return area( a, b, an ) >= 0 &&
area( a, ap, b ) >= 0;
576 return area( a, b, ap ) < 0 ||
area( a, an, b ) < 0;
625 if( !
reportPhase(
_(
"Checking nets for minimum connection width..." ) ) )
629 LSEQ copperLayers = copperLayerSet.
Seq();
637 std::set<int> distinctMinWidths
645 std::set<BOARD_ITEM*> Items;
649 std::unordered_map<NETCODE_LAYER_CACHE_KEY, ITEMS_POLY> dataset;
650 std::atomic<size_t> done( 1 );
653 [&](
const std::set<BOARD_ITEM*>& items,
PCB_LAYER_ID aLayer ) ->
size_t
661 ZONE* zone =
static_cast<ZONE*
>( item );
677 auto build_netlayer_polys =
678 [&](
int aNetcode,
const PCB_LAYER_ID aLayer ) ->
size_t
683 ITEMS_POLY& itemsPoly = dataset[ { aNetcode, aLayer } ];
693 done.fetch_add( calc_effort( itemsPoly.Items, aLayer ) );
702 [&](
const ITEMS_POLY& aItemsPoly,
const PCB_LAYER_ID aLayer,
int aMinWidth ) ->
size_t
709 for(
int ii = 0; ii < aItemsPoly.Poly.OutlineCount(); ++ii )
713 test.FindPairs( chain );
714 auto& ret =
test.GetVertices();
716 for(
const std::pair<int, int>& pt : ret )
732 std::vector<BOARD_ITEM*> contributingItems;
738 if( item->HitTest( location, aMinWidth ) )
739 contributingItems.push_back( item );
744 if( !rtree->GetObjectsAt( location, aLayer, aMinWidth ).empty()
745 && zone->HitTestFilledArea( aLayer, location, aMinWidth ) )
747 contributingItems.push_back( zone );
751 if( !contributingItems.empty() )
754 BOARD_ITEM* item2 = contributingItems.size() > 1 ? contributingItems[1]
757 item1, item2, aLayer );
764 msg =
formatMsg(
_(
"(%s minimum connection width %s; actual %s)" ),
771 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
775 drce->AddItem( item );
783 done.fetch_add( calc_effort( aItemsPoly.Items, aLayer ) );
793 dataset[ { zone->
GetNetCode(), layer } ].Items.emplace( zone );
800 if(
via->FlashLayer(
static_cast<int>( layer ) ) )
801 dataset[ {
via->GetNetCode(), layer } ].Items.emplace(
via );
803 else if( track->IsOnLayer( layer ) )
805 dataset[ { track->GetNetCode(), layer } ].Items.emplace( track );
811 for(
PAD*
pad : fp->Pads() )
813 if(
pad->FlashLayer(
static_cast<int>( layer ) ) )
814 dataset[ {
pad->GetNetCode(), layer } ].Items.emplace(
pad );
822 std::vector<std::future<size_t>> returns;
823 size_t total_effort = 0;
825 for(
const auto& [ netLayer, itemsPoly ] : dataset )
826 total_effort += calc_effort( itemsPoly.Items, netLayer.Layer );
828 total_effort += std::max( (
size_t) 1, total_effort ) * distinctMinWidths.size();
830 returns.reserve( dataset.size() );
832 for(
const auto& [ netLayer, itemsPoly ] : dataset )
834 returns.emplace_back(
tp.submit( build_netlayer_polys, netLayer.Netcode, netLayer.Layer ) );
837 for( std::future<size_t>& ret : returns )
839 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
841 while( status != std::future_status::ready )
844 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
849 returns.reserve( dataset.size() * distinctMinWidths.size() );
851 for(
const auto& [ netLayer, itemsPoly ] : dataset )
853 for(
int minWidth : distinctMinWidths )
854 returns.emplace_back(
tp.submit( min_checker, itemsPoly, netLayer.Layer, minWidth ) );
857 for( std::future<size_t>& ret : returns )
859 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
861 while( status != std::future_status::ready )
864 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
constexpr int ARC_HIGH_DEF
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
FOOTPRINTS & Footprints()
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
coord_type GetHeight() const
coord_type GetWidth() const
MINOPTMAX< int > & Value()
DRC_RULE * GetParentRule() const
std::set< int > QueryDistinctConstraints(DRC_CONSTRAINT_T aConstraintId)
bool ReportProgress(double aProgress)
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...
virtual bool reportPhase(const wxString &aStageName)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, int aConstraint, int aActual)
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Vertex * createList(const SHAPE_LINE_CHAIN &points)
Take a SHAPE_LINE_CHAIN and links each point into a circular, doubly-linked list.
bool FindPairs(const SHAPE_LINE_CHAIN &aPoly)
std::deque< Vertex > m_vertices
Vertex * getNextOutlineVertex(const Vertex *aPt) const
int32_t zOrder(const double aX, const double aY) const
Calculate the Morton code of the Vertex http://www.graphics.stanford.edu/~seander/bithacks....
double area(const Vertex *p, const Vertex *q, const Vertex *r) const
Return the twice the signed area of the triangle formed by vertices p, q, and r.
Vertex * getPrevOutlineVertex(const Vertex *aPt) const
std::set< std::pair< int, int > > & GetVertices()
std::set< std::pair< int, int > > m_hits
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...
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 * getKink(Vertex *aPt) const
constexpr bool same_point(const Vertex *aA, const Vertex *aB) const
Vertex * insertVertex(int aIndex, const VECTOR2I &pt, Vertex *last)
Create an entry in the vertices lookup and optionally inserts the newly created vertex into an existi...
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...
int PointCount() const
Return the number of points (vertices) in this line chain.
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.
extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
virtual bool IsOnLayer(PCB_LAYER_ID, bool aIncludeCourtyards=false) const override
Test to see if this object is on the given layer.
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
@ 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
Vertex & operator=(Vertex &&)=delete
void remove()
Remove the node from the linked list and z-ordered linked list.
void zSort()
Sort all vertices in this vertex's list by their Morton code.
Vertex & operator=(const Vertex &)=delete
void updateList()
After inserting or changing nodes, this function should be called to remove duplicate vertices and en...
Vertex(int aIndex, double aX, double aY, POLYGON_TEST *aParent)
bool operator!=(const Vertex &rhs) const
bool operator==(const Vertex &rhs) const
std::size_t operator()(const NETCODE_LAYER_CACHE_KEY &k) const
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::thread_pool thread_pool
double EuclideanNorm(const VECTOR2I &vector)
@ PCB_ZONE_T
class ZONE, a copper pour area