Add footprint library checking to DRC.

Fixes https://gitlab.com/kicad/code/kicad/issues/6821
This commit is contained in:
Jeff Young 2021-07-11 12:49:36 +01:00
parent c4432e5d03
commit 0a609dd48d
42 changed files with 657 additions and 166 deletions

View File

@ -238,7 +238,8 @@ set( PCBNEW_DRC_SRCS
drc/drc_test_provider_edge_clearance.cpp drc/drc_test_provider_edge_clearance.cpp
drc/drc_test_provider_hole_to_hole.cpp drc/drc_test_provider_hole_to_hole.cpp
drc/drc_test_provider_hole_size.cpp drc/drc_test_provider_hole_size.cpp
drc/drc_test_provider_lvs.cpp drc/drc_test_provider_library_parity.cpp
drc/drc_test_provider_schematic_parity.cpp
drc/drc_test_provider_misc.cpp drc/drc_test_provider_misc.cpp
drc/drc_test_provider_track_width.cpp drc/drc_test_provider_track_width.cpp
drc/drc_test_provider_via_diameter.cpp drc/drc_test_provider_via_diameter.cpp

View File

@ -508,7 +508,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataFromWindow()
// Copy the models from the panel to the footprint // Copy the models from the panel to the footprint
std::vector<FP_3DMODEL>& panelList = m_3dPanel->GetModelList(); std::vector<FP_3DMODEL>& panelList = m_3dPanel->GetModelList();
std::list<FP_3DMODEL>* fpList = &m_footprint->Models(); std::vector<FP_3DMODEL>* fpList = &m_footprint->Models();
fpList->clear(); fpList->clear();
fpList->insert( fpList->end(), panelList.begin(), panelList.end() ); fpList->insert( fpList->end(), panelList.begin(), panelList.end() );

View File

@ -443,7 +443,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
// Copy the models from the panel to the footprint // Copy the models from the panel to the footprint
std::vector<FP_3DMODEL>& panelList = m_3dPanel->GetModelList(); std::vector<FP_3DMODEL>& panelList = m_3dPanel->GetModelList();
std::list<FP_3DMODEL>* fpList = &m_footprint->Models(); std::vector<FP_3DMODEL>* fpList = &m_footprint->Models();
fpList->clear(); fpList->clear();
fpList->insert( fpList->end(), panelList.begin(), panelList.end() ); fpList->insert( fpList->end(), panelList.begin(), panelList.end() );

View File

@ -170,6 +170,10 @@ DRC_ITEM DRC_ITEM::netConflict( DRCE_NET_CONFLICT,
_( "Pad net doesn't match schematic" ), _( "Pad net doesn't match schematic" ),
wxT( "net_conflict" ) ); wxT( "net_conflict" ) );
DRC_ITEM DRC_ITEM::libFootprintIssues( DRCE_LIB_FOOTPRINT_ISSUES,
_( "Library footprint issue" ),
wxT( "lib_footprint_issues" ) );
DRC_ITEM DRC_ITEM::unresolvedVariable( DRCE_UNRESOLVED_VARIABLE, DRC_ITEM DRC_ITEM::unresolvedVariable( DRCE_UNRESOLVED_VARIABLE,
_( "Unresolved text variable" ), _( "Unresolved text variable" ),
wxT( "unresolved_variable" ) ); wxT( "unresolved_variable" ) );
@ -298,6 +302,7 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
case DRCE_DUPLICATE_FOOTPRINT: return std::make_shared<DRC_ITEM>( duplicateFootprints ); case DRCE_DUPLICATE_FOOTPRINT: return std::make_shared<DRC_ITEM>( duplicateFootprints );
case DRCE_NET_CONFLICT: return std::make_shared<DRC_ITEM>( netConflict ); case DRCE_NET_CONFLICT: return std::make_shared<DRC_ITEM>( netConflict );
case DRCE_EXTRA_FOOTPRINT: return std::make_shared<DRC_ITEM>( extraFootprint ); case DRCE_EXTRA_FOOTPRINT: return std::make_shared<DRC_ITEM>( extraFootprint );
case DRCE_LIB_FOOTPRINT_ISSUES: return std::make_shared<DRC_ITEM>( libFootprintIssues );
case DRCE_UNRESOLVED_VARIABLE: return std::make_shared<DRC_ITEM>( unresolvedVariable ); case DRCE_UNRESOLVED_VARIABLE: return std::make_shared<DRC_ITEM>( unresolvedVariable );
case DRCE_OVERLAPPING_SILK: return std::make_shared<DRC_ITEM>( silkOverlaps ); case DRCE_OVERLAPPING_SILK: return std::make_shared<DRC_ITEM>( silkOverlaps );
case DRCE_SILK_MASK_CLEARANCE: return std::make_shared<DRC_ITEM>( silkMaskClearance ); case DRCE_SILK_MASK_CLEARANCE: return std::make_shared<DRC_ITEM>( silkMaskClearance );

View File

