KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider_connectivity.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <board.h>
21#include <common.h>
22
25#include <pad.h>
26#include <pcb_track.h>
27#include <zone.h>
28#include <drc/drc_item.h>
30
31
32/*
33 Connectivity test provider. Not rule-driven.
34 Errors generated:
35 - DRCE_DANGLING_TRACK
36 - DRCE_DANGLING_VIA
37 - DRCE_ISOLATED_COPPER
38*/
39
41{
42public:
45
47
48 virtual bool Run() override;
49
50 virtual const wxString GetName() const override { return wxT( "connectivity" ); };
51};
52
53
55{
56 if( !reportPhase( _( "Checking pad, via and zone connections..." ) ) )
57 return false; // DRC cancelled
58
59 BOARD* board = m_drcEngine->GetBoard();
60 std::shared_ptr<CONNECTIVITY_DATA> connectivity = board->GetConnectivity();
61
62 int progressDelta = 250;
63 int ii = 0;
64 int count = board->Tracks().size() + board->m_ZoneIsolatedIslandsMap.size();
65
66 ii += count; // We gave half of this phase to CONNECTIVITY_DATA::Build()
67 count += count;
68
69 for( PCB_TRACK* track : board->Tracks() )
70 {
71 bool exceedT = m_drcEngine->IsErrorLimitExceeded( DRCE_DANGLING_TRACK );
72 bool exceedV = m_drcEngine->IsErrorLimitExceeded( DRCE_DANGLING_VIA );
73
74 if( exceedV && exceedT )
75 break;
76 else if( track->Type() == PCB_VIA_T && exceedV )
77 continue;
78 else if( ( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T ) && exceedT )
79 continue;
80
81 if( !reportProgress( ii++, count, progressDelta ) )
82 return false; // DRC cancelled
83
84 // Test for dangling items
85 int code = track->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;
86 VECTOR2I pos;
87
88 if( connectivity->TestTrackEndpointDangling( track, true, &pos ) )
89 {
90 std::shared_ptr<DRC_ITEM> drcItem;
91
92 if( track->Type() == PCB_VIA_T )
93 {
94 auto constraint = m_drcEngine->EvalRules( VIA_DANGLING_CONSTRAINT, track, nullptr,
95 track->GetLayer() );
96
97 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
98 continue;
99
100 drcItem = DRC_ITEM::Create( code );
101 drcItem->SetViolatingRule( constraint.GetParentRule() );
102 }
103 else
104 {
105 drcItem = DRC_ITEM::Create( code );
106 }
107
108 drcItem->SetItems( track );
109 reportViolation( drcItem, pos, track->GetLayer() );
110 }
111 }
112
113 // Test for tracks connecting to post-machined or backdrilled layers
114 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_ON_POST_MACHINED_LAYER ) )
115 {
116 for( PCB_TRACK* track : board->Tracks() )
117 {
118 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_ON_POST_MACHINED_LAYER ) )
119 break;
120
121 // Only check traces and arcs (not vias)
122 if( track->Type() != PCB_TRACE_T && track->Type() != PCB_ARC_T )
123 continue;
124
125 PCB_LAYER_ID layer = track->GetLayer();
126
127 // Get items connected to this track
128 const std::list<CN_ITEM*>& items = connectivity->GetConnectivityAlgo()->ItemEntry( track ).GetItems();
129
130 if( items.empty() )
131 continue;
132
133 CN_ITEM* citem = items.front();
134
135 if( !citem->Valid() )
136 continue;
137
138 for( CN_ITEM* connected : citem->ConnectedItems() )
139 {
140 BOARD_CONNECTED_ITEM* item = connected->Parent();
141
142 if( item->GetFlags() & IS_DELETED )
143 continue;
144
145 bool isPostMachined = false;
146
147 if( item->Type() == PCB_PAD_T )
148 {
149 PAD* pad = static_cast<PAD*>( item );
150 isPostMachined = pad->IsBackdrilledOrPostMachined( layer );
151 }
152 else if( item->Type() == PCB_VIA_T )
153 {
154 PCB_VIA* via = static_cast<PCB_VIA*>( item );
155 isPostMachined = via->IsBackdrilledOrPostMachined( layer );
156 }
157
158 if( isPostMachined )
159 {
160 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACK_ON_POST_MACHINED_LAYER );
161 drcItem->SetItems( track, item );
162
163 VECTOR2I pos = ( track->GetStart() + track->GetEnd() ) / 2;
164
165 // Use the endpoint that's closer to the pad/via
166 if( item->HitTest( track->GetStart() ) )
167 pos = track->GetStart();
168 else if( item->HitTest( track->GetEnd() ) )
169 pos = track->GetEnd();
170
171 reportViolation( drcItem, pos, layer );
172 break; // Only report once per track
173 }
174 }
175 }
176 }
177
178 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_NOT_CENTERED_ON_VIA ) )
179 {
180 for( PCB_TRACK* track : board->Tracks() )
181 {
182 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_NOT_CENTERED_ON_VIA ) )
183 break;
184
185 if( track->Type() != PCB_TRACE_T && track->Type() != PCB_ARC_T )
186 continue;
187
188 const std::list<CN_ITEM*>& items = connectivity->GetConnectivityAlgo()->ItemEntry( track ).GetItems();
189
190 if( items.empty() )
191 continue;
192
193 CN_ITEM* citem = items.front();
194
195 if( !citem->Valid() )
196 continue;
197
198 for( CN_ITEM* connected : citem->ConnectedItems() )
199 {
200 BOARD_CONNECTED_ITEM* item = connected->Parent();
201
202 if( item->GetFlags() & IS_DELETED )
203 continue;
204
205 if( item->Type() != PCB_VIA_T )
206 continue;
207
208 PCB_VIA* via = static_cast<PCB_VIA*>( item );
209 VECTOR2I viaPos = via->GetPosition();
210
211 bool startInVia = via->HitTest( track->GetStart() );
212 bool endInVia = via->HitTest( track->GetEnd() );
213
214 if( !startInVia && !endInVia )
215 continue;
216
217 // Check if any track on the same layer connected to this VIA
218 // reaches its center. If so, this side is properly connected.
219 bool layerHasCenteredTrack = false;
220 PCB_LAYER_ID trackLayer = track->GetLayer();
221
222 const std::list<CN_ITEM*>& viaEntries =
223 connectivity->GetConnectivityAlgo()->ItemEntry( via ).GetItems();
224
225 if( !viaEntries.empty() )
226 {
227 for( CN_ITEM* viaConnected : viaEntries.front()->ConnectedItems() )
228 {
229 BOARD_CONNECTED_ITEM* connItem = viaConnected->Parent();
230
231 if( connItem->Type() != PCB_TRACE_T && connItem->Type() != PCB_ARC_T )
232 continue;
233
234 PCB_TRACK* connTrack = static_cast<PCB_TRACK*>( connItem );
235
236 if( connTrack->GetLayer() != trackLayer )
237 continue;
238
239 if( connTrack->GetStart() == viaPos || connTrack->GetEnd() == viaPos )
240 {
241 layerHasCenteredTrack = true;
242 break;
243 }
244 }
245 }
246
247 if( layerHasCenteredTrack )
248 continue;
249
250 if( ( startInVia && track->GetStart() != viaPos ) || ( endInVia && track->GetEnd() != viaPos ) )
251 {
252 bool startViolation = startInVia && track->GetStart() != viaPos;
253 VECTOR2I pos = startViolation ? track->GetStart() : track->GetEnd();
254
255 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACK_NOT_CENTERED_ON_VIA );
256 drcItem->SetItems( track, via );
257 reportViolation( drcItem, pos, track->GetLayer() );
258 break;
259 }
260 }
261 }
262 }
263
264 /* test starved zones */
265 for( const auto& [ zone, zoneIslands ] : board->m_ZoneIsolatedIslandsMap )
266 {
267 if( m_drcEngine->IsErrorLimitExceeded( DRCE_ISOLATED_COPPER ) )
268 break;
269
270 if( !reportProgress( ii++, count, progressDelta ) )
271 return false; // DRC cancelled
272
273 // Copper-thieving fills are netless dummy copper by definition. Every
274 // stamp is an "isolated island" but that is the intended geometry; flagging
275 // would produce thousands of false violations on a real board.
276 if( zone->IsCopperThieving() )
277 continue;
278
279 for( const auto& [ layer, layerIslands ] : zoneIslands )
280 {
281 if( !IsCopperLayer( layer ) )
282 continue;
283
284 for( int polyIdx : layerIslands.m_IsolatedOutlines )
285 {
286 if( m_drcEngine->IsErrorLimitExceeded( DRCE_ISOLATED_COPPER ) )
287 break;
288
289 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
290
291 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ISOLATED_COPPER );
292 drcItem->SetItems( zone );
293 reportViolation( drcItem, poly->Outline( polyIdx ).CPoint( 0 ), layer );
294 }
295 }
296 }
297
298 if( m_drcEngine->IsErrorLimitExceeded( DRCE_UNCONNECTED_ITEMS ) )
299 return true; // continue with other tests
300
301 if( !reportPhase( _( "Checking net connections..." ) ) )
302 return false; // DRC cancelled
303
304 ii = 0;
305 count = connectivity->GetUnconnectedCount( false );
306
307 connectivity->RunOnUnconnectedEdges(
308 [&]( CN_EDGE& edge )
309 {
310 if( m_drcEngine->IsErrorLimitExceeded( DRCE_UNCONNECTED_ITEMS ) )
311 return false;
312
313 if( !reportProgress( ii++, count, progressDelta ) )
314 return false; // DRC cancelled
315
316 wxCHECK( edge.GetSourceNode() && !edge.GetSourceNode()->Dirty(), true );
317 wxCHECK( edge.GetTargetNode() && !edge.GetTargetNode()->Dirty(), true );
318
319 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS );
320 drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() );
321 reportViolation( drcItem, edge.GetSourceNode()->Pos(), UNDEFINED_LAYER );
322
323 return true;
324 } );
325
326 return !m_drcEngine->IsCancelled();
327}
328
329
330namespace detail
331{
333}
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
std::map< ZONE *, std::map< PCB_LAYER_ID, ISOLATED_ISLANDS > > m_ZoneIsolatedIslandsMap
Definition board.h:1700
const TRACKS & Tracks() const
Definition board.h:418
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:634
const VECTOR2I & Pos() const
bool Dirty() const
BOARD_CONNECTED_ITEM * Parent() const
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
std::shared_ptr< const CN_ANCHOR > GetSourceNode() const
std::shared_ptr< const CN_ANCHOR > GetTargetNode() const
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
const std::vector< CN_ITEM * > & ConnectedItems() const
bool Valid() const
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition drc_item.cpp:417
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual ~DRC_TEST_PROVIDER_CONNECTIVITY()=default
virtual const wxString GetName() const override
virtual bool reportPhase(const wxString &aStageName)
void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, const std::function< void(PCB_MARKER *)> &aPathGenerator=[](PCB_MARKER *){})
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
virtual bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const
Test if aPosition is inside or on the boundary of this item.
Definition eda_item.h:243
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:155
Definition pad.h:61
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
const VECTOR2I & GetEnd() const
Definition pcb_track.h:90
The common library.
@ DRCE_UNCONNECTED_ITEMS
Definition drc_item.h:36
@ DRCE_TRACK_ON_POST_MACHINED_LAYER
Definition drc_item.h:115
@ DRCE_TRACK_NOT_CENTERED_ON_VIA
Definition drc_item.h:117
@ DRCE_ISOLATED_COPPER
Definition drc_item.h:45
@ DRCE_DANGLING_VIA
Definition drc_item.h:47
@ DRCE_DANGLING_TRACK
Definition drc_item.h:48
@ VIA_DANGLING_CONSTRAINT
Definition drc_rule.h:87
#define _(s)
#define IS_DELETED
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ UNDEFINED_LAYER
Definition layer_ids.h:57
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
@ RPT_SEVERITY_IGNORE
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:91
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:89
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683