57 virtual bool Run()
override;
59 virtual const wxString
GetName()
const override {
return wxT(
"library_parity" ); };
68#define TEST( a, b, msg ) \
74 if( aReporter && wxString( msg ).length() ) \
75 aReporter->Report( msg ); \
78 if( diff && !aReporter ) \
83#define TEST_PT( a, b, msg ) \
85 if( abs( a.x - b.x ) > EPSILON \
86 || abs( a.y - b.y ) > EPSILON ) \
90 if( aReporter && wxString( msg ).length() ) \
91 aReporter->Report( msg ); \
94 if( diff && !aReporter ) \
98#define EPSILON_D 0.000002
99#define TEST_D( a, b, msg ) \
101 if( abs( a - b ) > EPSILON_D ) \
105 if( aReporter && wxString( msg ).length() ) \
106 aReporter->Report( msg ); \
109 if( diff && !aReporter ) \
113#define ITEM_DESC( item ) ( item )->GetItemDescription( &g_unitsProvider, true )
114#define PAD_DESC( pad ) wxString::Format( _( "Pad %s" ), ( pad )->GetNumber() )
132 const std::shared_ptr<PCB_SHAPE>& b )
137 TEST( a->GetShape(), b->GetShape(),
"" );
139 switch( a->GetShape() )
143 BOX2I aRect( a->GetStart(), a->GetEnd() - a->GetStart() );
144 BOX2I bRect( b->GetStart(), b->GetEnd() - b->GetStart() );
156 TEST_PT( a->GetStart(), b->GetStart(),
"" );
157 TEST_PT( a->GetEnd(), b->GetEnd(),
"" );
161 TEST_PT( a->GetStart(), b->GetStart(),
"" );
162 TEST_PT( a->GetEnd(), b->GetEnd(),
"" );
166 if( ( a->GetArcMid() - b->GetArcMid() ).EuclideanNorm() >
pcbIUScale.
mmToIU( 0.0005 ) )
172 TEST_PT( a->GetStart(), b->GetStart(),
"" );
173 TEST_PT( a->GetEnd(), b->GetEnd(),
"" );
174 TEST_PT( a->GetBezierC1(), b->GetBezierC1(),
"" );
175 TEST_PT( a->GetBezierC2(), b->GetBezierC2(),
"" );
179 TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(),
"" );
181 for(
int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
182 TEST_PT( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ),
"" );
190 TEST( a->GetStroke(), b->GetStroke(),
"" );
191 TEST( a->GetFillMode(), b->GetFillMode(),
"" );
201#define REPORT_MSG( s, p ) aReporter.Report( wxString::Format( s, p ) )
273 wxString::Format(
_(
"%s pad to die length differs." ),
PAD_DESC( a ) ) );
275 wxString::Format(
_(
"%s position differs." ),
PAD_DESC( a ) ) );
278 wxString::Format(
_(
"%s has different numbers." ),
PAD_DESC( a ) ) );
290 if( layerSettingsDiffer
296 aReporter->
Report( wxString::Format(
_(
"%s layers differ." ),
PAD_DESC( a ) ) );
302 wxString::Format(
_(
"%s pad type differs." ),
PAD_DESC( a ) ) );
304 wxString::Format(
_(
"%s fabrication property differs." ),
PAD_DESC( a ) ) );
309 wxString::Format(
_(
"%s orientation differs." ),
PAD_DESC( a ) ) );
320 wxString::Format(
_(
"%s pad shape type differs on layer %s." ),
325 wxString::Format(
_(
"%s size differs on layer %s." ),
330 wxString::Format(
_(
"%s trapezoid delta differs on layer %s." ),
336 wxString::Format(
_(
"%s rounded corners differ on layer %s." ),
342 wxString::Format(
_(
"%s chamfered corner sizes differ on layer %s." ),
348 wxString::Format(
_(
"%s chamfered corners differ on layer %s." ),
353 wxString::Format(
_(
"%s shape offset from hole differs on layer %s." ),
359 wxString::Format(
_(
"%s drill shape differs." ),
PAD_DESC( a ) ) );
361 wxString::Format(
_(
"%s drill size differs." ),
PAD_DESC( a ) ) );
376 bool primitivesDiffer =
false;
384 primitivesDiffer = true;
388 for( size_t ii = 0; ii < a->GetPrimitives( aLayer ).size(); ++ii )
390 if( primitiveNeedsUpdate( a->GetPrimitives( aLayer )[ii],
391 b->GetPrimitives( aLayer )[ii] ) )
393 primitivesDiffer = true;
400 firstDifferingLayer = aLayer;
404 if( primitivesDiffer )
407 layerName = board ? board->GetLayerName( firstDifferingLayer )
412 aReporter->Report( wxString::Format(
_(
"%s shape primitives differ on layer %s." ),
476 for(
int ii = 0; ii < curr_shape.
GetPolyShape().TotalVertices(); ++ii )
501 wxString::Format(
_(
"%s corner smoothing setting differs." ),
ITEM_DESC( a ) ) );
503 wxString::Format(
_(
"%s corner smoothing radius differs." ),
ITEM_DESC( a ) ) );
505 wxString::Format(
_(
"%s name differs." ),
ITEM_DESC( a ) ) );
507 wxString::Format(
_(
"%s priority differs." ),
ITEM_DESC( a ) ) );
510 wxString::Format(
_(
"%s keep-out property differs." ),
ITEM_DESC( a ) ) );
512 wxString::Format(
_(
"%s keep out zone fill setting differs." ),
ITEM_DESC( a ) ) );
514 wxString::Format(
_(
"%s keep out footprints setting differs." ),
ITEM_DESC( a ) ) );
516 wxString::Format(
_(
"%s keep out pads setting differs." ),
ITEM_DESC( a ) ) );
518 wxString::Format(
_(
"%s keep out tracks setting differs." ),
ITEM_DESC( a ) ) );
520 wxString::Format(
_(
"%s keep out vias setting differs." ),
ITEM_DESC( a ) ) );
523 wxString::Format(
_(
"%s layers differ." ),
ITEM_DESC( a ) ) );
526 wxString::Format(
_(
"%s pad connection property differs." ),
ITEM_DESC( a ) ) );
528 wxString::Format(
_(
"%s local clearance differs." ),
ITEM_DESC( a ) ) );
530 wxString::Format(
_(
"%s thermal relief gap differs." ),
ITEM_DESC( a ) ) );
532 wxString::Format(
_(
"%s thermal relief spoke width differs." ),
ITEM_DESC( a ) ) );
535 wxString::Format(
_(
"%s min thickness differs." ),
ITEM_DESC( a ) ) );
538 wxString::Format(
_(
"%s remove islands setting differs." ),
ITEM_DESC( a ) ) );
540 wxString::Format(
_(
"%s minimum island size setting differs." ),
ITEM_DESC( a ) ) );
543 wxString::Format(
_(
"%s fill type differs." ),
ITEM_DESC( a ) ) );
545 wxString::Format(
_(
"%s hatch width differs." ),
ITEM_DESC( a ) ) );
547 wxString::Format(
_(
"%s hatch gap differs." ),
ITEM_DESC( a ) ) );
549 wxString::Format(
_(
"%s hatch orientation differs." ),
ITEM_DESC( a ) ) );
551 wxString::Format(
_(
"%s hatch smoothing level differs." ),
ITEM_DESC( a ) ) );
553 wxString::Format(
_(
"%s hatch smoothing amount differs." ),
ITEM_DESC( a ) ) );
555 wxString::Format(
_(
"%s minimum hatch hole setting differs." ),
ITEM_DESC( a ) ) );
561 wxString::Format(
_(
"%s outline corner count differs." ),
ITEM_DESC( a ) ) );
563 bool cornersDiffer =
false;
565 for(
int ii = 0; ii < a->
Outline()->TotalVertices(); ++ii )
570 cornersDiffer =
true;
575 if( cornersDiffer && aReporter )
576 aReporter->
Report( wxString::Format(
_(
"%s corners differ." ),
ITEM_DESC( a ) ) );
593 std::unique_ptr<FOOTPRINT> temp(
static_cast<FOOTPRINT*
>( aLibFP->
Clone() ) );
600 temp->Flip( { 0, 0 }, FLIP_DIRECTION::TOP_BOTTOM );
609 for(
BOARD_ITEM* item : temp->GraphicalItems() )
610 item->NormalizeForCompare();
614 temp->SetParent(
nullptr );
618#define TEST_ATTR( a, b, attr, msg ) TEST( ( a & attr ), ( b & attr ), msg )
621 _(
"Footprint types differ." ) );
624 wxString::Format(
_(
"'%s' settings differ." ),
625 _(
"Allow bridged solder mask apertures between pads" ) ) );
631 wxString::Format(
_(
"'%s' settings differ." ),
632 _(
"Not in schematic" ) ) );
635 wxString::Format(
_(
"'%s' settings differ." ),
636 _(
"Exclude from position files" ) ) );
639 wxString::Format(
_(
"'%s' settings differ." ),
640 _(
"Exclude from bill of materials" ) ) );
643 wxString::Format(
_(
"'%s' settings differ." ),
644 _(
"Do not populate" ) ) );
647#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
648#define CHECKPOINT { if( diff && !aReporter ) return diff; }
665 REPORT(
_(
"Pad clearance overridden." ) );
672 REPORT(
_(
"Solder mask expansion overridden." ) );
680 REPORT(
_(
"Solder paste absolute clearance overridden." ) );
687 REPORT(
_(
"Solder paste relative clearance overridden." ) );
694 REPORT(
_(
"Zone connection overridden." ) );
699 _(
"Net tie pad groups differ." ) );
704 _(
"Net tie pad groups differ." ) );
726 dummy.SetParentGroup(
nullptr );
727 dummy.SetParent(
nullptr );
730 item->NormalizeForCompare();
732 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aShapes;
733 std::copy_if(
dummy.GraphicalItems().begin(),
dummy.GraphicalItems().end(),
734 std::inserter( aShapes, aShapes.begin() ),
737 return item->Type() == PCB_SHAPE_T;
740 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bShapes;
742 std::inserter( bShapes, bShapes.begin() ),
745 return item->Type() == PCB_SHAPE_T;
748 if( aShapes.size() != bShapes.size() )
751 REPORT(
_(
"Graphic item count differs." ) );
755 for(
auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
772 std::set<PAD*, FOOTPRINT::cmp_pads> aPads(
Pads().begin(),
Pads().
end() );
773 std::set<PAD*, FOOTPRINT::cmp_pads> bPads( aLibFP->
Pads().begin(), aLibFP->
Pads().end() );
775 if( aPads.size() != bPads.size() )
778 REPORT(
_(
"Pad count differs." ) );
782 for(
auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
793 std::set<ZONE*, FOOTPRINT::cmp_zones> aZones(
Zones().begin(),
Zones().
end() );
794 std::set<ZONE*, FOOTPRINT::cmp_zones> bZones( aLibFP->
Zones().begin(), aLibFP->
Zones().end() );
796 if( aZones.size() != bZones.size() )
799 REPORT(
_(
"Rule area count differs." ) );
803 for(
auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
818 REPORT_AUX(
_(
"No project loaded, skipping library parity tests." ) );
822 if( !
reportPhase(
_(
"Loading footprint library table..." ) ) )
825 std::map<LIB_ID, std::shared_ptr<FOOTPRINT>> libFootprintCache;
830 const int progressDelta = 250;
832 if( !
reportPhase(
_(
"Checking board footprints against library..." ) ) )
846 LIB_ID fpID = footprint->GetFPID();
851 if( libName.IsEmpty() )
859 libTableRow = libTable->
FindRow( libName );
870 msg.Printf(
_(
"The current configuration does not include the footprint library '%s'." ),
872 drcItem->SetErrorMessage( msg );
873 drcItem->SetItems( footprint );
879 else if( !libTable->
HasLibrary( libName,
true ) )
884 msg.Printf(
_(
"The footprint library '%s' is not enabled in the current configuration." ),
886 drcItem->SetErrorMessage( msg );
887 drcItem->SetItems( footprint );
898 msg.Printf(
_(
"The footprint library '%s' was not found at '%s'." ),
901 drcItem->SetErrorMessage( msg );
902 drcItem->SetItems( footprint );
909 auto cacheIt = libFootprintCache.find( fpID );
910 std::shared_ptr<FOOTPRINT> libFootprint;
912 if( cacheIt != libFootprintCache.end() )
914 libFootprint = cacheIt->second;
920 libFootprint.reset( libTable->
FootprintLoad( libName, fpName,
true ) );
923 libFootprintCache[ fpID ] = libFootprint;
935 msg.Printf(
_(
"Footprint '%s' not found in library '%s'." ),
938 drcItem->SetErrorMessage( msg );
939 drcItem->SetItems( footprint );
948 msg.Printf(
_(
"Footprint '%s' does not match copy in library '%s'." ),
951 drcItem->SetErrorMessage( msg );
952 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 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
bool IsErrorLimitExceeded(int error_code)
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()
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 void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER *aCustomHandler=nullptr)
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.
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)
#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)
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)
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
constexpr int mmToIU(double mm) const