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 <zone.h>
33#include <footprint.h>
34#include <pad.h>
35#include <drc/drc_engine.h>
36#include <drc/drc_item.h>
38#include <project_pcb.h>
39#include <string_utils.h>
40
41
42/*
43 Library parity test.
44
45 Errors generated:
46 - DRCE_LIB_FOOTPRINT_ISSUES
47 - DRCE_LIB_FOOTPRINT_MISMATCH
48*/
49
51{
52public:
57
59
60 virtual bool Run() override;
61
62 virtual const wxString GetName() const override { return wxT( "library_parity" ); };
63};
64
65
66//
67// The TEST*() macros have two modes:
68// In "Report" mode (aReporter != nullptr) all properties are checked and reported on.
69// In "DRC" mode (aReporter == nulltpr) properties are only checked until a difference is found.
70//
71#define TEST( a, b, msg ) \
72 do { \
73 if( a != b ) \
74 { \
75 diff = true; \
76 \
77 if( aReporter && wxString( msg ).length() ) \
78 aReporter->Report( msg ); \
79 } \
80 \
81 if( diff && !aReporter ) \
82 return diff; \
83 } while (0)
84
85#define EPSILON 2
86#define TEST_PT( a, b, msg ) \
87 do { \
88 if( abs( a.x - b.x ) > EPSILON \
89 || abs( a.y - b.y ) > EPSILON ) \
90 { \
91 diff = true; \
92 \
93 if( aReporter && wxString( msg ).length() ) \
94 aReporter->Report( msg ); \
95 } \
96 \
97 if( diff && !aReporter ) \
98 return diff; \
99 } while (0)
100
101#define EPSILON_D 0.000002
102#define TEST_D( a, b, msg ) \
103 do { \
104 if( abs( a - b ) > EPSILON_D ) \
105 { \
106 diff = true; \
107 \
108 if( aReporter && wxString( msg ).length() ) \
109 aReporter->Report( msg ); \
110 } \
111 \
112 if( diff && !aReporter ) \
113 return diff; \
114 } while (0)
115
116#define ITEM_DESC( item ) ( item )->GetItemDescription( &g_unitsProvider, true )
117#define PAD_DESC( pad ) wxString::Format( _( "Pad %s" ), ( pad )->GetNumber() )
118
119
121
122
123LSET getBoardNormalizedLayerSet( const BOARD_ITEM* aLibItem, const BOARD* aBoard )
124{
125 LSET lset = aLibItem->GetLayerSet();
126
127 if( aBoard )
128 lset &= aBoard->GetEnabledLayers();
129
130 return lset;
131}
132
133
134bool primitiveNeedsUpdate( const std::shared_ptr<PCB_SHAPE>& a,
135 const std::shared_ptr<PCB_SHAPE>& b )
136{
137 REPORTER* aReporter = nullptr;
138 bool diff = false;
139
140 TEST( a->GetShape(), b->GetShape(), "" );
141
142 switch( a->GetShape() )
143 {
145 {
146 BOX2I aRect( a->GetStart(), a->GetEnd() - a->GetStart() );
147 BOX2I bRect( b->GetStart(), b->GetEnd() - b->GetStart() );
148
149 aRect.Normalize();
150 bRect.Normalize();
151
152 TEST_PT( aRect.GetOrigin(), bRect.GetOrigin(), "" );
153 TEST_PT( aRect.GetEnd(), bRect.GetEnd(), "" );
154 break;
155 }
156
157 case SHAPE_T::SEGMENT:
158 case SHAPE_T::CIRCLE:
159 TEST_PT( a->GetStart(), b->GetStart(), "" );
160 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
161 break;
162
163 case SHAPE_T::ARC:
164 TEST_PT( a->GetStart(), b->GetStart(), "" );
165 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
166
167 // Arc center is calculated and so may have round-off errors when parents are
168 // differentially rotated.
169 if( ( a->GetArcMid() - b->GetArcMid() ).EuclideanNorm() > pcbIUScale.mmToIU( 0.0005 ) )
170 return true;
171
172 break;
173
174 case SHAPE_T::BEZIER:
175 TEST_PT( a->GetStart(), b->GetStart(), "" );
176 TEST_PT( a->GetEnd(), b->GetEnd(), "" );
177 TEST_PT( a->GetBezierC1(), b->GetBezierC1(), "" );
178 TEST_PT( a->GetBezierC2(), b->GetBezierC2(), "" );
179 break;
180
181 case SHAPE_T::POLY:
182 TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(), "" );
183
184 for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
185 TEST_PT( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), "" );
186
187 break;
188
189 default:
190 UNIMPLEMENTED_FOR( a->SHAPE_T_asString() );
191 }
192
193 TEST( a->GetStroke(), b->GetStroke(), "" );
194 TEST( a->GetFillMode(), b->GetFillMode(), "" );
195
196 return diff;
197}
198
199
200bool padHasOverrides( const PAD* a, const PAD* b, REPORTER& aReporter )
201{
202 bool diff = false;
203
204#define REPORT_MSG( s, p ) aReporter.Report( wxString::Format( s, p ) )
205
206 if( a->GetLocalClearance().has_value() && a->GetLocalClearance() != b->GetLocalClearance() )
207 {
208 diff = true;
209 REPORT_MSG( _( "%s has clearance override." ), PAD_DESC( a ) );
210 }
211
212 if( a->GetLocalSolderMaskMargin().has_value()
214 {
215 diff = true;
216 REPORT_MSG( _( "%s has solder mask expansion override." ), PAD_DESC( a ) );
217 }
218
219
220 if( a->GetLocalSolderPasteMargin().has_value()
222 {
223 diff = true;
224 REPORT_MSG( _( "%s has solder paste clearance override." ), PAD_DESC( a ) );
225 }
226
229 {
230 diff = true;
231 REPORT_MSG( _( "%s has solder paste clearance override." ), PAD_DESC( a ) );
232 }
233
236 {
237 diff = true;
238 REPORT_MSG( _( "%s has zone connection override." ), PAD_DESC( a ) );
239 }
240
241 if( a->GetLocalThermalGapOverride().has_value()
242 && a->GetThermalGap() != b->GetThermalGap() )
243 {
244 diff = true;
245 REPORT_MSG( _( "%s has thermal relief gap override." ), PAD_DESC( a ) );
246 }
247
248 if( a->GetLocalThermalSpokeWidthOverride().has_value()
250 {
251 diff = true;
252 REPORT_MSG( _( "%s has thermal relief spoke width override." ), PAD_DESC( a ) );
253 }
254
256 {
257 diff = true;
258 REPORT_MSG( _( "%s has thermal relief spoke angle override." ), PAD_DESC( a ) );
259 }
260
262 {
263 diff = true;
264 REPORT_MSG( _( "%s has zone knockout setting override." ), PAD_DESC( a ) );
265 }
266
267 return diff;
268}
269
270
271bool padNeedsUpdate( const PAD* a, const PAD* b, REPORTER* aReporter )
272{
273 bool diff = false;
274
276 wxString::Format( _( "%s pad to die length differs." ), PAD_DESC( a ) ) );
278 wxString::Format( _( "%s position differs." ), PAD_DESC( a ) ) );
279
280 TEST( a->GetNumber(), b->GetNumber(),
281 wxString::Format( _( "%s has different numbers." ), PAD_DESC( a ) ) );
282
283 // These are assigned from the schematic and not from the library
284 // TEST( a->GetPinFunction(), b->GetPinFunction() );
285 // TEST( a->GetPinType(), b->GetPinType() );
286
287 bool layerSettingsDiffer = a->GetRemoveUnconnected() != b->GetRemoveUnconnected();
288
289 // NB: KeepTopBottom is undefined if RemoveUnconnected is NOT set.
290 if( a->GetRemoveUnconnected() )
291 layerSettingsDiffer |= a->GetKeepTopBottom() != b->GetKeepTopBottom();
292
293 if( layerSettingsDiffer
295 {
296 diff = true;
297
298 if( aReporter )
299 aReporter->Report( wxString::Format( _( "%s layers differ." ), PAD_DESC( a ) ) );
300 else
301 return true;
302 }
303
304 TEST( a->GetAttribute(), b->GetAttribute(),
305 wxString::Format( _( "%s pad type differs." ), PAD_DESC( a ) ) );
306 TEST( a->GetProperty(), b->GetProperty(),
307 wxString::Format( _( "%s fabrication property differs." ), PAD_DESC( a ) ) );
308
309 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
312 wxString::Format( _( "%s orientation differs." ), PAD_DESC( a ) ) );
313
314 std::vector<PCB_LAYER_ID> layers = a->Padstack().UniqueLayers();
315 const BOARD* board = a->GetBoard();
316 wxString layerName;
317
318 for( PCB_LAYER_ID layer : layers )
319 {
320 layerName = board ? board->GetLayerName( layer ) : LayerName( layer );
321
322 TEST( a->GetShape( layer ), b->GetShape( layer ),
323 wxString::Format( _( "%s pad shape type differs on layer %s." ),
324 PAD_DESC( a ),
325 layerName ) );
326
327 TEST( a->GetSize( layer ), b->GetSize( layer ),
328 wxString::Format( _( "%s size differs on layer %s." ),
329 PAD_DESC( a ),
330 layerName ) );
331
332 TEST( a->GetDelta( layer ), b->GetDelta( layer ),
333 wxString::Format( _( "%s trapezoid delta differs on layer %s." ),
334 PAD_DESC( a ),
335 layerName ) );
336
337 if( a->GetShape( layer ) == PAD_SHAPE::ROUNDRECT || a->GetShape( layer ) == PAD_SHAPE::CHAMFERED_RECT)
338 {
339 TEST_D( a->GetRoundRectRadiusRatio( layer ),
340 b->GetRoundRectRadiusRatio( layer ),
341 wxString::Format( _( "%s rounded corners differ on layer %s." ),
342 PAD_DESC( a ),
343 layerName ) );
344 }
345
346 if( a->GetShape( layer ) == PAD_SHAPE::CHAMFERED_RECT)
347 {
348 TEST_D( a->GetChamferRectRatio( layer ),
349 b->GetChamferRectRatio( layer ),
350 wxString::Format( _( "%s chamfered corner sizes differ on layer %s." ),
351 PAD_DESC( a ),
352 layerName ) );
353
354 TEST( a->GetChamferPositions( layer ),
355 b->GetChamferPositions( layer ),
356 wxString::Format( _( "%s chamfered corners differ on layer %s." ),
357 PAD_DESC( a ),
358 layerName ) );
359 }
360
361 TEST_PT( a->GetOffset( layer ), b->GetOffset( layer ),
362 wxString::Format( _( "%s shape offset from hole differs on layer %s." ),
363 PAD_DESC( a ),
364 layerName ) );
365 }
366
367 TEST( a->GetDrillShape(), b->GetDrillShape(),
368 wxString::Format( _( "%s drill shape differs." ), PAD_DESC( a ) ) );
369 TEST( a->GetDrillSize(), b->GetDrillSize(),
370 wxString::Format( _( "%s drill size differs." ), PAD_DESC( a ) ) );
371
372 // Clearance and zone connection overrides are as likely to be set at the board level as in
373 // the library.
374 //
375 // If we ignore them and someone *does* change one of them in the library, then stale
376 // footprints won't be caught.
377 //
378 // On the other hand, if we report them then boards that override at the board level are
379 // going to be VERY noisy.
380 //
381 // So we just do it when we have a reporter.
382 if( aReporter && padHasOverrides( a, b, *aReporter ) )
383 diff = true;
384
385 bool primitivesDiffer = false;
386 PCB_LAYER_ID firstDifferingLayer = UNDEFINED_LAYER;
387
389 [&]( PCB_LAYER_ID aLayer )
390 {
391 if( a->GetPrimitives( aLayer ).size() != b->GetPrimitives( aLayer ).size() )
392 {
393 primitivesDiffer = true;
394 }
395 else
396 {
397 for( size_t ii = 0; ii < a->GetPrimitives( aLayer ).size(); ++ii )
398 {
399 if( primitiveNeedsUpdate( a->GetPrimitives( aLayer )[ii],
400 b->GetPrimitives( aLayer )[ii] ) )
401 {
402 primitivesDiffer = true;
403 break;
404 }
405 }
406 }
407
408 if( primitivesDiffer && firstDifferingLayer == UNDEFINED_LAYER )
409 firstDifferingLayer = aLayer;
410 } );
411
412
413 if( primitivesDiffer )
414 {
415 diff = true;
416 layerName = board ? board->GetLayerName( firstDifferingLayer )
417 : LayerName( firstDifferingLayer );
418
419 if( aReporter )
420 {
421 aReporter->Report( wxString::Format( _( "%s shape primitives differ on layer %s." ),
422 PAD_DESC( a ),
423 layerName ) );
424 }
425 else
426 {
427 return true;
428 }
429 }
430
431 return diff;
432}
433
434
435bool shapeNeedsUpdate( const PCB_SHAPE& curr_shape, const PCB_SHAPE& ref_shape )
436{
437 // curr_shape and ref_shape are expected to be normalized, for a more reliable test.
438 REPORTER* aReporter = nullptr;
439 bool diff = false;
440
441 TEST( curr_shape.GetShape(), ref_shape.GetShape(), "" );
442
443 switch( curr_shape.GetShape() )
444 {
446 {
447 BOX2I aRect( curr_shape.GetStart(), curr_shape.GetEnd() - curr_shape.GetStart() );
448 BOX2I bRect( ref_shape.GetStart(), ref_shape.GetEnd() - ref_shape.GetStart() );
449
450 aRect.Normalize();
451 bRect.Normalize();
452
453 TEST_PT( aRect.GetOrigin(), bRect.GetOrigin(), "" );
454 TEST_PT( aRect.GetEnd(), bRect.GetEnd(), "" );
455 break;
456 }
457
458 case SHAPE_T::SEGMENT:
459 case SHAPE_T::CIRCLE:
460 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
461 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
462 break;
463
464 case SHAPE_T::ARC:
465 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
466 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
467
468 // Arc center is calculated and so may have round-off errors when parents are
469 // differentially rotated.
470 if( ( curr_shape.GetArcMid() - ref_shape.GetArcMid() ).EuclideanNorm() > pcbIUScale.mmToIU( 0.0005 ) )
471 return true;
472
473 break;
474
475 case SHAPE_T::BEZIER:
476 TEST_PT( curr_shape.GetStart(), ref_shape.GetStart(), "" );
477 TEST_PT( curr_shape.GetEnd(), ref_shape.GetEnd(), "" );
478 TEST_PT( curr_shape.GetBezierC1(), ref_shape.GetBezierC1(), "" );
479 TEST_PT( curr_shape.GetBezierC2(), ref_shape.GetBezierC2(), "" );
480 break;
481
482 case SHAPE_T::POLY:
483 TEST( curr_shape.GetPolyShape().TotalVertices(), ref_shape.GetPolyShape().TotalVertices(), "" );
484
485 for( int ii = 0; ii < curr_shape.GetPolyShape().TotalVertices(); ++ii )
486 TEST_PT( curr_shape.GetPolyShape().CVertex( ii ), ref_shape.GetPolyShape().CVertex( ii ), "" );
487
488 break;
489
490 default:
491 UNIMPLEMENTED_FOR( curr_shape.SHAPE_T_asString() );
492 }
493
494 if( curr_shape.IsOnCopperLayer() )
495 TEST( curr_shape.GetStroke(), ref_shape.GetStroke(), "" );
496
497 TEST( curr_shape.GetFillMode(), ref_shape.GetFillMode(), "" );
498
499 TEST( curr_shape.GetLayer(), ref_shape.GetLayer(), "" );
500
501 return diff;
502}
503
504
505bool zoneNeedsUpdate( const ZONE* a, const ZONE* b, REPORTER* aReporter )
506{
507 bool diff = false;
508
510 wxString::Format( _( "%s corner smoothing setting differs." ), ITEM_DESC( a ) ) );
512 wxString::Format( _( "%s corner smoothing radius differs." ), ITEM_DESC( a ) ) );
513 TEST( a->GetZoneName(), b->GetZoneName(),
514 wxString::Format( _( "%s name differs." ), ITEM_DESC( a ) ) );
516 wxString::Format( _( "%s priority differs." ), ITEM_DESC( a ) ) );
517
518 TEST( a->GetIsRuleArea(), b->GetIsRuleArea(),
519 wxString::Format( _( "%s keep-out property differs." ), ITEM_DESC( a ) ) );
521 wxString::Format( _( "%s keep out zone fill setting differs." ), ITEM_DESC( a ) ) );
523 wxString::Format( _( "%s keep out footprints setting differs." ), ITEM_DESC( a ) ) );
525 wxString::Format( _( "%s keep out pads setting differs." ), ITEM_DESC( a ) ) );
527 wxString::Format( _( "%s keep out tracks setting differs." ), ITEM_DESC( a ) ) );
529 wxString::Format( _( "%s keep out vias setting differs." ), ITEM_DESC( a ) ) );
530
532 wxString::Format( _( "%s layers differ." ), ITEM_DESC( a ) ) );
533
535 wxString::Format( _( "%s pad connection property differs." ), ITEM_DESC( a ) ) );
537 wxString::Format( _( "%s local clearance differs." ), ITEM_DESC( a ) ) );
539 wxString::Format( _( "%s thermal relief gap differs." ), ITEM_DESC( a ) ) );
541 wxString::Format( _( "%s thermal relief spoke width differs." ), ITEM_DESC( a ) ) );
542
544 wxString::Format( _( "%s min thickness differs." ), ITEM_DESC( a ) ) );
545
547 wxString::Format( _( "%s remove islands setting differs." ), ITEM_DESC( a ) ) );
549 wxString::Format( _( "%s minimum island size setting differs." ), ITEM_DESC( a ) ) );
550
551 TEST( a->GetFillMode(), b->GetFillMode(),
552 wxString::Format( _( "%s fill type differs." ), ITEM_DESC( a ) ) );
554 wxString::Format( _( "%s hatch width differs." ), ITEM_DESC( a ) ) );
555 TEST( a->GetHatchGap(), b->GetHatchGap(),
556 wxString::Format( _( "%s hatch gap differs." ), ITEM_DESC( a ) ) );
558 wxString::Format( _( "%s hatch orientation differs." ), ITEM_DESC( a ) ) );
560 wxString::Format( _( "%s hatch smoothing level differs." ), ITEM_DESC( a ) ) );
562 wxString::Format( _( "%s hatch smoothing amount differs." ), ITEM_DESC( a ) ) );
564 wxString::Format( _( "%s minimum hatch hole setting differs." ), ITEM_DESC( a ) ) );
565
566 // This is just a display property
567 // TEST( a->GetHatchBorderAlgorithm(), b->GetHatchBorderAlgorithm() );
568
570 wxString::Format( _( "%s outline corner count differs." ), ITEM_DESC( a ) ) );
571
572 bool cornersDiffer = false;
573
574 for( int ii = 0; ii < a->Outline()->TotalVertices(); ++ii )
575 {
576 if( a->Outline()->CVertex( ii ) != b->Outline()->CVertex( ii ) )
577 {
578 diff = true;
579 cornersDiffer = true;
580 break;
581 }
582 }
583
584 if( cornersDiffer && aReporter )
585 aReporter->Report( wxString::Format( _( "%s corners differ." ), ITEM_DESC( a ) ) );
586
587 return diff;
588}
589
590
596bool stackupNeedsUpdate( const FOOTPRINT& a, const FOOTPRINT& b, REPORTER* aReporter )
597{
598 bool diff = false;
599
601 wxString::Format( _( "Footprint stackup mode differs." ) ) );
602
603 const LSET& aLayers = a.GetLayerSet();
604 const LSET& bLayers = b.GetLayerSet();
605
606 TEST( aLayers, bLayers,
607 wxString::Format( _( "Footprint layers differ." ) ) );
608
609 return diff;
610}
611
612
621bool footprintVsBoardStackup( const FOOTPRINT& aFp, const BOARD& aBoard, REPORTER* aReporter )
622{
624 return false;
625
626 // Filter only layers that can differ between footprint and board
627 const LSET& fpLayers = aFp.GetStackupLayers();
628 const LSET& brdLayers = aBoard.GetEnabledLayers() & ( LSET::AllCuMask() | LSET::UserDefinedLayersMask() );
629
630 bool mismatch = false;
631
632 // Any layer in the FP and not on the board is flagged
633 const LSET onlyInFp = fpLayers & ~brdLayers;
634
635 if( onlyInFp.count() )
636 {
637 mismatch = true;
638 if( aReporter )
639 aReporter->Report( wxString::Format( _( "Footprint has %lu layers not on board: %s" ), onlyInFp.count(),
640 LAYER_UTILS::AccumulateNames( onlyInFp, &aBoard ) ) );
641 }
642
643 // Only look at copper layers here: user layers on the board and not in the FP is normal
644 const LSET cuOnlyInBoard = ( brdLayers & ~fpLayers ) & LSET::AllCuMask();
645
646 if( cuOnlyInBoard.count() )
647 {
648 mismatch = true;
649 if( aReporter )
650 aReporter->Report( wxString::Format( _( "Board has %lu copper layers not in footprint: %s" ),
651 cuOnlyInBoard.count(),
652 LAYER_UTILS::AccumulateNames( cuOnlyInBoard, &aBoard ) ) );
653 }
654
655 return mismatch;
656}
657
658
659bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFP, int aCompareFlags,
660 REPORTER* aReporter )
661{
662 wxASSERT( aLibFP );
663 bool diff = false;
664
665 // To avoid issues when comparing the footprint on board and the footprint in library
666 // use the footprint from lib flipped, rotated and at same position as this.
667 // And using the footprint from lib with same changes as this minimize the issues
668 // due to rounding and shape modifications
669
670 std::unique_ptr<FOOTPRINT> temp( static_cast<FOOTPRINT*>( aLibFP->Clone() ) );
671
672 temp->SetParent( GetBoard() ); // Needed to know the copper layer count;
673
674 if( !( aCompareFlags & COMPARE_FLAGS::INSTANCE_TO_INSTANCE ) )
675 {
676 if( IsFlipped() != temp->IsFlipped() )
677 temp->Flip( { 0, 0 }, FLIP_DIRECTION::TOP_BOTTOM );
678
679 if( GetOrientation() != temp->GetOrientation() )
680 temp->SetOrientation( GetOrientation() );
681
682 if( GetPosition() != temp->GetPosition() )
683 temp->SetPosition( GetPosition() );
684 }
685
686 for( BOARD_ITEM* item : temp->GraphicalItems() )
687 item->NormalizeForCompare();
688
689 // This temporary footprint must not have a parent when it goes out of scope because it
690 // must not trigger the IncrementTimestamp call in ~FOOTPRINT.
691 temp->SetParent( nullptr );
692
693 aLibFP = temp.get();
694
695 // These checks don't set off errors, they're just informational
696 footprintVsBoardStackup( *this, *GetBoard(), aReporter );
697
698#define TEST_ATTR( a, b, attr, msg ) TEST( ( a & attr ), ( b & attr ), msg )
699
701 _( "Footprint types differ." ) );
702
704 wxString::Format( _( "'%s' settings differ." ),
705 _( "Allow bridged solder mask apertures between pads" ) ) );
706
707 if( !( aCompareFlags & COMPARE_FLAGS::DRC ) )
708 {
709 // These tests are skipped for DRC: they are presumed to relate to a given design.
711 wxString::Format( _( "'%s' settings differ." ),
712 _( "Not in schematic" ) ) );
713
715 wxString::Format( _( "'%s' settings differ." ),
716 _( "Exclude from position files" ) ) );
717
719 wxString::Format( _( "'%s' settings differ." ),
720 _( "Exclude from bill of materials" ) ) );
721
723 wxString::Format( _( "'%s' settings differ." ),
724 _( "Do not populate" ) ) );
725 }
726
727#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
728#define CHECKPOINT { if( diff && !aReporter ) return diff; }
729
730 if( stackupNeedsUpdate( *this, *aLibFP, aReporter ) )
731 {
732 diff = true;
733 REPORT( _( "Footprint stackup differs." ) );
734 }
735
736 // Clearance and zone connection overrides are as likely to be set at the board level as in
737 // the library.
738 //
739 // If we ignore them and someone *does* change one of them in the library, then stale
740 // footprints won't be caught.
741 //
742 // On the other hand, if we report them then boards that override at the board level are
743 // going to be VERY noisy.
744 //
745 // For report them as different, but we DON'T generate DRC errors on them.
746 if( !( aCompareFlags & COMPARE_FLAGS::DRC ) )
747 {
748 if( GetLocalClearance().has_value() && GetLocalClearance() != aLibFP->GetLocalClearance() )
749 {
750 diff = true;
751 REPORT( _( "Pad clearance overridden." ) );
752 }
753
754 if( GetLocalSolderMaskMargin().has_value()
756 {
757 diff = true;
758 REPORT( _( "Solder mask expansion overridden." ) );
759 }
760
761
762 if( GetLocalSolderPasteMargin().has_value()
764 {
765 diff = true;
766 REPORT( _( "Solder paste absolute clearance overridden." ) );
767 }
768
771 {
772 diff = true;
773 REPORT( _( "Solder paste relative clearance overridden." ) );
774 }
775
778 {
779 diff = true;
780 REPORT( _( "Zone connection overridden." ) );
781 }
782 }
783
784 TEST( GetNetTiePadGroups().size(), aLibFP->GetNetTiePadGroups().size(),
785 _( "Net tie pad groups differ." ) );
786
787 for( size_t ii = 0; ii < GetNetTiePadGroups().size(); ++ii )
788 {
789 TEST( GetNetTiePadGroups()[ii], aLibFP->GetNetTiePadGroups()[ii],
790 _( "Net tie pad groups differ." ) );
791 }
792
793 // Text items are really problematic. We don't want to test the reference, but after that
794 // it gets messy.
795 //
796 // What about the value? Depends on whether or not it's a singleton part.
797 //
798 // And what about other texts? They might be added only to instances on the board, or even
799 // changed for instances on the board. Or they might want to be tested for equality.
800 //
801 // Currently we punt and ignore all the text items.
802
803 // Drawings and pads are also somewhat problematic as there's no guarantee that they'll be
804 // in the same order in the two footprints. Rather than building some sophisticated hashing
805 // algorithm we use the footprint sorting functions to attempt to sort them in the same
806 // order.
807
808 // However FOOTPRINT::cmp_drawings uses PCB_SHAPE coordinates and other infos, so we have
809 // already normalized graphic items in model footprint from library, so we need to normalize
810 // graphic items in the footprint to test (*this). So normalize them using a copy of this
811 FOOTPRINT dummy( *this );
812 dummy.SetParentGroup( nullptr );
813 dummy.SetParent( nullptr );
814
815 for( BOARD_ITEM* item : dummy.GraphicalItems() )
816 item->NormalizeForCompare();
817
818 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aShapes;
819 std::copy_if( dummy.GraphicalItems().begin(), dummy.GraphicalItems().end(),
820 std::inserter( aShapes, aShapes.begin() ),
821 []( BOARD_ITEM* item )
822 {
823 return item->Type() == PCB_SHAPE_T;
824 } );
825
826 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bShapes;
827 std::copy_if( aLibFP->GraphicalItems().begin(), aLibFP->GraphicalItems().end(),
828 std::inserter( bShapes, bShapes.begin() ),
829 []( BOARD_ITEM* item )
830 {
831 return item->Type() == PCB_SHAPE_T;
832 } );
833
834 if( aShapes.size() != bShapes.size() )
835 {
836 diff = true;
837 REPORT( _( "Graphic item count differs." ) );
838 }
839 else
840 {
841 for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
842 {
843 // aShapes and bShapes are the tested footprint PCB_SHAPE and the model PCB_SHAPE.
844 // These shapes are already normalized.
845 PCB_SHAPE* curr_shape = static_cast<PCB_SHAPE*>( *aIt );
846 PCB_SHAPE* test_shape = static_cast<PCB_SHAPE*>( *bIt );
847
848 if( shapeNeedsUpdate( *curr_shape, *test_shape ) )
849 {
850 diff = true;
851 REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
852 }
853 }
854 }
855
857
858 std::set<PAD*, FOOTPRINT::cmp_pads> aPads( Pads().begin(), Pads().end() );
859 std::set<PAD*, FOOTPRINT::cmp_pads> bPads( aLibFP->Pads().begin(), aLibFP->Pads().end() );
860
861 if( aPads.size() != bPads.size() )
862 {
863 diff = true;
864 REPORT( _( "Pad count differs." ) );
865 }
866 else
867 {
868 for( auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
869 {
870 if( padNeedsUpdate( *aIt, *bIt, aReporter ) )
871 diff = true;
872 else if( aReporter && padHasOverrides( *aIt, *bIt, *aReporter ) )
873 diff = true;
874 }
875 }
876
878
879 std::set<ZONE*, FOOTPRINT::cmp_zones> aZones( Zones().begin(), Zones().end() );
880 std::set<ZONE*, FOOTPRINT::cmp_zones> bZones( aLibFP->Zones().begin(), aLibFP->Zones().end() );
881
882 if( aZones.size() != bZones.size() )
883 {
884 diff = true;
885 REPORT( _( "Rule area count differs." ) );
886 }
887 else
888 {
889 for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
890 diff |= zoneNeedsUpdate( *aIt, *bIt, aReporter );
891 }
892
893 return diff;
894}
895
896
898{
899 BOARD* board = m_drcEngine->GetBoard();
900 PROJECT* project = board->GetProject();
901
902 if( !project )
903 {
904 REPORT_AUX( _( "No project loaded, skipping library parity tests." ) );
905 return true; // Continue with other tests
906 }
907
908 if( !reportPhase( _( "Loading footprint library table..." ) ) )
909 return false; // DRC cancelled
910
911 std::map<LIB_ID, std::shared_ptr<FOOTPRINT>> libFootprintCache;
912
914 wxString msg;
915 int ii = 0;
916 const int progressDelta = 250;
917
918 if( !reportPhase( _( "Checking board footprints against library..." ) ) )
919 return false;
920
921 for( FOOTPRINT* footprint : board->Footprints() )
922 {
923 if( m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES )
924 && m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_MISMATCH ) )
925 {
926 return true; // Continue with other tests
927 }
928
929 if( !reportProgress( ii++, (int) board->Footprints().size(), progressDelta ) )
930 return false; // DRC cancelled
931
932 LIB_ID fpID = footprint->GetFPID();
933 wxString libName = fpID.GetLibNickname();
934 wxString fpName = fpID.GetLibItemName();
935 const LIB_TABLE_ROW* libTableRow = nullptr;
936
937 if( libName.IsEmpty() )
938 {
939 // Not much we can do here
940 continue;
941 }
942
943 try
944 {
945 libTableRow = libTable->FindRow( libName );
946 }
947 catch( const IO_ERROR& )
948 {
949 }
950
951 if( !libTableRow )
952 {
953 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
954 {
955 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
956 msg.Printf( _( "The current configuration does not include the footprint library '%s'" ),
957 UnescapeString( libName ) );
958 drcItem->SetErrorMessage( msg );
959 drcItem->SetItems( footprint );
960 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
961 }
962
963 continue;
964 }
965 else if( !libTable->HasLibrary( libName, true ) )
966 {
967 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
968 {
969 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
970 msg.Printf( _( "The footprint library '%s' is not enabled in the current configuration" ),
971 UnescapeString( libName ) );
972 drcItem->SetErrorMessage( msg );
973 drcItem->SetItems( footprint );
974 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
975 }
976
977 continue;
978 }
979 else if( !libTableRow->LibraryExists() )
980 {
981 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
982 {
983 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
984 msg.Printf( _( "The footprint library '%s' was not found at '%s'" ),
985 UnescapeString( libName ),
986 libTableRow->GetFullURI( true ) );
987 drcItem->SetErrorMessage( msg );
988 drcItem->SetItems( footprint );
989 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
990 }
991
992 continue;
993 }
994
995 auto cacheIt = libFootprintCache.find( fpID );
996 std::shared_ptr<FOOTPRINT> libFootprint;
997
998 if( cacheIt != libFootprintCache.end() )
999 {
1000 libFootprint = cacheIt->second;
1001 }
1002 else
1003 {
1004 try
1005 {
1006 libFootprint.reset( libTable->FootprintLoad( libName, fpName, true ) );
1007
1008 if( libFootprint )
1009 libFootprintCache[ fpID ] = libFootprint;
1010 }
1011 catch( const IO_ERROR& )
1012 {
1013 }
1014 }
1015
1016 if( !libFootprint )
1017 {
1018 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
1019 {
1020 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
1021 msg.Printf( _( "Footprint '%s' not found in library '%s'" ),
1022 fpName,
1023 libName );
1024 drcItem->SetErrorMessage( msg );
1025 drcItem->SetItems( footprint );
1026 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1027 }
1028 }
1029 else if( footprint->FootprintNeedsUpdate( libFootprint.get(), BOARD_ITEM::COMPARE_FLAGS::DRC ) )
1030 {
1031 if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_MISMATCH ) )
1032 {
1033 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_MISMATCH );
1034 msg.Printf( _( "Footprint '%s' does not match copy in library '%s'" ),
1035 fpName,
1036 libName );
1037 drcItem->SetErrorMessage( msg );
1038 drcItem->SetItems( footprint );
1039 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
1040 }
1041 }
1042 }
1043
1044 return true;
1045}
1046
1047
1048namespace detail
1049{
1051}
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:317
const FOOTPRINTS & Footprints() const
Definition board.h:358
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition board.cpp:691
PROJECT * GetProject() const
Definition board.h:537
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:923
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)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, const std::vector< PCB_SHAPE > &aShapes={})
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:75
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
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)
#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
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
VECTOR2I end