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 ) ) )
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 )
255 return a->z < b->z || ( a->z == b->z
258 || ( a->i < b->i ) ) );
261 Vertex* prev_elem =
nullptr;
263 for(
Vertex* elem : queue )
266 prev_elem->
nextZ = elem;
268 elem->
prevZ = prev_elem;
272 prev_elem->
nextZ =
nullptr;
297 int32_t
zOrder(
const double aX,
const double aY )
const
302 x = ( x | ( x << 8 ) ) & 0x00FF00FF;
303 x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
304 x = ( x | ( x << 2 ) ) & 0x33333333;
305 x = ( x | ( x << 1 ) ) & 0x55555555;
307 y = ( y | ( y << 8 ) ) & 0x00FF00FF;
308 y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
309 y = ( y | ( y << 2 ) ) & 0x33333333;
310 y = ( y | ( y << 1 ) ) & 0x55555555;
312 return x | ( y << 1 );
317 return aA && aB && aA->
x == aB->
x && aA->
y == aB->
y;
390 constexpr int all_dirs = 0b1111;
401 while( !
same_point( p0, aB ) && checked < total_pts && directions != all_dirs )
430 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
432 if( directions != all_dirs )
441 while( !
same_point( p0, aB ) && checked < total_pts && directions != all_dirs )
470 wxCHECK_MSG( checked < total_pts,
false, wxT(
"Invalid polygon detected. Missing points to check" ) );
472 return ( directions == all_dirs );
484 for(
int i = 0; i < points.
PointCount(); i++ )
489 sum += ( ( p2.
x - p1.
x ) * ( p2.
y + p1.
y ) );
494 for(
int i = points.
PointCount() - 1; i >= 0; i--)
499 for(
int i = 0; i < points.
PointCount(); i++ )
503 if( tail && ( *tail == *tail->
next ) )
524 SEG::ecoord min_dist = std::numeric_limits<SEG::ecoord>::max();
527 while( p && p->
z <= maxZ )
533 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0.0
545 while( p && p->
z >= minZ )
551 if( delta_i > 1 && dist2 < limit2 && dist2 < min_dist && dist2 > 0.0
569 return ( q->
y - p->
y ) * ( r->
x - q->
x ) - ( q->
x - p->
x ) * ( r->
y - q->
y );
587 if(
area( ap, a, an ) < 0 )
588 return area( a, b, an ) >= 0 &&
area( a, ap, b ) >= 0;
590 return area( a, b, ap ) < 0 ||
area( a, an, b ) < 0;
640 if( !
reportPhase(
_(
"Checking nets for minimum connection width..." ) ) )
644 LSEQ copperLayers = copperLayerSet.
Seq();
652 std::set<int> distinctMinWidths
660 std::set<BOARD_ITEM*> Items;
664 std::unordered_map<NETCODE_LAYER_CACHE_KEY, ITEMS_POLY> dataset;
665 std::atomic<size_t> done( 1 );
668 [&](
const std::set<BOARD_ITEM*>& items,
PCB_LAYER_ID aLayer ) ->
size_t
676 ZONE* zone =
static_cast<ZONE*
>( item );
692 auto build_netlayer_polys =
693 [&](
int aNetcode,
const PCB_LAYER_ID aLayer ) ->
size_t
698 ITEMS_POLY& itemsPoly = dataset[ { aNetcode, aLayer } ];
708 done.fetch_add( calc_effort( itemsPoly.Items, aLayer ) );
717 [&](
const ITEMS_POLY& aItemsPoly,
const PCB_LAYER_ID aLayer,
int aMinWidth ) ->
size_t
724 for(
int ii = 0; ii < aItemsPoly.Poly.OutlineCount(); ++ii )
728 test.FindPairs( chain );
729 auto& ret =
test.GetVertices();
731 for(
const std::pair<int, int>& pt : ret )
747 std::vector<BOARD_ITEM*> contributingItems;
753 if( item->HitTest( location, aMinWidth ) )
754 contributingItems.push_back( item );
759 if( !rtree->GetObjectsAt( location, aLayer, aMinWidth ).empty()
760 && zone->HitTestFilledArea( aLayer, location, aMinWidth ) )
762 contributingItems.push_back( zone );
766 if( !contributingItems.empty() )
769 BOARD_ITEM* item2 = contributingItems.size() > 1 ? contributingItems[1]
772 item1, item2, aLayer );
779 msg =
formatMsg(
_(
"(%s minimum connection width %s; actual %s)" ),
786 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
790 drce->AddItem( item );
798 done.fetch_add( calc_effort( aItemsPoly.Items, aLayer ) );
808 dataset[ { zone->
GetNetCode(), layer } ].Items.emplace( zone );
815 if(
via->FlashLayer(
static_cast<int>( layer ) ) )
816 dataset[ {
via->GetNetCode(), layer } ].Items.emplace(
via );
818 else if( track->IsOnLayer( layer ) )
820 dataset[ { track->GetNetCode(), layer } ].Items.emplace( track );
826 for(
PAD*
pad : fp->Pads() )
828 if(
pad->FlashLayer(
static_cast<int>( layer ) ) )
829 dataset[ {
pad->GetNetCode(), layer } ].Items.emplace(
pad );
837 std::vector<std::future<size_t>> returns;
838 size_t total_effort = 0;
840 for(
const auto& [ netLayer, itemsPoly ] : dataset )
841 total_effort += calc_effort( itemsPoly.Items, netLayer.Layer );
843 total_effort += std::max( (
size_t) 1, total_effort ) * distinctMinWidths.size();
845 returns.reserve( dataset.size() );
847 for(
const auto& [ netLayer, itemsPoly ] : dataset )
849 returns.emplace_back(
tp.submit( build_netlayer_polys, netLayer.Netcode, netLayer.Layer ) );
852 for( std::future<size_t>& ret : returns )
854 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
856 while( status != std::future_status::ready )
859 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
864 returns.reserve( dataset.size() * distinctMinWidths.size() );
866 for(
const auto& [ netLayer, itemsPoly ] : dataset )
868 for(
int minWidth : distinctMinWidths )
869 returns.emplace_back(
tp.submit( min_checker, itemsPoly, netLayer.Layer, minWidth ) );
872 for( std::future<size_t>& ret : returns )
874 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
876 while( status != std::future_status::ready )
879 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::unique_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)
BOARD_DESIGN_SETTINGS * GetDesignSettings() const
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_ITEMs and po...
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...
POLYGON_TEST(int aLimit, int aErrorLimit)
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:
bool signbit(T v)
Integral version of std::signbit that works all compilers.
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
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