Improve zone & rule area reporting.

Also removes a bunch of "wxEmptyString" where it was degrading readability.

Also fixes a bug where footprint zones were getting sorted incorrectly
due to rotation of coordinates.

Fixes https://gitlab.com/kicad/code/kicad/issues/14322
This commit is contained in:
Jeff Young 2023-03-17 11:07:37 +00:00
parent 967ee2c85b
commit ee1d9c561c
2 changed files with 204 additions and 175 deletions

View File

@ -74,87 +74,92 @@ public:
// In "Report" mode (aReporter != nullptr) all properties are checked and reported on. // In "Report" mode (aReporter != nullptr) all properties are checked and reported on.
// In "DRC" mode (aReporter == nulltpr) properties are only checked until a difference is found. // In "DRC" mode (aReporter == nulltpr) properties are only checked until a difference is found.
// //
#define TEST( a, b, msg ) \ #define TEST( a, b, msg ) \
{ \ { \
if( a != b ) \ if( a != b ) \
{ \ { \
diff = true; \ diff = true; \
\ \
if( aReporter ) \ if( aReporter && wxString( msg ).length() ) \
aReporter->Report( msg ); \ aReporter->Report( msg ); \
} \ } \
\ \
if( diff && !aReporter ) \ if( diff && !aReporter ) \
return diff; \ return diff; \
} }
#define EPSILON 0.000001 #define EPSILON 0.000001
#define TEST_D( a, b, msg ) \ #define TEST_D( a, b, msg ) \
{ \ { \
if( abs( a - b ) > EPSILON ) \ if( abs( a - b ) > EPSILON ) \
{ \ { \
diff = true; \ diff = true; \
\ \
if( aReporter ) \ if( aReporter && wxString( msg ).length() ) \
aReporter->Report( msg ); \ aReporter->Report( msg ); \
} \ } \
\ \
if( diff && !aReporter ) \ if( diff && !aReporter ) \
return diff; \ return diff; \
} }
#define TEST_V3D( a, b, msg ) \ #define TEST_V3D( a, b, msg ) \
{ \ { \
if( abs( a.x - b.x ) > EPSILON \ if( abs( a.x - b.x ) > EPSILON \
|| abs( a.y - b.y ) > EPSILON \ || abs( a.y - b.y ) > EPSILON \
|| abs( a.z - b.z ) > EPSILON ) \ || abs( a.z - b.z ) > EPSILON ) \
{ \ { \
diff = true; \ diff = true; \
\ \
if( aReporter ) \ if( aReporter && wxString( msg ).length() ) \
aReporter->Report( msg ); \ aReporter->Report( msg ); \
} \ } \
\ \
if( diff && !aReporter ) \ if( diff && !aReporter ) \
return diff; \ return diff; \
} }
#define ITEM_DESC( item ) ( item )->GetItemDescription( &g_unitsProvider )
UNITS_PROVIDER g_unitsProvider( pcbIUScale, EDA_UNITS::MILLIMETRES );
bool primitiveNeedsUpdate( const std::shared_ptr<PCB_SHAPE>& a, bool primitiveNeedsUpdate( const std::shared_ptr<PCB_SHAPE>& a,
const std::shared_ptr<PCB_SHAPE>& b ) const std::shared_ptr<PCB_SHAPE>& b )
{ {
REPORTER* aReporter = nullptr; REPORTER* aReporter = nullptr;
bool diff = false; bool diff = false;
TEST( a->GetShape(), b->GetShape(), wxEmptyString ); TEST( a->GetShape(), b->GetShape(), "" );
switch( a->GetShape() ) switch( a->GetShape() )
{ {
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
case SHAPE_T::RECT: case SHAPE_T::RECT:
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
TEST( a->GetStart(), b->GetStart(), wxEmptyString ); TEST( a->GetStart(), b->GetStart(), "" );
TEST( a->GetEnd(), b->GetEnd(), wxEmptyString ); TEST( a->GetEnd(), b->GetEnd(), "" );
break; break;
case SHAPE_T::ARC: case SHAPE_T::ARC:
TEST( a->GetStart(), b->GetStart(), wxEmptyString ); TEST( a->GetStart(), b->GetStart(), "" );
TEST( a->GetEnd(), b->GetEnd(), wxEmptyString ); TEST( a->GetEnd(), b->GetEnd(), "" );
TEST( a->GetCenter(), b->GetCenter(), wxEmptyString ); TEST( a->GetCenter(), b->GetCenter(), "" );
TEST_D( a->GetArcAngle().AsDegrees(), b->GetArcAngle().AsDegrees(), wxEmptyString ); TEST_D( a->GetArcAngle().AsDegrees(), b->GetArcAngle().AsDegrees(), "" );
break; break;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
TEST( a->GetStart(), b->GetStart(), wxEmptyString ); TEST( a->GetStart(), b->GetStart(), "" );
TEST( a->GetEnd(), b->GetEnd(), wxEmptyString ); TEST( a->GetEnd(), b->GetEnd(), "" );
TEST( a->GetBezierC1(), b->GetBezierC1(), wxEmptyString ); TEST( a->GetBezierC1(), b->GetBezierC1(), "" );
TEST( a->GetBezierC2(), b->GetBezierC2(), wxEmptyString ); TEST( a->GetBezierC2(), b->GetBezierC2(), "" );
break; break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(), wxEmptyString); TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(), "" );
for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii ) for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), wxEmptyString ); TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), "" );
break; break;
@ -162,8 +167,8 @@ bool primitiveNeedsUpdate( const std::shared_ptr<PCB_SHAPE>& a,
UNIMPLEMENTED_FOR( a->SHAPE_T_asString() ); UNIMPLEMENTED_FOR( a->SHAPE_T_asString() );
} }
TEST( a->GetStroke(), b->GetStroke(), wxEmptyString ); TEST( a->GetStroke(), b->GetStroke(), "" );
TEST( a->IsFilled(), b->IsFilled(), wxEmptyString ); TEST( a->IsFilled(), b->IsFilled(), "" );
return diff; return diff;
} }
@ -174,47 +179,47 @@ bool padNeedsUpdate( const PAD* a, const PAD* b )
REPORTER* aReporter = nullptr; REPORTER* aReporter = nullptr;
bool diff = false; bool diff = false;
TEST( a->GetPadToDieLength(), b->GetPadToDieLength(), wxEmptyString ); TEST( a->GetPadToDieLength(), b->GetPadToDieLength(), "" );
TEST( a->GetPos0(), b->GetPos0(), wxEmptyString ); TEST( a->GetPos0(), b->GetPos0(), "" );
TEST( a->GetNumber(), b->GetNumber(), wxEmptyString ); TEST( a->GetNumber(), b->GetNumber(), "" );
// These are assigned from the schematic and not from the library // These are assigned from the schematic and not from the library
// TEST( a->GetPinFunction(), b->GetPinFunction() ); // TEST( a->GetPinFunction(), b->GetPinFunction() );
// TEST( a->GetPinType(), b->GetPinType() ); // TEST( a->GetPinType(), b->GetPinType() );
TEST( a->GetRemoveUnconnected(), b->GetRemoveUnconnected(), wxEmptyString ); TEST( a->GetRemoveUnconnected(), b->GetRemoveUnconnected(), "" );
// NB: KeepTopBottom is undefined if RemoveUnconnected is NOT set. // NB: KeepTopBottom is undefined if RemoveUnconnected is NOT set.
if( a->GetRemoveUnconnected() ) if( a->GetRemoveUnconnected() )
TEST( a->GetKeepTopBottom(), b->GetKeepTopBottom(), wxEmptyString ); TEST( a->GetKeepTopBottom(), b->GetKeepTopBottom(), "" );
TEST( a->GetShape(), b->GetShape(), wxEmptyString ); TEST( a->GetShape(), b->GetShape(), "" );
// Trim layersets to the current board before comparing // Trim layersets to the current board before comparing
LSET enabledLayers = a->GetBoard()->GetEnabledLayers(); LSET enabledLayers = a->GetBoard()->GetEnabledLayers();
LSET aLayers = a->GetLayerSet() & enabledLayers; LSET aLayers = a->GetLayerSet() & enabledLayers;
LSET bLayers = b->GetLayerSet() & enabledLayers; LSET bLayers = b->GetLayerSet() & enabledLayers;
TEST( aLayers, bLayers, wxEmptyString ); TEST( aLayers, bLayers, "" );
TEST( a->GetAttribute(), b->GetAttribute(), wxEmptyString ); TEST( a->GetAttribute(), b->GetAttribute(), "" );
TEST( a->GetProperty(), b->GetProperty(), wxEmptyString ); TEST( a->GetProperty(), b->GetProperty(), "" );
// The pad orientation, for historical reasons is the pad rotation + parent rotation. // The pad orientation, for historical reasons is the pad rotation + parent rotation.
TEST_D( ( a->GetOrientation() - a->GetParent()->GetOrientation() ).Normalize().AsDegrees(), TEST_D( ( a->GetOrientation() - a->GetParent()->GetOrientation() ).Normalize().AsDegrees(),
( b->GetOrientation() - b->GetParent()->GetOrientation() ).Normalize().AsDegrees(), ( b->GetOrientation() - b->GetParent()->GetOrientation() ).Normalize().AsDegrees(),
wxEmptyString ); "" );
TEST( a->GetSize(), b->GetSize(), wxEmptyString ); TEST( a->GetSize(), b->GetSize(), "" );
TEST( a->GetDelta(), b->GetDelta(), wxEmptyString ); TEST( a->GetDelta(), b->GetDelta(), "" );
TEST( a->GetRoundRectCornerRadius(), b->GetRoundRectCornerRadius(), wxEmptyString ); TEST( a->GetRoundRectCornerRadius(), b->GetRoundRectCornerRadius(), "" );
TEST_D( a->GetRoundRectRadiusRatio(), b->GetRoundRectRadiusRatio(), wxEmptyString ); TEST_D( a->GetRoundRectRadiusRatio(), b->GetRoundRectRadiusRatio(), "" );
TEST_D( a->GetChamferRectRatio(), b->GetChamferRectRatio(), wxEmptyString ); TEST_D( a->GetChamferRectRatio(), b->GetChamferRectRatio(), "" );
TEST( a->GetChamferPositions(), b->GetChamferPositions(), wxEmptyString ); TEST( a->GetChamferPositions(), b->GetChamferPositions(), "" );
TEST( a->GetOffset(), b->GetOffset(), wxEmptyString ); TEST( a->GetOffset(), b->GetOffset(), "" );
TEST( a->GetDrillShape(), b->GetDrillShape(), wxEmptyString ); TEST( a->GetDrillShape(), b->GetDrillShape(), "" );
TEST( a->GetDrillSize(), b->GetDrillSize(), wxEmptyString ); TEST( a->GetDrillSize(), b->GetDrillSize(), "" );
// Clearance and zone connection overrides are as likely to be set at the board level as in // Clearance and zone connection overrides are as likely to be set at the board level as in
// the library. // the library.
@ -229,7 +234,7 @@ bool padNeedsUpdate( const PAD* a, const PAD* b )
return true; return true;
#endif #endif
TEST( a->GetPrimitives().size(), b->GetPrimitives().size(), wxEmptyString ); TEST( a->GetPrimitives().size(), b->GetPrimitives().size(), "" );
for( size_t ii = 0; ii < a->GetPrimitives().size(); ++ii ) for( size_t ii = 0; ii < a->GetPrimitives().size(); ++ii )
{ {
@ -246,16 +251,16 @@ bool padHasOverrides( const PAD* a, const PAD* b )
REPORTER* aReporter = nullptr; REPORTER* aReporter = nullptr;
bool diff = false; bool diff = false;
TEST( a->GetLocalClearance(), b->GetLocalClearance(), wxEmptyString ); TEST( a->GetLocalClearance(), b->GetLocalClearance(), "" );
TEST( a->GetLocalSolderMaskMargin(), b->GetLocalSolderMaskMargin(), wxEmptyString ); TEST( a->GetLocalSolderMaskMargin(), b->GetLocalSolderMaskMargin(), "" );
TEST( a->GetLocalSolderPasteMargin(), b->GetLocalSolderPasteMargin(), wxEmptyString ); TEST( a->GetLocalSolderPasteMargin(), b->GetLocalSolderPasteMargin(), "" );
TEST_D( a->GetLocalSolderPasteMarginRatio(), b->GetLocalSolderPasteMarginRatio(), wxEmptyString ); TEST_D( a->GetLocalSolderPasteMarginRatio(), b->GetLocalSolderPasteMarginRatio(), "" );
TEST( a->GetZoneConnection(), b->GetZoneConnection(), wxEmptyString ); TEST( a->GetZoneConnection(), b->GetZoneConnection(), "" );
TEST( a->GetThermalGap(), b->GetThermalGap(), wxEmptyString ); TEST( a->GetThermalGap(), b->GetThermalGap(), "" );
TEST( a->GetThermalSpokeWidth(), b->GetThermalSpokeWidth(), wxEmptyString ); TEST( a->GetThermalSpokeWidth(), b->GetThermalSpokeWidth(), "" );
TEST_D( a->GetThermalSpokeAngle().AsDegrees(), b->GetThermalSpokeAngle().AsDegrees(), wxEmptyString ); TEST_D( a->GetThermalSpokeAngle().AsDegrees(), b->GetThermalSpokeAngle().AsDegrees(), "" );
TEST( a->GetCustomShapeInZoneOpt(), b->GetCustomShapeInZoneOpt(), wxEmptyString ); TEST( a->GetCustomShapeInZoneOpt(), b->GetCustomShapeInZoneOpt(), "" );
return diff; return diff;
} }
@ -266,20 +271,20 @@ bool shapeNeedsUpdate( const FP_SHAPE* a, const FP_SHAPE* b )
REPORTER* aReporter = nullptr; REPORTER* aReporter = nullptr;
bool diff = false; bool diff = false;
TEST( a->GetShape(), b->GetShape(), wxEmptyString ); TEST( a->GetShape(), b->GetShape(), "" );
switch( a->GetShape() ) switch( a->GetShape() )
{ {
case SHAPE_T::SEGMENT: case SHAPE_T::SEGMENT:
case SHAPE_T::RECT: case SHAPE_T::RECT:
case SHAPE_T::CIRCLE: case SHAPE_T::CIRCLE:
TEST( a->GetStart0(), b->GetStart0(), wxEmptyString ); TEST( a->GetStart0(), b->GetStart0(), "" );
TEST( a->GetEnd0(), b->GetEnd0(), wxEmptyString ); TEST( a->GetEnd0(), b->GetEnd0(), "" );
break; break;
case SHAPE_T::ARC: case SHAPE_T::ARC:
TEST( a->GetStart0(), b->GetStart0(), wxEmptyString ); TEST( a->GetStart0(), b->GetStart0(), "" );
TEST( a->GetEnd0(), b->GetEnd0(), wxEmptyString ); TEST( a->GetEnd0(), b->GetEnd0(), "" );
// Arc center is calculated and so may have round-off errors when parents are // Arc center is calculated and so may have round-off errors when parents are
// differentially rotated. // differentially rotated.
@ -289,17 +294,17 @@ bool shapeNeedsUpdate( const FP_SHAPE* a, const FP_SHAPE* b )
break; break;
case SHAPE_T::BEZIER: case SHAPE_T::BEZIER:
TEST( a->GetStart0(), b->GetStart0(), wxEmptyString ); TEST( a->GetStart0(), b->GetStart0(), "" );
TEST( a->GetEnd0(), b->GetEnd0(), wxEmptyString ); TEST( a->GetEnd0(), b->GetEnd0(), "" );
TEST( a->GetBezierC1_0(), b->GetBezierC1_0(), wxEmptyString ); TEST( a->GetBezierC1_0(), b->GetBezierC1_0(), "" );
TEST( a->GetBezierC2_0(), b->GetBezierC2_0(), wxEmptyString ); TEST( a->GetBezierC2_0(), b->GetBezierC2_0(), "" );
break; break;
case SHAPE_T::POLY: case SHAPE_T::POLY:
TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(), wxEmptyString ); TEST( a->GetPolyShape().TotalVertices(), b->GetPolyShape().TotalVertices(), "" );
for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii ) for( int ii = 0; ii < a->GetPolyShape().TotalVertices(); ++ii )
TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), wxEmptyString ); TEST( a->GetPolyShape().CVertex( ii ), b->GetPolyShape().CVertex( ii ), "" );
break; break;
@ -307,101 +312,129 @@ bool shapeNeedsUpdate( const FP_SHAPE* a, const FP_SHAPE* b )
UNIMPLEMENTED_FOR( a->SHAPE_T_asString() ); UNIMPLEMENTED_FOR( a->SHAPE_T_asString() );
} }
TEST( a->GetStroke(), b->GetStroke(), wxEmptyString ); TEST( a->GetStroke(), b->GetStroke(), "" );
TEST( a->IsFilled(), b->IsFilled(), wxEmptyString ); TEST( a->IsFilled(), b->IsFilled(), "" );
TEST( a->GetLayer(), b->GetLayer(), wxEmptyString ); TEST( a->GetLayer(), b->GetLayer(), "" );
return diff; return diff;
} }
bool textsNeedUpdate( const FP_TEXT* a, const FP_TEXT* b ) bool textNeedsUpdate( const FP_TEXT* a, const FP_TEXT* b )
{ {
REPORTER* aReporter = nullptr; REPORTER* aReporter = nullptr;
bool diff = false; bool diff = false;
TEST( a->GetLayer(), b->GetLayer(), wxEmptyString ); TEST( a->GetLayer(), b->GetLayer(), "" );
TEST( a->IsKeepUpright(), b->IsKeepUpright(), wxEmptyString ); TEST( a->IsKeepUpright(), b->IsKeepUpright(), "" );
TEST( a->GetText(), b->GetText(), wxEmptyString ); TEST( a->GetText(), b->GetText(), "" );
TEST( a->GetTextThickness(), b->GetTextThickness(), wxEmptyString ); TEST( a->GetTextThickness(), b->GetTextThickness(), "" );
TEST( a->GetTextAngle(), b->GetTextAngle(), wxEmptyString ); TEST( a->GetTextAngle(), b->GetTextAngle(), "" );
TEST( a->IsItalic(), b->IsItalic(), wxEmptyString ); TEST( a->IsItalic(), b->IsItalic(), "" );
TEST( a->IsBold(), b->IsBold(), wxEmptyString ); TEST( a->IsBold(), b->IsBold(), "" );
TEST( a->IsVisible(), b->IsVisible(), wxEmptyString ); TEST( a->IsVisible(), b->IsVisible(), "" );
TEST( a->IsMirrored(), b->IsMirrored(), wxEmptyString ); TEST( a->IsMirrored(), b->IsMirrored(), "" );
TEST( a->GetHorizJustify(), b->GetHorizJustify(), wxEmptyString ); TEST( a->GetHorizJustify(), b->GetHorizJustify(), "" );
TEST( a->GetVertJustify(), b->GetVertJustify(), wxEmptyString ); TEST( a->GetVertJustify(), b->GetVertJustify(), "" );
TEST( a->GetTextSize(), b->GetTextSize(), wxEmptyString ); TEST( a->GetTextSize(), b->GetTextSize(), "" );
TEST( a->GetPos0(), b->GetPos0(), wxEmptyString ); TEST( a->GetPos0(), b->GetPos0(), "" );
return diff; return diff;
} }
bool zonesNeedUpdate( const FP_ZONE* a, const FP_ZONE* b ) bool zoneNeedsUpdate( const FP_ZONE* a, const FP_ZONE* b, REPORTER* aReporter )
{ {
REPORTER* aReporter = nullptr; bool diff = false;
bool diff = false;
TEST( a->GetCornerSmoothingType(), b->GetCornerSmoothingType(), wxEmptyString ); TEST( a->GetCornerSmoothingType(), b->GetCornerSmoothingType(),
TEST( a->GetCornerRadius(), b->GetCornerRadius(), wxEmptyString ); wxString::Format( _( "%s corner smoothing setting differs." ), ITEM_DESC( a ) ) );
TEST( a->GetZoneName(), b->GetZoneName(), wxEmptyString ); TEST( a->GetCornerRadius(), b->GetCornerRadius(),
TEST( a->GetAssignedPriority(), b->GetAssignedPriority(), wxEmptyString ); wxString::Format( _( "%s corner smoothing radius differs." ), ITEM_DESC( a ) ) );
TEST( a->GetZoneName(), b->GetZoneName(),
wxString::Format( _( "%s name differs." ), ITEM_DESC( a ) ) );
TEST( a->GetAssignedPriority(), b->GetAssignedPriority(),
wxString::Format( _( "%s priority differs." ), ITEM_DESC( a ) ) );
TEST( a->GetIsRuleArea(), b->GetIsRuleArea(), wxEmptyString ); TEST( a->GetIsRuleArea(), b->GetIsRuleArea(),
TEST( a->GetDoNotAllowCopperPour(), b->GetDoNotAllowCopperPour(), wxEmptyString ); wxString::Format( _( "%s keep-out property differs." ), ITEM_DESC( a ) ) );
TEST( a->GetDoNotAllowFootprints(), b->GetDoNotAllowFootprints(), wxEmptyString ); TEST( a->GetDoNotAllowCopperPour(), b->GetDoNotAllowCopperPour(),
TEST( a->GetDoNotAllowPads(), b->GetDoNotAllowPads(), wxEmptyString ); wxString::Format( _( "%s keep out copper fill setting differs." ), ITEM_DESC( a ) ) );
TEST( a->GetDoNotAllowTracks(), b->GetDoNotAllowTracks(), wxEmptyString ); TEST( a->GetDoNotAllowFootprints(), b->GetDoNotAllowFootprints(),
TEST( a->GetDoNotAllowVias(), b->GetDoNotAllowVias(), wxEmptyString ); wxString::Format( _( "%s keep out footprints setting differs." ), ITEM_DESC( a ) ) );
TEST( a->GetDoNotAllowPads(), b->GetDoNotAllowPads(),
wxString::Format( _( "%s keep out pads setting differs." ), ITEM_DESC( a ) ) );
TEST( a->GetDoNotAllowTracks(), b->GetDoNotAllowTracks(),
wxString::Format( _( "%s keep out tracks setting differs." ), ITEM_DESC( a ) ) );
TEST( a->GetDoNotAllowVias(), b->GetDoNotAllowVias(),
wxString::Format( _( "%s keep out vias setting differs." ), ITEM_DESC( a ) ) );
TEST( a->GetLayerSet(), b->GetLayerSet(), wxEmptyString ); TEST( a->GetLayerSet(), b->GetLayerSet(),
wxString::Format( _( "%s layers differ." ), ITEM_DESC( a ) ) );
TEST( a->GetPadConnection(), b->GetPadConnection(), wxEmptyString ); TEST( a->GetPadConnection(), b->GetPadConnection(),
TEST( a->GetLocalClearance(), b->GetLocalClearance(), wxEmptyString ); wxString::Format( _( "%s pad connection property differs." ), ITEM_DESC( a ) ) );
TEST( a->GetThermalReliefGap(), b->GetThermalReliefGap(), wxEmptyString ); TEST( a->GetLocalClearance(), b->GetLocalClearance(),
TEST( a->GetThermalReliefSpokeWidth(), b->GetThermalReliefSpokeWidth(), wxEmptyString ); wxString::Format( _( "%s local clearance differs." ), ITEM_DESC( a ) ) );
TEST( a->GetThermalReliefGap(), b->GetThermalReliefGap(),
wxString::Format( _( "%s thermal relief gap differs." ), ITEM_DESC( a ) ) );
TEST( a->GetThermalReliefSpokeWidth(), b->GetThermalReliefSpokeWidth(),
wxString::Format( _( "%s thermal relief spoke width differs." ), ITEM_DESC( a ) ) );
TEST( a->GetMinThickness(), b->GetMinThickness(), wxEmptyString ); TEST( a->GetMinThickness(), b->GetMinThickness(),
wxString::Format( _( "%s min thickness differs." ), ITEM_DESC( a ) ) );
TEST( a->GetIslandRemovalMode(), b->GetIslandRemovalMode(), wxEmptyString ); TEST( a->GetIslandRemovalMode(), b->GetIslandRemovalMode(),
TEST( a->GetMinIslandArea(), b->GetMinIslandArea(), wxEmptyString ); wxString::Format( _( "%s remove islands setting differs." ), ITEM_DESC( a ) ) );
TEST( a->GetMinIslandArea(), b->GetMinIslandArea(),
wxString::Format( _( "%s minimum island size setting differs." ), ITEM_DESC( a ) ) );
TEST( a->GetFillMode(), b->GetFillMode(), wxEmptyString ); TEST( a->GetFillMode(), b->GetFillMode(),
TEST( a->GetHatchThickness(), b->GetHatchThickness(), wxEmptyString ); wxString::Format( _( "%s fill type differs." ), ITEM_DESC( a ) ) );
TEST( a->GetHatchGap(), b->GetHatchGap(), wxEmptyString ); TEST( a->GetHatchThickness(), b->GetHatchThickness(),
TEST_D( a->GetHatchOrientation().AsDegrees(), b->GetHatchOrientation().AsDegrees(), wxEmptyString ); wxString::Format( _( "%s hatch width differs." ), ITEM_DESC( a ) ) );
TEST( a->GetHatchSmoothingLevel(), b->GetHatchSmoothingLevel(), wxEmptyString ); TEST( a->GetHatchGap(), b->GetHatchGap(),
TEST( a->GetHatchSmoothingValue(), b->GetHatchSmoothingValue(), wxEmptyString ); wxString::Format( _( "%s hatch gap differs." ), ITEM_DESC( a ) ) );
TEST( a->GetHatchHoleMinArea(), b->GetHatchHoleMinArea(), wxEmptyString ); TEST_D( a->GetHatchOrientation().AsDegrees(), b->GetHatchOrientation().AsDegrees(),
wxString::Format( _( "%s hatch orientation differs." ), ITEM_DESC( a ) ) );
TEST( a->GetHatchSmoothingLevel(), b->GetHatchSmoothingLevel(),
wxString::Format( _( "%s hatch smoothing level differs." ), ITEM_DESC( a ) ) );
TEST( a->GetHatchSmoothingValue(), b->GetHatchSmoothingValue(),
wxString::Format( _( "%s hatch smoothing amount differs." ), ITEM_DESC( a ) ) );
TEST( a->GetHatchHoleMinArea(), b->GetHatchHoleMinArea(),
wxString::Format( _( "%s minimum hatch hole setting differs." ), ITEM_DESC( a ) ) );
// This is just a display property // This is just a display property
// TEST( a->GetHatchBorderAlgorithm(), b->GetHatchBorderAlgorithm() ); // TEST( a->GetHatchBorderAlgorithm(), b->GetHatchBorderAlgorithm() );
TEST( a->Outline()->TotalVertices(), b->Outline()->TotalVertices(), wxEmptyString ); TEST( a->Outline()->TotalVertices(), b->Outline()->TotalVertices(),
wxString::Format( _( "%s outline corner count differs." ), ITEM_DESC( a ) ) );
// The footprint's zone will be in board position, so we must translate & rotate the library bool cornersDiffer = false;
// footprint's zone to match.
FOOTPRINT* parentFootprint = static_cast<FOOTPRINT*>( a->GetParentFootprint() );
const SHAPE_POLY_SET& aPoly = *a->Outline();
SHAPE_POLY_SET bPoly = b->Outline()->CloneDropTriangulation();
bPoly.Rotate( parentFootprint->GetOrientation() );
bPoly.Move( parentFootprint->GetPosition() );
for( int ii = 0; ii < a->Outline()->TotalVertices(); ++ii ) for( int ii = 0; ii < a->Outline()->TotalVertices(); ++ii )
TEST( aPoly.CVertex( ii ), bPoly.CVertex( ii ) , wxEmptyString); {
if( a->Outline()->CVertex( ii ) != b->Outline()->CVertex( ii ) )
{
diff = true;
cornersDiffer = true;
break;
}
}
if( cornersDiffer && aReporter )
aReporter->Report( wxString::Format( _( "%s corners differ." ), ITEM_DESC( a ) ) );
return diff; return diff;
} }
bool modelsNeedUpdate( const FP_3DMODEL& a, const FP_3DMODEL& b, REPORTER* aReporter ) bool modelNeedsUpdate( const FP_3DMODEL& a, const FP_3DMODEL& b, REPORTER* aReporter )
{ {
bool diff = false; bool diff = false;
@ -484,7 +517,6 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint, REPORTER*
} }
#define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); } #define REPORT( msg ) { if( aReporter ) aReporter->Report( msg ); }
#define ITEM_DESC( item ) ( item )->GetItemDescription( &unitsProvider )
#define CHECKPOINT { if( diff && !aReporter ) return diff; } #define CHECKPOINT { if( diff && !aReporter ) return diff; }
// Text items are really problematic. We don't want to test the reference, but after that // Text items are really problematic. We don't want to test the reference, but after that
@ -566,8 +598,27 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint, REPORTER*
CHECKPOINT; CHECKPOINT;
if( Models().size() != aLibFootprint->Models().size() )
{
diff = true;
REPORT( _( "3D model count differs." ) );
}
else
{
for( size_t ii = 0; ii < Models().size(); ++ii )
diff |= modelNeedsUpdate( Models()[ii], aLibFootprint->Models()[ii], aReporter );
}
CHECKPOINT;
// Rotate/position a copy of libFootprint so that zones sort the same
std::unique_ptr<FOOTPRINT> libCopy( static_cast<FOOTPRINT*>( aLibFootprint->Clone() ) );
libCopy->SetOrientation( GetOrientation() );
libCopy->Move( GetPosition() );
std::set<FP_ZONE*, FOOTPRINT::cmp_zones> aZones( Zones().begin(), Zones().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() ); std::set<FP_ZONE*, FOOTPRINT::cmp_zones> bZones( libCopy->Zones().begin(), libCopy->Zones().end() );
if( aZones.size() != bZones.size() ) if( aZones.size() != bZones.size() )
{ {
@ -577,29 +628,7 @@ bool FOOTPRINT::FootprintNeedsUpdate( const FOOTPRINT* aLibFootprint, REPORTER*
else else
{ {
for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ ) for( auto aIt = aZones.begin(), bIt = bZones.begin(); aIt != aZones.end(); aIt++, bIt++ )
{ diff |= zoneNeedsUpdate( *aIt, *bIt, aReporter );
if( zonesNeedUpdate( *aIt, *bIt ) )
{
diff = true;
REPORT( wxString::Format( _( "%s differs." ), ITEM_DESC( *aIt ) ) );
}
}
}
CHECKPOINT;
if( Models().size() != aLibFootprint->Models().size() )
{
diff = true;
REPORT( _( "3D model count differs." ) );
}
else
{
for( size_t ii = 0; ii < Models().size(); ++ii )
{
if( modelsNeedUpdate( Models()[ii], aLibFootprint->Models()[ii], aReporter ) )
diff = true;
}
} }
return diff; return diff;

View File

@ -689,7 +689,7 @@ void ZONE::MoveEdge( const VECTOR2I& offset, int aEdge )
void ZONE::Rotate( const VECTOR2I& aCentre, const EDA_ANGLE& aAngle ) void ZONE::Rotate( const VECTOR2I& aCentre, const EDA_ANGLE& aAngle )
{ {
m_Poly->Rotate( aAngle, VECTOR2I( aCentre ) ); m_Poly->Rotate( aAngle, aCentre );
HatchBorder(); HatchBorder();
/* rotate filled areas: */ /* rotate filled areas: */