KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider_library_parity.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 <layer_range.h>
25#include <layer_utils.h>
26#include <kiway.h>
27#include <macros.h>
30#include <board.h>
31#include <pcb_shape.h>
32#include <pcb_barcode.h>
33#include <zone.h>
34#include <footprint.h>
35#include <pad.h>
36#include <drc/drc_engine.h>
37#include <drc/drc_item.h>
39#include <project_pcb.h>
40#include <string_utils.h>
41
42
43/*
44 Library parity test.
45
46 Errors generated:
47 - DRCE_LIB_FOOTPRINT_ISSUES
48 - DRCE_LIB_FOOTPRINT_MISMATCH
49*/
50
52{
53public:
58
60
61 virtual bool Run() override;
62
63 virtual const wxString GetName() const override { return wxT( "library_parity" ); };
64};
65
66
67//
68// The TEST*() macros have two modes:
69// In "Report" mode (aReporter != nullptr) all properties are checked and reported on.
70// In "DRC" mode (aReporter == nulltpr) properties are only checked until a difference is found.
71//
72#define TEST( a, b, msg ) \
73 do { \
74 if( a != b ) \
75 { \
76 diff = true; \
77 \
78 if( aReporter && wxString( msg ).length() ) \
79 aReporter->Report( msg ); \
80 } \
81 \
82 if( diff && !aReporter ) \
83 return diff; \
84 } while (0)
85
86#define EPSILON 2
87#define TEST_PT( a, b, msg ) \
88 do { \
89 if( abs( a.x - b.x ) > EPSILON \
90 || abs( a.y - b.y ) > EPSILON ) \
91 { \
92 diff = true; \
93 \
94 if( aReporter && wxString( msg ).length() ) \
95 aReporter->Report( msg ); \
96 } \
97 \
98 if( diff && !aReporter ) \
99 return diff; \
100 } while (0)
101
102#define EPSILON_D 0.000002
103#define TEST_D( a, b, msg ) \
104 do { \
105 if( abs( a - b ) > EPSILON_D ) \
106 { \
107 diff = true; \
108 \
109 if( aReporter && wxString( msg ).length() ) \
110 aReporter->Report( msg ); \
111 } \
112 \
113 if( diff && !aReporter ) \
114 return diff; \
115 } while (0)
116
117#define ITEM_DESC( item ) ( item )->GetItemDescription( &g_unitsProvider, true )
118#define PAD_DESC( pad ) wxString::Format( _( "Pad %s" ), ( pad )->GetNumber() )
119
120
122
123
124LSET getBoardNormalizedLayerSet( const BOARD_ITEM* aLibItem, const BOARD* aBoard )
125{
126 LSET lset = aLibItem->GetLayerSet();
127
128 if( aBoard )
129 lset &= aBoard->GetEnabledLayers();
130
131 return lset;
132}
133
134
135static bool boardLayersMatchWithInnerLayerExpansion( const LSET& aItem, const LSET& bLib,
136 bool aAllowCuExpansion )
137{
138 if( !aAllowCuExpansion )
139 {
140 return aItem == bLib;
141 }
142
143 // first test non copper layers, these should exact match
144 const LSET nonCuMask = LSET::AllNonCuMask();
145 const LSET aNonCu = aItem & nonCuMask;
146 const LSET bNonCu = bLib & nonCuMask;
147
148 if( aNonCu != bNonCu )
149 return false;
150
151 // top and bottom copper must match exactly
152 if( ( aItem & LSET::ExternalCuMask() ) != ( bLib & LSET::ExternalCuMask() ) )
153 return false;
154
155 // technically we can ignore the inner layers entirely due to aAllowCuExpansion at this point
156 // since its assumed the layers got expanded elsewhere
157 // but it feels weird not to sanity this
158
159 // extract the inner layers to compare prescence
160 const LSET aInner = ( aItem & LSET::AllCuMask() ) & ~( LSET::ExternalCuMask() );
161 const LSET bInner = ( bLib & LSET::AllCuMask() ) & ~( LSET::ExternalCuMask() );
162
163 const LSET missingInnerInA = bInner & ~aInner;
164 if( missingInnerInA.count() )
165 return false;
166
167 return true;
168}
169
170
171bool primitiveNeedsUpdate( const std::shared_ptr<PCB_SHAPE>& a,
172 const std::shared_ptr<PCB_SHAPE>& b )
173{
174 REPORTER* aReporter = nullptr;
175 bool diff = false;
176
177 TEST( a->GetShape(), b->GetShape(), "" );
178
179 switch( a->GetShape() )
180 {
182 {
183 BOX2I aRect( a->GetStart(), a->GetEnd() - a->GetStart() );
184 BOX2I bRect( b->GetStart(), b->GetEnd() - b->GetStart() );
185
186 aRect.Normalize();
187 bRect.Normalize();
188
189 TEST_PT( aRect.GetOrigin(), bRect.GetOrigin(), "" );
190 TEST_PT( aRect.GetEnd(), bRect.GetEnd(), "" );
191 break;
192 }
193
194 case SHAPE_T::SEGMENT:
195 case SHAPE_T::CIRCLE:
196 TEST_PT( a->GetStart(), b->GetStart(), "" );
197 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
198 break;
199
200 case SHAPE_T::ARC:
201 TEST_PT( a->GetStart(), b->GetStart(), "" );
202 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
203
204 // Arc center is calculated and so may have round-off errors when parents are
205 // differentially rotated.
206 if( ( a->GetArcMid() - b->GetArcMid() ).EuclideanNorm() > pcbIUScale.mmToIU( 0.0005 ) )
207 return true;
208
209 break;
210
211 case SHAPE_T::BEZIER:
212 TEST_PT( a->GetStart(), b->GetStart(), "" );
213 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
214 TEST_PT( a->GetBezierC1(), b->GetBezierC1(), "" );
215 TEST_PT( a->GetBezierC2(), b->GetBezierC2(), "" );
216 break;
217
218 case SHAPE_T::POLY:
219 TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(), "" );
220
221 for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
222 TEST_PT( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), "" );
223
224 break;
225
226 default:
227 UNIMPLEMENTED_FOR( a->SHAPE_T_asString() );
228 }
229
230 TEST( a->GetStroke(), b->GetStroke(), "" );
231 TEST( a->GetFillMode(), b->GetFillMode(), "" );
232
233 return diff;
234}
235
236
237bool padHasOverrides( const PAD* a, const PAD* b, REPORTER& aReporter )
238{
239 bool diff = false;
240
241#define REPORT_MSG( s, p ) aReporter.Report( wxString::Format( s, p ) )
242
243 if( a->GetLocalClearance().has_value() && a->GetLocalClearance() != b->GetLocalClearance() )
244 {
245 diff = true;
246 REPORT_MSG( _( "%s has clearance override." ), PAD_DESC( a ) );
247 }
248
249 if( a->GetLocalSolderMaskMargin().has_value()
251 {
252 diff = true;
253 REPORT_MSG( _( "%s has solder mask expansion override." ), PAD_DESC( a ) );
254 }
255
256
257 if( a->GetLocalSolderPasteMargin().has_value()
259 {
260 diff = true;
261 REPORT_MSG( _( "%s has solder paste clearance override." ), PAD_DESC( a ) );
262 }
263
266 {
267 diff = true;
268 REPORT_MSG( _( "%s has solder paste clearance override." ), PAD_DESC( a ) );
269 }
270
273 {
274 diff = true;
275 REPORT_MSG( _( "%s has zone connection override." ), PAD_DESC( a ) );
276 }
277
278 if( a->GetLocalThermalGapOverride().has_value()
279 && a->GetThermalGap() != b->GetThermalGap() )
280 {
281 diff = true;
282 REPORT_MSG( _( "%s has thermal relief gap override." ), PAD_DESC( a ) );
283 }
284
285 if( a->GetLocalThermalSpokeWidthOverride().has_value()
287 {
288 diff = true;
289 REPORT_MSG( _( "%s has thermal relief spoke width override." ), PAD_DESC( a ) );
290 }
291
293 {
294 diff = true;
295 REPORT_MSG( _( "%s has thermal relief spoke angle override." ), PAD_DESC( a ) );
296 }
297
299 {
300 diff = true;
301 REPORT_MSG( _( "%s has zone knockout setting override." ), PAD_DESC( a ) );
302 }
303
304 return diff;
305}
306
307
308bool padNeedsUpdate( const PAD* a, const PAD* bLib, REPORTER* aReporter )
309{
310 bool diff = false;
311
313 wxString::Format( _( "%s pad to die length differs." ), PAD_DESC( a ) ) );
315 wxString::Format( _( "%s position differs." ), PAD_DESC( a ) ) );
316
317 TEST( a->GetNumber(), bLib->GetNumber(),
318 wxString::Format( _( "%s has different numbers." ), PAD_DESC( a ) ) );
319
320 // These are assigned from the schematic and not from the library
321 // TEST( a->GetPinFunction(), b->GetPinFunction() );
322 // TEST( a->GetPinType(), b->GetPinType() );
323
324 bool layerSettingsDiffer = a->GetRemoveUnconnected() != bLib->GetRemoveUnconnected();
325
326 // NB: KeepTopBottom is undefined if RemoveUnconnected is NOT set.
327 if( a->GetRemoveUnconnected() )
328 layerSettingsDiffer |= a->GetKeepTopBottom() != bLib->GetKeepTopBottom();
329
330 bool allowExpansion = false;
331 if( const FOOTPRINT* fp = a->GetParentFootprint() )
332 allowExpansion = ( fp->GetStackupMode() == FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS );
333
334 if( layerSettingsDiffer
337 allowExpansion ) )
338 {
339 diff = true;
340
341 if( aReporter )
342 aReporter->Report( wxString::Format( _( "%s layers differ." ), PAD_DESC( a ) ) );
343 else
344 return true;
345 }
346
347 TEST( a->GetAttribute(), bLib->GetAttribute(),
348 wxString::Format( _( "%s pad type differs." ), PAD_DESC( a ) ) );
349 TEST( a->GetProperty(), bLib->GetProperty(),
350 wxString::Format( _( "%s fabrication property differs." ), PAD_DESC( a ) ) );
351
352 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
355 wxString::Format( _( "%s orientation differs." ), PAD_DESC( a ) ) );
356
357 std::vector<PCB_LAYER_ID> layers = a->Padstack().UniqueLayers();
358 const BOARD* board = a->GetBoard();
359 wxString layerName;
360
361 for( PCB_LAYER_ID layer : layers )
362 {
363 layerName = board ? board->GetLayerName( layer ) : LayerName( layer );
364
365 TEST( a->GetShape( layer ), bLib->GetShape( layer ),
366 wxString::Format( _( "%s pad shape type differs on layer %s." ),
367 PAD_DESC( a ),
368 layerName ) );
369
370 TEST( a->GetSize( layer ), bLib->GetSize( layer ),
371 wxString::Format( _( "%s size differs on layer %s." ),
372 PAD_DESC( a ),
373 layerName ) );
374
375 TEST( a->GetDelta( layer ), bLib->GetDelta( layer ),
376 wxString::Format( _( "%s trapezoid delta differs on layer %s." ),
377 PAD_DESC( a ),
378 layerName ) );
379
380 if( a->GetShape( layer ) == PAD_SHAPE::ROUNDRECT || a->GetShape( layer ) == PAD_SHAPE::CHAMFERED_RECT)
381 {
382 TEST_D( a->GetRoundRectRadiusRatio( layer ),
383 bLib->GetRoundRectRadiusRatio( layer ),
384 wxString::Format( _( "%s rounded corners differ on layer %s." ),
385 PAD_DESC( a ),
386 layerName ) );
387 }
388
389 if( a->GetShape( layer ) == PAD_SHAPE::CHAMFERED_RECT)
390 {
391 TEST_D( a->GetChamferRectRatio( layer ),
392 bLib->GetChamferRectRatio( layer ),
393 wxString::Format( _( "%s chamfered corner sizes differ on layer %s." ),
394 PAD_DESC( a ),
395 layerName ) );
396
397 TEST( a->GetChamferPositions( layer ),
398 bLib->GetChamferPositions( layer ),
399 wxString::Format( _( "%s chamfered corners differ on layer %s." ),
400 PAD_DESC( a ),
401 layerName ) );
402 }
403
404 TEST_PT( a->GetOffset( layer ), bLib->GetOffset( layer ),
405 wxString::Format( _( "%s shape offset from hole differs on layer %s." ),
406 PAD_DESC( a ),
407 layerName ) );
408 }
409
410 TEST( a->GetDrillShape(), bLib->GetDrillShape(),
411 wxString::Format( _( "%s drill shape differs." ), PAD_DESC( a ) ) );
412 TEST( a->GetDrillSize(), bLib->GetDrillSize(),
413 wxString::Format( _( "%s drill size differs." ), PAD_DESC( a ) ) );
414
415 // Clearance and zone connection overrides are as likely to be set at the board level as in
416 // the library.
417 //
418 // If we ignore them and someone *does* change one of them in the library, then stale
419 // footprints won't be caught.
420 //
421 // On the other hand, if we report them then boards that override at the board level are
422 // going to be VERY noisy.
423 //
424 // So we just do it when we have a reporter.
425 if( aReporter && padHasOverrides( a, bLib, *aReporter ) )
426 diff = true;
427
428 bool primitivesDiffer = false;
429 PCB_LAYER_ID firstDifferingLayer = UNDEFINED_LAYER;
430
432 [&]( PCB_LAYER_ID aLayer )
433 {
434 if( a->GetPrimitives( aLayer ).size() != bLib->GetPrimitives( aLayer ).size() )
435 {
436 primitivesDiffer = true;
437 }
438 else
439 {
440 for( size_t ii = 0; ii < a->GetPrimitives( aLayer ).size(); ++ii )
441 {
442 if( primitiveNeedsUpdate( a->GetPrimitives( aLayer )[ii],
443 bLib->GetPrimitives( aLayer )[ii] ) )
444 {
445 primitivesDiffer = true;
446 break;
447 }
448 }
449 }
450
451 if( primitivesDiffer && firstDifferingLayer == UNDEFINED_LAYER )
452 firstDifferingLayer = aLayer;
453 } );
454
455
456 if( primitivesDiffer )
457 {
458 diff = true;
459 layerName = board ? board->GetLayerName( firstDifferingLayer )
460 : LayerName( firstDifferingLayer );
461
462 if( aReporter )
463 {
464 aReporter->Report( wxString::Format( _( "%s shape primitives differ on layer %s." ),
465 PAD_DESC( a ),
466 layerName ) );
467 }
468 else
469 {
470 return true;
471 }
472 }
473
474 return diff;
475}
476
477
478bool barcodeNeedsUpdate( const PCB_BARCODE& curr_barcode, const PCB_BARCODE& ref_barcode )
479{
480 REPORTER* aReporter = nullptr;
481 bool diff = false;
482
483 TEST( curr_barcode.GetText(), ref_barcode.GetText(),
484 wxString::Format( _( "%s text differs." ), ITEM_DESC( &curr_barcode ) ) );
485
486 TEST_PT( curr_barcode.GetPosition(), ref_barcode.GetPosition(),
487 wxString::Format( _( "%s position differs." ), ITEM_DESC( &curr_barcode ) ) );
488
489 TEST( curr_barcode.GetWidth(), ref_barcode.GetWidth(),
490 wxString::Format( _( "%s width differs." ), ITEM_DESC( &curr_barcode ) ) );
491 TEST( curr_barcode.GetHeight(), ref_barcode.GetHeight(),
492 wxString::Format( _( "%s height differs." ), ITEM_DESC( &curr_barcode ) ) );
493
494 TEST( curr_barcode.GetTextSize(), ref_barcode.GetTextSize(),
495 wxString::Format( _( "%s text size differs." ), ITEM_DESC( &curr_barcode ) ) );
496
497 TEST( (int) curr_barcode.GetKind(), (int) ref_barcode.GetKind(),
498 wxString::Format( _( "%s code differs." ), ITEM_DESC( &curr_barcode ) ) );
499 TEST( (int) curr_barcode.GetErrorCorrection(), (int) ref_barcode.GetErrorCorrection(),
500 wxString::Format( _( "%s error correction level differs." ), ITEM_DESC( &curr_barcode ) ) );
501
502 return diff;
503}
504
505
506bool shapeNeedsUpdate( const PCB_SHAPE& curr_shape, const PCB_SHAPE& ref_shape )
507{
508 // curr_shape and ref_shape are expected to be normalized, for a more reliable test.
509 REPORTER* aReporter = nullptr;
510 bool diff = false;
511
512 TEST( curr_shape.GetShape(), ref_shape.GetShape(), "" );
513
514 switch( curr_shape.GetShape() )
515 {
517 {
518 BOX2I aRect( curr_shape.GetStart(), curr_shape.GetEnd() - curr_shape.GetStart() );
519 BOX2I bRect( ref_shape.GetStart(), ref_shape.GetEnd() - ref_shape.GetStart() );
520
521 aRect.Normalize();
522 bRect.Normalize();
523
524 TEST_PT( aRect.GetOrigin(), bRect.GetOrigin(), "" );
525 TEST_PT( aRect.GetEnd(), bRect.GetEnd(), "" );
526 break;
527 }
528
529 case SHAPE_T::SEGMENT:
530 case SHAPE_T::CIRCLE:
531 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
532 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
533 break;
534
535 case SHAPE_T::ARC:
536 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
537 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
538
539 // Arc center is calculated and so may have round-off errors when parents are
540 // differentially rotated.
541 if( ( curr_shape.GetArcMid() - ref_shape.GetArcMid() ).EuclideanNorm() > pcbIUScale.mmToIU( 0.0005 ) )
542 return true;
543
544 break;
545
546 case SHAPE_T::BEZIER:
547 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
548 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
549 TEST_PT( curr_shape.GetBezierC1(), ref_shape.GetBezierC1(), "" );
550 TEST_PT( curr_shape.GetBezierC2(), ref_shape.GetBezierC2(), "" );
551 break;
552
553 case SHAPE_T::POLY:
554 TEST( curr_shape.GetPolyShape().TotalVertices(), ref_shape.GetPolyShape().TotalVertices(), "" );
555
556 for( int ii = 0; ii < curr_shape.GetPolyShape().TotalVertices(); ++ii )
557 TEST_PT( curr_shape.GetPolyShape().CVertex( ii ), ref_shape.GetPolyShape().CVertex( ii ), "" );
558
559 break;
560
561 default:
562 UNIMPLEMENTED_FOR( curr_shape.SHAPE_T_asString() );
563 }
564
565 if( curr_shape.IsOnCopperLayer() )
566 TEST( curr_shape.GetStroke(), ref_shape.GetStroke(), "" );
567
568 TEST( curr_shape.GetFillMode(), ref_shape.GetFillMode(), "" );
569
570 TEST( curr_shape.GetLayer(), ref_shape.GetLayer(), "" );
571
572 return diff;
573}
574
575
576bool zoneNeedsUpdate( const ZONE* a, const ZONE* b, REPORTER* aReporter )
577{
578 bool diff = false;
579
581 wxString::Format( _( "%s corner smoothing setting differs." ), ITEM_DESC( a ) ) );
583 wxString::Format( _( "%s corner smoothing radius differs." ), ITEM_DESC( a ) ) );
584 TEST( a->GetZoneName(), b->GetZoneName(),
585 wxString::Format( _( "%s name differs." ), ITEM_DESC( a ) ) );
587 wxString::Format( _( "%s priority differs." ), ITEM_DESC( a ) ) );
588
589 TEST( a->GetIsRuleArea(), b->GetIsRuleArea(),
590 wxString::Format( _( "%s keep-out property differs." ), ITEM_DESC( a ) ) );
592 wxString::Format( _( "%s keep out zone fill setting differs." ), ITEM_DESC( a ) ) );
594 wxString::Format( _( "%s keep out footprints setting differs." ), ITEM_DESC( a ) ) );
596 wxString::Format( _( "%s keep out pads setting differs." ), ITEM_DESC( a ) ) );
598 wxString::Format( _( "%s keep out tracks setting differs." ), ITEM_DESC( a ) ) );
600 wxString::Format( _( "%s keep out vias setting differs." ), ITEM_DESC( a ) ) );
601
602 // In1_Cu is used to indicate whether inner layer expansion is allowed on rulesets
603 // Kind of annoying footprint pads use both in1_cu and have an stackup mode setting
604 bool innerLayerExpansionAllowed = b->GetLayerSet().Contains( In1_Cu );
605
608 innerLayerExpansionAllowed ) )
609 {
610 diff = true;
611
612 if( aReporter )
613 {
614 aReporter->Report( wxString::Format( _( "%s layers differ." ), ITEM_DESC( a ) ) );
615 }
616 else
617 {
618 return true;
619 }
620 }
621
623 wxString::Format( _( "%s pad connection property differs." ), ITEM_DESC( a ) ) );
625 wxString::Format( _( "%s local clearance differs." ), ITEM_DESC( a ) ) );
627 wxString::Format( _( "%s thermal relief gap differs." ), ITEM_DESC( a ) ) );
629 wxString::Format( _( "%s thermal relief spoke width differs." ), ITEM_DESC( a ) ) );
630
632 wxString::Format( _( "%s min thickness differs." ), ITEM_DESC( a ) ) );
633
635 wxString::Format( _( "%s remove islands setting differs." ), ITEM_DESC( a ) ) );
637 wxString::Format( _( "%s minimum island size setting differs." ), ITEM_DESC( a ) ) );
638
639 TEST( a->GetFillMode(), b->GetFillMode(),
640 wxString::Format( _( "%s fill type differs." ), ITEM_DESC( a ) ) );
642 wxString::Format( _( "%s hatch width differs." ), ITEM_DESC( a ) ) );
643 TEST( a->GetHatchGap(), b->GetHatchGap(),
644 wxString::Format( _( "%s hatch gap differs." ), ITEM_DESC( a ) ) );
646 wxString::Format( _( "%s hatch orientation differs." ), ITEM_DESC( a ) ) );
648 wxString::Format( _( "%s hatch smoothing level differs." ), ITEM_DESC( a ) ) );
650 wxString::Format( _( "%s hatch smoothing amount differs." ), ITEM_DESC( a ) ) );
652 wxString::Format( _( "%s minimum hatch hole setting differs." ), ITEM_DESC( a ) ) );
653
654 // This is just a display property
655 // TEST( a->GetHatchBorderAlgorithm(), b->GetHatchBorderAlgorithm() );
656
658 wxString::Format( _( "%s outline corner count differs." ), ITEM_DESC( a ) ) );
659
660 bool cornersDiffer = false;
661
662 for( int ii = 0; ii < a->Outline()->TotalVertices(); ++ii )
663 {
664 if( a->Outline()->CVertex( ii ) != b->Outline()->CVertex( ii ) )
665 {
666 diff = true;
667 cornersDiffer = true;
668 break;
669 }
670 }
671
672 if( cornersDiffer && aReporter )
673 aReporter->Report( wxString::Format( _( "%s corners differ." ), ITEM_DESC( a ) ) );
674
675 return diff;
676}
677
678
684bool stackupNeedsUpdate( const FOOTPRINT& a, const FOOTPRINT& b, REPORTER* aReporter )
685{
686 bool diff = false;
687
689 wxString::Format( _( "Footprint stackup mode differs." ) ) );
690
691 const LSET& aLayers = a.GetLayerSet();
692 const LSET& bLayers = b.GetLayerSet();
693
694 TEST( aLayers, bLayers,
695 wxString::Format( _( "Footprint layers differ." ) ) );
696
697 return diff;
698}
699
700
709bool footprintVsBoardStackup( const FOOTPRINT& aFp, const BOARD& aBoard, REPORTER* aReporter )
710{
712 return false;
713
714 // Filter only layers that can differ between footprint and board
715 const LSET& fpLayers = aFp.GetStackupLayers();
716 const LSET& brdLayers = aBoard.GetEnabledLayers() & ( LSET::AllCuMask() | LSET::UserDefinedLayersMask() );
717
718 bool mismatch = false;
719
720 // Any layer in the FP and not on the board is flagged
721 const LSET onlyInFp = fpLayers & ~brdLayers;
722
723 if( onlyInFp.count() )
724 {
725 mismatch = true;
726 if( aReporter )
727 aReporter->Report( wxString::Format( _( "Footprint has %lu layers not on board: %s" ), onlyInFp.count(),
728 LAYER_UTILS::AccumulateNames( onlyInFp, &aBoard ) ) );
729 }
730
731 // Only look at copper layers here: user layers on the board and not in the FP is normal
732 const LSET cuOnlyInBoard = ( brdLayers & ~fpLayers ) & LSET::AllCuMask();
733
734 if( cuOnlyInBoard.count() )
735 {
736 mismatch = true;
737 if( aReporter )
738 aReporter->Report( wxString::Format( _( "Board has %lu copper layers not in footprint: %s" ),
739 cuOnlyInBoard.count(),
740 LAYER_UTILS::AccumulateNames( cuOnlyInBoard, &aBoard ) ) );
741 }
742
743 return mismatch;
744}
745
746
747bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFP, int aCompareFlags,
748 REPORTER* aReporter )
749{
750 wxASSERT( aLibFP );
751 bool diff = false;
752
753 // To avoid issues when comparing the footprint on board and the footprint in library
754 // use the footprint from lib flipped, rotated and at same position as this.
755 // And using the footprint from lib with same changes as this minimize the issues
756 // due to rounding and shape modifications
757
758 std::unique_ptr<FOOTPRINT> temp( static_cast<FOOTPRINT*>( aLibFP->Clone() ) );
759
760 temp->SetParent( GetBoard() ); // Needed to know the copper layer count;
761
762 if( !( aCompareFlags & COMPARE_FLAGS::INSTANCE_TO_INSTANCE ) )
763 {
764 if( IsFlipped() != temp->IsFlipped() )
765 temp->Flip( { 0, 0 }, FLIP_DIRECTION::TOP_BOTTOM );
766
767 if( GetOrientation() != temp->GetOrientation() )
768 temp->SetOrientation( GetOrientation() );
769
770 if( GetPosition() != temp->GetPosition() )
771 temp->SetPosition( GetPosition() );
772 }
773
774 for( BOARD_ITEM* item : temp->GraphicalItems() )
775 item->NormalizeForCompare();
776
777 // This temporary footprint must not have a parent when it goes out of scope because it
778 // must not trigger the IncrementTimestamp call in ~FOOTPRINT.
779 temp->SetParent( nullptr );
780
781 aLibFP = temp.get();
782
783 // These checks don't set off errors, they're just informational
784 footprintVsBoardStackup( *this, *GetBoard(), aReporter );
785
786#define TEST_ATTR( a, b, attr, msg ) TEST( ( a & attr ), ( b & attr ), msg )
787
789 _( "Footprint types differ." ) );
790
792 wxString::Format( _( "'%s' settings differ." ),
793 _( "Allow bridged solder mask apertures between pads" ) ) );
794
795 if( !( aCompareFlags & COMPARE_FLAGS::DRC ) )
796 {
797 // These tests are skipped for DRC: they are presumed to relate to a given design.
799 wxString::Format( _( "'%s' settings differ." ),
800 _( "Not in schematic" ) ) );
801
803 wxString::Format( _( "'%s' settings differ." ),
804 _( "Exclude from position files" ) ) );
805
807 wxString::Format( _( "'%s' settings differ." ),
808 _( "Exclude from bill of materials" ) ) );
809
811 wxString::Format( _( "'%s' settings differ." ),
812 _( "Do not populate" ) ) );
813 }
814
815#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
816#define CHECKPOINT { if( diff && !aReporter ) return diff; }
817
818 if( stackupNeedsUpdate( *this, *aLibFP, aReporter ) )
819 {
820 diff = true;
821 REPORT( _( "Footprint stackup differs." ) );
822 }
823
824 // Clearance and zone connection overrides are as likely to be set at the board level as in
825 // the library.
826 //
827 // If we ignore them and someone *does* change one of them in the library, then stale
828 // footprints won't be caught.
829 //
830 // On the other hand, if we report them then boards that override at the board level are
831 // going to be VERY noisy.
832 //
833 // For report them as different, but we DON'T generate DRC errors on them.
834 if( !( aCompareFlags & COMPARE_FLAGS::DRC ) )
835 {
836 if( GetLocalClearance().has_value() && GetLocalClearance() != aLibFP->GetLocalClearance() )
837 {
838 diff = true;
839 REPORT( _( "Pad clearance overridden." ) );
840 }
841
842 if( GetLocalSolderMaskMargin().has_value()
844 {
845 diff = true;
846 REPORT( _( "Solder mask expansion overridden." ) );
847 }
848
849
850 if( GetLocalSolderPasteMargin().has_value()
852 {
853 diff = true;
854 REPORT( _( "Solder paste absolute clearance overridden." ) );
855 }
856
859 {
860 diff = true;
861 REPORT( _( "Solder paste relative clearance overridden." ) );
862 }
863
866 {
867 diff = true;
868 REPORT( _( "Zone connection overridden." ) );
869 }
870 }
871
872 TEST( GetNetTiePadGroups().size(), aLibFP->GetNetTiePadGroups().size(),
873 _( "Net tie pad groups differ." ) );
874
875 for( size_t ii = 0; ii < GetNetTiePadGroups().size(); ++ii )
876 {
877 TEST( GetNetTiePadGroups()[ii], aLibFP->GetNetTiePadGroups()[ii],
878 _( "Net tie pad groups differ." ) );
879 }
880
881 // Text items are really problematic. We don't want to test the reference, but after that
882 // it gets messy.
883 //
884 // What about the value? Depends on whether or not it's a singleton part.
885 //
886 // And what about other texts? They might be added only to instances on the board, or even
887 // changed for instances on the board. Or they might want to be tested for equality.
888 //
889 // Currently we punt and ignore all the text items.
890
891 // Drawings and pads are also somewhat problematic as there's no guarantee that they'll be
892 // in the same order in the two footprints. Rather than building some sophisticated hashing
893 // algorithm we use the footprint sorting functions to attempt to sort them in the same
894 // order.
895
896 // However FOOTPRINT::cmp_drawings uses PCB_SHAPE coordinates and other infos, so we have
897 // already normalized graphic items in model footprint from library, so we need to normalize
898 // graphic items in the footprint to test (*this). So normalize them using a copy of this
899 FOOTPRINT dummy( *this );
900 dummy.SetParentGroup( nullptr );
901 dummy.SetParent( nullptr );
902
903 for( BOARD_ITEM* item : dummy.GraphicalItems() )
904 item->NormalizeForCompare();
905
906 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aShapes;
907 std::copy_if( dummy.GraphicalItems().begin(), dummy.GraphicalItems().end(),
908 std::inserter( aShapes, aShapes.begin() ),
909 []( BOARD_ITEM* item )
910 {
911 return item->Type() == PCB_SHAPE_T;
912 } );
913
914 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bShapes;
915 std::copy_if( aLibFP->GraphicalItems().begin(), aLibFP->GraphicalItems().end(),
916 std::inserter( bShapes, bShapes.begin() ),
917 []( BOARD_ITEM* item )
918 {
919 return item->Type() == PCB_SHAPE_T;
920 } );
921
922 if( aShapes.size() != bShapes.size() )
923 {
924 diff = true;
925 REPORT( _( "Graphic item count differs." ) );
926 }
927 else
928 {
929 for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
930 {
931 // aShapes and bShapes are the tested footprint PCB_SHAPE and the model PCB_SHAPE.
932 // These shapes are already normalized.
933 PCB_SHAPE* curr_shape = static_cast<PCB_SHAPE*>( *aIt );
934 PCB_SHAPE* test_shape = static_cast<PCB_SHAPE*>( *bIt );
935
936 if( shapeNeedsUpdate( *curr_shape, *test_shape ) )
937 {
938 diff = true;
939 REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
940 }
941 }
942 }
943
945
946 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aBarcodes;
947 std::copy_if( dummy.GraphicalItems().begin(), dummy.GraphicalItems().end(),
948 std::inserter( aBarcodes, aBarcodes.begin() ),
949 []( BOARD_ITEM* item )
950 {
951 return item->Type() == PCB_BARCODE_T;
952 } );
953
954 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bBarcodes;
955 std::copy_if( aLibFP->GraphicalItems().begin(), aLibFP->GraphicalItems().end(),
956 std::inserter( bBarcodes, bBarcodes.begin() ),
957 []( BOARD_ITEM* item )
958 {
959 return item->Type() == PCB_BARCODE_T;
960 } );
961
962 if( aBarcodes.size() != bBarcodes.size() )
963 {
964 diff = true;
965 REPORT( _( "Barcode count differs." ) );
966 }
967 else
968 {
969 for( auto aIt = aBarcodes.begin(), bIt = bBarcodes.begin(); aIt != aBarcodes.end(); aIt++, bIt++ )
970 {
971 // aBarcodes and bBarcodes are the tested footprint PCB_BARCODE and the model PCB_BARCODE.
972 // These shapes are already normalized.
973 PCB_BARCODE* curr_barcode = static_cast<PCB_BARCODE*>( *aIt );
974 PCB_BARCODE* test_barcode = static_cast<PCB_BARCODE*>( *bIt );
975
976 if( barcodeNeedsUpdate( *curr_barcode, *test_barcode ) )
977 {
978 diff = true;
979 REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
980 }
981 }
982 }
983
985
986 std::set<PAD*, FOOTPRINT::cmp_pads> aPads( Pads().begin(), Pads().end() );
987 std::set<PAD*, FOOTPRINT::cmp_pads> bLibPads( aLibFP->Pads().begin(), aLibFP->Pads().end() );
988
989 if( aPads.size() != bLibPads.size() )
990 {
991 diff = true;
992 REPORT( _( "Pad count differs." ) );
993 }
994 else
995 {
996 for( auto aIt = aPads.begin(), bLibIt = bLibPads.begin(); aIt != aPads.end(); aIt++, bLibIt++ )
997 {
998 if( padNeedsUpdate( *aIt, *bLibIt, aReporter ) )
999 diff = true;
1000 else if( aReporter && padHasOverrides( *aIt, *bLibIt, *aReporter ) )
1001 diff = true;
1002 }
1003 }
1004
1005 CHECKPOINT;
1006
1007 std::set<ZONE*, FOOTPRINT::cmp_zones> aZones( Zones().begin(), Zones().end() );
1008 std::set<ZONE*, FOOTPRINT::cmp_zones> bZones( aLibFP->Zones().begin(), aLibFP->Zones().end() );
1009
1010 if( aZones.size() != bZones.size() )
1011 {
1012 diff = true;
1013 REPORT( _( "Rule area count differs." ) );
1014 }
1015 else
1016 {
1017 for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
1018 diff |= zoneNeedsUpdate( *aIt, *bIt, aReporter );
1019 }
1020
1021 return diff;
1022}
1023
1024
1026{
1027 BOARD* board = m_drcEngine->GetBoard();
1028 PROJECT* project = board->GetProject();
1029
1030 if( !project )
1031 {
1032 REPORT_AUX( _( "No project loaded, skipping library parity tests." ) );
1033 return true; // Continue with other tests
1034 }
1035
1036 if( !reportPhase( _( "Loading footprint library table..." ) ) )
1037 return false; // DRC cancelled
1038
1039 std::map<LIB_ID, std::shared_ptr<FOOTPRINT>> libFootprintCache;
1040
1042 wxString msg;
1043 int ii = 0;
1044 const int progressDelta = 250;
1045
1046 if( !reportPhase( _( "Checking board footprints against library..." ) ) )
1047 return false;
1048
1049 for( FOOTPRINT* footprint : board->Footprints() )
1050 {
1051 if( m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES )
1052 && m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_MISMATCH ) )
1053 {
1054 return true; // Continue with other tests
1055 }
1056
1057 if( !reportProgress( ii++, (int) board->Footprints().size(), progressDelta ) )
1058 return false; // DRC cancelled
1059
1060 LIB_ID fpID = footprint->GetFPID();
1061 wxString libName = fpID.GetLibNickname();
1062 wxString fpName = fpID.GetLibItemName();
1063 LIBRARY_TABLE_ROW* libTableRow = nullptr;
1064
1065 if( libName.IsEmpty() )
1066 {
1067 // Not much we can do here
1068 continue;
1069 }
1070
1071 if( std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( libName ); optRow )
1072 libTableRow = *optRow;
1073
1074 if( !libTableRow )
1075 {
1076 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1077 {
1078 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1079 msg.Printf( _( "The current configuration does not include the footprint library '%s'" ),
1080 UnescapeString( libName ) );
1081 drcItem->SetErrorMessage( msg );
1082 drcItem->SetItems( footprint );
1083 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1084 }
1085
1086 continue;
1087 }
1088 else if( !adapter->HasLibrary( libName, true ) )
1089 {
1090 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1091 {
1092 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1093 msg.Printf( _( "The footprint library '%s' is not enabled in the current configuration" ),
1094 UnescapeString( libName ) );
1095 drcItem->SetErrorMessage( msg );
1096 drcItem->SetItems( footprint );
1097 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1098 }
1099
1100 continue;
1101 }
1102 else if( !adapter->IsLibraryLoaded( libName ) )
1103 {
1104 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1105 {
1106 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1107 msg.Printf( _( "The footprint library '%s' was not found at '%s'" ),
1108 UnescapeString( libName ),
1109 LIBRARY_MANAGER::GetFullURI( libTableRow, true ) );
1110 drcItem->SetErrorMessage( msg );
1111 drcItem->SetItems( footprint );
1112 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1113 }
1114
1115 continue;
1116 }
1117
1118 auto cacheIt = libFootprintCache.find( fpID );
1119 std::shared_ptr<FOOTPRINT> libFootprint;
1120
1121 if( cacheIt != libFootprintCache.end() )
1122 {
1123 libFootprint = cacheIt->second;
1124 }
1125 else
1126 {
1127 try
1128 {
1129 libFootprint.reset( adapter->LoadFootprint( libName, fpName, true ) );
1130
1131 if( libFootprint )
1132 libFootprintCache[ fpID ] = libFootprint;
1133 }
1134 catch( const IO_ERROR& )
1135 {
1136 }
1137 }
1138
1139 if( !libFootprint )
1140 {
1141 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1142 {
1143 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1144 msg.Printf( _( "Footprint '%s' not found in library '%s'" ),
1145 fpName,
1146 libName );
1147 drcItem->SetErrorMessage( msg );
1148 drcItem->SetItems( footprint );
1149 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1150 }
1151 }
1152 else if( footprint->FootprintNeedsUpdate( libFootprint.get(), BOARD_ITEM::COMPARE_FLAGS::DRC ) )
1153 {
1154 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_MISMATCH ) )
1155 {
1156 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_MISMATCH );
1157 msg.Printf( _( "Footprint '%s' does not match copy in library '%s'" ),
1158 fpName,
1159 libName );
1160 drcItem->SetErrorMessage( msg );
1161 drcItem->SetItems( footprint );
1162 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1163 }
1164 }
1165 }
1166
1167 return true;
1168}
1169
1170
1171namespace detail
1172{
1174}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:85
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
VECTOR2I GetFPRelativePosition() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:256
@ INSTANCE_TO_INSTANCE
Definition board_item.h:446
virtual bool IsOnCopperLayer() const
Definition board_item.h:155
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const FOOTPRINTS & Footprints() const
Definition board.h:363
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:715
PROJECT * GetProject() const
Definition board.h:554
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:954
constexpr const Vec GetEnd() const
Definition box2.h:212
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr const Vec & GetOrigin() const
Definition box2.h:210
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition drc_item.cpp:400
virtual ~DRC_TEST_PROVIDER_LIBRARY_PARITY()=default
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
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)
EDA_ANGLE Normalize()
Definition eda_angle.h:229
double AsDegrees() const
Definition eda_angle.h:116
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:258
FILL_T GetFillMode() const
Definition eda_shape.h:142
SHAPE_POLY_SET & GetPolyShape()
Definition eda_shape.h:336
SHAPE_T GetShape() const
Definition eda_shape.h:168
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:215
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:173
wxString SHAPE_T_asString() const
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:255
VECTOR2I GetArcMid() const
An interface to the global shared library manager that is schematic-specific and linked to one projec...
FOOTPRINT * LoadFootprint(const wxString &aNickname, const wxString &aName, bool aKeepUUID)
Load a FOOTPRINT having aName from the library given by aNickname.
bool AllowSolderMaskBridges() const
Definition footprint.h:333
ZONE_CONNECTION GetLocalZoneConnection() const
Definition footprint.h:309
EDA_ANGLE GetOrientation() const
Definition footprint.h:248
ZONES & Zones()
Definition footprint.h:230
bool FootprintNeedsUpdate(const FOOTPRINT *aLibFP, int aCompareFlags=0, REPORTER *aReporter=nullptr)
Return true if a board footprint differs from the library version.
std::optional< int > GetLocalSolderPasteMargin() const
Definition footprint.h:302
EDA_ITEM * Clone() const override
Invoke a function on all children.
std::optional< int > GetLocalClearance() const
Definition footprint.h:296
std::deque< PAD * > & Pads()
Definition footprint.h:224
int GetAttributes() const
Definition footprint.h:327
FOOTPRINT(BOARD *parent)
Definition footprint.cpp:76
bool IsFlipped() const
Definition footprint.h:434
const std::vector< wxString > & GetNetTiePadGroups() const
Definition footprint.h:382
const LSET & GetStackupLayers() const
Definition footprint.h:325
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition footprint.h:305
std::optional< int > GetLocalSolderMaskMargin() const
Definition footprint.h:299
FOOTPRINT_STACKUP GetStackupMode() const
Definition footprint.h:318
VECTOR2I GetPosition() const override
Definition footprint.h:245
DRAWINGS & GraphicalItems()
Definition footprint.h:227
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
bool IsLibraryLoaded(const wxString &aNickname)
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:610
static const LSET & ExternalCuMask()
Return a mask holding the Front and Bottom layers.
Definition lset.cpp:617
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
static LSET UserDefinedLayersMask(int aUserDefinedLayerCount=MAX_USER_DEFINED_LAYERS)
Return a mask with the requested number of user defined layers.
Definition lset.cpp:687
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:591
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
std::vector< PCB_LAYER_ID > UniqueLayers() const
Definition pad.h:55
PAD_PROP GetProperty() const
Definition pad.h:561
bool GetRemoveUnconnected() const
Definition pad.h:851
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives(PCB_LAYER_ID aLayer) const
Accessor to the basic shape list for custom-shaped pads.
Definition pad.h:372
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition pad.h:593
const VECTOR2I & GetDrillSize() const
Definition pad.h:312
PAD_ATTRIB GetAttribute() const
Definition pad.h:558
const wxString & GetNumber() const
Definition pad.h:137
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
Definition pad.h:299
EDA_ANGLE GetThermalSpokeAngle() const
Definition pad.h:743
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:789
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:196
bool GetKeepTopBottom() const
Definition pad.h:866
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition pad.h:576
const PADSTACK & Padstack() const
Definition pad.h:328
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.h:324
PAD_DRILL_SHAPE GetDrillShape() const
Definition pad.h:432
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition pad.h:829
std::optional< int > GetLocalSolderPasteMargin() const
Definition pad.h:586
std::optional< int > GetLocalSolderMaskMargin() const
Definition pad.h:579
EDA_ANGLE GetFPRelativeOrientation() const
Definition pad.cpp:1409
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:812
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition pad.h:727
ZONE_CONNECTION GetLocalZoneConnection() const
Definition pad.h:604
CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition pad.h:222
int GetThermalGap() const
Definition pad.h:759
int GetLocalThermalGapOverride(wxString *aSource) const
Definition pad.cpp:1768
int GetPadToDieLength() const
Definition pad.h:571
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition pad.h:264
VECTOR2I GetPosition() const override
Get the position (center) of the barcode in internal units.
wxString GetText() const
int GetTextSize() const
int GetHeight() const
Get the barcode height (in internal units).
BARCODE_ECC_T GetErrorCorrection() const
BARCODE_T GetKind() const
Returns the type of the barcode (QR, CODE_39, etc.).
int GetWidth() const
Get the barcode width (in internal units).
STROKE_PARAMS GetStroke() const override
Definition pcb_shape.h:91
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:71
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Definition project.h:65
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
int TotalVertices() const
Return total number of vertices stored in the set.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
Handle a list of polygons defining a copper zone.
Definition zone.h:74
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:701
std::optional< int > GetLocalClearance() const override
Definition zone.cpp:806
bool GetDoNotAllowVias() const
Definition zone.h:712
bool GetDoNotAllowPads() const
Definition zone.h:714
bool GetDoNotAllowTracks() const
Definition zone.h:713
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition zone.h:723
SHAPE_POLY_SET * Outline()
Definition zone.h:331
long long int GetMinIslandArea() const
Definition zone.h:726
const wxString & GetZoneName() const
Definition zone.h:159
int GetMinThickness() const
Definition zone.h:297
ZONE_CONNECTION GetPadConnection() const
Definition zone.h:294
int GetHatchThickness() const
Definition zone.h:306
double GetHatchHoleMinArea() const
Definition zone.h:321
int GetThermalReliefSpokeWidth() const
Definition zone.h:241
EDA_ANGLE GetHatchOrientation() const
Definition zone.h:312
bool GetDoNotAllowFootprints() const
Definition zone.h:715
ZONE_FILL_MODE GetFillMode() const
Definition zone.h:220
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:136
int GetHatchGap() const
Definition zone.h:309
double GetHatchSmoothingValue() const
Definition zone.h:318
bool GetDoNotAllowZoneFills() const
Definition zone.h:711
int GetHatchSmoothingLevel() const
Definition zone.h:315
unsigned int GetCornerRadius() const
Definition zone.h:646
int GetCornerSmoothingType() const
Definition zone.h:642
int GetThermalReliefGap() const
Definition zone.h:230
unsigned GetAssignedPriority() const
Definition zone.h:126
@ DRCE_LIB_FOOTPRINT_ISSUES
Definition drc_item.h:83
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition drc_item.h:84
#define REPORT_AUX(s)
UNITS_PROVIDER g_unitsProvider(pcbIUScale, EDA_UNITS::MM)
bool footprintVsBoardStackup(const FOOTPRINT &aFp, const BOARD &aBoard, REPORTER *aReporter)
Report board->footprint stackup differences.
#define TEST_PT(a, b, msg)
bool padNeedsUpdate(const PAD *a, const PAD *bLib, REPORTER *aReporter)
#define PAD_DESC(pad)
bool primitiveNeedsUpdate(const std::shared_ptr< PCB_SHAPE > &a, const std::shared_ptr< PCB_SHAPE > &b)
static bool boardLayersMatchWithInnerLayerExpansion(const LSET &aItem, const LSET &bLib, bool aAllowCuExpansion)
#define TEST(a, b, msg)
bool padHasOverrides(const PAD *a, const PAD *b, REPORTER &aReporter)
bool shapeNeedsUpdate(const PCB_SHAPE &curr_shape, const PCB_SHAPE &ref_shape)
bool zoneNeedsUpdate(const ZONE *a, const ZONE *b, REPORTER *aReporter)
bool barcodeNeedsUpdate(const PCB_BARCODE &curr_barcode, const PCB_BARCODE &ref_barcode)
#define TEST_ATTR(a, b, attr, msg)
#define TEST_D(a, b, msg)
bool stackupNeedsUpdate(const FOOTPRINT &a, const FOOTPRINT &b, REPORTER *aReporter)
Compare the stackup related settings of two footprints.
#define CHECKPOINT
LSET getBoardNormalizedLayerSet(const BOARD_ITEM *aLibItem, const BOARD *aBoard)
#define REPORT_MSG(s, p)
#define ITEM_DESC(item)
#define _(s)
#define TEST(a, b)
@ SEGMENT
Definition eda_shape.h:45
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
@ FP_SMD
Definition footprint.h:82
@ FP_DNP
Definition footprint.h:87
@ FP_EXCLUDE_FROM_POS_FILES
Definition footprint.h:83
@ FP_BOARD_ONLY
Definition footprint.h:85
@ FP_EXCLUDE_FROM_BOM
Definition footprint.h:84
@ FP_THROUGH_HOLE
Definition footprint.h:81
@ EXPAND_INNER_LAYERS
The 'normal' stackup handling, where there is a single inner layer (In1) and rule areas using it expa...
Definition footprint.h:96
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
Definition layer_id.cpp:31
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ In1_Cu
Definition layer_ids.h:66
#define REPORT(msg)
#define ITEM_DESC(item)
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:29
wxString AccumulateNames(const LSEQ &aLayers, const BOARD *aBoard)
Accumulate layer names from a layer set into a comma separated string.
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
@ CHAMFERED_RECT
Definition padstack.h:60
@ ROUNDRECT
Definition padstack.h:57
BARCODE class definition.
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
VECTOR2I end