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 (C) 2021-2023 KiCad Developers.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <kiway.h>
25#include <macros.h>
27#include <fp_lib_table.h>
28#include <board.h>
29#include <pcb_shape.h>
30#include <zone.h>
31#include <footprint.h>
32#include <pad.h>
33#include <drc/drc_engine.h>
34#include <drc/drc_item.h>
36
37/*
38 Library parity test.
39
40 Errors generated:
41 - DRCE_LIB_FOOTPRINT_ISSUES
42 - DRCE_LIB_FOOTPRINT_MISMATCH
43*/
44
46{
47public:
49 {
50 m_isRuleDriven = false;
51 }
52
54 {
55 }
56
57 virtual bool Run() override;
58
59 virtual const wxString GetName() const override
60 {
61 return wxT( "library_parity" );
62 };
63
64 virtual const wxString GetDescription() const override
65 {
66 return wxT( "Performs board footprint vs library integity checks" );
67 }
68};
69
70
71//
72// The TEST*() macros have two modes:
73// In "Report" mode (aReporter != nullptr) all properties are checked and reported on.
74// In "DRC" mode (aReporter == nulltpr) properties are only checked until a difference is found.
75//
76#define TEST( a, b, msg ) \
77 do { \
78 if( a != b ) \
79 { \
80 diff = true; \
81 \
82 if( aReporter && wxString( msg ).length() ) \
83 aReporter->Report( msg ); \
84 } \
85 \
86 if( diff && !aReporter ) \
87 return diff; \
88 } while (0)
89
90#define EPSILON 0.000001
91#define TEST_D( a, b, msg ) \
92 do { \
93 if( abs( a - b ) > EPSILON ) \
94 { \
95 diff = true; \
96 \
97 if( aReporter && wxString( msg ).length() ) \
98 aReporter->Report( msg ); \
99 } \
100 \
101 if( diff && !aReporter ) \
102 return diff; \
103 } while (0)
104
105#define TEST_V3D( a, b, msg ) \
106 do { \
107 if( abs( a.x - b.x ) > EPSILON \
108 || abs( a.y - b.y ) > EPSILON \
109 || abs( a.z - b.z ) > EPSILON ) \
110 { \
111 diff = true; \
112 \
113 if( aReporter && wxString( msg ).length() ) \
114 aReporter->Report( msg ); \
115 } \
116 \
117 if( diff && !aReporter ) \
118 return diff; \
119 } while (0)
120
121#define ITEM_DESC( item ) ( item )->GetItemDescription( &g_unitsProvider )
122
124
125
126bool primitiveNeedsUpdate( const std::shared_ptr<PCB_SHAPE>& a,
127 const std::shared_ptr<PCB_SHAPE>& b )
128{
129 REPORTER* aReporter = nullptr;
130 bool diff = false;
131
132 TEST( a->GetShape(), b->GetShape(), "" );
133
134 switch( a->GetShape() )
135 {
136 case SHAPE_T::SEGMENT:
137 case SHAPE_T::RECT:
138 case SHAPE_T::CIRCLE:
139 TEST( a->GetStart(), b->GetStart(), "" );
140 TEST( a->GetEnd(), b->GetEnd(), "" );
141 break;
142
143 case SHAPE_T::ARC:
144 TEST( a->GetStart(), b->GetStart(), "" );
145 TEST( a->GetEnd(), b->GetEnd(), "" );
146 TEST( a->GetCenter(), b->GetCenter(), "" );
147 TEST_D( a->GetArcAngle().AsDegrees(), b->GetArcAngle().AsDegrees(), "" );
148 break;
149
150 case SHAPE_T::BEZIER:
151 TEST( a->GetStart(), b->GetStart(), "" );
152 TEST( a->GetEnd(), b->GetEnd(), "" );
153 TEST( a->GetBezierC1(), b->GetBezierC1(), "" );
154 TEST( a->GetBezierC2(), b->GetBezierC2(), "" );
155 break;
156
157 case SHAPE_T::POLY:
158 TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(), "" );
159
160 for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
161 TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), "" );
162
163 break;
164
165 default:
166 UNIMPLEMENTED_FOR( a->SHAPE_T_asString() );
167 }
168
169 TEST( a->GetStroke(), b->GetStroke(), "" );
170 TEST( a->IsFilled(), b->IsFilled(), "" );
171
172 return diff;
173}
174
175
176bool padNeedsUpdate( const PAD* a, const PAD* b )
177{
178 REPORTER* aReporter = nullptr;
179 bool diff = false;
180
181 TEST( a->GetPadToDieLength(), b->GetPadToDieLength(), "" );
183
184 TEST( a->GetNumber(), b->GetNumber(), "" );
185
186 // These are assigned from the schematic and not from the library
187 // TEST( a->GetPinFunction(), b->GetPinFunction() );
188 // TEST( a->GetPinType(), b->GetPinType() );
189
191
192 // NB: KeepTopBottom is undefined if RemoveUnconnected is NOT set.
193 if( a->GetRemoveUnconnected() )
194 TEST( a->GetKeepTopBottom(), b->GetKeepTopBottom(), "" );
195
196 TEST( a->GetShape(), b->GetShape(), "" );
197
198 // Trim layersets to the current board before comparing
199 LSET enabledLayers = a->GetBoard()->GetEnabledLayers();
200 LSET aLayers = a->GetLayerSet() & enabledLayers;
201 LSET bLayers = b->GetLayerSet() & enabledLayers;
202 TEST( aLayers, bLayers, "" );
203
204 TEST( a->GetAttribute(), b->GetAttribute(), "" );
205 TEST( a->GetProperty(), b->GetProperty(), "" );
206
207 // The pad orientation, for historical reasons is the pad rotation + parent rotation.
208 TEST_D( ( a->GetOrientation() - a->GetParent()->GetOrientation() ).Normalize().AsDegrees(),
209 ( b->GetOrientation() - b->GetParent()->GetOrientation() ).Normalize().AsDegrees(),
210 "" );
211
212 TEST( a->GetSize(), b->GetSize(), "" );
213 TEST( a->GetDelta(), b->GetDelta(), "" );
218 TEST( a->GetOffset(), b->GetOffset(), "" );
219
220 TEST( a->GetDrillShape(), b->GetDrillShape(), "" );
221 TEST( a->GetDrillSize(), b->GetDrillSize(), "" );
222
223 // Clearance and zone connection overrides are as likely to be set at the board level as in
224 // the library.
225 //
226 // If we ignore them and someone *does* change one of them in the library, then stale
227 // footprints won't be caught.
228 //
229 // On the other hand, if we report them then boards that override at the board level are
230 // going to be VERY noisy.
231#if 0
232 if( padHasOverrides( a, b )
233 return true;
234#endif
235
236 TEST( a->GetPrimitives().size(), b->GetPrimitives().size(), "" );
237
238 for( size_t ii = 0; ii < a->GetPrimitives().size(); ++ii )
239 {
240 if( primitiveNeedsUpdate( a->GetPrimitives()[ii], b->GetPrimitives()[ii] ) )
241 return true;
242 }
243
244 return diff;
245}
246
247
248bool padHasOverrides( const PAD* a, const PAD* b )
249{
250 REPORTER* aReporter = nullptr;
251 bool diff = false;
252
253 TEST( a->GetLocalClearance(), b->GetLocalClearance(), "" );
257
258 TEST( a->GetZoneConnection(), b->GetZoneConnection(), "" );
259 TEST( a->GetThermalGap(), b->GetThermalGap(), "" );
263
264 return diff;
265}
266
267
268bool shapeNeedsUpdate( const PCB_SHAPE* a, const PCB_SHAPE* b )
269{
270 REPORTER* aReporter = nullptr;
271 bool diff = false;
272
273 TEST( a->GetShape(), b->GetShape(), "" );
274
275 switch( a->GetShape() )
276 {
277 case SHAPE_T::SEGMENT:
278 case SHAPE_T::RECT:
279 case SHAPE_T::CIRCLE:
280 TEST( a->GetStart(), b->GetStart(), "" );
281 TEST( a->GetEnd(), b->GetEnd(), "" );
282 break;
283
284 case SHAPE_T::ARC:
285 TEST( a->GetStart(), b->GetStart(), "" );
286 TEST( a->GetEnd(), b->GetEnd(), "" );
287
288 // Arc center is calculated and so may have round-off errors when parents are
289 // differentially rotated.
290 if( ( a->GetCenter() - b->GetCenter() ).EuclideanNorm() > pcbIUScale.mmToIU( 0.0001 ) )
291 return true;
292
293 break;
294
295 case SHAPE_T::BEZIER:
296 TEST( a->GetStart(), b->GetStart(), "" );
297 TEST( a->GetEnd(), b->GetEnd(), "" );
298 TEST( a->GetBezierC1(), b->GetBezierC1(), "" );
299 TEST( a->GetBezierC2(), b->GetBezierC2(), "" );
300 break;
301
302 case SHAPE_T::POLY:
304
305 for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
306 TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), "" );
307
308 break;
309
310 default:
312 }
313
314 TEST( a->GetStroke(), b->GetStroke(), "" );
315 TEST( a->IsFilled(), b->IsFilled(), "" );
316
317 TEST( a->GetLayer(), b->GetLayer(), "" );
318
319 return diff;
320}
321
322
323bool textNeedsUpdate( const PCB_TEXT* a, const PCB_TEXT* b )
324{
325 REPORTER* aReporter = nullptr;
326 bool diff = false;
327
328 TEST( a->GetLayer(), b->GetLayer(), "" );
329 TEST( a->IsKeepUpright(), b->IsKeepUpright(), "" );
330
331 TEST( a->GetText(), b->GetText(), "" );
332
333 TEST( a->GetTextThickness(), b->GetTextThickness(), "" );
334 TEST( a->GetTextAngle(), b->GetTextAngle(), "" );
335 TEST( a->IsItalic(), b->IsItalic(), "" );
336 TEST( a->IsBold(), b->IsBold(), "" );
337 TEST( a->IsVisible(), b->IsVisible(), "" );
338 TEST( a->IsMirrored(), b->IsMirrored(), "" );
339
340 TEST( a->GetHorizJustify(), b->GetHorizJustify(), "" );
341 TEST( a->GetVertJustify(), b->GetVertJustify(), "" );
342
343 TEST( a->GetTextSize(), b->GetTextSize(), "" );
345
346 return diff;
347}
348
349
350bool zoneNeedsUpdate( const ZONE* a, const ZONE* b, REPORTER* aReporter )
351{
352 bool diff = false;
353
355 wxString::Format( _( "%s corner smoothing setting differs." ), ITEM_DESC( a ) ) );
357 wxString::Format( _( "%s corner smoothing radius differs." ), ITEM_DESC( a ) ) );
358 TEST( a->GetZoneName(), b->GetZoneName(),
359 wxString::Format( _( "%s name differs." ), ITEM_DESC( a ) ) );
361 wxString::Format( _( "%s priority differs." ), ITEM_DESC( a ) ) );
362
363 TEST( a->GetIsRuleArea(), b->GetIsRuleArea(),
364 wxString::Format( _( "%s keep-out property differs." ), ITEM_DESC( a ) ) );
366 wxString::Format( _( "%s keep out copper fill setting differs." ), ITEM_DESC( a ) ) );
368 wxString::Format( _( "%s keep out footprints setting differs." ), ITEM_DESC( a ) ) );
370 wxString::Format( _( "%s keep out pads setting differs." ), ITEM_DESC( a ) ) );
372 wxString::Format( _( "%s keep out tracks setting differs." ), ITEM_DESC( a ) ) );
374 wxString::Format( _( "%s keep out vias setting differs." ), ITEM_DESC( a ) ) );
375
376 TEST( a->GetLayerSet(), b->GetLayerSet(),
377 wxString::Format( _( "%s layers differ." ), ITEM_DESC( a ) ) );
378
380 wxString::Format( _( "%s pad connection property differs." ), ITEM_DESC( a ) ) );
382 wxString::Format( _( "%s local clearance differs." ), ITEM_DESC( a ) ) );
384 wxString::Format( _( "%s thermal relief gap differs." ), ITEM_DESC( a ) ) );
386 wxString::Format( _( "%s thermal relief spoke width differs." ), ITEM_DESC( a ) ) );
387
389 wxString::Format( _( "%s min thickness differs." ), ITEM_DESC( a ) ) );
390
392 wxString::Format( _( "%s remove islands setting differs." ), ITEM_DESC( a ) ) );
394 wxString::Format( _( "%s minimum island size setting differs." ), ITEM_DESC( a ) ) );
395
396 TEST( a->GetFillMode(), b->GetFillMode(),
397 wxString::Format( _( "%s fill type differs." ), ITEM_DESC( a ) ) );
399 wxString::Format( _( "%s hatch width differs." ), ITEM_DESC( a ) ) );
400 TEST( a->GetHatchGap(), b->GetHatchGap(),
401 wxString::Format( _( "%s hatch gap differs." ), ITEM_DESC( a ) ) );
403 wxString::Format( _( "%s hatch orientation differs." ), ITEM_DESC( a ) ) );
405 wxString::Format( _( "%s hatch smoothing level differs." ), ITEM_DESC( a ) ) );
407 wxString::Format( _( "%s hatch smoothing amount differs." ), ITEM_DESC( a ) ) );
409 wxString::Format( _( "%s minimum hatch hole setting differs." ), ITEM_DESC( a ) ) );
410
411 // This is just a display property
412 // TEST( a->GetHatchBorderAlgorithm(), b->GetHatchBorderAlgorithm() );
413
415 wxString::Format( _( "%s outline corner count differs." ), ITEM_DESC( a ) ) );
416
417 bool cornersDiffer = false;
418
419 for( int ii = 0; ii < a->Outline()->TotalVertices(); ++ii )
420 {
421 if( a->Outline()->CVertex( ii ) != b->Outline()->CVertex( ii ) )
422 {
423 diff = true;
424 cornersDiffer = true;
425 break;
426 }
427 }
428
429 if( cornersDiffer && aReporter )
430 aReporter->Report( wxString::Format( _( "%s corners differ." ), ITEM_DESC( a ) ) );
431
432 return diff;
433}
434
435
436bool modelNeedsUpdate( const FP_3DMODEL& a, const FP_3DMODEL& b, REPORTER* aReporter )
437{
438 bool diff = false;
439
440 TEST_V3D( a.m_Scale, b.m_Scale, _( "3D model scale doesn't match: " ) + a.m_Filename );
441 TEST_V3D( a.m_Rotation, b.m_Rotation, _( "3D model rotation doesn't match: " ) + a.m_Filename );
442 TEST_V3D( a.m_Offset, b.m_Offset, _( "3D model offset doesn't match: " ) + a.m_Filename );
443 TEST( a.m_Opacity, b.m_Opacity, _( "3D model opacity doesn't match: " ) + a.m_Filename );
444 TEST( a.m_Filename, b.m_Filename, _( "3D model doesn't match: " ) + a.m_Filename );
445 TEST( a.m_Show, b.m_Show, _( "3D model visibility doesn't match: " ) + a.m_Filename );
446
447 return diff;
448}
449
450
451bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint, REPORTER* aReporter )
452{
453 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MILLIMETRES );
454
455 wxASSERT( aLibFootprint );
456 bool diff = false;
457
458 // To avoid issues when comparing the footprint on board and the footprint in library
459 // use a footprint not flipped, not rotated and at position 0,0.
460 // Otherwise one can see differences when comparing coordinates of some items
461 if( IsFlipped() || GetPosition() != VECTOR2I( 0, 0 ) || GetOrientation() != ANGLE_0 )
462 {
463 std::unique_ptr<FOOTPRINT> temp( static_cast<FOOTPRINT*>( Clone() ) );
464 temp->SetParentGroup( nullptr );
465
466 if( IsFlipped() )
467 temp->Flip( {0,0}, false );
468
469 if( GetPosition() != VECTOR2I( 0, 0 ) )
470 temp->SetPosition( { 0, 0 } );
471
472 if( GetOrientation() != ANGLE_0 )
473 temp->SetOrientation( ANGLE_0 );
474
475 diff = temp->FootprintNeedsUpdate( aLibFootprint, aReporter );
476
477 // This temporary footprint must not have a parent when it goes out of scope because it must
478 // not trigger the IncrementTimestamp call in ~FOOTPRINT.
479 temp->SetParent( nullptr );
480 return diff;
481 }
482
483 TEST( GetDescription(), aLibFootprint->GetDescription(),
484 _( "Footprint descriptions differ." ) );
485 TEST( GetKeywords(), aLibFootprint->GetKeywords(),
486 _( "Footprint keywords differ." ) );
487
488#define TEST_ATTR( a, b, attr, msg ) TEST( ( a & attr ), ( b & attr ), msg )
489
491 _( "Footprint types differ." ) );
493 _( "Allow bridged solder mask apertures between pads settings differ." ) );
495 _( "Exempt from courtyard requirement settings differ." ) );
496
497 // Clearance and zone connection overrides are as likely to be set at the board level as in
498 // the library.
499 //
500 // If we ignore them and someone *does* change one of them in the library, then stale
501 // footprints won't be caught.
502 //
503 // On the other hand, if we report them then boards that override at the board level are
504 // going to be VERY noisy.
505 if( aReporter )
506 {
507 TEST( GetLocalClearance(), aLibFootprint->GetLocalClearance(),
508 _( "Pad clearance overridden." ) );
510 _( "Solder mask expansion overridden." ) );
512 _( "Solder paste absolute clearance overridden." ) );
514 _( "Solder paste relative clearance overridden." ) );
515
516 TEST( GetZoneConnection(), aLibFootprint->GetZoneConnection(),
517 _( "Zone connection overridden." ) );
518 }
519
520 TEST( GetNetTiePadGroups().size(), aLibFootprint->GetNetTiePadGroups().size(),
521 _( "Net tie pad groups differ." ) );
522
523 for( size_t ii = 0; ii < GetNetTiePadGroups().size(); ++ii )
524 {
525 TEST( GetNetTiePadGroups()[ii], aLibFootprint->GetNetTiePadGroups()[ii],
526 _( "Net tie pad groups differ." ) );
527 }
528
529#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
530#define CHECKPOINT { if( diff && !aReporter ) return diff; }
531
532 // Text items are really problematic. We don't want to test the reference, but after that
533 // it gets messy.
534 //
535 // What about the value? Depends on whether or not it's a singleton part.
536 //
537 // And what about other texts? They might be added only to instances on the board, or even
538 // changed for instances on the board. Or they might want to be tested for equality.
539 //
540 // Currently we punt and ignore all the text items.
541
542 // Drawings and pads are also somewhat problematic as there's no guarantee that they'll be
543 // in the same order in the two footprints. Rather than building some sophisticated hashing
544 // algorithm we use the footprint sorting functions to attempt to sort them in the same
545 // order.
546
547 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aShapes;
548 std::copy_if( GraphicalItems().begin(), GraphicalItems().end(),
549 std::inserter( aShapes, aShapes.begin() ),
550 []( BOARD_ITEM* item )
551 {
552 return item->Type() == PCB_SHAPE_T;
553 } );
554 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bShapes;
555 std::copy_if( aLibFootprint->GraphicalItems().begin(), aLibFootprint->GraphicalItems().end(),
556 std::inserter( bShapes, bShapes.begin() ),
557 []( BOARD_ITEM* item )
558 {
559 return item->Type() == PCB_SHAPE_T;
560 } );
561
562 if( aShapes.size() != bShapes.size() )
563 {
564 diff = true;
565 REPORT( _( "Graphic item count differs." ) );
566 }
567 else
568 {
569 for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
570 {
571 if( ( *aIt )->Type() == PCB_SHAPE_T )
572 {
573 if( shapeNeedsUpdate( static_cast<PCB_SHAPE*>( *aIt ), static_cast<PCB_SHAPE*>( *bIt ) ) )
574 {
575 diff = true;
576 REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
577 }
578 }
579 }
580 }
581
583
584 std::set<PAD*, FOOTPRINT::cmp_pads> aPads( Pads().begin(), Pads().end() );
585 std::set<PAD*, FOOTPRINT::cmp_pads> bPads( aLibFootprint->Pads().begin(), aLibFootprint->Pads().end() );
586
587 if( aPads.size() != bPads.size() )
588 {
589 diff = true;
590 REPORT( _( "Pad count differs." ) );
591 }
592 else
593 {
594 for( auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
595 {
596 if( padNeedsUpdate( *aIt, *bIt ) )
597 {
598 diff = true;
599 REPORT( wxString::Format( _( "Pad %s differs." ), (*aIt)->GetNumber() ) );
600 }
601 else if( aReporter && padHasOverrides( *aIt, *bIt ) )
602 {
603 diff = true;
604 REPORT( wxString::Format( _( "Pad %s has overrides." ), (*aIt)->GetNumber() ) );
605 }
606 }
607 }
608
610
611 if( Models().size() != aLibFootprint->Models().size() )
612 {
613 diff = true;
614 REPORT( _( "3D model count differs." ) );
615 }
616 else
617 {
618 for( size_t ii = 0; ii < Models().size(); ++ii )
619 diff |= modelNeedsUpdate( Models()[ii], aLibFootprint->Models()[ii], aReporter );
620 }
621
623
624 // Rotate/position a copy of libFootprint so that zones sort the same
625 std::unique_ptr<FOOTPRINT> libCopy( static_cast<FOOTPRINT*>( aLibFootprint->Clone() ) );
626
627 libCopy->SetOrientation( GetOrientation() );
628 libCopy->Move( GetPosition() );
629
630 std::set<ZONE*, FOOTPRINT::cmp_zones> aZones( Zones().begin(), Zones().end() );
631 std::set<ZONE*, FOOTPRINT::cmp_zones> bZones( libCopy->Zones().begin(), libCopy->Zones().end() );
632
633 if( aZones.size() != bZones.size() )
634 {
635 diff = true;
636 REPORT( _( "Rule area count differs." ) );
637 }
638 else
639 {
640 for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
641 diff |= zoneNeedsUpdate( *aIt, *bIt, aReporter );
642 }
643
644 return diff;
645}
646
647
649{
650 BOARD* board = m_drcEngine->GetBoard();
651 PROJECT* project = board->GetProject();
652
653 if( !project )
654 {
655 reportAux( _( "No project loaded, skipping library parity tests." ) );
656 return true; // Continue with other tests
657 }
658
659 if( !reportPhase( _( "Loading footprint library table..." ) ) )
660 return false; // DRC cancelled
661
662 std::map<LIB_ID, std::shared_ptr<FOOTPRINT>> libFootprintCache;
663
664 FP_LIB_TABLE* libTable = project->PcbFootprintLibs();
665 wxString msg;
666 int ii = 0;
667 const int progressDelta = 250;
668
669 if( !reportPhase( _( "Checking board footprints against library..." ) ) )
670 return false;
671
672 for( FOOTPRINT* footprint : board->Footprints() )
673 {
676 {
677 return true; // Continue with other tests
678 }
679
680 if( !reportProgress( ii++, (int) board->Footprints().size(), progressDelta ) )
681 return false; // DRC cancelled
682
683 LIB_ID fpID = footprint->GetFPID();
684 wxString libName = fpID.GetLibNickname();
685 wxString fpName = fpID.GetLibItemName();
686 const LIB_TABLE_ROW* libTableRow = nullptr;
687
688 try
689 {
690 libTableRow = libTable->FindRow( libName );
691 }
692 catch( const IO_ERROR& )
693 {
694 }
695
696 if( !libTableRow )
697 {
699 {
700 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
701 msg.Printf( _( "The current configuration does not include the library '%s'." ),
702 libName );
703 drcItem->SetErrorMessage( msg );
704 drcItem->SetItems( footprint );
705 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
706 }
707
708 continue;
709 }
710 else if( !libTable->HasLibrary( libName, true ) )
711 {
713 {
714 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
715 msg.Printf( _( "The library '%s' is not enabled in the current configuration." ),
716 libName );
717 drcItem->SetErrorMessage( msg );
718 drcItem->SetItems( footprint );
719 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
720 }
721
722 continue;
723 }
724
725 auto cacheIt = libFootprintCache.find( fpID );
726 std::shared_ptr<FOOTPRINT> libFootprint;
727
728 if( cacheIt != libFootprintCache.end() )
729 {
730 libFootprint = cacheIt->second;
731 }
732 else
733 {
734 try
735 {
736 libFootprint.reset( libTable->FootprintLoad( libName, fpName, true ) );
737
738 if( libFootprint )
739 libFootprintCache[ fpID ] = libFootprint;
740 }
741 catch( const IO_ERROR& )
742 {
743 }
744 }
745
746 if( !libFootprint )
747 {
749 {
750 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
751 msg.Printf( _( "Footprint '%s' not found in library '%s'." ),
752 fpName,
753 libName );
754 drcItem->SetErrorMessage( msg );
755 drcItem->SetItems( footprint );
756 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
757 }
758 }
759 else if( footprint->FootprintNeedsUpdate( libFootprint.get() ) )
760 {
762 {
763 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_MISMATCH );
764 msg.Printf( _( "Footprint '%s' does not match copy in library '%s'." ),
765 fpName,
766 libName );
767 drcItem->SetErrorMessage( msg );
768 drcItem->SetItems( footprint );
769 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
770 }
771 }
772 }
773
774 return true;
775}
776
777
778namespace detail
779{
781}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:71
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:196
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:44
VECTOR2I GetFPRelativePosition() const
Definition: board_item.cpp:254
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:270
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:611
FOOTPRINTS & Footprints()
Definition: board.h:312
PROJECT * GetProject() const
Definition: board.h:448
BOARD * GetBoard() const
Definition: drc_engine.h:89
bool IsErrorLimitExceeded(int error_code)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:325
virtual const wxString GetDescription() const override
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual const wxString GetName() const override
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out DRC_ITEM and posi...
virtual bool reportPhase(const wxString &aStageName)
virtual bool reportProgress(int aCount, int aSize, int aDelta)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
DRC_ENGINE * m_drcEngine
void reportAux(const wxString &aMsg)
double AsDegrees() const
Definition: eda_angle.h:149
const VECTOR2I & GetBezierC2() const
Definition: eda_shape.h:179
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:247
bool IsFilled() const
Definition: eda_shape.h:90
SHAPE_T GetShape() const
Definition: eda_shape.h:113
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:145
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:120
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:75
const VECTOR2I & GetBezierC1() const
Definition: eda_shape.h:176
bool IsItalic() const
Definition: eda_text.h:133
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:123
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
bool IsKeepUpright() const
Definition: eda_text.h:158
virtual bool IsVisible() const
Definition: eda_text.h:139
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:152
bool IsMirrored() const
Definition: eda_text.h:142
bool IsBold() const
Definition: eda_text.h:136
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:155
int GetTextThickness() const
Definition: eda_text.h:115
VECTOR2I GetTextSize() const
Definition: eda_text.h:199
EDA_ANGLE GetOrientation() const
Definition: footprint.h:193
ZONES & Zones()
Definition: footprint.h:178
int GetLocalClearance() const
Definition: footprint.h:232
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: footprint.cpp:1386
wxString GetDescription() const
Definition: footprint.h:220
double GetLocalSolderPasteMarginRatio() const
Definition: footprint.h:246
int GetAttributes() const
Definition: footprint.h:252
bool IsFlipped() const
Definition: footprint.h:326
PADS & Pads()
Definition: footprint.h:172
int GetLocalSolderPasteMargin() const
Definition: footprint.h:243
const std::vector< wxString > & GetNetTiePadGroups() const
Definition: footprint.h:274
bool FootprintNeedsUpdate(const FOOTPRINT *aLibFootprint, REPORTER *aReporter=nullptr)
Return true if a board footprint differs from the library version.
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:186
ZONE_CONNECTION GetZoneConnection() const
Definition: footprint.h:250
wxString GetKeywords() const
Definition: footprint.h:223
VECTOR2I GetPosition() const override
Definition: footprint.h:190
DRAWINGS & GraphicalItems()
Definition: footprint.h:175
int GetLocalSolderMaskMargin() const
Definition: footprint.h:229
VECTOR3D m_Offset
3D model offset (mm)
Definition: footprint.h:95
double m_Opacity
Definition: footprint.h:96
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: footprint.h:94
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition: footprint.h:93
wxString m_Filename
The 3D shape filename in 3D library.
Definition: footprint.h:97
bool m_Show
Include model in rendering.
Definition: footprint.h:98
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.
Definition: ki_exception.h:76
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.
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: layer_ids.h:536
Definition: pad.h:59
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: pad.cpp:815
PAD_PROP GetProperty() const
Definition: pad.h:396
bool GetRemoveUnconnected() const
Definition: pad.h:602
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: pad.h:376
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:390
const VECTOR2I & GetDrillSize() const
Definition: pad.h:258
PAD_ATTRIB GetAttribute() const
Definition: pad.h:393
ZONE_CONNECTION GetZoneConnection() const
Definition: pad.h:515
const wxString & GetNumber() const
Definition: pad.h:135
double GetLocalSolderPasteMarginRatio() const
Definition: pad.h:418
int GetRoundRectCornerRadius() const
Definition: pad.cpp:329
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:321
EDA_ANGLE GetThermalSpokeAngle() const
Definition: pad.h:534
const VECTOR2I & GetOffset() const
Definition: pad.h:265
int GetLocalSolderMaskMargin() const
Definition: pad.h:408
bool GetKeepTopBottom() const
Definition: pad.h:608
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: pad.h:212
FOOTPRINT * GetParent() const
Definition: pad.cpp:1479
const VECTOR2I & GetDelta() const
Definition: pad.h:255
PAD_SHAPE GetShape() const
Definition: pad.h:194
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:362
int GetThermalSpokeWidth() const
Definition: pad.h:524
int GetLocalSolderPasteMargin() const
Definition: pad.h:415
int GetChamferPositions() const
Definition: pad.h:587
double GetRoundRectRadiusRatio() const
Definition: pad.h:568
int GetThermalGap() const
Definition: pad.h:547
const VECTOR2I & GetSize() const
Definition: pad.h:248
double GetChamferRectRatio() const
Definition: pad.h:577
int GetPadToDieLength() const
Definition: pad.h:406
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:67
STROKE_PARAMS GetStroke() const override
Definition: pcb_shape.h:71
Container for project specific data.
Definition: project.h:64
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
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:72
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:710
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:724
SHAPE_POLY_SET * Outline()
Definition: zone.h:325
long long int GetMinIslandArea() const
Definition: zone.h:727
wxString GetZoneName() const
Definition: zone.h:131
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: zone.cpp:498
int GetMinThickness() const
Definition: zone.h:258
ZONE_CONNECTION GetPadConnection() const
Definition: zone.h:255
int GetHatchThickness() const
Definition: zone.h:273
double GetHatchHoleMinArea() const
Definition: zone.h:288
int GetThermalReliefSpokeWidth() const
Definition: zone.h:202
EDA_ANGLE GetHatchOrientation() const
Definition: zone.h:279
bool GetDoNotAllowFootprints() const
Definition: zone.h:715
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:181
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:129
bool GetDoNotAllowCopperPour() const
Definition: zone.h:711
int GetHatchGap() const
Definition: zone.h:276
double GetHatchSmoothingValue() const
Definition: zone.h:285
int GetHatchSmoothingLevel() const
Definition: zone.h:282
unsigned int GetCornerRadius() const
Definition: zone.h:665
int GetCornerSmoothingType() const
Definition: zone.h:661
int GetThermalReliefGap() const
Definition: zone.h:191
unsigned GetAssignedPriority() const
Definition: zone.h:119
@ DRCE_LIB_FOOTPRINT_ISSUES
Definition: drc_item.h:76
@ DRCE_LIB_FOOTPRINT_MISMATCH
Definition: drc_item.h:77
bool textNeedsUpdate(const PCB_TEXT *a, const PCB_TEXT *b)
bool padNeedsUpdate(const PAD *a, const PAD *b)
#define TEST_V3D(a, b, msg)
UNITS_PROVIDER g_unitsProvider(pcbIUScale, EDA_UNITS::MILLIMETRES)
bool primitiveNeedsUpdate(const std::shared_ptr< PCB_SHAPE > &a, const std::shared_ptr< PCB_SHAPE > &b)
#define TEST(a, b, msg)
bool modelNeedsUpdate(const FP_3DMODEL &a, const FP_3DMODEL &b, REPORTER *aReporter)
bool zoneNeedsUpdate(const ZONE *a, const ZONE *b, REPORTER *aReporter)
#define TEST_ATTR(a, b, attr, msg)
bool padHasOverrides(const PAD *a, const PAD *b)
#define TEST_D(a, b, msg)
bool shapeNeedsUpdate(const PCB_SHAPE *a, const PCB_SHAPE *b)
#define CHECKPOINT
#define ITEM_DESC(item)
#define _(s)
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:429
#define TEST(a, b)
@ FP_SMD
Definition: footprint.h:70
@ FP_ALLOW_MISSING_COURTYARD
Definition: footprint.h:76
@ FP_THROUGH_HOLE
Definition: footprint.h:69
@ FP_ALLOW_SOLDERMASK_BRIDGES
Definition: footprint.h:75
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
#define REPORT(msg)
Definition: lib_symbol.cpp:240
#define ITEM_DESC(item)
Definition: lib_symbol.cpp:241
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:120
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588