KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider_misc.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 (C) 2004-2023 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
25#include <drc/drc_engine.h>
26#include <drc/drc_item.h>
27#include <drc/drc_rule.h>
30#include <pad.h>
31#include <pcb_track.h>
32
35
36/*
37 Miscellaneous tests:
38
39 - DRCE_DISABLED_LAYER_ITEM, ///< item on a disabled layer
40 - DRCE_INVALID_OUTLINE, ///< invalid board outline
41 - DRCE_UNRESOLVED_VARIABLE,
42 - DRCE_ASSERTION_FAILURE, ///< user-defined assertions
43 - DRCE_GENERIC_WARNING ///< user-defined warnings
44 - DRCE_GENERIC_ERROR ///< user-defined errors
45*/
46
48{
49public:
51 m_board( nullptr )
52 {
53 m_isRuleDriven = false;
54 }
55
57 {
58 }
59
60 virtual bool Run() override;
61
62 virtual const wxString GetName() const override
63 {
64 return wxT( "miscellaneous" );
65 };
66
67 virtual const wxString GetDescription() const override
68 {
69 return wxT( "Misc checks (board outline, missing textvars)" );
70 }
71
72private:
73 void testOutline();
74 void testDisabledLayers();
75 void testTextVars();
76 void testAssertions();
77
79};
80
81
83{
84 SHAPE_POLY_SET dummyOutline;
85 bool errorHandled = false;
86
87 OUTLINE_ERROR_HANDLER errorHandler =
88 [&]( const wxString& msg, BOARD_ITEM* itemA, BOARD_ITEM* itemB, const VECTOR2I& pt )
89 {
90 errorHandled = true;
91
93 return;
94
95 if( !itemA ) // If we only have a single item, make sure it's A
96 std::swap( itemA, itemB );
97
98 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
99
100 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
101 drcItem->SetItems( itemA, itemB );
102
103 reportViolation( drcItem, pt, Edge_Cuts );
104 };
105
106 // Test for very small graphic items (a few nm size) that can create issues
107 // when trying to build the board outlines, and they are not easy to locate onn screen.
108 const int minSizeForValideGraphics = pcbIUScale.mmToIU( 0.001 );
109
110 if( !TestBoardOutlinesGraphicItems(m_board, minSizeForValideGraphics, &errorHandler ) )
111 {
112 if( errorHandled )
113 {
114 // if there are invalid items on Edge.Cuts, they are already reported
115 }
116 else
117 {
118 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
119 wxString msg;
120
121 msg.Printf( _( "(Suspicious items found on Edge.Cuts layer)" ) );
122
123 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
124 drcItem->SetItems( m_board );
125
127 }
128 }
129
130
131 // Use the standard chaining epsilon here so that we report errors that might affect
132 // other tools (such as 3D viewer).
133 int chainingEpsilon = m_board->GetOutlinesChainingEpsilon();
134
136 chainingEpsilon, &errorHandler ) )
137 {
138 if( errorHandled )
139 {
140 // if there is an invalid outline, then there must be an outline
141 }
142 else
143 {
144 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
145 wxString msg;
146
147 msg.Printf( _( "(no edges found on Edge.Cuts layer)" ) );
148
149 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
150 drcItem->SetItems( m_board );
151
153 }
154 }
155}
156
157
159{
160 const int progressDelta = 2000;
161 int ii = 0;
162 int items = 0;
163
164 auto countItems =
165 [&]( BOARD_ITEM* item ) -> bool
166 {
167 ++items;
168 return true;
169 };
170
171 LSET disabledLayers = m_board->GetEnabledLayers().flip();
172
173 // Perform the test only for copper layers
174 disabledLayers &= LSET::AllCuMask();
175
176 auto checkDisabledLayers =
177 [&]( BOARD_ITEM* item ) -> bool
178 {
180 return false;
181
182 if( !reportProgress( ii++, items, progressDelta ) )
183 return false;
184
185 PCB_LAYER_ID badLayer = UNDEFINED_LAYER;
186
187 if( item->Type() == PCB_PAD_T )
188 {
189 PAD* pad = static_cast<PAD*>( item );
190
191 if( pad->GetAttribute() == PAD_ATTRIB::SMD
192 || pad->GetAttribute() == PAD_ATTRIB::CONN )
193 {
194 if( disabledLayers.test( pad->GetPrincipalLayer() ) )
195 badLayer = item->GetLayer();
196 }
197 else
198 {
199 // Through hole pad pierces all physical layers.
200 }
201 }
202 else if( item->Type() == PCB_VIA_T )
203 {
204 PCB_VIA* via = static_cast<PCB_VIA*>( item );
205 PCB_LAYER_ID top;
206 PCB_LAYER_ID bottom;
207
208 via->LayerPair( &top, &bottom );
209
210 if( disabledLayers.test( top ) )
211 badLayer = top;
212 else if( disabledLayers.test( bottom ) )
213 badLayer = bottom;
214 }
215 else if( item->Type() == PCB_ZONE_T )
216 {
217 // Footprint zones just get a top/bottom/inner setting, so they're on
218 // whatever inner layers there are.
219 }
220 else
221 {
222 LSET badLayers = disabledLayers & item->GetLayerSet();
223
224 if( badLayers.any() )
225 badLayer = badLayers.Seq().front();
226 }
227
228 if( badLayer != UNDEFINED_LAYER )
229 {
231 wxString msg;
232
233 msg.Printf( _( "(layer %s)" ), LayerName( badLayer ) );
234
235 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
236 drcItem->SetItems( item );
237
238 reportViolation( drcItem, item->GetPosition(), UNDEFINED_LAYER );
239 }
240
241 return true;
242 };
243
246}
247
248
250{
251 const int progressDelta = 2000;
252 int ii = 0;
253 int items = 0;
254
255 auto countItems =
256 [&]( BOARD_ITEM* item ) -> bool
257 {
258 ++items;
259 return true;
260 };
261
262 auto checkAssertions =
263 [&]( BOARD_ITEM* item ) -> bool
264 {
265 if( !reportProgress( ii++, items, progressDelta ) )
266 return false;
267
269 {
271 [&]( const DRC_CONSTRAINT* c )
272 {
274 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " (" )
275 + c->GetName() + wxS( ")" ) );
276 drcItem->SetItems( item );
277 drcItem->SetViolatingRule( c->GetParentRule() );
278
279 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
280 } );
281 }
282
283 return true;
284 };
285
286 forEachGeometryItem( {}, LSET::AllLayersMask(), countItems );
287 forEachGeometryItem( {}, LSET::AllLayersMask(), checkAssertions );
288}
289
290
292{
293 const int progressDelta = 2000;
294 int ii = 0;
295 int items = 0;
296
297 static const std::vector<KICAD_T> itemTypes = {
302 };
303
304 auto testAssertion =
305 [&]( BOARD_ITEM* item, const wxString& text, const VECTOR2I& pos, int layer )
306 {
307 static wxRegEx warningExpr( wxS( "^\\$\\{DRC_WARNING\\s*([^}]*)\\}(.*)$" ) );
308 static wxRegEx errorExpr( wxS( "^\\$\\{DRC_ERROR\\s*([^}]*)\\}(.*)$" ) );
309
310 if( warningExpr.Matches( text ) )
311 {
313 {
314 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_WARNING );
315 wxString drcText = warningExpr.GetMatch( text, 1 );
316
317 if( item )
318 drcItem->SetItems( item );
319 else
320 drcText += _( " (in drawing sheet)" );
321
322 drcItem->SetErrorMessage( drcText );
323
324 reportViolation( drcItem, pos, layer );
325 }
326
327 return true;
328 }
329
330 if( errorExpr.Matches( text ) )
331 {
333 {
334 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_ERROR );
335 wxString drcText = errorExpr.GetMatch( text, 1 );
336
337 if( item )
338 drcItem->SetItems( item );
339 else
340 drcText += _( " (in drawing sheet)" );
341
342 drcItem->SetErrorMessage( drcText );
343
344 reportViolation( drcItem, pos, layer );
345 }
346
347 return true;
348 }
349
350 return false;
351 };
352
354 [&]( BOARD_ITEM* item ) -> bool
355 {
356 ++items;
357 return true;
358 } );
359
361 [&]( BOARD_ITEM* item ) -> bool
362 {
364 return false;
365
366 if( !reportProgress( ii++, items, progressDelta ) )
367 return false;
368
369 if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( item ) )
370 {
371 wxString result = ExpandEnvVarSubstitutions( textItem->GetShownText( true ),
372 nullptr /*project already done*/ );
373
374 if( result.Matches( wxT( "*${*}*" ) ) )
375 {
377 drcItem->SetItems( item );
378
379 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
380 }
381
382 testAssertion( item, textItem->GetText(), item->GetPosition(), item->GetLayer() );
383 }
384
385 return true;
386 } );
387
390
392 return;
393
394 drawItems.SetPageNumber( wxT( "1" ) );
395 drawItems.SetSheetCount( 1 );
396 drawItems.SetFileName( wxT( "dummyFilename" ) );
397 drawItems.SetSheetName( wxT( "dummySheet" ) );
398 drawItems.SetSheetLayer( wxT( "dummyLayer" ) );
399 drawItems.SetProject( m_board->GetProject() );
400 drawItems.BuildDrawItemsList( drawingSheet->GetPageInfo(), drawingSheet->GetTitleBlock() );
401
402 for( DS_DRAW_ITEM_BASE* item = drawItems.GetFirst(); item; item = drawItems.GetNext() )
403 {
405 break;
406
407 if( m_drcEngine->IsCancelled() )
408 return;
409
410 if( DS_DRAW_ITEM_TEXT* text = dynamic_cast<DS_DRAW_ITEM_TEXT*>( item ) )
411 {
412 if( testAssertion( nullptr, text->GetText(), text->GetPosition(), LAYER_DRAWINGSHEET ) )
413 {
414 // Don't run unresolved test
415 }
416 else if( text->GetShownText( true ).Matches( wxT( "*${*}*" ) ) )
417 {
418 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
419 drcItem->SetItems( drawingSheet );
420
421 reportViolation( drcItem, text->GetPosition(), LAYER_DRAWINGSHEET );
422 }
423 }
424 }
425}
426
427
429{
431
433 {
434 if( !reportPhase( _( "Checking board outline..." ) ) )
435 return false; // DRC cancelled
436
437 testOutline();
438 }
439
441 {
442 if( !reportPhase( _( "Checking disabled layers..." ) ) )
443 return false; // DRC cancelled
444
446 }
447
449 {
450 if( !reportPhase( _( "Checking text variables..." ) ) )
451 return false; // DRC cancelled
452
453 testTextVars();
454 }
455
459 {
460 if( !reportPhase( _( "Checking assertions..." ) ) )
461 return false; // DRC cancelled
462
464 }
465
466 return !m_drcEngine->IsCancelled();
467}
468
469
470namespace detail
471{
473}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
BASE_SET & flip(size_t pos)
Definition: base_set.h:159
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:237
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:778
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: board.h:915
int GetOutlinesChainingEpsilon()
Definition: board.h:739
PROJECT * GetProject() const
Definition: board.h:491
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:895
constexpr Vec Centre() const
Definition: box2.h:97
wxString GetName() const
Definition: drc_rule.h:160
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:156
DS_PROXY_VIEW_ITEM * GetDrawingSheet() const
Definition: drc_engine.h:105
BOARD * GetBoard() const
Definition: drc_engine.h:96
bool IsErrorLimitExceeded(int error_code)
void ProcessAssertions(const BOARD_ITEM *a, std::function< void(const DRC_CONSTRAINT *)> aFailureHandler, REPORTER *aReporter=nullptr)
bool IsCancelled() const
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:395
virtual const wxString GetName() const override
virtual const wxString GetDescription() const override
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out DRC_ITEM and posi...
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, LSET aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER *aCustomHandler=nullptr)
static std::vector< KICAD_T > s_allBasicItems
DRC_ENGINE * m_drcEngine
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
Base class to handle basic graphic items.
Definition: ds_draw_item.h:59
Store the list of graphic items: rect, lines, polygons and texts to draw/plot the title block and fra...
Definition: ds_draw_item.h:401
DS_DRAW_ITEM_BASE * GetFirst()
Definition: ds_draw_item.h:512
void BuildDrawItemsList(const PAGE_INFO &aPageInfo, const TITLE_BLOCK &aTitleBlock)
Drawing or plot the drawing sheet.
void SetFileName(const wxString &aFileName)
Set the filename to draw/plot.
Definition: ds_draw_item.h:445
void SetSheetName(const wxString &aSheetName)
Set the sheet name to draw/plot.
Definition: ds_draw_item.h:450
void SetSheetLayer(const wxString &aSheetLayer)
Set the sheet layer to draw/plot.
Definition: ds_draw_item.h:460
void SetSheetCount(int aSheetCount)
Set the value of the count of sheets, for basic inscriptions.
Definition: ds_draw_item.h:499
void SetPageNumber(const wxString &aPageNumber)
Set the value of the sheet number.
Definition: ds_draw_item.h:489
DS_DRAW_ITEM_BASE * GetNext()
Definition: ds_draw_item.h:522
void SetProject(const PROJECT *aProject)
Definition: ds_draw_item.h:425
A graphic text.
Definition: ds_draw_item.h:313
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:243
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:80
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
static LSET AllLayersMask()
Definition: lset.cpp:711
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:686
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:420
Definition: pad.h:54
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pad.cpp:312
Represent a set of closed polygons.
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:348
#define FOR_ERC_DRC
Expand '${var-name}' templates in text.
Definition: common.h:91
bool TestBoardOutlinesGraphicItems(BOARD *aBoard, int aMinDist, OUTLINE_ERROR_HANDLER *aErrorHandler)
Test a board graphic items on edge cut layer for validity.
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, OUTLINE_ERROR_HANDLER *aErrorHandler, bool aAllowUseArcsInPolygons)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const VECTOR2I &pt)> OUTLINE_ERROR_HANDLER
@ DRCE_DISABLED_LAYER_ITEM
Definition: drc_item.h:71
@ DRCE_INVALID_OUTLINE
Definition: drc_item.h:72
@ DRCE_GENERIC_ERROR
Definition: drc_item.h:90
@ DRCE_UNRESOLVED_VARIABLE
Definition: drc_item.h:87
@ DRCE_ASSERTION_FAILURE
Definition: drc_item.h:88
@ DRCE_GENERIC_WARNING
Definition: drc_item.h:89
#define _(s)
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition: layer_id.cpp:31
@ LAYER_DRAWINGSHEET
drawingsheet frame and titleblock
Definition: layer_ids.h:218
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ Edge_Cuts
Definition: layer_ids.h:112
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100