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;
404 && checked < total_pts
405 && !( x_change && y_change ) )
423 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
425 if( !
same_point( p, aA ) && ( !x_change || !y_change ) )
436 && checked < total_pts
437 && !( x_change && y_change ) )
456 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
458 return (
same_point( p, aA ) || ( x_change && y_change ) );
470 for(
int i = 0; i < points.
PointCount(); i++ )
475 sum += ( ( p2.
x - p1.
x ) * ( p2.
y + p1.
y ) );
480 for(
int i = points.
PointCount() - 1; i >= 0; i--)
485 for(
int i = 0; i < points.
PointCount(); i++ )
489 if( tail && ( *tail == *tail->
next ) )
515 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
518 while( p && p->
z <= maxZ )
524 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0.0
536 while( p && p->
z >= minZ )
542 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0.0
560 return ( q->
y - p->
y ) * ( r->
x - q->
x ) - ( q->
x - p->
x ) * ( r->
y - q->
y );
578 if(
area( ap, a, an ) < 0 )
579 return area( a, b, an ) >= 0 &&
area( a, ap, b ) >= 0;
581 return area( a, b, ap ) < 0 ||
area( a, an, b ) < 0;
630 if( !
reportPhase(
_(
"Checking nets for minimum connection width..." ) ) )
634 LSEQ copperLayers = copperLayerSet.
Seq();
642 std::set<int> distinctMinWidths
650 std::set<BOARD_ITEM*> Items;
654 std::unordered_map<NETCODE_LAYER_CACHE_KEY, ITEMS_POLY> dataset;
655 std::atomic<size_t> done( 1 );
658 [&](
const std::set<BOARD_ITEM*>& items,
PCB_LAYER_ID aLayer ) ->
size_t
666 ZONE* zone =
static_cast<ZONE*
>( item );
682 auto build_netlayer_polys =
683 [&](
int aNetcode,
const PCB_LAYER_ID aLayer ) ->
size_t
688 ITEMS_POLY& itemsPoly = dataset[ { aNetcode, aLayer } ];
698 done.fetch_add( calc_effort( itemsPoly.Items, aLayer ) );
707 [&](
const ITEMS_POLY& aItemsPoly,
const PCB_LAYER_ID aLayer,
int aMinWidth ) ->
size_t
714 for(
int ii = 0; ii < aItemsPoly.Poly.OutlineCount(); ++ii )
718 test.FindPairs( chain );
719 auto& ret =
test.GetVertices();
721 for(
const std::pair<int, int>& pt : ret )
737 std::vector<BOARD_ITEM*> contributingItems;
743 if( item->HitTest( location, aMinWidth ) )
744 contributingItems.push_back( item );
752 auto obj_list = rtree->GetObjectsAt( location, aLayer, aMinWidth );
754 if( !obj_list.empty() && zone->HitTestFilledArea( aLayer, location, aMinWidth ) )
756 contributingItems.push_back( zone );
760 if( !contributingItems.empty() )
763 BOARD_ITEM* item2 = contributingItems.size() > 1 ? contributingItems[1]
766 item1, item2, aLayer );
773 msg =
formatMsg(
_(
"(%s minimum connection width %s; actual %s)" ),
780 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
784 drce->AddItem( item );
792 done.fetch_add( calc_effort( aItemsPoly.Items, aLayer ) );
802 dataset[ { zone->
GetNetCode(), layer } ].Items.emplace( zone );
809 if(
via->FlashLayer(
static_cast<int>( layer ) ) )
810 dataset[ {
via->GetNetCode(), layer } ].Items.emplace(
via );
812 else if( track->IsOnLayer( layer ) )
814 dataset[ { track->GetNetCode(), layer } ].Items.emplace( track );
820 for(
PAD*
pad : fp->Pads() )
822 if(
pad->FlashLayer(
static_cast<int>( layer ) ) )
823 dataset[ {
pad->GetNetCode(), layer } ].Items.emplace(
pad );
831 std::vector<std::future<size_t>> returns;
832 size_t total_effort = 0;
834 for(
const auto& [ netLayer, itemsPoly ] : dataset )
835 total_effort += calc_effort( itemsPoly.Items, netLayer.Layer );
837 total_effort += std::max( (
size_t) 1, total_effort ) * distinctMinWidths.size();
839 returns.reserve( dataset.size() );
841 for(
const auto& [ netLayer, itemsPoly ] : dataset )
843 returns.emplace_back(
tp.submit( build_netlayer_polys, netLayer.Netcode, netLayer.Layer ) );
846 for( std::future<size_t>& ret : returns )
848 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
850 while( status != std::future_status::ready )
853 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
858 returns.reserve( dataset.size() * distinctMinWidths.size() );
860 for(
const auto& [ netLayer, itemsPoly ] : dataset )
862 for(
int minWidth : distinctMinWidths )
863 returns.emplace_back(
tp.submit( min_checker, itemsPoly, netLayer.Layer, minWidth ) );
866 for( std::future<size_t>& ret : returns )
868 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
870 while( status != std::future_status::ready )
873 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
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
size_type GetHeight() const
size_type GetWidth() 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)
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.
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:
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
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
BS::thread_pool thread_pool
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
double EuclideanNorm(const VECTOR2I &vector)
@ PCB_ZONE_T
class ZONE, a copper pour area