@ -68,6 +68,7 @@ enum PCB_DRC_CODE {
DRCE_NET_CONFLICT, // pad net doesn't match netlist DRCE_NET_CONFLICT, // pad net doesn't match netlist
DRCE_FOOTPRINT_TYPE_MISMATCH, // footprint attribute does not match actual pads DRCE_FOOTPRINT_TYPE_MISMATCH, // footprint attribute does not match actual pads
DRCE_LIB_FOOTPRINT_ISSUES, // footprint does not match the current library
DRCE_PAD_TH_WITH_NO_HOLE, // footprint has Plated Through-Hole with no hole DRCE_PAD_TH_WITH_NO_HOLE, // footprint has Plated Through-Hole with no hole
DRCE_UNRESOLVED_VARIABLE, DRCE_UNRESOLVED_VARIABLE,
@ -164,6 +165,7 @@ private:
static DRC_ITEM missingFootprint; static DRC_ITEM missingFootprint;
static DRC_ITEM extraFootprint; static DRC_ITEM extraFootprint;
static DRC_ITEM netConflict; static DRC_ITEM netConflict;
static DRC_ITEM libFootprintIssues;
static DRC_ITEM unresolvedVariable; static DRC_ITEM unresolvedVariable;
static DRC_ITEM silkMaskClearance; static DRC_ITEM silkMaskClearance;
static DRC_ITEM silkOverlaps; static DRC_ITEM silkOverlaps;

View File

@ -91,13 +91,6 @@ public:
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const = 0; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const = 0;
virtual int GetNumPhases() const = 0;
virtual bool IsRuleDriven() const
{
return m_isRuleDriven;
}
bool IsEnabled() const bool IsEnabled() const
{ {
return m_enabled; return m_enabled;

View File

@ -63,8 +63,6 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -164,12 +162,6 @@ bool DRC_TEST_PROVIDER_ANNULAR_WIDTH::Run()
} }
int DRC_TEST_PROVIDER_ANNULAR_WIDTH::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_ANNULAR_WIDTH::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_ANNULAR_WIDTH::GetConstraintTypes() const
{ {
return { ANNULAR_WIDTH_CONSTRAINT }; return { ANNULAR_WIDTH_CONSTRAINT };

View File

@ -65,8 +65,6 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -175,12 +173,6 @@ bool DRC_TEST_PROVIDER_CONNECTIVITY::Run()
} }
int DRC_TEST_PROVIDER_CONNECTIVITY::GetNumPhases() const
{
return 3;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_CONNECTIVITY::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_CONNECTIVITY::GetConstraintTypes() const
{ {
return {}; return {};

View File

@ -80,8 +80,6 @@ public:
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
bool testTrackAgainstItem( PCB_TRACK* track, SHAPE* trackShape, PCB_LAYER_ID layer, bool testTrackAgainstItem( PCB_TRACK* track, SHAPE* trackShape, PCB_LAYER_ID layer,
BOARD_ITEM* other ); BOARD_ITEM* other );
@ -1006,12 +1004,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
} }
int DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetNumPhases() const
{
return 4;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_COPPER_CLEARANCE::GetConstraintTypes() const
{ {
return { CLEARANCE_CONSTRAINT, HOLE_CLEARANCE_CONSTRAINT }; return { CLEARANCE_CONSTRAINT, HOLE_CLEARANCE_CONSTRAINT };

View File

@ -69,8 +69,6 @@ public:
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
bool testFootprintCourtyardDefinitions(); bool testFootprintCourtyardDefinitions();
@ -319,12 +317,6 @@ bool DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Run()
} }
int DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetNumPhases() const
{
return 2;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetConstraintTypes() const
{ {
return { COURTYARD_CLEARANCE_CONSTRAINT }; return { COURTYARD_CLEARANCE_CONSTRAINT };

View File

@ -74,11 +74,6 @@ public:
return "Tests differential pair coupling"; return "Tests differential pair coupling";
} }
virtual int GetNumPhases() const override
{
return 1;
}
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
private: private:

View File

@ -60,8 +60,6 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -169,12 +167,6 @@ bool DRC_TEST_PROVIDER_DISALLOW::Run()
} }
int DRC_TEST_PROVIDER_DISALLOW::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_DISALLOW::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_DISALLOW::GetConstraintTypes() const
{ {
return { DISALLOW_CONSTRAINT }; return { DISALLOW_CONSTRAINT };

View File

@ -70,8 +70,6 @@ public:
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
bool testAgainstEdge( BOARD_ITEM* item, SHAPE* itemShape, BOARD_ITEM* other, bool testAgainstEdge( BOARD_ITEM* item, SHAPE* itemShape, BOARD_ITEM* other,
DRC_CONSTRAINT_T aConstraintType, PCB_DRC_CODE aErrorCode ); DRC_CONSTRAINT_T aConstraintType, PCB_DRC_CODE aErrorCode );
@ -282,12 +280,6 @@ bool DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run()
} }
int DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetConstraintTypes() const
{ {
return { EDGE_CLEARANCE_CONSTRAINT, SILK_CLEARANCE_CONSTRAINT }; return { EDGE_CLEARANCE_CONSTRAINT, SILK_CLEARANCE_CONSTRAINT };

View File

@ -62,8 +62,6 @@ public:
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
void checkVia( PCB_VIA* via, bool aExceedMicro, bool aExceedStd ); void checkVia( PCB_VIA* via, bool aExceedMicro, bool aExceedStd );
void checkPad( PAD* aPad ); void checkPad( PAD* aPad );
@ -251,12 +249,6 @@ void DRC_TEST_PROVIDER_HOLE_SIZE::checkVia( PCB_VIA* via, bool aExceedMicro, boo
} }
int DRC_TEST_PROVIDER_HOLE_SIZE::GetNumPhases() const
{
return 2;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_HOLE_SIZE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_HOLE_SIZE::GetConstraintTypes() const
{ {
return { HOLE_SIZE_CONSTRAINT }; return { HOLE_SIZE_CONSTRAINT };

View File

@ -70,8 +70,6 @@ public:
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
bool testHoleAgainstHole( BOARD_ITEM* aItem, SHAPE_CIRCLE* aHole, BOARD_ITEM* aOther ); bool testHoleAgainstHole( BOARD_ITEM* aItem, SHAPE_CIRCLE* aHole, BOARD_ITEM* aOther );
@ -327,12 +325,6 @@ bool DRC_TEST_PROVIDER_HOLE_TO_HOLE::testHoleAgainstHole( BOARD_ITEM* aItem, SHA
} }
int DRC_TEST_PROVIDER_HOLE_TO_HOLE::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_HOLE_TO_HOLE::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_HOLE_TO_HOLE::GetConstraintTypes() const
{ {
return { HOLE_TO_HOLE_CONSTRAINT }; return { HOLE_TO_HOLE_CONSTRAINT };

View File

@ -0,0 +1,519 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2021 KiCad Developers.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <kiway.h>
#include <netlist_reader/pcb_netlist.h>
#include <fp_lib_table.h>
#include <board.h>
#include <fp_shape.h>
#include <fp_text.h>
#include <zone.h>
#include <footprint.h>
#include <pad.h>
#include <drc/drc_engine.h>
#include <drc/drc_item.h>
#include <drc/drc_test_provider.h>
#include <macros.h>
/*
Library parity test.
Errors generated:
- DRCE_LIB_FOOTPRINT_ISSUES
*/
class DRC_TEST_PROVIDER_LIBRARY_PARITY : public DRC_TEST_PROVIDER
{
public:
DRC_TEST_PROVIDER_LIBRARY_PARITY()
{
m_isRuleDriven = false;
}
virtual ~DRC_TEST_PROVIDER_LIBRARY_PARITY()
{
}
virtual bool Run() override;
virtual const wxString GetName() const override
{
return "library_parity";
};
virtual const wxString GetDescription() const override
{
return "Performs board footprint vs library integity checks";
}
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
};
#define TEST( a, b ) { if( a != b ) return true; }
#define TEST_PADS( a, b ) { if( padsNeedUpdate( a, b ) ) return true; }
#define TEST_SHAPES( a, b ) { if( shapesNeedUpdate( a, b ) ) return true; }
#define TEST_PRIMITIVES( a, b ) { if( primitivesNeedUpdate( a, b ) ) return true; }
#define TEST_ZONES( a, b ) { if( zonesNeedUpdate( a, b ) ) return true; }
#define TEST_MODELS( a, b ) { if( modelsNeedUpdate( a, b ) ) return true; }
bool primitivesNeedUpdate( const std::shared_ptr<PCB_SHAPE>& a,
const std::shared_ptr<PCB_SHAPE>& b )
{
TEST( a->GetShape(), b->GetShape() );
switch( a->GetShape() )
{
case SHAPE_T::SEGMENT:
case SHAPE_T::RECT:
case SHAPE_T::CIRCLE:
TEST( a->GetStart(), b->GetStart() );
TEST( a->GetEnd(), b->GetEnd() );
break;
case SHAPE_T::ARC:
TEST( a->GetStart(), b->GetStart() );
TEST( a->GetEnd(), b->GetEnd() );
TEST( a->GetCenter(), b->GetCenter() );
TEST( a->GetArcAngle(), b->GetArcAngle() );
break;
case SHAPE_T::BEZIER:
TEST( a->GetStart(), b->GetStart() );
TEST( a->GetEnd(), b->GetEnd() );
TEST( a->GetBezierC1(), b->GetBezierC1() );
TEST( a->GetBezierC2(), b->GetBezierC2() );
break;
case SHAPE_T::POLY:
TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices() );
for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ) );
break;
default:
UNIMPLEMENTED_FOR( a->SHAPE_T_asString() );
}
TEST( a->GetWidth(), b->GetWidth() );
TEST( a->IsFilled(), b->IsFilled() );
return false;
}
bool padsNeedUpdate( const PAD* a, const PAD* b )
{
TEST( a->GetPadToDieLength(), b->GetPadToDieLength() );
TEST( a->GetPos0(), b->GetPos0() );
TEST( a->GetNumber(), b->GetNumber() );
// These are assigned from the schematic and not from the library
// TEST( a->GetPinFunction(), b->GetPinFunction() );
// TEST( a->GetPinType(), b->GetPinType() );
TEST( a->GetRemoveUnconnected(), b->GetRemoveUnconnected() );
// NB: KeepTopBottom is undefined if RemoveUnconnected is NOT set.
if( a->GetRemoveUnconnected() )
TEST( a->GetKeepTopBottom(), b->GetKeepTopBottom() );
TEST( a->GetShape(), b->GetShape() );
TEST( a->GetLayerSet(), b->GetLayerSet() );
TEST( a->GetAttribute(), b->GetAttribute() );
TEST( a->GetProperty(), b->GetProperty() );
// The pad orientation, for historical reasons is the pad rotation + parent rotation.
TEST( NormalizeAnglePos( a->GetOrientation() - a->GetParent()->GetOrientation() ),
NormalizeAnglePos( b->GetOrientation() - b->GetParent()->GetOrientation() ) );
TEST( a->GetSize(), b->GetSize() );
TEST( a->GetDelta(), b->GetDelta() );
TEST( a->GetRoundRectCornerRadius(), b->GetRoundRectCornerRadius() );
TEST( a->GetRoundRectRadiusRatio(), b->GetRoundRectRadiusRatio() );
TEST( a->GetChamferRectRatio(), b->GetChamferRectRatio() );
TEST( a->GetChamferPositions(), b->GetChamferPositions() );
TEST( a->GetOffset(), b->GetOffset() );
TEST( a->GetDrillShape(), b->GetDrillShape() );
TEST( a->GetDrillSize(), b->GetDrillSize() );
TEST( a->GetLocalClearance(), b->GetLocalClearance() );
TEST( a->GetLocalSolderMaskMargin(), b->GetLocalSolderMaskMargin() );
TEST( a->GetLocalSolderPasteMargin(), b->GetLocalSolderPasteMargin() );
TEST( a->GetLocalSolderPasteMarginRatio(), b->GetLocalSolderPasteMarginRatio() );
TEST( a->GetZoneConnection(), b->GetZoneConnection() );
TEST( a->GetThermalGap(), b->GetThermalGap() );
TEST( a->GetThermalSpokeWidth(), b->GetThermalSpokeWidth() );
TEST( a->GetCustomShapeInZoneOpt(), b->GetCustomShapeInZoneOpt() );
TEST( a->GetPrimitives().size(), b->GetPrimitives().size() );
for( size_t ii = 0; ii < a->GetPrimitives().size(); ++ii )
TEST_PRIMITIVES( a->GetPrimitives()[ii], b->GetPrimitives()[ii] );
return false;
}
bool shapesNeedUpdate( const FP_SHAPE* a, const FP_SHAPE* b )
{
TEST( a->GetShape(), b->GetShape() );
switch( a->GetShape() )
{
case SHAPE_T::SEGMENT:
case SHAPE_T::RECT:
case SHAPE_T::CIRCLE:
TEST( a->GetStart0(), b->GetStart0() );
TEST( a->GetEnd0(), b->GetEnd0() );
break;
case SHAPE_T::ARC:
TEST( a->GetStart0(), b->GetStart0() );
TEST( a->GetEnd0(), b->GetEnd0() );
TEST( a->GetCenter0(), b->GetCenter0() );
TEST( a->GetArcAngle(), b->GetArcAngle() );
break;
case SHAPE_T::BEZIER:
TEST( a->GetStart0(), b->GetStart0() );
TEST( a->GetEnd0(), b->GetEnd0() );
TEST( a->GetBezierC1_0(), b->GetBezierC1_0() );
TEST( a->GetBezierC2_0(), b->GetBezierC2_0() );
break;
case SHAPE_T::POLY:
TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices() );
for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ) );
break;
default:
UNIMPLEMENTED_FOR( a->SHAPE_T_asString() );
}
TEST( a->GetWidth(), b->GetWidth() );
TEST( a->IsFilled(), b->IsFilled() );
TEST( a->GetLayer(), b->GetLayer() );
return false;
}
bool textsNeedUpdate( const FP_TEXT* a, const FP_TEXT* b )
{
TEST( a->GetLayer(), b->GetLayer() );
TEST( a->IsKeepUpright(), b->IsKeepUpright() );
TEST( a->GetText(), b->GetText() );
TEST( a->GetTextThickness(), b->GetTextThickness() );
TEST( a->GetTextAngle(), b->GetTextAngle() );
TEST( a->IsItalic(), b->IsItalic() );
TEST( a->IsBold(), b->IsBold() );
TEST( a->IsVisible(), b->IsVisible() );
TEST( a->IsMirrored(), b->IsMirrored() );
TEST( a->GetHorizJustify(), b->GetHorizJustify() );
TEST( a->GetVertJustify(), b->GetVertJustify() );
TEST( a->GetTextSize(), b->GetTextSize() );
TEST( a->GetPos0(), b->GetPos0() );
return false;
}
bool zonesNeedUpdate( const FP_ZONE* a, const FP_ZONE* b )
{
TEST( a->GetCornerSmoothingType(), b->GetCornerSmoothingType() );
TEST( a->GetCornerRadius(), b->GetCornerRadius() );
TEST( a->GetZoneName(), b->GetZoneName() );
TEST( a->GetPriority(), b->GetPriority() );
TEST( a->GetIsRuleArea(), b->GetIsRuleArea() );
TEST( a->GetDoNotAllowCopperPour(), b->GetDoNotAllowCopperPour() );
TEST( a->GetDoNotAllowFootprints(), b->GetDoNotAllowFootprints() );
TEST( a->GetDoNotAllowPads(), b->GetDoNotAllowPads() );
TEST( a->GetDoNotAllowTracks(), b->GetDoNotAllowTracks() );
TEST( a->GetDoNotAllowVias(), b->GetDoNotAllowVias() );
TEST( a->GetLayerSet(), b->GetLayerSet() );
TEST( a->GetPadConnection(), b->GetPadConnection() );
TEST( a->GetLocalClearance(), b->GetLocalClearance() );
TEST( a->GetThermalReliefGap(), b->GetThermalReliefGap() );
TEST( a->GetThermalReliefSpokeWidth(), b->GetThermalReliefSpokeWidth() );
TEST( a->GetMinThickness(), b->GetMinThickness() );
TEST( a->GetFillVersion(), b->GetFillVersion() );
TEST( a->GetIslandRemovalMode(), b->GetIslandRemovalMode() );
TEST( a->GetMinIslandArea(), b->GetMinIslandArea() );
TEST( a->GetFillMode(), b->GetFillMode() );
TEST( a->GetHatchThickness(), b->GetHatchThickness() );
TEST( a->GetHatchGap(), b->GetHatchGap() );
TEST( a->GetHatchOrientation(), b->GetHatchOrientation() );
TEST( a->GetHatchSmoothingLevel(), b->GetHatchSmoothingLevel() );
TEST( a->GetHatchSmoothingValue(), b->GetHatchSmoothingValue() );
TEST( a->GetHatchBorderAlgorithm(), b->GetHatchBorderAlgorithm() );
TEST( a->GetHatchHoleMinArea(), b->GetHatchHoleMinArea() );
TEST( a->Outline()->TotalVertices(), b->Outline()->TotalVertices() );
for( int ii = 0; ii < a->Outline()->TotalVertices(); ++ii )
{
TEST( a->Outline()->CVertex( ii ) - a->GetParent()->GetPosition(),
b->Outline()->CVertex( ii ) - b->GetParent()->GetPosition() );
}
return false;
}
bool modelsNeedUpdate( const FP_3DMODEL& a, const FP_3DMODEL& b )
{
#define EPSILON 0.000001
#define TEST_V3D( a, b ) { if( abs( a.x - b.x ) > EPSILON \
|| abs( a.y - b.y ) > EPSILON \
|| abs( a.z - b.z ) > EPSILON ) \
return true; }
TEST_V3D( a.m_Scale, b.m_Scale );
TEST_V3D( a.m_Rotation, b.m_Rotation );
TEST_V3D( a.m_Offset, b.m_Offset );
TEST( a.m_Opacity, b.m_Opacity );
TEST( a.m_Filename, b.m_Filename );
TEST( a.m_Show, b.m_Show );
return false;
}
bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint )
{
TEST( GetDescription(), aLibFootprint->GetDescription() );
TEST( GetKeywords(), aLibFootprint->GetKeywords() );
TEST( GetAttributes(), aLibFootprint->GetAttributes() );
TEST( GetPlacementCost90(), aLibFootprint->GetPlacementCost90() );
TEST( GetPlacementCost180(), aLibFootprint->GetPlacementCost180() );
TEST( GetLocalClearance(), aLibFootprint->GetLocalClearance() );
TEST( GetLocalSolderMaskMargin(), aLibFootprint->GetLocalSolderMaskMargin() );
TEST( GetLocalSolderPasteMargin(), aLibFootprint->GetLocalSolderPasteMargin() );
TEST( GetLocalSolderPasteMarginRatio(), aLibFootprint->GetLocalSolderPasteMarginRatio() );
TEST( GetZoneConnection(), aLibFootprint->GetZoneConnection() );
// Text items are really problematic. We don't want to test the reference, but after that
// it gets messy. What about the value? Depends on whether or not it's a singleton part.
// And what about other texts? They might be added only to instances on the board, or even
// changed for instances on the board. Or they might want to be tested for equality.
// Currently we punt and ignore all the text items.
// Drawings and pads are also somewhat problematic as there's no gaurantee that they'll be
// in the same order in the two footprints. Rather than builds some sophisticated hashing
// algorithm we use the footprint sorting functions to attempt to sort them in the same order.
std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> aShapes;
std::copy_if( GraphicalItems().begin(), GraphicalItems().end(),
std::inserter( aShapes, aShapes.begin() ),
[]( BOARD_ITEM* item )
{
return item->Type() == PCB_FP_SHAPE_T;
} );
std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> bShapes;
std::copy_if( aLibFootprint->GraphicalItems().begin(), aLibFootprint->GraphicalItems().end(),
std::inserter( bShapes, bShapes.begin() ),
[]( BOARD_ITEM* item )
{
return item->Type() == PCB_FP_SHAPE_T;
} );
std::set<PAD*, FOOTPRINT::cmp_pads> aPads( Pads().begin(), Pads().end() );
std::set<PAD*, FOOTPRINT::cmp_pads> bPads( aLibFootprint->Pads().begin(), aLibFootprint->Pads().end() );
std::set<FP_ZONE*, FOOTPRINT::cmp_zones> aZones( Zones().begin(), Zones().end() );
std::set<FP_ZONE*, FOOTPRINT::cmp_zones> bZones( aLibFootprint->Zones().begin(), aLibFootprint->Zones().end() );
TEST( aPads.size(), bPads.size() );
TEST( aZones.size(), bZones.size() );
TEST( aShapes.size(), bShapes.size() );
for( auto aIt = aPads.begin(), bIt = bPads.begin(); aIt != aPads.end(); aIt++, bIt++ )
TEST_PADS( *aIt, *bIt );
for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
{
if( ( *aIt )->Type() == PCB_FP_SHAPE_T )
TEST_SHAPES( static_cast<FP_SHAPE*>( *aIt ), static_cast<FP_SHAPE*>( *bIt ) );
}
for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
TEST_ZONES( *aIt, *bIt );
TEST( Models().size(), aLibFootprint->Models().size() );
for( size_t ii = 0; ii < Models().size(); ++ii )
TEST_MODELS( Models()[ii], aLibFootprint->Models()[ii] );
return false;
}
bool DRC_TEST_PROVIDER_LIBRARY_PARITY::Run()
{
BOARD* board = m_drcEngine->GetBoard();
PROJECT* project = board->GetProject();
if( !project )
{
reportAux( _( "No project loaded, skipping library parity tests." ) );
return true; // Continue with other tests
}
if( !reportPhase( _( "Loading footprint library table..." ) ) )
return false; // DRC cancelled
std::map<LIB_ID, std::shared_ptr<FOOTPRINT>> libFootprintCache;
FP_LIB_TABLE* libTable = project->PcbFootprintLibs();
wxString msg;
int ii = 0;
const int delta = 50; // Number of tests between calls to progress bar
if( !reportPhase( _( "Checking board footprints against library..." ) ) )
return false;
for( FOOTPRINT* footprint : board->Footprints() )
{
if( m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
return true; // Continue with other tests
if( !reportProgress( ii++, board->Footprints().size(), delta ) )
return false; // DRC cancelled
LIB_ID fpID = footprint->GetFPID();
wxString libName = fpID.GetLibNickname();
wxString fpName = fpID.GetLibItemName();
const LIB_TABLE_ROW* libTableRow = nullptr;
try
{
libTableRow = libTable->FindRow( libName );
}
catch( const IO_ERROR& )
{
}
if( !libTableRow )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
msg.Printf( _( "The current configuration does not include the library '%s'." ),
libName );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( footprint );
reportViolation( drcItem, footprint->GetCenter() );
continue;
}
else if( !libTable->HasLibrary( libName, true ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
msg.Printf( _( "The library '%s' is not enabled in the current configuration." ),
libName );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( footprint );
reportViolation( drcItem, footprint->GetCenter() );
continue;
}
auto cacheIt = libFootprintCache.find( fpID );
std::shared_ptr<FOOTPRINT> libFootprint;
if( cacheIt != libFootprintCache.end() )
{
libFootprint = cacheIt->second;
}
else
{
try
{
libFootprint.reset( libTable->FootprintLoad( libName, fpName, true ) );
if( libFootprint )
libFootprintCache[ fpID ] = libFootprint;
}
catch( const IO_ERROR& )
{
}
}
if( !libFootprint )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
msg.Printf( "Footprint '%s' not found in library '%s'.",
fpName,
libName );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( footprint );
reportViolation( drcItem, footprint->GetCenter() );
}
else if( footprint->FootprintNeedsUpdate( libFootprint.get() ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
msg.Printf( "Footprint '%s' does not match copy in library '%s'.",
fpName,
libName );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( footprint );
reportViolation( drcItem, footprint->GetCenter() );
}
}
return true;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_LIBRARY_PARITY::GetConstraintTypes() const
{
return {};
}
namespace detail
{
static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_LIBRARY_PARITY> dummy;
}

View File

@ -66,11 +66,6 @@ public:
return "Tests matched track lengths."; return "Tests matched track lengths.";
} }
virtual int GetNumPhases() const override
{
return 1;
}
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
DRC_LENGTH_REPORT BuildLengthReport() const; DRC_LENGTH_REPORT BuildLengthReport() const;

