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>
29#include <fp_lib_table.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
135bool primitiveNeedsUpdate( const std::shared_ptr<PCB_SHAPE>& a,
136 const std::shared_ptr<PCB_SHAPE>& b )
137{
138 REPORTER* aReporter = nullptr;
139 bool diff = false;
140
141 TEST( a->GetShape(), b->GetShape(), "" );
142
143 switch( a->GetShape() )
144 {
146 {
147 BOX2I aRect( a->GetStart(), a->GetEnd() - a->GetStart() );
148 BOX2I bRect( b->GetStart(), b->GetEnd() - b->GetStart() );
149
150 aRect.Normalize();
151 bRect.Normalize();
152
153 TEST_PT( aRect.GetOrigin(), bRect.GetOrigin(), "" );
154 TEST_PT( aRect.GetEnd(), bRect.GetEnd(), "" );
155 break;
156 }
157
158 case SHAPE_T::SEGMENT:
159 case SHAPE_T::CIRCLE:
160 TEST_PT( a->GetStart(), b->GetStart(), "" );
161 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
162 break;
163
164 case SHAPE_T::ARC:
165 TEST_PT( a->GetStart(), b->GetStart(), "" );
166 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
167
168 // Arc center is calculated and so may have round-off errors when parents are
169 // differentially rotated.
170 if( ( a->GetArcMid() - b->GetArcMid() ).EuclideanNorm() > pcbIUScale.mmToIU( 0.0005 ) )
171 return true;
172
173 break;
174
175 case SHAPE_T::BEZIER:
176 TEST_PT( a->GetStart(), b->GetStart(), "" );
177 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
178 TEST_PT( a->GetBezierC1(), b->GetBezierC1(), "" );
179 TEST_PT( a->GetBezierC2(), b->GetBezierC2(), "" );
180 break;
181
182 case SHAPE_T::POLY:
183 TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(), "" );
184
185 for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
186 TEST_PT( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), "" );
187
188 break;
189
190 default:
191 UNIMPLEMENTED_FOR( a->SHAPE_T_asString() );
192 }
193
194 TEST( a->GetStroke(), b->GetStroke(), "" );
195 TEST( a->GetFillMode(), b->GetFillMode(), "" );
196
197 return diff;
198}
199
200
201bool padHasOverrides( const PAD* a, const PAD* b, REPORTER& aReporter )
202{
203 bool diff = false;
204
205#define REPORT_MSG( s, p ) aReporter.Report( wxString::Format( s, p ) )
206
207 if( a->GetLocalClearance().has_value() && a->GetLocalClearance() != b->GetLocalClearance() )
208 {
209 diff = true;
210 REPORT_MSG( _( "%s has clearance override." ), PAD_DESC( a ) );
211 }
212
213 if( a->GetLocalSolderMaskMargin().has_value()
215 {
216 diff = true;
217 REPORT_MSG( _( "%s has solder mask expansion override." ), PAD_DESC( a ) );
218 }
219
220
221 if( a->GetLocalSolderPasteMargin().has_value()
223 {
224 diff = true;
225 REPORT_MSG( _( "%s has solder paste clearance override." ), PAD_DESC( a ) );
226 }
227
230 {
231 diff = true;
232 REPORT_MSG( _( "%s has solder paste clearance override." ), PAD_DESC( a ) );
233 }
234
237 {
238 diff = true;
239 REPORT_MSG( _( "%s has zone connection override." ), PAD_DESC( a ) );
240 }
241
242 if( a->GetLocalThermalGapOverride().has_value()
243 && a->GetThermalGap() != b->GetThermalGap() )
244 {
245 diff = true;
246 REPORT_MSG( _( "%s has thermal relief gap override." ), PAD_DESC( a ) );
247 }
248
249 if( a->GetLocalThermalSpokeWidthOverride().has_value()
251 {
252 diff = true;
253 REPORT_MSG( _( "%s has thermal relief spoke width override." ), PAD_DESC( a ) );
254 }
255
257 {
258 diff = true;
259 REPORT_MSG( _( "%s has thermal relief spoke angle override." ), PAD_DESC( a ) );
260 }
261
263 {
264 diff = true;
265 REPORT_MSG( _( "%s has zone knockout setting override." ), PAD_DESC( a ) );
266 }
267
268 return diff;
269}
270
271
272bool padNeedsUpdate( const PAD* a, const PAD* b, REPORTER* aReporter )
273{
274 bool diff = false;
275
277 wxString::Format( _( "%s pad to die length differs." ), PAD_DESC( a ) ) );
279 wxString::Format( _( "%s position differs." ), PAD_DESC( a ) ) );
280
281 TEST( a->GetNumber(), b->GetNumber(),
282 wxString::Format( _( "%s has different numbers." ), PAD_DESC( a ) ) );
283
284 // These are assigned from the schematic and not from the library
285 // TEST( a->GetPinFunction(), b->GetPinFunction() );
286 // TEST( a->GetPinType(), b->GetPinType() );
287
288 bool layerSettingsDiffer = a->GetRemoveUnconnected() != b->GetRemoveUnconnected();
289
290 // NB: KeepTopBottom is undefined if RemoveUnconnected is NOT set.
291 if( a->GetRemoveUnconnected() )
292 layerSettingsDiffer |= a->GetKeepTopBottom() != b->GetKeepTopBottom();
293
294 if( layerSettingsDiffer
296 {
297 diff = true;
298
299 if( aReporter )
300 aReporter->Report( wxString::Format( _( "%s layers differ." ), PAD_DESC( a ) ) );
301 else
302 return true;
303 }
304
305 TEST( a->GetAttribute(), b->GetAttribute(),
306 wxString::Format( _( "%s pad type differs." ), PAD_DESC( a ) ) );
307 TEST( a->GetProperty(), b->GetProperty(),
308 wxString::Format( _( "%s fabrication property differs." ), PAD_DESC( a ) ) );
309
310 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
313 wxString::Format( _( "%s orientation differs." ), PAD_DESC( a ) ) );
314
315 std::vector<PCB_LAYER_ID> layers = a->Padstack().UniqueLayers();
316 const BOARD* board = a->GetBoard();
317 wxString layerName;
318
319 for( PCB_LAYER_ID layer : layers )
320 {
321 layerName = board ? board->GetLayerName( layer ) : LayerName( layer );
322
323 TEST( a->GetShape( layer ), b->GetShape( layer ),
324 wxString::Format( _( "%s pad shape type differs on layer %s." ),
325 PAD_DESC( a ),
326 layerName ) );
327
328 TEST( a->GetSize( layer ), b->GetSize( layer ),
329 wxString::Format( _( "%s size differs on layer %s." ),
330 PAD_DESC( a ),
331 layerName ) );
332
333 TEST( a->GetDelta( layer ), b->GetDelta( layer ),
334 wxString::Format( _( "%s trapezoid delta differs on layer %s." ),
335 PAD_DESC( a ),
336 layerName ) );
337
338 if( a->GetShape( layer ) == PAD_SHAPE::ROUNDRECT || a->GetShape( layer ) == PAD_SHAPE::CHAMFERED_RECT)
339 {
340 TEST_D( a->GetRoundRectRadiusRatio( layer ),
341 b->GetRoundRectRadiusRatio( layer ),
342 wxString::Format( _( "%s rounded corners differ on layer %s." ),
343 PAD_DESC( a ),
344 layerName ) );
345 }
346
347 if( a->GetShape( layer ) == PAD_SHAPE::CHAMFERED_RECT)
348 {
349 TEST_D( a->GetChamferRectRatio( layer ),
350 b->GetChamferRectRatio( layer ),
351 wxString::Format( _( "%s chamfered corner sizes differ on layer %s." ),
352 PAD_DESC( a ),
353 layerName ) );
354
355 TEST( a->GetChamferPositions( layer ),
356 b->GetChamferPositions( layer ),
357 wxString::Format( _( "%s chamfered corners differ on layer %s." ),
358 PAD_DESC( a ),
359 layerName ) );
360 }
361
362 TEST_PT( a->GetOffset( layer ), b->GetOffset( layer ),
363 wxString::Format( _( "%s shape offset from hole differs on layer %s." ),
364 PAD_DESC( a ),
365 layerName ) );
366 }
367
368 TEST( a->GetDrillShape(), b->GetDrillShape(),
369 wxString::Format( _( "%s drill shape differs." ), PAD_DESC( a ) ) );
370 TEST( a->GetDrillSize(), b->GetDrillSize(),
371 wxString::Format( _( "%s drill size differs." ), PAD_DESC( a ) ) );
372
373 // Clearance and zone connection overrides are as likely to be set at the board level as in
374 // the library.
375 //
376 // If we ignore them and someone *does* change one of them in the library, then stale
377 // footprints won't be caught.
378 //
379 // On the other hand, if we report them then boards that override at the board level are
380 // going to be VERY noisy.
381 //
382 // So we just do it when we have a reporter.
383 if( aReporter && padHasOverrides( a, b, *aReporter ) )
384 diff = true;
385
386 bool primitivesDiffer = false;
387 PCB_LAYER_ID firstDifferingLayer = UNDEFINED_LAYER;
388
390 [&]( PCB_LAYER_ID aLayer )
391 {
392 if( a->GetPrimitives( aLayer ).size() != b->GetPrimitives( aLayer ).size() )
393 {
394 primitivesDiffer = true;
395 }
396 else
397 {
398 for( size_t ii = 0; ii < a->GetPrimitives( aLayer ).size(); ++ii )
399 {
400 if( primitiveNeedsUpdate( a->GetPrimitives( aLayer )[ii],
401 b->GetPrimitives( aLayer )[ii] ) )
402 {
403 primitivesDiffer = true;
404 break;
405 }
406 }
407 }
408
409 if( primitivesDiffer && firstDifferingLayer == UNDEFINED_LAYER )
410 firstDifferingLayer = aLayer;
411 } );
412
413
414 if( primitivesDiffer )
415 {
416 diff = true;
417 layerName = board ? board->GetLayerName( firstDifferingLayer )
418 : LayerName( firstDifferingLayer );
419
420 if( aReporter )
421 {
422 aReporter->Report( wxString::Format( _( "%s shape primitives differ on layer %s." ),
423 PAD_DESC( a ),
424 layerName ) );
425 }
426 else
427 {
428 return true;
429 }
430 }
431
432 return diff;
433}
434
435
436bool barcodeNeedsUpdate( const PCB_BARCODE& curr_barcode, const PCB_BARCODE& ref_barcode )
437{
438 REPORTER* aReporter = nullptr;
439 bool diff = false;
440
441 TEST( curr_barcode.GetText(), ref_barcode.GetText(),
442 wxString::Format( _( "%s text differs." ), ITEM_DESC( &curr_barcode ) ) );
443
444 TEST_PT( curr_barcode.GetPosition(), ref_barcode.GetPosition(),
445 wxString::Format( _( "%s position differs." ), ITEM_DESC( &curr_barcode ) ) );
446
447 TEST( curr_barcode.GetWidth(), ref_barcode.GetWidth(),
448 wxString::Format( _( "%s width differs." ), ITEM_DESC( &curr_barcode ) ) );
449 TEST( curr_barcode.GetHeight(), ref_barcode.GetHeight(),
450 wxString::Format( _( "%s height differs." ), ITEM_DESC( &curr_barcode ) ) );
451
452 TEST( curr_barcode.GetTextSize(), ref_barcode.GetTextSize(),
453 wxString::Format( _( "%s text size differs." ), ITEM_DESC( &curr_barcode ) ) );
454
455 TEST( (int) curr_barcode.GetKind(), (int) ref_barcode.GetKind(),
456 wxString::Format( _( "%s code differs." ), ITEM_DESC( &curr_barcode ) ) );
457 TEST( (int) curr_barcode.GetErrorCorrection(), (int) ref_barcode.GetErrorCorrection(),
458 wxString::Format( _( "%s error correction level differs." ), ITEM_DESC( &curr_barcode ) ) );
459
460 return diff;
461}
462
463
464bool shapeNeedsUpdate( const PCB_SHAPE& curr_shape, const PCB_SHAPE& ref_shape )
465{
466 // curr_shape and ref_shape are expected to be normalized, for a more reliable test.
467 REPORTER* aReporter = nullptr;
468 bool diff = false;
469
470 TEST( curr_shape.GetShape(), ref_shape.GetShape(), "" );
471
472 switch( curr_shape.GetShape() )
473 {
475 {
476 BOX2I aRect( curr_shape.GetStart(), curr_shape.GetEnd() - curr_shape.GetStart() );
477 BOX2I bRect( ref_shape.GetStart(), ref_shape.GetEnd() - ref_shape.GetStart() );
478
479 aRect.Normalize();
480 bRect.Normalize();
481
482 TEST_PT( aRect.GetOrigin(), bRect.GetOrigin(), "" );
483 TEST_PT( aRect.GetEnd(), bRect.GetEnd(), "" );
484 break;
485 }
486
487 case SHAPE_T::SEGMENT:
488 case SHAPE_T::CIRCLE:
489 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
490 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
491 break;
492
493 case SHAPE_T::ARC:
494 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
495 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
496
497 // Arc center is calculated and so may have round-off errors when parents are
498 // differentially rotated.
499 if( ( curr_shape.GetArcMid() - ref_shape.GetArcMid() ).EuclideanNorm() > pcbIUScale.mmToIU( 0.0005 ) )
500 return true;
501
502 break;
503
504 case SHAPE_T::BEZIER:
505 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
506 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
507 TEST_PT( curr_shape.GetBezierC1(), ref_shape.GetBezierC1(), "" );
508 TEST_PT( curr_shape.GetBezierC2(), ref_shape.GetBezierC2(), "" );
509 break;
510
511 case SHAPE_T::POLY:
512 TEST( curr_shape.GetPolyShape().TotalVertices(), ref_shape.GetPolyShape().TotalVertices(), "" );
513
514 for( int ii = 0; ii < curr_shape.GetPolyShape().TotalVertices(); ++ii )
515 TEST_PT( curr_shape.GetPolyShape().CVertex( ii ), ref_shape.GetPolyShape().CVertex( ii ), "" );
516
517 break;
518
519 default:
520 UNIMPLEMENTED_FOR( curr_shape.SHAPE_T_asString() );
521 }
522
523 if( curr_shape.IsOnCopperLayer() )
524 TEST( curr_shape.GetStroke(), ref_shape.GetStroke(), "" );
525
526 TEST( curr_shape.GetFillMode(), ref_shape.GetFillMode(), "" );
527
528 TEST( curr_shape.GetLayer(), ref_shape.GetLayer(), "" );
529
530 return diff;
531}
532
533
534bool zoneNeedsUpdate( const ZONE* a, const ZONE* b, REPORTER* aReporter )
535{
536 bool diff = false;
537
539 wxString::Format( _( "%s corner smoothing setting differs." ), ITEM_DESC( a ) ) );
541 wxString::Format( _( "%s corner smoothing radius differs." ), ITEM_DESC( a ) ) );
542 TEST( a->GetZoneName(), b->GetZoneName(),
543 wxString::Format( _( "%s name differs." ), ITEM_DESC( a ) ) );
545 wxString::Format( _( "%s priority differs." ), ITEM_DESC( a ) ) );
546
547 TEST( a->GetIsRuleArea(), b->GetIsRuleArea(),
548 wxString::Format( _( "%s keep-out property differs." ), ITEM_DESC( a ) ) );
550 wxString::Format( _( "%s keep out zone fill setting differs." ), ITEM_DESC( a ) ) );
552 wxString::Format( _( "%s keep out footprints setting differs." ), ITEM_DESC( a ) ) );
554 wxString::Format( _( "%s keep out pads setting differs." ), ITEM_DESC( a ) ) );
556 wxString::Format( _( "%s keep out tracks setting differs." ), ITEM_DESC( a ) ) );
558 wxString::Format( _( "%s keep out vias setting differs." ), ITEM_DESC( a ) ) );
559
561 wxString::Format( _( "%s layers differ." ), ITEM_DESC( a ) ) );
562
564 wxString::Format( _( "%s pad connection property differs." ), ITEM_DESC( a ) ) );
566 wxString::Format( _( "%s local clearance differs." ), ITEM_DESC( a ) ) );
568 wxString::Format( _( "%s thermal relief gap differs." ), ITEM_DESC( a ) ) );
570 wxString::Format( _( "%s thermal relief spoke width differs." ), ITEM_DESC( a ) ) );
571
573 wxString::Format( _( "%s min thickness differs." ), ITEM_DESC( a ) ) );
574
576 wxString::Format( _( "%s remove islands setting differs." ), ITEM_DESC( a ) ) );
578 wxString::Format( _( "%s minimum island size setting differs." ), ITEM_DESC( a ) ) );
579
580 TEST( a->GetFillMode(), b->GetFillMode(),
581 wxString::Format( _( "%s fill type differs." ), ITEM_DESC( a ) ) );
583 wxString::Format( _( "%s hatch width differs." ), ITEM_DESC( a ) ) );
584 TEST( a->GetHatchGap(), b->GetHatchGap(),
585 wxString::Format( _( "%s hatch gap differs." ), ITEM_DESC( a ) ) );
587 wxString::Format( _( "%s hatch orientation differs." ), ITEM_DESC( a ) ) );
589 wxString::Format( _( "%s hatch smoothing level differs." ), ITEM_DESC( a ) ) );
591 wxString::Format( _( "%s hatch smoothing amount differs." ), ITEM_DESC( a ) ) );
593 wxString::Format( _( "%s minimum hatch hole setting differs." ), ITEM_DESC( a ) ) );
594
595 // This is just a display property
596 // TEST( a->GetHatchBorderAlgorithm(), b->GetHatchBorderAlgorithm() );
597
599 wxString::Format( _( "%s outline corner count differs." ), ITEM_DESC( a ) ) );
600
601 bool cornersDiffer = false;
602
603 for( int ii = 0; ii < a->Outline()->TotalVertices(); ++ii )
604 {
605 if( a->Outline()->CVertex( ii ) != b->Outline()->CVertex( ii ) )
606 {
607 diff = true;
608 cornersDiffer = true;
609 break;
610 }
611 }
612
613 if( cornersDiffer && aReporter )
614 aReporter->Report( wxString::Format( _( "%s corners differ." ), ITEM_DESC( a ) ) );
615
616 return diff;
617}
618
619
625bool stackupNeedsUpdate( const FOOTPRINT& a, const FOOTPRINT& b, REPORTER* aReporter )
626{
627 bool diff = false;
628
630 wxString::Format( _( "Footprint stackup mode differs." ) ) );
631
632 const LSET& aLayers = a.GetLayerSet();
633 const LSET& bLayers = b.GetLayerSet();
634
635 TEST( aLayers, bLayers,
636 wxString::Format( _( "Footprint layers differ." ) ) );
637
638 return diff;
639}
640
641
650bool footprintVsBoardStackup( const FOOTPRINT& aFp, const BOARD& aBoard, REPORTER* aReporter )
651{
653 return false;
654
655 // Filter only layers that can differ between footprint and board
656 const LSET& fpLayers = aFp.GetStackupLayers();
657 const LSET& brdLayers = aBoard.GetEnabledLayers() & ( LSET::AllCuMask() | LSET::UserDefinedLayersMask() );
658
659 bool mismatch = false;
660
661 // Any layer in the FP and not on the board is flagged
662 const LSET onlyInFp = fpLayers & ~brdLayers;
663
664 if( onlyInFp.count() )
665 {
666 mismatch = true;
667 if( aReporter )
668 aReporter->Report( wxString::Format( _( "Footprint has %lu layers not on board: %s" ), onlyInFp.count(),
669 LAYER_UTILS::AccumulateNames( onlyInFp, &aBoard ) ) );
670 }
671
672 // Only look at copper layers here: user layers on the board and not in the FP is normal
673 const LSET cuOnlyInBoard = ( brdLayers & ~fpLayers ) & LSET::AllCuMask();
674
675 if( cuOnlyInBoard.count() )
676 {
677 mismatch = true;
678 if( aReporter )
679 aReporter->Report( wxString::Format( _( "Board has %lu copper layers not in footprint: %s" ),
680 cuOnlyInBoard.count(),
681 LAYER_UTILS::AccumulateNames( cuOnlyInBoard, &aBoard ) ) );
682 }
683
684 return mismatch;
685}
686
687
688bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFP, int aCompareFlags,
689 REPORTER* aReporter )
690{
691 wxASSERT( aLibFP );
692 bool diff = false;
693
694 // To avoid issues when comparing the footprint on board and the footprint in library
695 // use the footprint from lib flipped, rotated and at same position as this.
696 // And using the footprint from lib with same changes as this minimize the issues
697 // due to rounding and shape modifications
698
699 std::unique_ptr<FOOTPRINT> temp( static_cast<FOOTPRINT*>( aLibFP->Clone() ) );
700
701 temp->SetParent( GetBoard() ); // Needed to know the copper layer count;
702
703 if( !( aCompareFlags & COMPARE_FLAGS::INSTANCE_TO_INSTANCE ) )
704 {
705 if( IsFlipped() != temp->IsFlipped() )
706 temp->Flip( { 0, 0 }, FLIP_DIRECTION::TOP_BOTTOM );
707
708 if( GetOrientation() != temp->GetOrientation() )
709 temp->SetOrientation( GetOrientation() );
710
711 if( GetPosition() != temp->GetPosition() )
712 temp->SetPosition( GetPosition() );
713 }
714
715 for( BOARD_ITEM* item : temp->GraphicalItems() )
716 item->NormalizeForCompare();
717
718 // This temporary footprint must not have a parent when it goes out of scope because it
719 // must not trigger the IncrementTimestamp call in ~FOOTPRINT.
720 temp->SetParent( nullptr );
721
722 aLibFP = temp.get();
723
724 // These checks don't set off errors, they're just informational
725 footprintVsBoardStackup( *this, *GetBoard(), aReporter );
726
727#define TEST_ATTR( a, b, attr, msg ) TEST( ( a & attr ), ( b & attr ), msg )
728
730 _( "Footprint types differ." ) );
731
733 wxString::Format( _( "'%s' settings differ." ),
734 _( "Allow bridged solder mask apertures between pads" ) ) );
735
736 if( !( aCompareFlags & COMPARE_FLAGS::DRC ) )
737 {
738 // These tests are skipped for DRC: they are presumed to relate to a given design.
740 wxString::Format( _( "'%s' settings differ." ),
741 _( "Not in schematic" ) ) );
742
744 wxString::Format( _( "'%s' settings differ." ),
745 _( "Exclude from position files" ) ) );
746
748 wxString::Format( _( "'%s' settings differ." ),
749 _( "Exclude from bill of materials" ) ) );
750
752 wxString::Format( _( "'%s' settings differ." ),
753 _( "Do not populate" ) ) );
754 }
755
756#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
757#define CHECKPOINT { if( diff && !aReporter ) return diff; }
758
759 if( stackupNeedsUpdate( *this, *aLibFP, aReporter ) )
760 {
761 diff = true;
762 REPORT( _( "Footprint stackup differs." ) );
763 }
764
765 // Clearance and zone connection overrides are as likely to be set at the board level as in
766 // the library.
767 //
768 // If we ignore them and someone *does* change one of them in the library, then stale
769 // footprints won't be caught.
770 //
771 // On the other hand, if we report them then boards that override at the board level are
772 // going to be VERY noisy.
773 //
774 // For report them as different, but we DON'T generate DRC errors on them.
775 if( !( aCompareFlags & COMPARE_FLAGS::DRC ) )
776 {
777 if( GetLocalClearance().has_value() && GetLocalClearance() != aLibFP->GetLocalClearance() )
778 {
779 diff = true;
780 REPORT( _( "Pad clearance overridden." ) );
781 }
782
783 if( GetLocalSolderMaskMargin().has_value()
785 {
786 diff = true;
787 REPORT( _( "Solder mask expansion overridden." ) );
788 }
789
790
791 if( GetLocalSolderPasteMargin().has_value()
793 {
794 diff = true;
795 REPORT( _( "Solder paste absolute clearance overridden." ) );
796 }
797
800 {
801 diff = true;
802 REPORT( _( "Solder paste relative clearance overridden." ) );
803 }
804
807 {
808 diff = true;
809 REPORT( _( "Zone connection overridden." ) );
810 }
811 }
812
813 TEST( GetNetTiePadGroups().size(), aLibFP->GetNetTiePadGroups().size(),
814 _( "Net tie pad groups differ." ) );
815
816 for( size_t ii = 0; ii < GetNetTiePadGroups().size(); ++ii )
817 {
818 TEST( GetNetTiePadGroups()[ii], aLibFP->GetNetTiePadGroups()[ii],
819 _( "Net tie pad groups differ." ) );
820 }
821
822 // Text items are really problematic. We don't want to test the reference, but after that
823 // it gets messy.
824 //
825 // What about the value? Depends on whether or not it's a singleton part.
826 //
827 // And what about other texts? They might be added only to instances on the board, or even
828 // changed for instances on the board. Or they might want to be tested for equality.
829 //
830 // Currently we punt and ignore all the text items.
831
832 // Drawings and pads are also somewhat problematic as there's no guarantee that they'll be
833 // in the same order in the two footprints. Rather than building some sophisticated hashing
834 // algorithm we use the footprint sorting functions to attempt to sort them in the same
835 // order.
836
837 // However FOOTPRINT::cmp_drawings uses PCB_SHAPE coordinates and other infos, so we have
838 // already normalized graphic items in model footprint from library, so we need to normalize
839 // graphic items in the footprint to test (*this). So normalize them using a copy of this
840 FOOTPRINT dummy( *this );
841 dummy.SetParentGroup( nullptr );
842 dummy.SetParent( nullptr );
843
844 for( BOARD_ITEM* item : dummy.GraphicalItems() )
845 item->NormalizeForCompare();
846
847 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aShapes;
848 std::copy_if( dummy.GraphicalItems().begin(), dummy.GraphicalItems().end(),
849 std::inserter( aShapes, aShapes.begin() ),
850 []( BOARD_ITEM* item )
851 {
852 return item->Type() == PCB_SHAPE_T;
853 } );
854
855 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bShapes;
856 std::copy_if( aLibFP->GraphicalItems().begin(), aLibFP->GraphicalItems().end(),
857 std::inserter( bShapes, bShapes.begin() ),
858 []( BOARD_ITEM* item )
859 {
860 return item->Type() == PCB_SHAPE_T;
861 } );
862
863 if( aShapes.size() != bShapes.size() )
864 {
865 diff = true;
866 REPORT( _( "Graphic item count differs." ) );
867 }
868 else
869 {
870 for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
871 {
872 // aShapes and bShapes are the tested footprint PCB_SHAPE and the model PCB_SHAPE.
873 // These shapes are already normalized.
874 PCB_SHAPE* curr_shape = static_cast<PCB_SHAPE*>( *aIt );
875 PCB_SHAPE* test_shape = static_cast<PCB_SHAPE*>( *bIt );
876
877 if( shapeNeedsUpdate( *curr_shape, *test_shape ) )
878 {
879 diff = true;
880 REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
881 }
882 }
883 }
884
886
887 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aBarcodes;
888 std::copy_if( dummy.GraphicalItems().begin(), dummy.GraphicalItems().end(),
889 std::inserter( aBarcodes, aBarcodes.begin() ),
890 []( BOARD_ITEM* item )
891 {
892 return item->Type() == PCB_BARCODE_T;
893 } );
894
895 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bBarcodes;
896 std::copy_if( aLibFP->GraphicalItems().begin(), aLibFP->GraphicalItems().end(),
897 std::inserter( bBarcodes, bBarcodes.begin() ),
898 []( BOARD_ITEM* item )
899 {
900 return item->Type() == PCB_BARCODE_T;
901 } );
902
903 if( aBarcodes.size() != bBarcodes.size() )
904 {
905 diff = true;
906 REPORT( _( "Barcode count differs." ) );
907 }
908 else
909 {
910 for( auto aIt = aBarcodes.begin(), bIt = bBarcodes.begin(); aIt != aBarcodes.end(); aIt++, bIt++ )
911 {
912 // aBarcodes and bBarcodes are the tested footprint PCB_BARCODE and the model PCB_BARCODE.
913 // These shapes are already normalized.
914 PCB_BARCODE* curr_barcode = static_cast<PCB_BARCODE*>( *aIt );
915 PCB_BARCODE* test_barcode = static_cast<PCB_BARCODE*>( *bIt );
916
917 if( barcodeNeedsUpdate( *curr_barcode, *test_barcode ) )
918 {
919 diff = true;
920 REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
921 }
922 }
923 }
924
926
927 std::set<PAD*, FOOTPRINT::cmp_pads> aPads( Pads().begin(), Pads().end() );
928 std::set<PAD*, FOOTPRINT::cmp_pads> bPads( aLibFP->Pads().begin(), aLibFP->Pads().end() );
929
930 if( aPads.size() != bPads.size() )
931 {
932 diff = true;
933 REPORT( _( "Pad count differs." ) );
934 }
935 else
936 {
937 for( auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
938 {
939 if( padNeedsUpdate( *aIt, *bIt, aReporter ) )
940 diff = true;
941 else if( aReporter && padHasOverrides( *aIt, *bIt, *aReporter ) )
942 diff = true;
943 }
944 }
945
947
948 std::set<ZONE*, FOOTPRINT::cmp_zones> aZones( Zones().begin(), Zones().end() );
949 std::set<ZONE*, FOOTPRINT::cmp_zones> bZones( aLibFP->Zones().begin(), aLibFP->Zones().end() );
950
951 if( aZones.size() != bZones.size() )
952 {
953 diff = true;
954 REPORT( _( "Rule area count differs." ) );
955 }
956 else
957 {
958 for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
959 diff |= zoneNeedsUpdate( *aIt, *bIt, aReporter );
960 }
961
962 return diff;
963}
964
965
967{
968 BOARD* board = m_drcEngine->GetBoard();
969 PROJECT* project = board->GetProject();
970
971 if( !project )
972 {
973 REPORT_AUX( _( "No project loaded, skipping library parity tests." ) );
974 return true; // Continue with other tests
975 }
976
977 if( !reportPhase( _( "Loading footprint library table..." ) ) )
978 return false; // DRC cancelled
979
980 std::map<LIB_ID, std::shared_ptr<FOOTPRINT>> libFootprintCache;
981
983 wxString msg;
984 int ii = 0;
985 const int progressDelta = 250;
986
987 if( !reportPhase( _( "Checking board footprints against library..." ) ) )
988 return false;
989
990 for( FOOTPRINT* footprint : board->Footprints() )
991 {
992 if( m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES )
993 && m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_MISMATCH ) )
994 {
995 return true; // Continue with other tests
996 }
997
998 if( !reportProgress( ii++, (int) board->Footprints().size(), progressDelta ) )
999 return false; // DRC cancelled
1000
1001 LIB_ID fpID = footprint->GetFPID();
1002 wxString libName = fpID.GetLibNickname();
1003 wxString fpName = fpID.GetLibItemName();
1004 const LIB_TABLE_ROW* libTableRow = nullptr;
1005
1006 if( libName.IsEmpty() )
1007 {
1008 // Not much we can do here
1009 continue;
1010 }
1011
1012 try
1013 {
1014 libTableRow = libTable->FindRow( libName );
1015 }
1016 catch( const IO_ERROR& )
1017 {
1018 }
1019
1020 if( !libTableRow )
1021 {
1022 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1023 {
1024 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1025 msg.Printf( _( "The current configuration does not include the footprint library '%s'" ),
1026 UnescapeString( libName ) );
1027 drcItem->SetErrorMessage( msg );
1028 drcItem->SetItems( footprint );
1029 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1030 }
1031
1032 continue;
1033 }
1034 else if( !libTable->HasLibrary( libName, true ) )
1035 {
1036 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1037 {
1038 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1039 msg.Printf( _( "The footprint library '%s' is not enabled in the current configuration" ),
1040 UnescapeString( libName ) );
1041 drcItem->SetErrorMessage( msg );
1042 drcItem->SetItems( footprint );
1043 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1044 }
1045
1046 continue;
1047 }
1048 else if( !libTableRow->LibraryExists() )
1049 {
1050 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1051 {
1052 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1053 msg.Printf( _( "The footprint library '%s' was not found at '%s'" ),
1054 UnescapeString( libName ),
1055 libTableRow->GetFullURI( true ) );
1056 drcItem->SetErrorMessage( msg );
1057 drcItem->SetItems( footprint );
1058 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1059 }
1060
1061 continue;
1062 }
1063
1064 auto cacheIt = libFootprintCache.find( fpID );
1065 std::shared_ptr<FOOTPRINT> libFootprint;
1066
1067 if( cacheIt != libFootprintCache.end() )
1068 {
1069 libFootprint = cacheIt->second;
1070 }
1071 else
1072 {
1073 try
1074 {
1075 libFootprint.reset( libTable->FootprintLoad( libName, fpName, true ) );
1076
1077 if( libFootprint )
1078 libFootprintCache[ fpID ] = libFootprint;
1079 }
1080 catch( const IO_ERROR& )
1081 {
1082 }
1083 }
1084
1085 if( !libFootprint )
1086 {
1087 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1088 {
1089 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1090 msg.Printf( _( "Footprint '%s' not found in library '%s'" ),
1091 fpName,
1092 libName );
1093 drcItem->SetErrorMessage( msg );
1094 drcItem->SetItems( footprint );
1095 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1096 }
1097 }
1098 else if( footprint->FootprintNeedsUpdate( libFootprint.get(), BOARD_ITEM::COMPARE_FLAGS::DRC ) )
1099 {
1100 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_MISMATCH ) )
1101 {
1102 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_MISMATCH );
1103 msg.Printf( _( "Footprint '%s' does not match copy in library '%s'" ),
1104 fpName,
1105 libName );
1106 drcItem->SetErrorMessage( msg );
1107 drcItem->SetItems( footprint );
1108 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1109 }
1110 }
1111 }
1112
1113 return true;
1114}
1115
1116
1117namespace detail
1118{
1120}
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:79
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:81
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
VECTOR2I GetFPRelativePosition() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:252
@ INSTANCE_TO_INSTANCE
Definition board_item.h:436
virtual bool IsOnCopperLayer() const
Definition board_item.h:151
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:692
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:924
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:381
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:337
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
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
const FP_LIB_TABLE_ROW * FindRow(const wxString &aNickName, bool aCheckIfEnabled=false)
Return an FP_LIB_TABLE_ROW if aNickName is found in this table or in any chained fall back table frag...
FOOTPRINT * FootprintLoad(const wxString &aNickname, const wxString &aFootprintName, bool aKeepUUID=false)
Load a footprint having aFootprintName from the library given by aNickname.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
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
Hold a record identifying a library accessed by the appropriate plug in object in the LIB_TABLE.
virtual bool LibraryExists() const =0
const wxString GetFullURI(bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
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
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::...
Definition padstack.cpp:882
std::vector< PCB_LAYER_ID > UniqueLayers() const
Definition padstack.cpp:909
Definition pad.h:54
PAD_PROP GetProperty() const
Definition pad.h:443
bool GetRemoveUnconnected() const
Definition pad.h:733
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:365
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition pad.h:475
const VECTOR2I & GetDrillSize() const
Definition pad.h:305
PAD_ATTRIB GetAttribute() const
Definition pad.h:440
const wxString & GetNumber() const
Definition pad.h:136
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
Definition pad.h:299
EDA_ANGLE GetThermalSpokeAngle() const
Definition pad.h:625
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:671
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:195
bool GetKeepTopBottom() const
Definition pad.h:748
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition pad.h:458
const PADSTACK & Padstack() const
Definition pad.h:321
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.h:317
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition pad.h:221
PAD_DRILL_SHAPE GetDrillShape() const
Definition pad.h:422
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition pad.h:711
std::optional< int > GetLocalSolderPasteMargin() const
Definition pad.h:468
std::optional< int > GetLocalSolderMaskMargin() const
Definition pad.h:461
EDA_ANGLE GetFPRelativeOrientation() const
Definition pad.cpp:974
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:694
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition pad.h:609
ZONE_CONNECTION GetLocalZoneConnection() const
Definition pad.h:486
int GetThermalGap() const
Definition pad.h:641
int GetLocalThermalGapOverride(wxString *aSource) const
Definition pad.cpp:1333
int GetPadToDieLength() const
Definition pad.h:453
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 FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
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:704
std::optional< int > GetLocalClearance() const override
Definition zone.cpp:814
bool GetDoNotAllowVias() const
Definition zone.h:720
bool GetDoNotAllowPads() const
Definition zone.h:722
bool GetDoNotAllowTracks() const
Definition zone.h:721
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition zone.h:731
SHAPE_POLY_SET * Outline()
Definition zone.h:335
long long int GetMinIslandArea() const
Definition zone.h:734
const wxString & GetZoneName() const
Definition zone.h:163
int GetMinThickness() const
Definition zone.h:301
ZONE_CONNECTION GetPadConnection() const
Definition zone.h:298
int GetHatchThickness() const
Definition zone.h:310
double GetHatchHoleMinArea() const
Definition zone.h:325
int GetThermalReliefSpokeWidth() const
Definition zone.h:245
EDA_ANGLE GetHatchOrientation() const
Definition zone.h:316
bool GetDoNotAllowFootprints() const
Definition zone.h:723
ZONE_FILL_MODE GetFillMode() const
Definition zone.h:224
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:313
double GetHatchSmoothingValue() const
Definition zone.h:322
bool GetDoNotAllowZoneFills() const
Definition zone.h:719
int GetHatchSmoothingLevel() const
Definition zone.h:319
unsigned int GetCornerRadius() const
Definition zone.h:650
int GetCornerSmoothingType() const
Definition zone.h:646
int GetThermalReliefGap() const
Definition zone.h:234
unsigned GetAssignedPriority() const
Definition zone.h:126
@ DRCE_LIB_FOOTPRINT_ISSUES
Definition drc_item.h:82
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition drc_item.h:83
#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)
#define PAD_DESC(pad)
bool primitiveNeedsUpdate(const std::shared_ptr< PCB_SHAPE > &a, const std::shared_ptr< PCB_SHAPE > &b)
#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 padNeedsUpdate(const PAD *a, const PAD *b, REPORTER *aReporter)
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
#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