60 virtual bool Run()
override;
62 virtual const wxString
GetName()
const override {
return wxT(
"library_parity" ); };
71#define TEST( a, b, msg ) \
77 if( aReporter && wxString( msg ).length() ) \
78 aReporter->Report( msg ); \
81 if( diff && !aReporter ) \
86#define TEST_PT( a, b, msg ) \
88 if( abs( a.x - b.x ) > EPSILON \
89 || abs( a.y - b.y ) > EPSILON ) \
93 if( aReporter && wxString( msg ).length() ) \
94 aReporter->Report( msg ); \
97 if( diff && !aReporter ) \
101#define EPSILON_D 0.000002
102#define TEST_D( a, b, msg ) \
104 if( abs( a - b ) > EPSILON_D ) \
108 if( aReporter && wxString( msg ).length() ) \
109 aReporter->Report( msg ); \
112 if( diff && !aReporter ) \
116#define ITEM_DESC( item ) ( item )->GetItemDescription( &g_unitsProvider, true )
117#define PAD_DESC( pad ) wxString::Format( _( "Pad %s" ), ( pad )->GetNumber() )
135 const std::shared_ptr<PCB_SHAPE>& b )
140 TEST( a->GetShape(), b->GetShape(),
"" );
142 switch( a->GetShape() )
146 BOX2I aRect( a->GetStart(), a->GetEnd() - a->GetStart() );
147 BOX2I bRect( b->GetStart(), b->GetEnd() - b->GetStart() );
159 TEST_PT( a->GetStart(), b->GetStart(),
"" );
160 TEST_PT( a->GetEnd(), b->GetEnd(),
"" );
164 TEST_PT( a->GetStart(), b->GetStart(),
"" );
165 TEST_PT( a->GetEnd(), b->GetEnd(),
"" );
169 if( ( a->GetArcMid() - b->GetArcMid() ).EuclideanNorm() >
pcbIUScale.mmToIU( 0.0005 ) )
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(),
"" );
182 TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(),
"" );
184 for(
int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
185 TEST_PT( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ),
"" );
193 TEST( a->GetStroke(), b->GetStroke(),
"" );
194 TEST( a->GetFillMode(), b->GetFillMode(),
"" );
204#define REPORT_MSG( s, p ) aReporter.Report( wxString::Format( s, p ) )
276 wxString::Format(
_(
"%s pad to die length differs." ),
PAD_DESC( a ) ) );
278 wxString::Format(
_(
"%s position differs." ),
PAD_DESC( a ) ) );
281 wxString::Format(
_(
"%s has different numbers." ),
PAD_DESC( a ) ) );
293 if( layerSettingsDiffer
299 aReporter->
Report( wxString::Format(
_(
"%s layers differ." ),
PAD_DESC( a ) ) );
305 wxString::Format(
_(
"%s pad type differs." ),
PAD_DESC( a ) ) );
307 wxString::Format(
_(
"%s fabrication property differs." ),
PAD_DESC( a ) ) );
312 wxString::Format(
_(
"%s orientation differs." ),
PAD_DESC( a ) ) );
323 wxString::Format(
_(
"%s pad shape type differs on layer %s." ),
328 wxString::Format(
_(
"%s size differs on layer %s." ),
333 wxString::Format(
_(
"%s trapezoid delta differs on layer %s." ),
341 wxString::Format(
_(
"%s rounded corners differ on layer %s." ),
350 wxString::Format(
_(
"%s chamfered corner sizes differ on layer %s." ),
356 wxString::Format(
_(
"%s chamfered corners differ on layer %s." ),
362 wxString::Format(
_(
"%s shape offset from hole differs on layer %s." ),
368 wxString::Format(
_(
"%s drill shape differs." ),
PAD_DESC( a ) ) );
370 wxString::Format(
_(
"%s drill size differs." ),
PAD_DESC( a ) ) );
385 bool primitivesDiffer =
false;
393 primitivesDiffer =
true;
397 for(
size_t ii = 0; ii < a->
GetPrimitives( aLayer ).size(); ++ii )
402 primitivesDiffer =
true;
409 firstDifferingLayer = aLayer;
413 if( primitivesDiffer )
416 layerName = board ? board->
GetLayerName( firstDifferingLayer )
421 aReporter->
Report( wxString::Format(
_(
"%s shape primitives differ on layer %s." ),
485 for(
int ii = 0; ii < curr_shape.
GetPolyShape().TotalVertices(); ++ii )
510 wxString::Format(
_(
"%s corner smoothing setting differs." ),
ITEM_DESC( a ) ) );
512 wxString::Format(
_(
"%s corner smoothing radius differs." ),
ITEM_DESC( a ) ) );
514 wxString::Format(
_(
"%s name differs." ),
ITEM_DESC( a ) ) );
516 wxString::Format(
_(
"%s priority differs." ),
ITEM_DESC( a ) ) );
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 ) ) );
532 wxString::Format(
_(
"%s layers differ." ),
ITEM_DESC( a ) ) );
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 ) ) );
544 wxString::Format(
_(
"%s min thickness differs." ),
ITEM_DESC( a ) ) );
547 wxString::Format(
_(
"%s remove islands setting differs." ),
ITEM_DESC( a ) ) );
549 wxString::Format(
_(
"%s minimum island size setting differs." ),
ITEM_DESC( a ) ) );
552 wxString::Format(
_(
"%s fill type differs." ),
ITEM_DESC( a ) ) );
554 wxString::Format(
_(
"%s hatch width differs." ),
ITEM_DESC( a ) ) );
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 ) ) );
570 wxString::Format(
_(
"%s outline corner count differs." ),
ITEM_DESC( a ) ) );
572 bool cornersDiffer =
false;
574 for(
int ii = 0; ii < a->
Outline()->TotalVertices(); ++ii )
579 cornersDiffer =
true;
584 if( cornersDiffer && aReporter )
585 aReporter->
Report( wxString::Format(
_(
"%s corners differ." ),
ITEM_DESC( a ) ) );
601 wxString::Format(
_(
"Footprint stackup mode differs." ) ) );
606 TEST( aLayers, bLayers,
607 wxString::Format(
_(
"Footprint layers differ." ) ) );
630 bool mismatch =
false;
633 const LSET onlyInFp = fpLayers & ~brdLayers;
635 if( onlyInFp.count() )
639 aReporter->
Report( wxString::Format(
_(
"Footprint has %lu layers not on board: %s" ), onlyInFp.count(),
646 if( cuOnlyInBoard.count() )
650 aReporter->
Report( wxString::Format(
_(
"Board has %lu copper layers not in footprint: %s" ),
651 cuOnlyInBoard.count(),
670 std::unique_ptr<FOOTPRINT> temp(
static_cast<FOOTPRINT*
>( aLibFP->
Clone() ) );
686 for(
BOARD_ITEM* item : temp->GraphicalItems() )
687 item->NormalizeForCompare();
691 temp->SetParent(
nullptr );
698#define TEST_ATTR( a, b, attr, msg ) TEST( ( a & attr ), ( b & attr ), msg )
701 _(
"Footprint types differ." ) );
704 wxString::Format(
_(
"'%s' settings differ." ),
705 _(
"Allow bridged solder mask apertures between pads" ) ) );
711 wxString::Format(
_(
"'%s' settings differ." ),
712 _(
"Not in schematic" ) ) );
715 wxString::Format(
_(
"'%s' settings differ." ),
716 _(
"Exclude from position files" ) ) );
719 wxString::Format(
_(
"'%s' settings differ." ),
720 _(
"Exclude from bill of materials" ) ) );
723 wxString::Format(
_(
"'%s' settings differ." ),
724 _(
"Do not populate" ) ) );
727#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
728#define CHECKPOINT { if( diff && !aReporter ) return diff; }
733 REPORT(
_(
"Footprint stackup differs." ) );
751 REPORT(
_(
"Pad clearance overridden." ) );
758 REPORT(
_(
"Solder mask expansion overridden." ) );
766 REPORT(
_(
"Solder paste absolute clearance overridden." ) );
773 REPORT(
_(
"Solder paste relative clearance overridden." ) );
780 REPORT(
_(
"Zone connection overridden." ) );
785 _(
"Net tie pad groups differ." ) );
790 _(
"Net tie pad groups differ." ) );
812 dummy.SetParentGroup(
nullptr );
813 dummy.SetParent(
nullptr );
816 item->NormalizeForCompare();
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() ),
823 return item->Type() == PCB_SHAPE_T;
826 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bShapes;
828 std::inserter( bShapes, bShapes.begin() ),
831 return item->Type() == PCB_SHAPE_T;
834 if( aShapes.size() != bShapes.size() )
837 REPORT(
_(
"Graphic item count differs." ) );
841 for(
auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
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() );
861 if( aPads.size() != bPads.size() )
864 REPORT(
_(
"Pad count differs." ) );
868 for(
auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
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() );
882 if( aZones.size() != bZones.size() )
885 REPORT(
_(
"Rule area count differs." ) );
889 for(
auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
904 REPORT_AUX(
_(
"No project loaded, skipping library parity tests." ) );
908 if( !
reportPhase(
_(
"Loading footprint library table..." ) ) )
911 std::map<LIB_ID, std::shared_ptr<FOOTPRINT>> libFootprintCache;
916 const int progressDelta = 250;
918 if( !
reportPhase(
_(
"Checking board footprints against library..." ) ) )
932 LIB_ID fpID = footprint->GetFPID();
937 if( libName.IsEmpty() )
945 libTableRow = libTable->
FindRow( libName );
956 msg.Printf(
_(
"The current configuration does not include the footprint library '%s'" ),
958 drcItem->SetErrorMessage( msg );
959 drcItem->SetItems( footprint );
965 else if( !libTable->
HasLibrary( libName,
true ) )
970 msg.Printf(
_(
"The footprint library '%s' is not enabled in the current configuration" ),
972 drcItem->SetErrorMessage( msg );
973 drcItem->SetItems( footprint );
984 msg.Printf(
_(
"The footprint library '%s' was not found at '%s'" ),
987 drcItem->SetErrorMessage( msg );
988 drcItem->SetItems( footprint );
995 auto cacheIt = libFootprintCache.find( fpID );
996 std::shared_ptr<FOOTPRINT> libFootprint;
998 if( cacheIt != libFootprintCache.end() )
1000 libFootprint = cacheIt->second;
1006 libFootprint.reset( libTable->
FootprintLoad( libName, fpName,
true ) );
1009 libFootprintCache[ fpID ] = libFootprint;
1021 msg.Printf(
_(
"Footprint '%s' not found in library '%s'" ),
1024 drcItem->SetErrorMessage( msg );
1025 drcItem->SetItems( footprint );
1034 msg.Printf(
_(
"Footprint '%s' does not match copy in library '%s'" ),
1037 drcItem->SetErrorMessage( msg );
1038 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...
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
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.
virtual bool IsOnCopperLayer() const
Information pertinent to a Pcbnew printed circuit board.
const FOOTPRINTS & Footprints() const
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
PROJECT * GetProject() const
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
constexpr const Vec GetEnd() const
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
constexpr const Vec & GetOrigin() const
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
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
DRC_TEST_PROVIDER_LIBRARY_PARITY()
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)
const VECTOR2I & GetBezierC2() const
FILL_T GetFillMode() 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
VECTOR2I GetArcMid() const
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.
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.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
static LSET UserDefinedLayersMask(int aUserDefinedLayerCount=MAX_USER_DEFINED_LAYERS)
Return a mask with the requested number of user defined layers.
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
std::vector< PCB_LAYER_ID > UniqueLayers() const
PAD_PROP GetProperty() const
bool GetRemoveUnconnected() const
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives(PCB_LAYER_ID aLayer) const
Accessor to the basic shape list for custom-shaped pads.
std::optional< double > GetLocalSolderPasteMarginRatio() const
const VECTOR2I & GetDrillSize() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
EDA_ANGLE GetThermalSpokeAngle() const
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
bool GetKeepTopBottom() const
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
const PADSTACK & Padstack() const
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
PAD_DRILL_SHAPE GetDrillShape() const
int GetChamferPositions(PCB_LAYER_ID aLayer) const
std::optional< int > GetLocalSolderPasteMargin() const
std::optional< int > GetLocalSolderMaskMargin() const
EDA_ANGLE GetFPRelativeOrientation() const
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
std::optional< int > GetLocalThermalSpokeWidthOverride() const
ZONE_CONNECTION GetLocalZoneConnection() const
int GetThermalGap() const
int GetLocalThermalGapOverride(wxString *aSource) const
int GetPadToDieLength() const
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
STROKE_PARAMS GetStroke() const override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
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)
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:
std::optional< int > GetLocalClearance() const override
bool GetDoNotAllowVias() const
bool GetDoNotAllowPads() const
bool GetDoNotAllowTracks() const
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
SHAPE_POLY_SET * Outline()
long long int GetMinIslandArea() const
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.
double GetHatchSmoothingValue() const
bool GetDoNotAllowZoneFills() 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
UNITS_PROVIDER g_unitsProvider(pcbIUScale, EDA_UNITS::MM)
bool footprintVsBoardStackup(const FOOTPRINT &aFp, const BOARD &aBoard, REPORTER *aReporter)
Report board->footprint stackup differences.
#define TEST_PT(a, b, msg)
bool primitiveNeedsUpdate(const std::shared_ptr< PCB_SHAPE > &a, const std::shared_ptr< PCB_SHAPE > &b)
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.
LSET getBoardNormalizedLayerSet(const BOARD_ITEM *aLibItem, const BOARD *aBoard)
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
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
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)