Add footprint library checking to DRC.
Fixes https://gitlab.com/kicad/code/kicad/issues/6821
This commit is contained in:
parent
c4432e5d03
commit
0a609dd48d
|
@ -238,7 +238,8 @@ set( PCBNEW_DRC_SRCS
|
|||
drc/drc_test_provider_edge_clearance.cpp
|
||||
drc/drc_test_provider_hole_to_hole.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_track_width.cpp
|
||||
drc/drc_test_provider_via_diameter.cpp
|
||||
|
|
|
@ -508,7 +508,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataFromWindow()
|
|||
|
||||
// Copy the models from the panel to the footprint
|
||||
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->insert( fpList->end(), panelList.begin(), panelList.end() );
|
||||
|
||||
|
|
|
@ -443,7 +443,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
|
|||
|
||||
// Copy the models from the panel to the footprint
|
||||
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->insert( fpList->end(), panelList.begin(), panelList.end() );
|
||||
|
||||
|
|
|
@ -170,6 +170,10 @@ DRC_ITEM DRC_ITEM::netConflict( DRCE_NET_CONFLICT,
|
|||
_( "Pad net doesn't match schematic" ),
|
||||
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,
|
||||
_( "Unresolved text 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_NET_CONFLICT: return std::make_shared<DRC_ITEM>( netConflict );
|
||||
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_OVERLAPPING_SILK: return std::make_shared<DRC_ITEM>( silkOverlaps );
|
||||
case DRCE_SILK_MASK_CLEARANCE: return std::make_shared<DRC_ITEM>( silkMaskClearance );
|
||||
|
|
|
@ -68,6 +68,7 @@ enum PCB_DRC_CODE {
|
|||
DRCE_NET_CONFLICT, // pad net doesn't match netlist
|
||||
|
||||
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_UNRESOLVED_VARIABLE,
|
||||
|
@ -164,6 +165,7 @@ private:
|
|||
static DRC_ITEM missingFootprint;
|
||||
static DRC_ITEM extraFootprint;
|
||||
static DRC_ITEM netConflict;
|
||||
static DRC_ITEM libFootprintIssues;
|
||||
static DRC_ITEM unresolvedVariable;
|
||||
static DRC_ITEM silkMaskClearance;
|
||||
static DRC_ITEM silkOverlaps;
|
||||
|
|
|
@ -91,13 +91,6 @@ public:
|
|||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const = 0;
|
||||
|
||||
virtual int GetNumPhases() const = 0;
|
||||
|
||||
virtual bool IsRuleDriven() const
|
||||
{
|
||||
return m_isRuleDriven;
|
||||
}
|
||||
|
||||
bool IsEnabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
|
|
|
@ -63,8 +63,6 @@ public:
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
return { ANNULAR_WIDTH_CONSTRAINT };
|
||||
|
|
|
@ -65,8 +65,6 @@ public:
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
return {};
|
||||
|
|
|
@ -80,8 +80,6 @@ public:
|
|||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
int GetNumPhases() const override;
|
||||
|
||||
private:
|
||||
bool testTrackAgainstItem( PCB_TRACK* track, SHAPE* trackShape, PCB_LAYER_ID layer,
|
||||
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
|
||||
{
|
||||
return { CLEARANCE_CONSTRAINT, HOLE_CLEARANCE_CONSTRAINT };
|
||||
|
|
|
@ -69,8 +69,6 @@ public:
|
|||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
int GetNumPhases() const override;
|
||||
|
||||
private:
|
||||
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
|
||||
{
|
||||
return { COURTYARD_CLEARANCE_CONSTRAINT };
|
||||
|
|
|
@ -74,11 +74,6 @@ public:
|
|||
return "Tests differential pair coupling";
|
||||
}
|
||||
|
||||
virtual int GetNumPhases() const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -60,8 +60,6 @@ public:
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
return { DISALLOW_CONSTRAINT };
|
||||
|
|
|
@ -70,8 +70,6 @@ public:
|
|||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
int GetNumPhases() const override;
|
||||
|
||||
private:
|
||||
bool testAgainstEdge( BOARD_ITEM* item, SHAPE* itemShape, BOARD_ITEM* other,
|
||||
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
|
||||
{
|
||||
return { EDGE_CLEARANCE_CONSTRAINT, SILK_CLEARANCE_CONSTRAINT };
|
||||
|
|
|
@ -62,8 +62,6 @@ public:
|
|||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
int GetNumPhases() const override;
|
||||
|
||||
private:
|
||||
void checkVia( PCB_VIA* via, bool aExceedMicro, bool aExceedStd );
|
||||
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
|
||||
{
|
||||
return { HOLE_SIZE_CONSTRAINT };
|
||||
|
|
|
@ -70,8 +70,6 @@ public:
|
|||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
int GetNumPhases() const override;
|
||||
|
||||
private:
|
||||
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
|
||||
{
|
||||
return { HOLE_TO_HOLE_CONSTRAINT };
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -66,11 +66,6 @@ public:
|
|||
return "Tests matched track lengths.";
|
||||
}
|
||||
|
||||
virtual int GetNumPhases() const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
DRC_LENGTH_REPORT BuildLengthReport() const;
|
||||
|
|
|
@ -70,8 +70,6 @@ public:
|
|||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
int GetNumPhases() const override;
|
||||
|
||||
private:
|
||||
void testOutline();
|
||||
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
|
||||
{
|
||||
return {};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -32,7 +32,7 @@
|
|||
#include <netlist_reader/pcb_netlist.h>
|
||||
|
||||
/*
|
||||
Layout-versus-schematic (LVS) test.
|
||||
Schematic parity test.
|
||||
|
||||
Errors generated:
|
||||
- DRCE_MISSING_FOOTPRINT
|
||||
|
@ -44,15 +44,15 @@
|
|||
- 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:
|
||||
DRC_TEST_PROVIDER_LVS()
|
||||
DRC_TEST_PROVIDER_SCHEMATIC_PARITY()
|
||||
{
|
||||
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
|
||||
{
|
||||
return "LVS";
|
||||
return "schematic_parity";
|
||||
};
|
||||
|
||||
virtual const wxString GetDescription() const override
|
||||
|
@ -70,14 +70,12 @@ public:
|
|||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
int GetNumPhases() const override;
|
||||
|
||||
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();
|
||||
|
||||
|
@ -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() )
|
||||
{
|
||||
|
@ -222,11 +220,11 @@ bool DRC_TEST_PROVIDER_LVS::Run()
|
|||
|
||||
if( !netlist )
|
||||
{
|
||||
reportAux( _("No netlist provided, skipping LVS.") );
|
||||
reportAux( _( "No netlist provided, skipping schematic parity tests." ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
testFootprints( *netlist );
|
||||
testNetlist( *netlist );
|
||||
|
||||
reportRuleStatistics();
|
||||
}
|
||||
|
@ -235,13 +233,7 @@ bool DRC_TEST_PROVIDER_LVS::Run()
|
|||
}
|
||||
|
||||
|
||||
int DRC_TEST_PROVIDER_LVS::GetNumPhases() const
|
||||
{
|
||||
return m_drcEngine->GetTestFootprints() ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
|
||||
std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_SCHEMATIC_PARITY::GetConstraintTypes() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
@ -249,5 +241,5 @@ std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
|
|||
|
||||
namespace detail
|
||||
{
|
||||
static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_LVS> dummy;
|
||||
static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_SCHEMATIC_PARITY> dummy;
|
||||
}
|
|
@ -68,11 +68,6 @@ public:
|
|||
return "Tests for overlapping silkscreen features.";
|
||||
}
|
||||
|
||||
virtual int GetNumPhases() const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -65,11 +65,6 @@ public:
|
|||
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;
|
||||
|
||||
private:
|
||||
|
|
|
@ -59,8 +59,6 @@ public:
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
return { TRACK_WIDTH_CONSTRAINT };
|
||||
|
|
|
@ -58,8 +58,6 @@ public:
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
return { VIA_DIAMETER_CONSTRAINT };
|
||||
|
|
|
@ -2168,28 +2168,48 @@ bool FOOTPRINT::HasThroughHolePads() const
|
|||
}
|
||||
|
||||
|
||||
bool FOOTPRINT::cmp_drawings::operator()( const BOARD_ITEM* aFirst,
|
||||
const BOARD_ITEM* aSecond ) const
|
||||
#define TEST( a, b ) { if( a != b ) return a < b; }
|
||||
#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() )
|
||||
return aFirst->Type() < aSecond->Type();
|
||||
TEST( itemA->Type(), itemB->Type() );
|
||||
TEST( itemA->GetLayer(), itemB->GetLayer() );
|
||||
|
||||
if( aFirst->GetLayer() != aSecond->GetLayer() )
|
||||
return aFirst->GetLayer() < aSecond->GetLayer();
|
||||
|
||||
if( aFirst->Type() == PCB_FP_SHAPE_T )
|
||||
if( itemA->Type() == PCB_FP_SHAPE_T )
|
||||
{
|
||||
const FP_SHAPE* dwgA = static_cast<const FP_SHAPE*>( aFirst );
|
||||
const FP_SHAPE* dwgB = static_cast<const FP_SHAPE*>( aSecond );
|
||||
const FP_SHAPE* dwgA = static_cast<const FP_SHAPE*>( itemA );
|
||||
const FP_SHAPE* dwgB = static_cast<const FP_SHAPE*>( itemB );
|
||||
|
||||
if( dwgA->GetShape() != dwgB->GetShape() )
|
||||
return dwgA->GetShape() < dwgB->GetShape();
|
||||
TEST( 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
|
||||
return aFirst->m_Uuid < aSecond->m_Uuid;
|
||||
TEST( dwgA->GetWidth(), dwgB->GetWidth() );
|
||||
}
|
||||
|
||||
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() )
|
||||
return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0;
|
||||
|
||||
if( aFirst->m_Uuid != aSecond->m_Uuid ) // shopuld be always the case foer valid boards
|
||||
return aFirst->m_Uuid < aSecond->m_Uuid;
|
||||
TEST_PT( aFirst->GetPos0(), aSecond->GetPos0() );
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
PCB_LAYER_ID aLayer, int aClearance,
|
||||
int aMaxError, ERROR_LOC aErrorLoc,
|
||||
|
|
|
@ -180,8 +180,8 @@ public:
|
|||
|
||||
bool HasThroughHolePads() const;
|
||||
|
||||
std::list<FP_3DMODEL>& Models() { return m_3D_Drawings; }
|
||||
const std::list<FP_3DMODEL>& Models() const { return m_3D_Drawings; }
|
||||
std::vector<FP_3DMODEL>& Models() { return m_3D_Drawings; }
|
||||
const std::vector<FP_3DMODEL>& Models() const { return m_3D_Drawings; }
|
||||
|
||||
void SetPosition( const wxPoint& aPos ) override;
|
||||
wxPoint GetPosition() const override { return m_pos; }
|
||||
|
@ -655,6 +655,11 @@ public:
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -723,6 +728,11 @@ public:
|
|||
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)
|
||||
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_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;
|
||||
wxArrayString* m_initial_comments; // s-expression comments in the footprint,
|
||||
// lazily allocated only if needed for speed
|
||||
|
|
|
@ -1225,7 +1225,7 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
|
|||
std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> sorted_drawings(
|
||||
aFootprint->GraphicalItems().begin(),
|
||||
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() );
|
||||
std::set<BOARD_ITEM*, PCB_GROUP::ptr_cmp> sorted_groups( aFootprint->Groups().begin(),
|
||||
aFootprint->Groups().end() );
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"items_not_allowed": "error",
|
||||
"keepout": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_too_small": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"items_not_allowed": "error",
|
||||
"keepout": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_too_small": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -48,13 +48,20 @@
|
|||
"min_clearance": 0.508
|
||||
}
|
||||
},
|
||||
"diff_pair_dimensions": [],
|
||||
"diff_pair_dimensions": [
|
||||
{
|
||||
"gap": 0.0,
|
||||
"via_gap": 0.0,
|
||||
"width": 0.0
|
||||
}
|
||||
],
|
||||
"drc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"rule_severities": {
|
||||
"annular_width": "error",
|
||||
"aperture_clearance": "error",
|
||||
"clearance": "error",
|
||||
"copper_edge_clearance": "error",
|
||||
"courtyards_overlap": "error",
|
||||
|
@ -69,6 +76,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
@ -81,6 +89,9 @@
|
|||
"silk_over_copper": "warning",
|
||||
"silk_overlap": "warning",
|
||||
"skew_out_of_range": "error",
|
||||
"starved_thermal": "error",
|
||||
"text_height": "warning",
|
||||
"text_thickness": "warning",
|
||||
"too_many_vias": "error",
|
||||
"track_dangling": "warning",
|
||||
"track_width": "error",
|
||||
|
@ -95,21 +106,32 @@
|
|||
"allow_blind_buried_vias": false,
|
||||
"allow_microvias": false,
|
||||
"max_error": 0.005,
|
||||
"min_aperture_clearance": 0.049999999999999996,
|
||||
"min_clearance": 0.0,
|
||||
"min_copper_edge_clearance": 0.01,
|
||||
"min_hole_clearance": 0.0,
|
||||
"min_hole_to_hole": 0.25,
|
||||
"min_microvia_diameter": 0.19999999999999998,
|
||||
"min_microvia_drill": 0.09999999999999999,
|
||||
"min_resolved_spokes": 2,
|
||||
"min_silk_clearance": 0.0,
|
||||
"min_text_height": 0.7999999999999999,
|
||||
"min_text_thickness": 0.12,
|
||||
"min_through_hole_diameter": 0.3,
|
||||
"min_track_width": 0.19999999999999998,
|
||||
"min_via_annular_width": 0.049999999999999996,
|
||||
"min_via_diameter": 0.39999999999999997,
|
||||
"use_height_for_length_calcs": true
|
||||
},
|
||||
"track_widths": [],
|
||||
"via_dimensions": [],
|
||||
"track_widths": [
|
||||
0.0
|
||||
],
|
||||
"via_dimensions": [
|
||||
{
|
||||
"diameter": 0.0,
|
||||
"drill": 0.0
|
||||
}
|
||||
],
|
||||
"zones_allow_external_fillets": false,
|
||||
"zones_use_no_outline": true
|
||||
},
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"lib_footprint_issues": "ignore",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
|
|
|
@ -44,7 +44,7 @@ add_executable( drc_proto
|
|||
../../pcbnew/drc/drc_test_provider_connectivity.cpp
|
||||
../../pcbnew/drc/drc_test_provider_courtyard_clearance.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_silk_to_mask.cpp
|
||||
../../pcbnew/drc/drc_test_provider_silk_clearance.cpp
|
||||
|
|
|
@ -43,7 +43,7 @@ add_executable( test_pns
|
|||
../../pcbnew/drc/drc_test_provider_connectivity.cpp
|
||||
../../pcbnew/drc/drc_test_provider_courtyard_clearance.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_silk_to_mask.cpp
|
||||
../../pcbnew/drc/drc_test_provider_silk_clearance.cpp
|
||||
|
|
Loading…
Reference in New Issue