57 virtual bool Run()
override;
59 virtual const wxString
GetName()
const override
61 return wxT(
"library_parity" );
66 return wxT(
"Performs board footprint vs library integity checks" );
76#define TEST( a, b, msg ) \
82 if( aReporter && wxString( msg ).length() ) \
83 aReporter->Report( msg ); \
86 if( diff && !aReporter ) \
90#define EPSILON 0.000001
91#define TEST_D( a, b, msg ) \
93 if( abs( a - b ) > EPSILON ) \
97 if( aReporter && wxString( msg ).length() ) \
98 aReporter->Report( msg ); \
101 if( diff && !aReporter ) \
105#define TEST_V3D( a, b, msg ) \
107 if( abs( a.x - b.x ) > EPSILON \
108 || abs( a.y - b.y ) > EPSILON \
109 || abs( a.z - b.z ) > EPSILON ) \
113 if( aReporter && wxString( msg ).length() ) \
114 aReporter->Report( msg ); \
117 if( diff && !aReporter ) \
121#define ITEM_DESC( item ) ( item )->GetItemDescription( &g_unitsProvider )
122#define PAD_DESC( pad ) wxString::Format( _( "Pad %s" ), ( pad )->GetNumber() )
129 const std::shared_ptr<PCB_SHAPE>& b )
134 TEST( a->GetShape(), b->GetShape(),
"" );
136 switch( a->GetShape() )
140 BOX2I aRect( a->GetStart(), a->GetEnd() - a->GetStart() );
141 BOX2I bRect( b->GetStart(), b->GetEnd() - b->GetStart() );
153 TEST( a->GetStart(), b->GetStart(),
"" );
154 TEST( a->GetEnd(), b->GetEnd(),
"" );
158 TEST( a->GetStart(), b->GetStart(),
"" );
159 TEST( a->GetEnd(), b->GetEnd(),
"" );
160 TEST( a->GetCenter(), b->GetCenter(),
"" );
161 TEST_D( a->GetArcAngle().AsDegrees(), b->GetArcAngle().AsDegrees(),
"" );
165 TEST( a->GetStart(), b->GetStart(),
"" );
166 TEST( a->GetEnd(), b->GetEnd(),
"" );
167 TEST( a->GetBezierC1(), b->GetBezierC1(),
"" );
168 TEST( a->GetBezierC2(), b->GetBezierC2(),
"" );
172 TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(),
"" );
174 for(
int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
175 TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ),
"" );
183 TEST( a->GetStroke(), b->GetStroke(),
"" );
184 TEST( a->IsFilled(), b->IsFilled(),
"" );
195 wxString::Format(
_(
"%s has clearance override." ),
PAD_DESC( a ) ) );
197 wxString::Format(
_(
"%s has solder mask expansion override." ),
PAD_DESC( a ) ) );
199 wxString::Format(
_(
"%s has solder paste clearance override." ),
PAD_DESC( a ) ) );
201 wxString::Format(
_(
"%s has solder paste clearance override." ),
PAD_DESC( a ) ) );
204 wxString::Format(
_(
"%s has zone connection override." ),
PAD_DESC( a ) ) );
206 wxString::Format(
_(
"%s has thermal relief gap override." ),
PAD_DESC( a ) ) );
208 wxString::Format(
_(
"%s has thermal relief spoke width override." ),
PAD_DESC( a ) ) );
210 wxString::Format(
_(
"%s has thermal relief spoke angle override." ),
PAD_DESC( a ) ) );
212 wxString::Format(
_(
"%s has zone knockout setting override." ),
PAD_DESC( a ) ) );
223 wxString::Format(
_(
"%s pad to die length differs." ),
PAD_DESC( a ) ) );
225 wxString::Format(
_(
"%s position differs." ),
PAD_DESC( a ) ) );
228 wxString::Format(
_(
"%s has different numbers." ),
PAD_DESC( a ) ) );
245 if( layerSettingsDiffer || aLayers != bLayers )
250 aReporter->
Report( wxString::Format(
_(
"%s layers differ." ),
PAD_DESC( a ) ) );
256 wxString::Format(
_(
"%s pad shape type differs." ),
PAD_DESC( a ) ) );
259 wxString::Format(
_(
"%s pad type differs." ),
PAD_DESC( a ) ) );
261 wxString::Format(
_(
"%s fabrication property differs." ),
PAD_DESC( a ) ) );
266 wxString::Format(
_(
"%s orientation differs." ),
PAD_DESC( a ) ) );
269 wxString::Format(
_(
"%s size differs." ),
PAD_DESC( a ) ) );
271 wxString::Format(
_(
"%s trapezoid delta differs." ),
PAD_DESC( a ) ) );
279 aReporter->
Report( wxString::Format(
_(
"%s rounded corners differ." ),
PAD_DESC( a ) ) );
290 aReporter->
Report( wxString::Format(
_(
"%s chamfered corners differ." ),
PAD_DESC( a ) ) );
296 wxString::Format(
_(
"%s shape offset from hole differs." ),
PAD_DESC( a ) ) );
299 wxString::Format(
_(
"%s drill shape differs." ),
PAD_DESC( a ) ) );
301 wxString::Format(
_(
"%s drill size differs." ),
PAD_DESC( a ) ) );
316 bool primitivesDiffer =
false;
320 primitivesDiffer =
true;
328 primitivesDiffer =
true;
334 if( primitivesDiffer )
339 aReporter->
Report( wxString::Format(
_(
"%s shape primitives differ." ),
PAD_DESC( a ) ) );
397 for(
int ii = 0; ii < a->
GetPolyShape().TotalVertices(); ++ii )
447 wxString::Format(
_(
"%s corner smoothing setting differs." ),
ITEM_DESC( a ) ) );
449 wxString::Format(
_(
"%s corner smoothing radius differs." ),
ITEM_DESC( a ) ) );
451 wxString::Format(
_(
"%s name differs." ),
ITEM_DESC( a ) ) );
453 wxString::Format(
_(
"%s priority differs." ),
ITEM_DESC( a ) ) );
456 wxString::Format(
_(
"%s keep-out property differs." ),
ITEM_DESC( a ) ) );
458 wxString::Format(
_(
"%s keep out copper fill setting differs." ),
ITEM_DESC( a ) ) );
460 wxString::Format(
_(
"%s keep out footprints setting differs." ),
ITEM_DESC( a ) ) );
462 wxString::Format(
_(
"%s keep out pads setting differs." ),
ITEM_DESC( a ) ) );
464 wxString::Format(
_(
"%s keep out tracks setting differs." ),
ITEM_DESC( a ) ) );
466 wxString::Format(
_(
"%s keep out vias setting differs." ),
ITEM_DESC( a ) ) );
469 wxString::Format(
_(
"%s layers differ." ),
ITEM_DESC( a ) ) );
472 wxString::Format(
_(
"%s pad connection property differs." ),
ITEM_DESC( a ) ) );
474 wxString::Format(
_(
"%s local clearance differs." ),
ITEM_DESC( a ) ) );
476 wxString::Format(
_(
"%s thermal relief gap differs." ),
ITEM_DESC( a ) ) );
478 wxString::Format(
_(
"%s thermal relief spoke width differs." ),
ITEM_DESC( a ) ) );
481 wxString::Format(
_(
"%s min thickness differs." ),
ITEM_DESC( a ) ) );
484 wxString::Format(
_(
"%s remove islands setting differs." ),
ITEM_DESC( a ) ) );
486 wxString::Format(
_(
"%s minimum island size setting differs." ),
ITEM_DESC( a ) ) );
489 wxString::Format(
_(
"%s fill type differs." ),
ITEM_DESC( a ) ) );
491 wxString::Format(
_(
"%s hatch width differs." ),
ITEM_DESC( a ) ) );
493 wxString::Format(
_(
"%s hatch gap differs." ),
ITEM_DESC( a ) ) );
495 wxString::Format(
_(
"%s hatch orientation differs." ),
ITEM_DESC( a ) ) );
497 wxString::Format(
_(
"%s hatch smoothing level differs." ),
ITEM_DESC( a ) ) );
499 wxString::Format(
_(
"%s hatch smoothing amount differs." ),
ITEM_DESC( a ) ) );
501 wxString::Format(
_(
"%s minimum hatch hole setting differs." ),
ITEM_DESC( a ) ) );
507 wxString::Format(
_(
"%s outline corner count differs." ),
ITEM_DESC( a ) ) );
509 bool cornersDiffer =
false;
511 for(
int ii = 0; ii < a->
Outline()->TotalVertices(); ++ii )
516 cornersDiffer =
true;
521 if( cornersDiffer && aReporter )
522 aReporter->
Report( wxString::Format(
_(
"%s corners differ." ),
ITEM_DESC( a ) ) );
547 wxASSERT( aLibFootprint );
555 std::unique_ptr<FOOTPRINT> temp(
static_cast<FOOTPRINT*
>(
Clone() ) );
556 temp->SetParentGroup(
nullptr );
559 temp->Flip( {0,0}, false );
562 temp->SetPosition( { 0, 0 } );
565 temp->SetOrientation(
ANGLE_0 );
567 for(
BOARD_ITEM* item : temp->GraphicalItems() )
570 static_cast<PCB_SHAPE*
>( item )->NormalizeRect();
573 diff = temp->FootprintNeedsUpdate( aLibFootprint, aReporter );
582 _(
"Footprint descriptions differ." ) );
584 _(
"Footprint keywords differ." ) );
586#define TEST_ATTR( a, b, attr, msg ) TEST( ( a & attr ), ( b & attr ), msg )
589 _(
"Footprint types differ." ) );
591 _(
"Allow bridged solder mask apertures between pads settings differ." ) );
593 _(
"Exempt from courtyard requirement settings differ." ) );
606 _(
"Pad clearance overridden." ) );
608 _(
"Solder mask expansion overridden." ) );
610 _(
"Solder paste absolute clearance overridden." ) );
612 _(
"Solder paste relative clearance overridden." ) );
615 _(
"Zone connection overridden." ) );
619 _(
"Net tie pad groups differ." ) );
624 _(
"Net tie pad groups differ." ) );
627#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
628#define CHECKPOINT { if( diff && !aReporter ) return diff; }
645 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aShapes;
647 std::inserter( aShapes, aShapes.begin() ),
650 return item->Type() == PCB_SHAPE_T;
652 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bShapes;
654 std::inserter( bShapes, bShapes.begin() ),
657 return item->Type() == PCB_SHAPE_T;
660 if( aShapes.size() != bShapes.size() )
663 REPORT(
_(
"Graphic item count differs." ) );
667 for(
auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
682 std::set<PAD*, FOOTPRINT::cmp_pads> aPads(
Pads().begin(),
Pads().end() );
683 std::set<PAD*, FOOTPRINT::cmp_pads> bPads( aLibFootprint->
Pads().begin(), aLibFootprint->
Pads().end() );
685 if( aPads.size() != bPads.size() )
688 REPORT(
_(
"Pad count differs." ) );
692 for(
auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
706 REPORT(
_(
"3D model count differs." ) );
710 for(
size_t ii = 0; ii <
Models().size(); ++ii )
717 std::unique_ptr<FOOTPRINT> libCopy(
static_cast<FOOTPRINT*
>( aLibFootprint->
Clone() ) );
722 std::set<ZONE*, FOOTPRINT::cmp_zones> aZones(
Zones().begin(),
Zones().end() );
723 std::set<ZONE*, FOOTPRINT::cmp_zones> bZones( libCopy->Zones().begin(), libCopy->Zones().end() );
725 if( aZones.size() != bZones.size() )
728 REPORT(
_(
"Rule area count differs." ) );
732 for(
auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
747 reportAux(
_(
"No project loaded, skipping library parity tests." ) );
751 if( !
reportPhase(
_(
"Loading footprint library table..." ) ) )
754 std::map<LIB_ID, std::shared_ptr<FOOTPRINT>> libFootprintCache;
759 const int progressDelta = 250;
761 if( !
reportPhase(
_(
"Checking board footprints against library..." ) ) )
775 LIB_ID fpID = footprint->GetFPID();
782 libTableRow = libTable->
FindRow( libName );
793 msg.Printf(
_(
"The current configuration does not include the library '%s'." ),
795 drcItem->SetErrorMessage( msg );
796 drcItem->SetItems( footprint );
802 else if( !libTable->
HasLibrary( libName,
true ) )
807 msg.Printf(
_(
"The library '%s' is not enabled in the current configuration." ),
809 drcItem->SetErrorMessage( msg );
810 drcItem->SetItems( footprint );
817 auto cacheIt = libFootprintCache.find( fpID );
818 std::shared_ptr<FOOTPRINT> libFootprint;
820 if( cacheIt != libFootprintCache.end() )
822 libFootprint = cacheIt->second;
828 libFootprint.reset( libTable->
FootprintLoad( libName, fpName,
true ) );
831 libFootprintCache[ fpID ] = libFootprint;
843 msg.Printf(
_(
"Footprint '%s' not found in library '%s'." ),
846 drcItem->SetErrorMessage( msg );
847 drcItem->SetItems( footprint );
851 else if( footprint->FootprintNeedsUpdate( libFootprint.get() ) )
856 msg.Printf(
_(
"Footprint '%s' does not match copy in library '%s'." ),
859 drcItem->SetErrorMessage( msg );
860 drcItem->SetItems( footprint );
constexpr EDA_IU_SCALE pcbIUScale
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
VECTOR2I GetFPRelativePosition() const
Information pertinent to a Pcbnew printed circuit board.
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
FOOTPRINTS & Footprints()
PROJECT * GetProject() const
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
const Vec & GetOrigin() const
bool IsErrorLimitExceeded(int error_code)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
virtual const wxString GetDescription() const override
virtual ~DRC_TEST_PROVIDER_LIBRARY_PARITY()
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual const wxString GetName() const override
DRC_TEST_PROVIDER_LIBRARY_PARITY()
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)
void reportAux(const wxString &aMsg)
virtual void SetParent(EDA_ITEM *aParent)
const VECTOR2I & GetBezierC2() const
SHAPE_POLY_SET & GetPolyShape()
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
wxString SHAPE_T_asString() const
const VECTOR2I & GetBezierC1() const
const EDA_ANGLE & GetTextAngle() const
virtual const wxString & GetText() const
Return the string associated with the text object.
bool IsKeepUpright() const
virtual bool IsVisible() const
GR_TEXT_H_ALIGN_T GetHorizJustify() const
GR_TEXT_V_ALIGN_T GetVertJustify() const
int GetTextThickness() const
VECTOR2I GetTextSize() const
VECTOR3D m_Offset
3D model offset (mm)
VECTOR3D m_Rotation
3D model rotation (degrees)
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
wxString m_Filename
The 3D shape filename in 3D library.
bool m_Show
Include model in rendering.
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.
const UTF8 & GetLibItemName() const
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
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.
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
PAD_PROP GetProperty() const
bool GetRemoveUnconnected() const
PAD_DRILL_SHAPE_T GetDrillShape() const
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
const VECTOR2I & GetDrillSize() const
PAD_ATTRIB GetAttribute() const
ZONE_CONNECTION GetZoneConnection() const
const wxString & GetNumber() const
double GetLocalSolderPasteMarginRatio() const
int GetRoundRectCornerRadius() const
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives() const
Accessor to the basic shape list for custom-shaped pads.
EDA_ANGLE GetThermalSpokeAngle() const
const VECTOR2I & GetOffset() const
int GetLocalSolderMaskMargin() const
bool GetKeepTopBottom() const
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
const VECTOR2I & GetDelta() const
PAD_SHAPE GetShape() const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
int GetThermalSpokeWidth() const
int GetLocalSolderPasteMargin() const
int GetChamferPositions() const
double GetRoundRectRadiusRatio() const
int GetThermalGap() const
const VECTOR2I & GetSize() const
double GetChamferRectRatio() const
int GetPadToDieLength() const
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
STROKE_PARAMS GetStroke() const override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Container for project specific data.
A pure virtual class used to derive REPORTER objects from.
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.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
bool GetDoNotAllowVias() const
bool GetDoNotAllowPads() const
bool GetDoNotAllowTracks() const
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
SHAPE_POLY_SET * Outline()
long long int GetMinIslandArea() const
int GetLocalClearance(wxString *aSource) const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
const wxString & GetZoneName() const
int GetMinThickness() const
ZONE_CONNECTION GetPadConnection() const
int GetHatchThickness() const
double GetHatchHoleMinArea() const
int GetThermalReliefSpokeWidth() const
EDA_ANGLE GetHatchOrientation() const
bool GetDoNotAllowFootprints() const
ZONE_FILL_MODE GetFillMode() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool GetDoNotAllowCopperPour() const
double GetHatchSmoothingValue() const
int GetHatchSmoothingLevel() const
unsigned int GetCornerRadius() const
int GetCornerSmoothingType() const
int GetThermalReliefGap() const
unsigned GetAssignedPriority() const
@ DRCE_LIB_FOOTPRINT_ISSUES
@ DRCE_LIB_FOOTPRINT_MISMATCH
bool textNeedsUpdate(const PCB_TEXT *a, const PCB_TEXT *b)
bool padHasOverrides(const PAD *a, const PAD *b, REPORTER *aReporter)
#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)
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)
#define TEST_D(a, b, msg)
bool padNeedsUpdate(const PAD *a, const PAD *b, REPORTER *aReporter)
bool shapeNeedsUpdate(const PCB_SHAPE *a, const PCB_SHAPE *b)
static constexpr EDA_ANGLE & ANGLE_0
@ ARC
use RECTANGLE instead of RECT to avoid collision in a Windows header
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
constexpr int mmToIU(double mm) const
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers