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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <board.h>
25#include <common.h>
26
29#include <pad.h>
30#include <pcb_track.h>
31#include <zone.h>
32#include <drc/drc_item.h>
34
35
36/*
37 Connectivity test provider. Not rule-driven.
38 Errors generated:
39 - DRCE_DANGLING_TRACK
40 - DRCE_DANGLING_VIA
41 - DRCE_ISOLATED_COPPER
42*/
43
45{
46public:
49
51
52 virtual bool Run() override;
53
54 virtual const wxString GetName() const override { return wxT( "connectivity" ); };
55};
56
57
59{
60 if( !reportPhase( _( "Checking pad, via and zone connections..." ) ) )
61 return false; // DRC cancelled
62
63 BOARD* board = m_drcEngine->GetBoard();
64 std::shared_ptr<CONNECTIVITY_DATA> connectivity = board->GetConnectivity();
65
66 int progressDelta = 250;
67 int ii = 0;
68 int count = board->Tracks().size() + board->m_ZoneIsolatedIslandsMap.size();
69
70 ii += count; // We gave half of this phase to CONNECTIVITY_DATA::Build()
71 count += count;
72
73 for( PCB_TRACK* track : board->Tracks() )
74 {
75 bool exceedT = m_drcEngine->IsErrorLimitExceeded( DRCE_DANGLING_TRACK );
76 bool exceedV = m_drcEngine->IsErrorLimitExceeded( DRCE_DANGLING_VIA );
77
78 if( exceedV && exceedT )
79 break;
80 else if( track->Type() == PCB_VIA_T && exceedV )
81 continue;
82 else if( ( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T ) && exceedT )
83 continue;
84
85 if( !reportProgress( ii++, count, progressDelta ) )
86 return false; // DRC cancelled
87
88 // Test for dangling items
89 int code = track->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK;
90 VECTOR2I pos;
91
92 if( connectivity->TestTrackEndpointDangling( track, true, &pos ) )
93 {
94 std::shared_ptr<DRC_ITEM> drcItem;
95
96 if( track->Type() == PCB_VIA_T )
97 {
98 auto constraint = m_drcEngine->EvalRules( VIA_DANGLING_CONSTRAINT, track, nullptr,
99 track->GetLayer() );
100
101 if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
102 continue;
103
104 drcItem = DRC_ITEM::Create( code );
105 drcItem->SetViolatingRule( constraint.GetParentRule() );
106 }
107 else
108 {
109 drcItem = DRC_ITEM::Create( code );
110 }
111
112 drcItem->SetItems( track );
113 reportViolation( drcItem, pos, track->GetLayer() );
114 }
115 }
116
117 // Test for tracks connecting to post-machined or backdrilled layers
118 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_ON_POST_MACHINED_LAYER ) )
119 {
120 for( PCB_TRACK* track : board->Tracks() )
121 {
122 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_ON_POST_MACHINED_LAYER ) )
123 break;
124
125 // Only check traces and arcs (not vias)
126 if( track->Type() != PCB_TRACE_T && track->Type() != PCB_ARC_T )
127 continue;
128
129 PCB_LAYER_ID layer = track->GetLayer();
130
131 // Get items connected to this track
132 const std::list<CN_ITEM*>& items = connectivity->GetConnectivityAlgo()->ItemEntry( track ).GetItems();
133
134 if( items.empty() )
135 continue;
136
137 CN_ITEM* citem = items.front();
138
139 if( !citem->Valid() )
140 continue;
141
142 for( CN_ITEM* connected : citem->ConnectedItems() )
143 {
144 BOARD_CONNECTED_ITEM* item = connected->Parent();
145
146 if( item->GetFlags() & IS_DELETED )
147 continue;
148
149 bool isPostMachined = false;
150
151 if( item->Type() == PCB_PAD_T )
152 {
153 PAD* pad = static_cast<PAD*>( item );
154 isPostMachined = pad->IsBackdrilledOrPostMachined( layer );
155 }
156 else if( item->Type() == PCB_VIA_T )
157 {
158 PCB_VIA* via = static_cast<PCB_VIA*>( item );
159 isPostMachined = via->IsBackdrilledOrPostMachined( layer );
160 }
161
162 if( isPostMachined )
163 {
164 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACK_ON_POST_MACHINED_LAYER );
165 drcItem->SetItems( track, item );
166
167 VECTOR2I pos = ( track->GetStart() + track->GetEnd() ) / 2;
168
169 // Use the endpoint that's closer to the pad/via
170 if( item->HitTest( track->GetStart() ) )
171 pos = track->GetStart();
172 else if( item->HitTest( track->GetEnd() ) )
173 pos = track->GetEnd();
174
175 reportViolation( drcItem, pos, layer );
176 break; // Only report once per track
177 }
178 }
179 }
180 }
181
182 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_NOT_CENTERED_ON_VIA ) )
183 {
184 for( PCB_TRACK* track : board->Tracks() )
185 {
186 if( m_drcEngine->IsErrorLimitExceeded( DRCE_TRACK_NOT_CENTERED_ON_VIA ) )
187 break;
188
189 if( track->Type() != PCB_TRACE_T && track->Type() != PCB_ARC_T )
190 continue;
191
192 const std::list<CN_ITEM*>& items = connectivity->GetConnectivityAlgo()->ItemEntry( track ).GetItems();
193
194 if( items.empty() )
195 continue;
196
197 CN_ITEM* citem = items.front();
198
199 if( !citem->Valid() )
200 continue;
201
202 for( CN_ITEM* connected : citem->ConnectedItems() )
203 {
204 BOARD_CONNECTED_ITEM* item = connected->Parent();
205
206 if( item->GetFlags() & IS_DELETED )
207 continue;
208
209 if( item->Type() != PCB_VIA_T )
210 continue;
211
212 PCB_VIA* via = static_cast<PCB_VIA*>( item );
213 VECTOR2I viaPos = via->GetPosition();
214
215 bool startInVia = via->HitTest( track->GetStart() );
216 bool endInVia = via->HitTest( track->GetEnd() );
217
218 if( !startInVia && !endInVia )
219 continue;
220
221 // Check if any track on the same layer connected to this VIA
222 // reaches its center. If so, this side is properly connected.
223 bool layerHasCenteredTrack = false;
224 PCB_LAYER_ID trackLayer = track->GetLayer();
225
226 const std::list<CN_ITEM*>& viaEntries =
227 connectivity->GetConnectivityAlgo()->ItemEntry( via ).GetItems();
228
229 if( !viaEntries.empty() )
230 {
231 for( CN_ITEM* viaConnected : viaEntries.front()->ConnectedItems() )
232 {
233 BOARD_CONNECTED_ITEM* connItem = viaConnected->Parent();
234
235 if( connItem->Type() != PCB_TRACE_T && connItem->Type() != PCB_ARC_T )
236 continue;
237
238 PCB_TRACK* connTrack = static_cast<PCB_TRACK*>( connItem );
239
240 if( connTrack->GetLayer() != trackLayer )
241 continue;
242
243 if( connTrack->GetStart() == viaPos || connTrack->GetEnd() == viaPos )
244 {
245 layerHasCenteredTrack = true;
246 break;
247 }
248 }
249 }
250
251 if( layerHasCenteredTrack )
252 continue;
253
254 if( ( startInVia && track->GetStart() != viaPos ) || ( endInVia && track->GetEnd() != viaPos ) )
255 {
256 bool startViolation = startInVia && track->GetStart() != viaPos;
257 VECTOR2I pos = startViolation ? track->GetStart() : track->GetEnd();
258
259 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_TRACK_NOT_CENTERED_ON_VIA );
260 drcItem->SetItems( track, via );
261 reportViolation( drcItem, pos, track->GetLayer() );
262 break;
263 }
264 }
265 }
266 }
267
268 /* test starved zones */
269 for( const auto& [ zone, zoneIslands ] : board->m_ZoneIsolatedIslandsMap )
270 {
271 if( m_drcEngine->IsErrorLimitExceeded( DRCE_ISOLATED_COPPER ) )
272 break;
273
274 if( !reportProgress( ii++, count, progressDelta ) )
275 return false; // DRC cancelled
276
277 for( const auto& [ layer, layerIslands ] : zoneIslands )
278 {
279 if( !IsCopperLayer( layer ) )
280 continue;
281
282 for( int polyIdx : layerIslands.m_IsolatedOutlines )
283 {
284 if( m_drcEngine->IsErrorLimitExceeded( DRCE_ISOLATED_COPPER ) )
285 break;
286
287 std::shared_ptr<SHAPE_POLY_SET> poly = zone->GetFilledPolysList( layer );
288
289 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ISOLATED_COPPER );
290 drcItem->SetItems( zone );
291 reportViolation( drcItem, poly->Outline( polyIdx ).CPoint( 0 ), layer );
292 }
293 }
294 }
295
296 if( m_drcEngine->IsErrorLimitExceeded( DRCE_UNCONNECTED_ITEMS ) )
297 return true; // continue with other tests
298
299 if( !reportPhase( _( "Checking net connections..." ) ) )
300 return false; // DRC cancelled
301
302 ii = 0;
303 count = connectivity->GetUnconnectedCount( false );
304
305 connectivity->RunOnUnconnectedEdges(
306 [&]( CN_EDGE& edge )
307 {
308 if( m_drcEngine->IsErrorLimitExceeded( DRCE_UNCONNECTED_ITEMS ) )
309 return false;
310
311 if( !reportProgress( ii++, count, progressDelta ) )
312 return false; // DRC cancelled
313
314 wxCHECK( edge.GetSourceNode() && !edge.GetSourceNode()->Dirty(), true );
315 wxCHECK( edge.GetTargetNode() && !edge.GetTargetNode()->Dirty(), true );
316
317 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS );
318 drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() );
319 reportViolation( drcItem, edge.GetSourceNode()->Pos(), UNDEFINED_LAYER );
320
321 return true;
322 } );
323
324 return !m_drcEngine->IsCancelled();
325}
326
327
328namespace detail
329{
331}
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:322
std::map< ZONE *, std::map< PCB_LAYER_ID, ISOLATED_ISLANDS > > m_ZoneIsolatedIslandsMap
Definition board.h:1493
const TRACKS & Tracks() const
Definition board.h:361
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:563
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:405
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:111
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:239
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:151
Definition pad.h:55
const VECTOR2I & GetStart() const
Definition pcb_track.h:97
const VECTOR2I & GetEnd() const
Definition pcb_track.h:94
The common library.
@ DRCE_UNCONNECTED_ITEMS
Definition drc_item.h:40
@ DRCE_TRACK_ON_POST_MACHINED_LAYER
Definition drc_item.h:116
@ DRCE_TRACK_NOT_CENTERED_ON_VIA
Definition drc_item.h:118
@ DRCE_ISOLATED_COPPER
Definition drc_item.h:49
@ DRCE_DANGLING_VIA
Definition drc_item.h:51
@ DRCE_DANGLING_TRACK
Definition drc_item.h:52
@ VIA_DANGLING_CONSTRAINT
Definition drc_rule.h:82
#define _(s)
#define IS_DELETED
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:677
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
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:97
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695