View File

@ -70,8 +70,6 @@ public:
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
void testOutline(); void testOutline();
void testDisabledLayers(); void testDisabledLayers();
@ -284,12 +282,6 @@ bool DRC_TEST_PROVIDER_MISC::Run()
} }
int DRC_TEST_PROVIDER_MISC::GetNumPhases() const
{
return 3;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_MISC::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_MISC::GetConstraintTypes() const
{ {
return {}; return {};

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2004-2020 KiCad Developers. * Copyright (C) 2004-2021 KiCad Developers.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -32,7 +32,7 @@
#include <netlist_reader/pcb_netlist.h> #include <netlist_reader/pcb_netlist.h>
/* /*
Layout-versus-schematic (LVS) test. Schematic parity test.
Errors generated: Errors generated:
- DRCE_MISSING_FOOTPRINT - DRCE_MISSING_FOOTPRINT
@ -44,15 +44,15 @@
- cross-check PCB fields against SCH fields - cross-check PCB fields against SCH fields
*/ */
class DRC_TEST_PROVIDER_LVS : public DRC_TEST_PROVIDER class DRC_TEST_PROVIDER_SCHEMATIC_PARITY : public DRC_TEST_PROVIDER
{ {
public: public:
DRC_TEST_PROVIDER_LVS() DRC_TEST_PROVIDER_SCHEMATIC_PARITY()
{ {
m_isRuleDriven = false; m_isRuleDriven = false;
} }
virtual ~DRC_TEST_PROVIDER_LVS() virtual ~DRC_TEST_PROVIDER_SCHEMATIC_PARITY()
{ {
} }
@ -60,7 +60,7 @@ public:
virtual const wxString GetName() const override virtual const wxString GetName() const override
{ {
return "LVS"; return "schematic_parity";
}; };
virtual const wxString GetDescription() const override virtual const wxString GetDescription() const override
@ -70,14 +70,12 @@ public:
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
private: private:
void testFootprints( NETLIST& aNetlist ); void testNetlist( NETLIST& aNetlist );
}; };
void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist ) void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist )
{ {
BOARD* board = m_drcEngine->GetBoard(); BOARD* board = m_drcEngine->GetBoard();
@ -211,7 +209,7 @@ void DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist )
} }
bool DRC_TEST_PROVIDER_LVS::Run() bool DRC_TEST_PROVIDER_SCHEMATIC_PARITY::Run()
{ {
if( m_drcEngine->GetTestFootprints() ) if( m_drcEngine->GetTestFootprints() )
{ {
@ -222,11 +220,11 @@ bool DRC_TEST_PROVIDER_LVS::Run()
if( !netlist ) if( !netlist )
{ {
reportAux( _("No netlist provided, skipping LVS.") ); reportAux( _( "No netlist provided, skipping schematic parity tests." ) );
return true; return true;
} }
testFootprints( *netlist ); testNetlist( *netlist );
reportRuleStatistics(); reportRuleStatistics();
} }
@ -235,13 +233,7 @@ bool DRC_TEST_PROVIDER_LVS::Run()
} }
int DRC_TEST_PROVIDER_LVS::GetNumPhases() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_SCHEMATIC_PARITY::GetConstraintTypes() const
{
return m_drcEngine->GetTestFootprints() ? 1 : 0;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
{ {
return {}; return {};
} }
@ -249,5 +241,5 @@ std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
namespace detail namespace detail
{ {
static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_LVS> dummy; static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_SCHEMATIC_PARITY> dummy;
} }

View File

@ -68,11 +68,6 @@ public:
return "Tests for overlapping silkscreen features."; return "Tests for overlapping silkscreen features.";
} }
virtual int GetNumPhases() const override
{
return 1;
}
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
private: private:

