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 );
747 auto obj_list = rtree->GetObjectsAt( location, aLayer, aMinWidth );
749 if( !obj_list.empty() && zone->HitTestFilledArea( aLayer, location, aMinWidth ) )
751 contributingItems.push_back( zone );
755 if( !contributingItems.empty() )
758 BOARD_ITEM* item2 = contributingItems.size() > 1 ? contributingItems[1]
761 item1, item2, aLayer );
768 msg =
formatMsg(
_(
"(%s minimum connection width %s; actual %s)" ),
775 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
779 drce->AddItem( item );
787 done.fetch_add( calc_effort( aItemsPoly.Items, aLayer ) );
797 dataset[ { zone->
GetNetCode(), layer } ].Items.emplace( zone );
804 if(
via->FlashLayer(
static_cast<int>( layer ) ) )
805 dataset[ {
via->GetNetCode(), layer } ].Items.emplace(
via );
807 else if( track->IsOnLayer( layer ) )
809 dataset[ { track->GetNetCode(), layer } ].Items.emplace( track );
815 for(
PAD*
pad : fp->Pads() )
817 if(
pad->FlashLayer(
static_cast<int>( layer ) ) )
818 dataset[ {
pad->GetNetCode(), layer } ].Items.emplace(
pad );
826 std::vector<std::future<size_t>> returns;
827 size_t total_effort = 0;
829 for(
const auto& [ netLayer, itemsPoly ] : dataset )
830 total_effort += calc_effort( itemsPoly.Items, netLayer.Layer );
832 total_effort += std::max( (
size_t) 1, total_effort ) * distinctMinWidths.size();
834 returns.reserve( dataset.size() );
836 for(
const auto& [ netLayer, itemsPoly ] : dataset )
838 returns.emplace_back(
tp.submit( build_netlayer_polys, netLayer.Netcode, netLayer.Layer ) );
841 for( std::future<size_t>& ret : returns )
843 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
845 while( status != std::future_status::ready )
848 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
853 returns.reserve( dataset.size() * distinctMinWidths.size() );
855 for(
const auto& [ netLayer, itemsPoly ] : dataset )
857 for(
int minWidth : distinctMinWidths )
858 returns.emplace_back(
tp.submit( min_checker, itemsPoly, netLayer.Layer, minWidth ) );
861 for( std::future<size_t>& ret : returns )
863 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
865 while( status != std::future_status::ready )
868 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...
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)
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