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 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
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
135 // Arc to segment approximation error (not critical here: we do not use the outline shape):
136 int maxError = pcbIUScale.mmToIU( 0.05 );
137
138 if( !BuildBoardPolygonOutlines( m_board, dummyOutline, maxError, chainingEpsilon, &errorHandler ) )
139 {
140 if( errorHandled )
141 {
142 // if there is an invalid outline, then there must be an outline
143 }
144 else
145 {
146 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE );
147 wxString msg;
148
149 msg.Printf( _( "(no edges found on Edge.Cuts layer)" ) );
150
151 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
152 drcItem->SetItems( m_board );
153
155 }
156 }
157}
158
159
161{
162 const int progressDelta = 2000;
163 int ii = 0;
164 int items = 0;
165
166 auto countItems =
167 [&]( BOARD_ITEM* item ) -> bool
168 {
169 ++items;
170 return true;
171 };
172
173 LSET disabledLayers = LSET( m_board->GetEnabledLayers() ).flip();
174
175 // Perform the test only for copper layers
176 disabledLayers &= LSET::AllCuMask();
177
178 auto checkDisabledLayers =
179 [&]( BOARD_ITEM* item ) -> bool
180 {
182 return false;
183
184 if( !reportProgress( ii++, items, progressDelta ) )
185 return false;
186
187 PCB_LAYER_ID badLayer = UNDEFINED_LAYER;
188
189 if( item->Type() == PCB_PAD_T )
190 {
191 PAD* pad = static_cast<PAD*>( item );
192
193 if( pad->GetAttribute() == PAD_ATTRIB::SMD
194 || pad->GetAttribute() == PAD_ATTRIB::CONN )
195 {
196 if( disabledLayers.test( pad->GetPrincipalLayer() ) )
197 badLayer = item->GetLayer();
198 }
199 else
200 {
201 // Through hole pad pierces all physical layers.
202 }
203 }
204 else if( item->Type() == PCB_VIA_T )
205 {
206 PCB_VIA* via = static_cast<PCB_VIA*>( item );
207 PCB_LAYER_ID top;
208 PCB_LAYER_ID bottom;
209
210 via->LayerPair( &top, &bottom );
211
212 if( disabledLayers.test( top ) )
213 badLayer = top;
214 else if( disabledLayers.test( bottom ) )
215 badLayer = bottom;
216 }
217 else if( item->Type() == PCB_ZONE_T )
218 {
219 // Footprint zones just get a top/bottom/inner setting, so they're on
220 // whatever inner layers there are.
221 }
222 else
223 {
224 LSET badLayers = disabledLayers & item->GetLayerSet();
225
226 if( badLayers.any() )
227 badLayer = badLayers.Seq().front();
228 }
229
230 if( badLayer != UNDEFINED_LAYER )
231 {
233 wxString msg;
234
235 msg.Printf( _( "(layer %s)" ), LayerName( badLayer ) );
236
237 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
238 drcItem->SetItems( item );
239
240 reportViolation( drcItem, item->GetPosition(), UNDEFINED_LAYER );
241 }
242
243 return true;
244 };
245
248}
249
250
252{
253 const int progressDelta = 2000;
254 int ii = 0;
255 int items = 0;
256
257 auto countItems =
258 [&]( BOARD_ITEM* item ) -> bool
259 {
260 ++items;
261 return true;
262 };
263
264 auto checkAssertions =
265 [&]( BOARD_ITEM* item ) -> bool
266 {
267 if( !reportProgress( ii++, items, progressDelta ) )
268 return false;
269
271 {
273 [&]( const DRC_CONSTRAINT* c )
274 {
276 drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " (" )
277 + c->GetName() + wxS( ")" ) );
278 drcItem->SetItems( item );
279 drcItem->SetViolatingRule( c->GetParentRule() );
280
281 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
282 } );
283 }
284
285 return true;
286 };
287
288 forEachGeometryItem( {}, LSET::AllLayersMask(), countItems );
289 forEachGeometryItem( {}, LSET::AllLayersMask(), checkAssertions );
290}
291
292
294{
295 const int progressDelta = 2000;
296 int ii = 0;
297 int items = 0;
298
299 static const std::vector<KICAD_T> itemTypes = {
303 };
304
305 auto testAssertion =
306 [&]( BOARD_ITEM* item, const wxString& text, const VECTOR2I& pos, int layer )
307 {
308 static wxRegEx warningExpr( wxS( "^\\$\\{DRC_WARNING\\s*([^}]*)\\}(.*)$" ) );
309 static wxRegEx errorExpr( wxS( "^\\$\\{DRC_ERROR\\s*([^}]*)\\}(.*)$" ) );
310
311 if( warningExpr.Matches( text ) )
312 {
314 {
315 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_WARNING );
316 wxString drcText = warningExpr.GetMatch( text, 1 );
317
318 if( item )
319 drcItem->SetItems( item );
320 else
321 drcText += _( " (in drawing sheet)" );
322
323 drcItem->SetErrorMessage( drcText );
324
325 reportViolation( drcItem, pos, layer );
326 }
327
328 return true;
329 }
330
331 if( errorExpr.Matches( text ) )
332 {
334 {
335 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_GENERIC_ERROR );
336 wxString drcText = errorExpr.GetMatch( text, 1 );
337
338 if( item )
339 drcItem->SetItems( item );
340 else
341 drcText += _( " (in drawing sheet)" );
342
343 drcItem->SetErrorMessage( drcText );
344
345 reportViolation( drcItem, pos, layer );
346 }
347
348 return true;
349 }
350
351 return false;
352 };
353
355 [&]( BOARD_ITEM* item ) -> bool
356 {
357 ++items;
358 return true;
359 } );
360
362 [&]( BOARD_ITEM* item ) -> bool
363 {
365 return false;
366
367 if( !reportProgress( ii++, items, progressDelta ) )
368 return false;
369
370 if( EDA_TEXT* textItem = dynamic_cast<EDA_TEXT*>( item ) )
371 {
372 wxString result = ExpandEnvVarSubstitutions( textItem->GetShownText( true ),
373 nullptr /*project already done*/ );
374
375 if( result.Matches( wxT( "*${*}*" ) ) )
376 {
378 drcItem->SetItems( item );
379
380 reportViolation( drcItem, item->GetPosition(), item->GetLayer() );
381 }
382
383 testAssertion( item, textItem->GetText(), item->GetPosition(), item->GetLayer() );
384 }
385
386 return true;
387 } );
388
391
393 return;
394
395 drawItems.SetPageNumber( wxT( "1" ) );
396 drawItems.SetSheetCount( 1 );
397 drawItems.SetFileName( wxT( "dummyFilename" ) );
398 drawItems.SetSheetName( wxT( "dummySheet" ) );
399 drawItems.SetSheetLayer( wxT( "dummyLayer" ) );
400 drawItems.SetProject( m_board->GetProject() );
401 drawItems.BuildDrawItemsList( drawingSheet->GetPageInfo(), drawingSheet->GetTitleBlock() );
402
403 for( DS_DRAW_ITEM_BASE* item = drawItems.GetFirst(); item; item = drawItems.GetNext() )
404 {
406 break;
407
408 if( m_drcEngine->IsCancelled() )
409 return;
410
411 if( DS_DRAW_ITEM_TEXT* text = dynamic_cast<DS_DRAW_ITEM_TEXT*>( item ) )
412 {
413 if( testAssertion( nullptr, text->GetText(), text->GetPosition(), LAYER_DRAWINGSHEET ) )
414 {
415 // Don't run unresolved test
416 }
417 else if( text->GetShownText( true ).Matches( wxT( "*${*}*" ) ) )
418 {
419 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE );
420 drcItem->SetItems( drawingSheet );
421
422 reportViolation( drcItem, text->GetPosition(), LAYER_DRAWINGSHEET );
423 }
424 }
425 }
426}
427
428
430{
432
434 {
435 if( !reportPhase( _( "Checking board outline..." ) ) )
436 return false; // DRC cancelled
437
438 testOutline();
439 }
440
442 {
443 if( !reportPhase( _( "Checking disabled layers..." ) ) )
444 return false; // DRC cancelled
445
447 }
448
450 {
451 if( !reportPhase( _( "Checking text variables..." ) ) )
452 return false; // DRC cancelled
453
454 testTextVars();
455 }
456
460 {
461 if( !reportPhase( _( "Checking assertions..." ) ) )
462 return false; // DRC cancelled
463
465 }
466
467 return !m_drcEngine->IsCancelled();
468}
469
470
471namespace detail
472{
474}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:110
BASE_SET & flip(size_t pos)
Definition: base_set.h:160
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:78
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:229
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:297
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: board.h:941
int GetOutlinesChainingEpsilon()
Definition: board.h:765
PROJECT * GetProject() const
Definition: board.h:511
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:838
constexpr Vec Centre() const
Definition: box2.h:97
wxString GetName() const
Definition: drc_rule.h:165
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:161
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:393
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)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER *aCustomHandler=nullptr)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
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:256
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:583
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:297
static const LSET & AllLayersMask()
Definition: lset.cpp:627
Definition: pad.h:54
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pad.cpp:329
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:353
#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
Sheet frame and title block.
Definition: layer_ids.h:277
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:90
@ 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_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition: typeinfo.h:95
@ 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