View File

@ -65,11 +65,6 @@ public:
return "Tests for silkscreen being clipped by solder mask"; return "Tests for silkscreen being clipped by solder mask";
} }
virtual int GetNumPhases() const override
{
return 1;
}
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
private: private:

View File

@ -59,8 +59,6 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -171,12 +169,6 @@ bool DRC_TEST_PROVIDER_TRACK_WIDTH::Run()
} }
int DRC_TEST_PROVIDER_TRACK_WIDTH::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_TRACK_WIDTH::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_TRACK_WIDTH::GetConstraintTypes() const
{ {
return { TRACK_WIDTH_CONSTRAINT }; return { TRACK_WIDTH_CONSTRAINT };

View File

@ -58,8 +58,6 @@ public:
} }
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override; virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
int GetNumPhases() const override;
}; };
@ -160,12 +158,6 @@ bool DRC_TEST_PROVIDER_VIA_DIAMETER::Run()
} }
int DRC_TEST_PROVIDER_VIA_DIAMETER::GetNumPhases() const
{
return 1;
}
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_VIA_DIAMETER::GetConstraintTypes() const std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_VIA_DIAMETER::GetConstraintTypes() const
{ {
return { VIA_DIAMETER_CONSTRAINT }; return { VIA_DIAMETER_CONSTRAINT };

View File

@ -2168,28 +2168,48 @@ bool FOOTPRINT::HasThroughHolePads() const
} }
bool FOOTPRINT::cmp_drawings::operator()( const BOARD_ITEM* aFirst, #define TEST( a, b ) { if( a != b ) return a < b; }
const BOARD_ITEM* aSecond ) const #define TEST_PT( a, b ) { if( a.x != b.x ) return a.x < b.x; if( a.y != b.y ) return a.y < b.y; }
bool FOOTPRINT::cmp_drawings::operator()( const BOARD_ITEM* itemA, const BOARD_ITEM* itemB ) const
{ {
if( aFirst->Type() != aSecond->Type() ) TEST( itemA->Type(), itemB->Type() );
return aFirst->Type() < aSecond->Type(); TEST( itemA->GetLayer(), itemB->GetLayer() );
if( aFirst->GetLayer() != aSecond->GetLayer() ) if( itemA->Type() == PCB_FP_SHAPE_T )
return aFirst->GetLayer() < aSecond->GetLayer();
if( aFirst->Type() == PCB_FP_SHAPE_T )
{ {
const FP_SHAPE* dwgA = static_cast<const FP_SHAPE*>( aFirst ); const FP_SHAPE* dwgA = static_cast<const FP_SHAPE*>( itemA );
const FP_SHAPE* dwgB = static_cast<const FP_SHAPE*>( aSecond ); const FP_SHAPE* dwgB = static_cast<const FP_SHAPE*>( itemB );
if( dwgA->GetShape() != dwgB->GetShape() ) TEST( dwgA->GetShape(), dwgB->GetShape() );
return dwgA->GetShape() < dwgB->GetShape();
TEST_PT( dwgA->GetStart0(), dwgB->GetStart0() );
TEST_PT( dwgA->GetEnd0(), dwgB->GetEnd0() );
if( dwgA->GetShape() == SHAPE_T::ARC )
{
TEST_PT( dwgA->GetCenter0(), dwgB->GetCenter0() );
}
else if( dwgA->GetShape() == SHAPE_T::BEZIER )
{
TEST_PT( dwgA->GetBezierC1_0(), dwgB->GetBezierC1_0() );
TEST_PT( dwgA->GetBezierC2_0(), dwgB->GetBezierC2_0() );
}
else if( dwgA->GetShape() == SHAPE_T::POLY )
{
TEST( dwgA->GetPolyShape().TotalVertices(), dwgB->GetPolyShape().TotalVertices() );
for( int ii = 0; ii < dwgA->GetPolyShape().TotalVertices(); ++ii )
TEST_PT( dwgA->GetPolyShape().CVertex( ii ), dwgB->GetPolyShape().CVertex( ii ) );
} }
if( aFirst->m_Uuid != aSecond->m_Uuid ) // shopuld be always the case foer valid boards TEST( dwgA->GetWidth(), dwgB->GetWidth() );
return aFirst->m_Uuid < aSecond->m_Uuid; }
return aFirst < aSecond; TEST( itemA->m_Uuid, itemB->m_Uuid ); // should be always the case for valid boards
return itemA < itemB;
} }
@ -2198,13 +2218,35 @@ bool FOOTPRINT::cmp_pads::operator()( const PAD* aFirst, const PAD* aSecond ) co
if( aFirst->GetNumber() != aSecond->GetNumber() ) if( aFirst->GetNumber() != aSecond->GetNumber() )
return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0; return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0;
if( aFirst->m_Uuid != aSecond->m_Uuid ) // shopuld be always the case foer valid boards TEST_PT( aFirst->GetPos0(), aSecond->GetPos0() );
return aFirst->m_Uuid < aSecond->m_Uuid; TEST_PT( aFirst->GetSize(), aSecond->GetSize() );
TEST( aFirst->GetShape(), aSecond->GetShape() );
TEST( aFirst->m_Uuid, aSecond->m_Uuid ); // should be always the case for valid boards
return aFirst < aSecond; return aFirst < aSecond;
} }
bool FOOTPRINT::cmp_zones::operator()( const FP_ZONE* aFirst, const FP_ZONE* aSecond ) const
{
TEST( aFirst->GetPriority(), aSecond->GetPriority() );
TEST( aFirst->GetLayerSet().Seq(), aSecond->GetLayerSet().Seq() );
TEST( aFirst->Outline()->TotalVertices(), aSecond->Outline()->TotalVertices() );
for( int ii = 0; ii < aFirst->Outline()->TotalVertices(); ++ii )
TEST_PT( aFirst->Outline()->CVertex( ii ), aSecond->Outline()->CVertex( ii ) );
TEST( aFirst->m_Uuid, aSecond->m_Uuid ); // should be always the case for valid boards
return aFirst < aSecond;
}
#undef TEST
void FOOTPRINT::TransformPadsWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, void FOOTPRINT::TransformPadsWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
PCB_LAYER_ID aLayer, int aClearance, PCB_LAYER_ID aLayer, int aClearance,
int aMaxError, ERROR_LOC aErrorLoc, int aMaxError, ERROR_LOC aErrorLoc,

