Allow custom pads with 0-sized anchor pads.

(Surprisingly we used to in 5.1, so this is a regression.)

Also had to go back to the nag dialog as on a small screen the infobar
comes up behind the dialog.  A lot of the errors have also been turned
into warnings, so the overall effect should still be to reduce nagging.

Fixes https://gitlab.com/kicad/code/kicad/issues/6992
This commit is contained in:
Jeff Young 2021-01-08 17:45:04 +00:00
parent 3467e643e5
commit 8fffb75347
2 changed files with 74 additions and 75 deletions

View File

@ -1196,7 +1196,6 @@ void DIALOG_PAD_PROPERTIES::OnSetLayers( wxCommandEvent& event )
bool DIALOG_PAD_PROPERTIES::padValuesOK()
{
bool error = transferDataToPad( m_dummyPad );
bool skip_tstoffset = false; // the offset prm is not always tested
wxArrayString error_msgs;
wxArrayString warning_msgs;
@ -1204,10 +1203,19 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
wxSize pad_size = m_dummyPad->GetSize();
wxSize drill_size = m_dummyPad->GetDrillSize();
// Test for incorrect values
if( pad_size.x <= 0 || ( pad_size.y <= 0 && m_dummyPad->GetShape() != PAD_SHAPE_CIRCLE ) )
if( m_dummyPad->GetShape() == PAD_SHAPE_CUSTOM )
{
error_msgs.Add( _( "Warning: Pad size is less than zero." ) );
// allow 0-sized anchor pads
}
else if( m_dummyPad->GetShape() == PAD_SHAPE_CIRCLE )
{
if( pad_size.x <= 0 )
warning_msgs.Add( _( "Warning: Pad size is less than zero." ) );
}
else
{
if( pad_size.x <= 0 || pad_size.y <= 0 )
warning_msgs.Add( _( "Warning: Pad size is less than zero." ) );
}
// Test hole size against pad size
@ -1230,18 +1238,15 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
drillOutline.BooleanSubtract( padOutline, SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
if( ( drillOutline.BBox().GetWidth() > 0 ) || ( drillOutline.BBox().GetHeight() > 0 ) )
if( drillOutline.BBox().GetWidth() > 0 || drillOutline.BBox().GetHeight() > 0 )
{
warning_msgs.Add( _( "Warning: Pad drill will leave no copper or drill shape and "
"pad shape do not overlap." ) );
skip_tstoffset = true; // offset parameter will be not tested because if the drill
// value is incorrect the offset parameter is always seen as
// incorrect, even if it is 0
}
}
if( m_dummyPad->GetLocalClearance() < 0 )
error_msgs.Add( _( "Error: Negative local clearance values will have no effect." ) );
warning_msgs.Add( _( "Warning: Negative local clearance values will have no effect." ) );
// Some pads need a negative solder mask clearance (mainly for BGA with small pads)
// However the negative solder mask clearance must not create negative mask size
@ -1250,8 +1255,8 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
// allowed for custom pad shape
if( m_dummyPad->GetLocalSolderMaskMargin() < 0 && m_dummyPad->GetShape() == PAD_SHAPE_CUSTOM )
{
error_msgs.Add( _( "Error: Negative solder mask clearances are not supported for custom "
"pad shapes." ) );
warning_msgs.Add( _( "Warning: Negative solder mask clearances are not supported for "
"custom pad shapes." ) );
}
else
{
@ -1263,8 +1268,8 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
if( solder_size.x <= 0 || solder_size.y <= 0 )
{
error_msgs.Add( _( "Warning: Negative solder mask clearance larger than pad. No "
"solder mask will be generated." ) );
warning_msgs.Add( _( "Warning: Negative solder mask clearance larger than pad. No "
"solder mask will be generated." ) );
}
}
@ -1282,8 +1287,8 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
if( paste_size.x <= 0 || paste_size.y <= 0 )
{
error_msgs.Add( _( "Warning: Negative solder paste margins larger than pad. No solder "
"paste mask will be generated." ) );
warning_msgs.Add( _( "Warning: Negative solder paste margins larger than pad. No solder "
"paste mask will be generated." ) );
}
LSET padlayers_mask = m_dummyPad->GetLayerSet();
@ -1300,22 +1305,6 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
}
}
//Note: the below test might be unnecessary
if( !skip_tstoffset && m_dummyPad->GetShape() != PAD_SHAPE_CUSTOM )
{
wxPoint max_size;
max_size.x = std::abs( m_dummyPad->GetOffset().x );
max_size.y = std::abs( m_dummyPad->GetOffset().y );
max_size.x += m_dummyPad->GetDrillSize().x / 2;
max_size.y += m_dummyPad->GetDrillSize().y / 2;
if( ( m_dummyPad->GetSize().x / 2 < max_size.x ) ||
( m_dummyPad->GetSize().y / 2 < max_size.y ) )
{
error_msgs.Add( _( "Incorrect value for pad offset." ) );
}
}
if( error )
error_msgs.Add( _( "Too large value for pad delta size." ) );
@ -1326,15 +1315,15 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
if( drill_size.x <= 0
|| ( drill_size.y <= 0 && m_dummyPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ) )
{
error_msgs.Add( _( "Error: Through hole pad has no hole." ) );
warning_msgs.Add( _( "Warning: Through hole pad has no hole." ) );
}
break;
case PAD_ATTRIB_CONN: // Connector pads are smd pads, just they do not have solder paste.
if( padlayers_mask[B_Paste] || padlayers_mask[F_Paste] )
{
error_msgs.Add( _( "Error: Connector pads have no solder paste. Use an SMD pad "
"instead." ) );
warning_msgs.Add( _( "Warning: Connector pads normally have no solder paste. Use an "
"SMD pad instead." ) );
}
KI_FALLTHROUGH;
@ -1342,44 +1331,41 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
{
LSET innerlayers_mask = padlayers_mask & LSET::InternalCuMask();
if( ( padlayers_mask[F_Cu] && padlayers_mask[B_Cu] ) ||
innerlayers_mask.count() != 0 )
{
if( ( padlayers_mask[F_Cu] && padlayers_mask[B_Cu] ) || innerlayers_mask.count() != 0 )
warning_msgs.Add( _( "Warning: SMD pad has no outer layers." ) );
}
}
break;
}
if( ( m_dummyPad->GetProperty() == PAD_PROP_FIDUCIAL_GLBL
|| m_dummyPad->GetProperty() == PAD_PROP_FIDUCIAL_LOCAL )
&& m_dummyPad->GetAttribute() == PAD_ATTRIB_NPTH )
if( ( m_dummyPad->GetProperty() == PAD_PROP_FIDUCIAL_GLBL ||
m_dummyPad->GetProperty() == PAD_PROP_FIDUCIAL_LOCAL ) &&
m_dummyPad->GetAttribute() == PAD_ATTRIB_NPTH )
{
error_msgs.Add( _( "Warning: Fiducial property cannot be set on NPTH pads." ) );
warning_msgs.Add( _( "Warning: Fiducial property makes no sense on NPTH pads." ) );
}
if( m_dummyPad->GetProperty() == PAD_PROP_TESTPOINT &&
m_dummyPad->GetAttribute() == PAD_ATTRIB_NPTH )
{
error_msgs.Add( _( "Warning: Testpoint property cannot be set on NPTH pads." ) );
warning_msgs.Add( _( "Warning: Testpoint property makes no sense on NPTH pads." ) );
}
if( m_dummyPad->GetProperty() == PAD_PROP_HEATSINK &&
m_dummyPad->GetAttribute() == PAD_ATTRIB_NPTH )
{
error_msgs.Add( _( "Warning: Heatsink property cannot be set on NPTH pads." ) );
warning_msgs.Add( _( "Warning: Heatsink property makes no sense of NPTH pads." ) );
}
if( m_dummyPad->GetProperty() == PAD_PROP_CASTELLATED &&
m_dummyPad->GetAttribute() != PAD_ATTRIB_PTH )
{
error_msgs.Add( _( "Warning: Castellated property can be set only on PTH pads." ) );
warning_msgs.Add( _( "Warning: Castellated property is for PTH pads." ) );
}
if( m_dummyPad->GetProperty() == PAD_PROP_BGA &&
m_dummyPad->GetAttribute() != PAD_ATTRIB_SMD )
{
error_msgs.Add( _( "Warning: BGA property can be set only on SMD pads." ) );
warning_msgs.Add( _( "Warning: BGA property is for SMD pads." ) );
}
if( m_dummyPad->GetShape() == PAD_SHAPE_ROUNDRECT ||
@ -1398,7 +1384,7 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
if( rrRadiusRatioPercent < 0.0 )
error_msgs.Add( _( "Error: Negative corner size." ) );
else if( rrRadiusRatioPercent > 50.0 )
error_msgs.Add( _( "Warning: Corner size will make pad circular." ) );
warning_msgs.Add( _( "Warning: Corner size will make pad circular." ) );
}
}
@ -1413,9 +1399,12 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
}
if( error_msgs.GetCount() )
if( error_msgs.GetCount() || warning_msgs.GetCount() )
{
HTML_MESSAGE_BOX dlg( this, _( "Pad setup errors list" ) );
wxString title = error_msgs.GetCount() ? _( "Pad Properties Errors" )
: _( "Pad Properties Warnings" );
HTML_MESSAGE_BOX dlg( this, title );
dlg.ListSet( error_msgs );
if( warning_msgs.GetCount() )
@ -1423,11 +1412,6 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK()
dlg.ShowModal();
}
else
{
for( size_t i = 0; i < warning_msgs.GetCount(); ++i )
m_parent->ShowInfoBarWarning( warning_msgs[i] );
}
return error_msgs.GetCount() == 0;
}