View File

@ -180,8 +180,8 @@ public:
bool HasThroughHolePads() const; bool HasThroughHolePads() const;
std::list<FP_3DMODEL>& Models() { return m_3D_Drawings; } std::vector<FP_3DMODEL>& Models() { return m_3D_Drawings; }
const std::list<FP_3DMODEL>& Models() const { return m_3D_Drawings; } const std::vector<FP_3DMODEL>& Models() const { return m_3D_Drawings; }
void SetPosition( const wxPoint& aPos ) override; void SetPosition( const wxPoint& aPos ) override;
wxPoint GetPosition() const override { return m_pos; } wxPoint GetPosition() const override { return m_pos; }
@ -655,6 +655,11 @@ public:
*/ */
static const wxChar* StringLibNameInvalidChars( bool aUserReadable ); static const wxChar* StringLibNameInvalidChars( bool aUserReadable );
/**
* Return true if a board footprint differs from the library version.
*/
bool FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint );
/** /**
* Take ownership of caller's heap allocated aInitialComments block. * Take ownership of caller's heap allocated aInitialComments block.
* *
@ -723,6 +728,11 @@ public:
bool operator()( const PAD* aFirst, const PAD* aSecond ) const; bool operator()( const PAD* aFirst, const PAD* aSecond ) const;
}; };
struct cmp_zones
{
bool operator()( const FP_ZONE* aFirst, const FP_ZONE* aSecond ) const;
};
#if defined(DEBUG) #if defined(DEBUG)
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); } virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
@ -778,7 +788,7 @@ private:
int m_rot90Cost; // Horizontal automatic placement cost ( 0..10 ). int m_rot90Cost; // Horizontal automatic placement cost ( 0..10 ).
int m_rot180Cost; // Vertical automatic placement cost ( 0..10 ). int m_rot180Cost; // Vertical automatic placement cost ( 0..10 ).
std::list<FP_3DMODEL> m_3D_Drawings; // Linked list of 3D models. std::vector<FP_3DMODEL> m_3D_Drawings; // 3D models.
std::map<wxString, wxString> m_properties; std::map<wxString, wxString> m_properties;
wxArrayString* m_initial_comments; // s-expression comments in the footprint, wxArrayString* m_initial_comments; // s-expression comments in the footprint,
// lazily allocated only if needed for speed // lazily allocated only if needed for speed

View File

@ -1225,7 +1225,7 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> sorted_drawings( std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> sorted_drawings(
aFootprint->GraphicalItems().begin(), aFootprint->GraphicalItems().begin(),
aFootprint->GraphicalItems().end() ); aFootprint->GraphicalItems().end() );
std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_zones( aFootprint->Zones().begin(), std::set<FP_ZONE*, FOOTPRINT::cmp_zones> sorted_zones( aFootprint->Zones().begin(),
aFootprint->Zones().end() ); aFootprint->Zones().end() );
std::set<BOARD_ITEM*, PCB_GROUP::ptr_cmp> sorted_groups( aFootprint->Groups().begin(), std::set<BOARD_ITEM*, PCB_GROUP::ptr_cmp> sorted_groups( aFootprint->Groups().begin(),
aFootprint->Groups().end() ); aFootprint->Groups().end() );

View File

@ -70,6 +70,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -70,6 +70,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -75,6 +75,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -75,6 +75,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -76,6 +76,7 @@
"items_not_allowed": "error", "items_not_allowed": "error",
"keepout": "error", "keepout": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_too_small": "error", "microvia_drill_too_small": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -76,6 +76,7 @@
"items_not_allowed": "error", "items_not_allowed": "error",
"keepout": "error", "keepout": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_too_small": "error", "microvia_drill_too_small": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -75,6 +75,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -75,6 +75,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -75,6 +75,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -75,6 +75,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -75,6 +75,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -48,13 +48,20 @@
"min_clearance": 0.508 "min_clearance": 0.508
} }
}, },
"diff_pair_dimensions": [], "diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [], "drc_exclusions": [],
"meta": { "meta": {
"version": 2 "version": 2
}, },
"rule_severities": { "rule_severities": {
"annular_width": "error", "annular_width": "error",
"aperture_clearance": "error",
"clearance": "error", "clearance": "error",
"copper_edge_clearance": "error", "copper_edge_clearance": "error",
"courtyards_overlap": "error", "courtyards_overlap": "error",
@ -69,6 +76,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",
@ -81,6 +89,9 @@
"silk_over_copper": "warning", "silk_over_copper": "warning",
"silk_overlap": "warning", "silk_overlap": "warning",
"skew_out_of_range": "error", "skew_out_of_range": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"too_many_vias": "error", "too_many_vias": "error",
"track_dangling": "warning", "track_dangling": "warning",
"track_width": "error", "track_width": "error",
@ -95,21 +106,32 @@
"allow_blind_buried_vias": false, "allow_blind_buried_vias": false,
"allow_microvias": false, "allow_microvias": false,
"max_error": 0.005, "max_error": 0.005,
"min_aperture_clearance": 0.049999999999999996,
"min_clearance": 0.0, "min_clearance": 0.0,
"min_copper_edge_clearance": 0.01, "min_copper_edge_clearance": 0.01,
"min_hole_clearance": 0.0, "min_hole_clearance": 0.0,
"min_hole_to_hole": 0.25, "min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998, "min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999, "min_microvia_drill": 0.09999999999999999,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0, "min_silk_clearance": 0.0,
"min_text_height": 0.7999999999999999,
"min_text_thickness": 0.12,
"min_through_hole_diameter": 0.3, "min_through_hole_diameter": 0.3,
"min_track_width": 0.19999999999999998, "min_track_width": 0.19999999999999998,
"min_via_annular_width": 0.049999999999999996, "min_via_annular_width": 0.049999999999999996,
"min_via_diameter": 0.39999999999999997, "min_via_diameter": 0.39999999999999997,
"use_height_for_length_calcs": true "use_height_for_length_calcs": true
}, },
"track_widths": [], "track_widths": [
"via_dimensions": [], 0.0
],
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
}
],
"zones_allow_external_fillets": false, "zones_allow_external_fillets": false,
"zones_use_no_outline": true "zones_use_no_outline": true
}, },

View File

@ -83,6 +83,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -75,6 +75,7 @@
"item_on_disabled_layer": "error", "item_on_disabled_layer": "error",
"items_not_allowed": "error", "items_not_allowed": "error",
"length_out_of_range": "error", "length_out_of_range": "error",
"lib_footprint_issues": "ignore",
"malformed_courtyard": "error", "malformed_courtyard": "error",
"microvia_drill_out_of_range": "error", "microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",

View File

@ -44,7 +44,7 @@ add_executable( drc_proto
../../pcbnew/drc/drc_test_provider_connectivity.cpp ../../pcbnew/drc/drc_test_provider_connectivity.cpp
../../pcbnew/drc/drc_test_provider_courtyard_clearance.cpp ../../pcbnew/drc/drc_test_provider_courtyard_clearance.cpp
../../pcbnew/drc/drc_test_provider_via_diameter.cpp ../../pcbnew/drc/drc_test_provider_via_diameter.cpp
../../pcbnew/drc/drc_test_provider_lvs.cpp ../../pcbnew/drc/drc_test_provider_schematic_parity.cpp
../../pcbnew/drc/drc_test_provider_misc.cpp ../../pcbnew/drc/drc_test_provider_misc.cpp
../../pcbnew/drc/drc_test_provider_silk_to_mask.cpp ../../pcbnew/drc/drc_test_provider_silk_to_mask.cpp
../../pcbnew/drc/drc_test_provider_silk_clearance.cpp ../../pcbnew/drc/drc_test_provider_silk_clearance.cpp

View File

@ -43,7 +43,7 @@ add_executable( test_pns
../../pcbnew/drc/drc_test_provider_connectivity.cpp ../../pcbnew/drc/drc_test_provider_connectivity.cpp
../../pcbnew/drc/drc_test_provider_courtyard_clearance.cpp ../../pcbnew/drc/drc_test_provider_courtyard_clearance.cpp
../../pcbnew/drc/drc_test_provider_via_diameter.cpp ../../pcbnew/drc/drc_test_provider_via_diameter.cpp
../../pcbnew/drc/drc_test_provider_lvs.cpp ../../pcbnew/drc/drc_test_provider_schematic_parity.cpp
../../pcbnew/drc/drc_test_provider_misc.cpp ../../pcbnew/drc/drc_test_provider_misc.cpp
../../pcbnew/drc/drc_test_provider_silk_to_mask.cpp ../../pcbnew/drc/drc_test_provider_silk_to_mask.cpp
../../pcbnew/drc/drc_test_provider_silk_clearance.cpp ../../pcbnew/drc/drc_test_provider_silk_clearance.cpp