View File

@ -928,6 +928,7 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() );
}
else if( aLayer == LAYER_PADS_TH
&& aPad->GetShape() != PAD_SHAPE_CUSTOM
&& aPad->GetSizeX() <= aPad->GetDrillSizeX()
&& aPad->GetSizeY() <= aPad->GetDrillSizeY() )
{
@ -955,18 +956,19 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
break;
}
if( pad_size.x + margin.x <= 0 || pad_size.y + margin.y <= 0 )
return;
std::unique_ptr<PAD> dummyPad;
std::shared_ptr<SHAPE_COMPOUND> shapes;
bool simpleShapes = true;
if( margin.x != margin.y )
if( margin.x != margin.y && aPad->GetShape() != PAD_SHAPE_CUSTOM )
{
// Our algorithms below (polygon inflation in particular) can't handle differential
// inflation along separate axes. So for those cases we build a dummy pad instead,
// and inflate it.
if( pad_size.x + margin.x <= 0 || pad_size.y + margin.y <= 0 )
return;
dummyPad.reset( static_cast<PAD*>( aPad->Duplicate() ) );
dummyPad->SetSize( pad_size + margin + margin );
shapes = std::dynamic_pointer_cast<SHAPE_COMPOUND>( dummyPad->GetEffectiveShape() );
@ -1011,43 +1013,55 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
case SH_SEGMENT:
{
const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shape;
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B,
seg->GetWidth() + 2 * margin.x );
int effectiveWidth = seg->GetWidth() + 2 * margin.x;
if( effectiveWidth > 0 )
m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, effectiveWidth );
}
break;
case SH_CIRCLE:
{
const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shape;
m_gal->DrawCircle( circle->GetCenter(), circle->GetRadius() + margin.x );
int effectiveRadius = circle->GetRadius() + margin.x;
if( effectiveRadius > 0 )
m_gal->DrawCircle( circle->GetCenter(), effectiveRadius );
}
break;
case SH_RECT:
{
const SHAPE_RECT* r = (SHAPE_RECT*) shape;
VECTOR2I position = r->GetPosition();
VECTOR2I effectiveSize = r->GetSize() + margin;
// At this point, if margin.x < 0 the actual rectangle size is
// smaller than SHAPE_RECT r (the pad size was not modifed)
if( margin.x < 0 )
m_gal->DrawRectangle( r->GetPosition() - margin,
r->GetPosition() + r->GetSize() + margin );
else
m_gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
if( margin.x > 0 ) // We draw a roudned rect shape
{
m_gal->DrawSegment( r->GetPosition(),
r->GetPosition() + VECTOR2I( r->GetWidth(), 0 ),
if( effectiveSize.x > 0 && effectiveSize.y > 0 )
m_gal->DrawRectangle( position - margin, position + effectiveSize );
}
else
{
m_gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
}
// Now add on a rounded margin (using segments) if the margin > 0
if( margin.x > 0 )
{
m_gal->DrawSegment( position,
position + VECTOR2I( r->GetWidth(), 0 ),
margin.x * 2 );
m_gal->DrawSegment( r->GetPosition() + VECTOR2I( r->GetWidth(), 0 ),
r->GetPosition() + r->GetSize(),
m_gal->DrawSegment( position + VECTOR2I( r->GetWidth(), 0 ),
position + r->GetSize(),
margin.x * 2 );
m_gal->DrawSegment( r->GetPosition() + r->GetSize(),
r->GetPosition() + VECTOR2I( 0, r->GetHeight() ),
m_gal->DrawSegment( position + r->GetSize(),
position + VECTOR2I( 0, r->GetHeight() ),
margin.x * 2 );
m_gal->DrawSegment( r->GetPosition() + VECTOR2I( 0, r->GetHeight() ),
r->GetPosition(),
m_gal->DrawSegment( position + VECTOR2I( 0, r->GetHeight() ),
position,
margin.x * 2 );
}
}
@ -1058,6 +1072,7 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
m_gal->DrawPolygon( poly->Vertices() );
// Now add on a rounded margin (using segments) if the margin > 0
if( margin.x > 0 )
{
for( size_t ii = 0; ii < poly->GetSegmentCount(); ++ii )