Move pad and via properties into PADSTACK
This commit is contained in:
parent
c800fb790d
commit
e16130a02c
|
@ -103,3 +103,45 @@ ZONE_CONNECTION FromProtoEnum( types::ZoneConnectionStyle aValue )
|
|||
"Unhandled case in FromProtoEnum<types::ZoneConnectionStyle>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
types::UnconnectedLayerRemoval ToProtoEnum( PADSTACK::UNCONNECTED_LAYER_MODE aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL:
|
||||
return types::UnconnectedLayerRemoval::ULR_KEEP;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL:
|
||||
return types::UnconnectedLayerRemoval::ULR_REMOVE;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END:
|
||||
return types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, types::UnconnectedLayerRemoval::ULR_UNKNOWN,
|
||||
"Unhandled case in ToProtoEnum<PADSTACK::UNCONNECTED_LAYER_MODE>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE FromProtoEnum( types::UnconnectedLayerRemoval aValue )
|
||||
{
|
||||
switch( aValue )
|
||||
{
|
||||
case types::UnconnectedLayerRemoval::ULR_KEEP:
|
||||
return PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL;
|
||||
|
||||
case types::UnconnectedLayerRemoval::ULR_REMOVE:
|
||||
return PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL;
|
||||
|
||||
case types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END:
|
||||
return PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL,
|
||||
"Unhandled case in FromProtoEnum<types::UnconnectedLayerRemoval>");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -676,7 +676,7 @@ void DIALOG_PAD_PROPERTIES::initValues()
|
|||
case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
|
||||
}
|
||||
|
||||
if( m_previewPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
if( m_previewPad->GetCustomShapeInZoneOpt() == PADSTACK::CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL )
|
||||
m_ZoneCustomPadShape->SetSelection( 1 );
|
||||
else
|
||||
m_ZoneCustomPadShape->SetSelection( 0 );
|
||||
|
@ -1620,9 +1620,8 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow()
|
|||
m_currentPad->SetAnchorPadShape( m_masterPad->GetAnchorPadShape() );
|
||||
m_currentPad->ReplacePrimitives( m_masterPad->GetPrimitives() );
|
||||
|
||||
m_currentPad->SetPadstack( m_masterPad->Padstack() );
|
||||
m_currentPad->SetLayerSet( m_masterPad->GetLayerSet() );
|
||||
m_currentPad->SetRemoveUnconnected( m_masterPad->GetRemoveUnconnected() );
|
||||
m_currentPad->SetKeepTopBottom( m_masterPad->GetKeepTopBottom() );
|
||||
|
||||
m_currentPad->SetNumber( m_masterPad->GetNumber() );
|
||||
|
||||
|
@ -1947,8 +1946,8 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( PAD* aPad )
|
|||
// shapes are convex to begin with, this really only makes any difference for custom
|
||||
// pad shapes.
|
||||
aPad->SetCustomShapeInZoneOpt( m_ZoneCustomPadShape->GetSelection() == 0 ?
|
||||
CUST_PAD_SHAPE_IN_ZONE_OUTLINE :
|
||||
CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL );
|
||||
PADSTACK::CUSTOM_SHAPE_ZONE_MODE::OUTLINE :
|
||||
PADSTACK::CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL );
|
||||
|
||||
switch( aPad->GetAttribute() )
|
||||
{
|
||||
|
@ -2001,8 +2000,7 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( PAD* aPad )
|
|||
LSET padLayerMask = LSET();
|
||||
int copperLayersChoice = m_rbCopperLayersSel->GetSelection();
|
||||
|
||||
aPad->SetRemoveUnconnected( false );
|
||||
aPad->SetKeepTopBottom( false );
|
||||
aPad->Padstack().SetUnconnectedLayerMode( PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL );
|
||||
|
||||
switch( m_padType->GetSelection() )
|
||||
{
|
||||
|
@ -2017,14 +2015,14 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( PAD* aPad )
|
|||
case 1:
|
||||
// Front, back and connected
|
||||
padLayerMask |= LSET::AllCuMask();
|
||||
aPad->SetRemoveUnconnected( true );
|
||||
aPad->SetKeepTopBottom( true );
|
||||
aPad->Padstack().SetUnconnectedLayerMode(
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Connected only
|
||||
padLayerMask |= LSET::AllCuMask();
|
||||
aPad->SetRemoveUnconnected( true );
|
||||
aPad->Padstack().SetUnconnectedLayerMode( PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
|
|
|
@ -115,12 +115,13 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
|
|||
auto getAnnularRingSelection =
|
||||
[]( const PCB_VIA* via ) -> int
|
||||
{
|
||||
if( !via->GetRemoveUnconnected() )
|
||||
return 0;
|
||||
else if( via->GetKeepStartEnd() )
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
switch( via->Padstack().UnconnectedLayerMode() )
|
||||
{
|
||||
default:
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL: return 0;
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END: return 1;
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL: return 2;
|
||||
}
|
||||
};
|
||||
|
||||
// Look for values that are common for every item that is selected
|
||||
|
@ -649,15 +650,16 @@ bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow()
|
|||
switch( m_annularRingsCtrl->GetSelection() )
|
||||
{
|
||||
case 0:
|
||||
v->SetRemoveUnconnected( false );
|
||||
v->Padstack().SetUnconnectedLayerMode(
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL );
|
||||
break;
|
||||
case 1:
|
||||
v->SetRemoveUnconnected( true );
|
||||
v->SetKeepStartEnd( true );
|
||||
v->Padstack().SetUnconnectedLayerMode(
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END );
|
||||
break;
|
||||
case 2:
|
||||
v->SetRemoveUnconnected( true );
|
||||
v->SetKeepStartEnd( false );
|
||||
v->Padstack().SetUnconnectedLayerMode(
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
294
pcbnew/pad.cpp
294
pcbnew/pad.cpp
|
@ -68,8 +68,10 @@ using KIGFX::PCB_RENDER_SETTINGS;
|
|||
PAD::PAD( FOOTPRINT* parent ) :
|
||||
BOARD_CONNECTED_ITEM( parent, PCB_PAD_T )
|
||||
{
|
||||
m_size.x = m_size.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 60 ); // Default pad size 60 mils.
|
||||
m_drill.x = m_drill.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 30 ); // Default drill size 30 mils.
|
||||
VECTOR2I& drill = m_padStack.Drill().size;
|
||||
VECTOR2I& size = m_padStack.Size();
|
||||
size.x = size.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 60 ); // Default pad size 60 mils.
|
||||
drill.x = drill.y = EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 30 ); // Default drill size 30 mils.
|
||||
m_orient = ANGLE_0;
|
||||
m_lengthPadToDie = 0;
|
||||
|
||||
|
@ -84,28 +86,19 @@ PAD::PAD( FOOTPRINT* parent ) :
|
|||
SetProperty( PAD_PROP::NONE ); // no special fabrication property
|
||||
|
||||
// Parameters for round rect only:
|
||||
m_roundedCornerScale = 0.25; // from IPC-7351C standard
|
||||
m_padStack.SetRoundRectRadiusRatio( 0.25 ); // from IPC-7351C standard
|
||||
|
||||
// Parameters for chamfered rect only:
|
||||
m_chamferScale = 0.2; // Size of chamfer: ratio of smallest of X,Y size
|
||||
m_chamferPositions = RECT_NO_CHAMFER; // No chamfered corner
|
||||
|
||||
m_zoneConnection = ZONE_CONNECTION::INHERITED; // Use parent setting by default
|
||||
m_thermalSpokeWidth = 0; // Use parent setting by default
|
||||
m_thermalSpokeAngle = ANGLE_45; // Default for circular pads
|
||||
m_thermalGap = 0; // Use parent setting by default
|
||||
|
||||
m_customShapeClearanceArea = CUST_PAD_SHAPE_IN_ZONE_OUTLINE;
|
||||
m_padStack.SetChamferRatio( 0.2 );
|
||||
m_padStack.SetChamferPositions( RECT_NO_CHAMFER );
|
||||
|
||||
// Set layers mask to default for a standard thru hole pad.
|
||||
m_layerMask = PTHMask();
|
||||
m_padStack.SetLayerSet( PTHMask() );
|
||||
|
||||
SetSubRatsnest( 0 ); // used in ratsnest calculations
|
||||
|
||||
SetDirty();
|
||||
m_effectiveBoundingRadius = 0;
|
||||
m_removeUnconnectedLayer = false;
|
||||
m_keepTopBottomLayer = true;
|
||||
|
||||
m_zoneLayerOverrides.fill( ZLO_NONE );
|
||||
}
|
||||
|
@ -132,8 +125,6 @@ PAD& PAD::operator=( const PAD &aOther )
|
|||
SetPinFunction( aOther.GetPinFunction() );
|
||||
SetSubRatsnest( aOther.GetSubRatsnest() );
|
||||
m_effectiveBoundingRadius = aOther.m_effectiveBoundingRadius;
|
||||
m_removeUnconnectedLayer = aOther.m_removeUnconnectedLayer;
|
||||
m_keepTopBottomLayer = aOther.m_keepTopBottomLayer;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -167,21 +158,9 @@ void PAD::Serialize( google::protobuf::Any &aContainer ) const
|
|||
stackLayer->set_shape(
|
||||
ToProtoEnum<PAD_SHAPE, kiapi::board::types::PadStackShape>( GetShape() ) );
|
||||
|
||||
kiapi::board::types::UnconnectedLayerRemoval ulr;
|
||||
|
||||
if( m_removeUnconnectedLayer )
|
||||
{
|
||||
if( m_keepTopBottomLayer )
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END;
|
||||
else
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP;
|
||||
}
|
||||
|
||||
padstack->set_unconnected_layer_removal( ulr );
|
||||
padstack->set_unconnected_layer_removal(
|
||||
ToProtoEnum<PADSTACK::UNCONNECTED_LAYER_MODE,
|
||||
kiapi::board::types::UnconnectedLayerRemoval>( GetUnconnectedLayerMode() ) );
|
||||
|
||||
kiapi::board::types::DesignRuleOverrides* overrides = pad.mutable_overrides();
|
||||
|
||||
|
@ -240,24 +219,8 @@ bool PAD::Deserialize( const google::protobuf::Any &aContainer )
|
|||
SetShape( FromProtoEnum<PAD_SHAPE>( layer.shape() ) );
|
||||
}
|
||||
|
||||
switch( padstack.unconnected_layer_removal() )
|
||||
{
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE:
|
||||
m_removeUnconnectedLayer = true;
|
||||
m_keepTopBottomLayer = false;
|
||||
break;
|
||||
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END:
|
||||
m_removeUnconnectedLayer = true;
|
||||
m_keepTopBottomLayer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP:
|
||||
m_removeUnconnectedLayer = false;
|
||||
m_keepTopBottomLayer = false;
|
||||
break;
|
||||
}
|
||||
SetUnconnectedLayerMode(
|
||||
FromProtoEnum<PADSTACK::UNCONNECTED_LAYER_MODE>( padstack.unconnected_layer_removal() ) );
|
||||
|
||||
const kiapi::board::types::DesignRuleOverrides& overrides = pad.overrides();
|
||||
|
||||
|
@ -453,13 +416,18 @@ bool PAD::FlashLayer( int aLayer, bool aOnlyCheckIfPermitted ) const
|
|||
if( GetProperty() == PAD_PROP::HEATSINK )
|
||||
return true;
|
||||
|
||||
if( !m_removeUnconnectedLayer )
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE mode = m_padStack.UnconnectedLayerMode();
|
||||
|
||||
if( mode == PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL )
|
||||
return true;
|
||||
|
||||
// Plated through hole pads need copper on the top/bottom layers for proper soldering
|
||||
// Unless the user has removed them in the pad dialog
|
||||
if( m_keepTopBottomLayer && ( aLayer == F_Cu || aLayer == B_Cu ) )
|
||||
if( mode == PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END
|
||||
&& ( aLayer == F_Cu || aLayer == B_Cu ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( const BOARD* board = GetBoard() )
|
||||
{
|
||||
|
@ -482,22 +450,19 @@ bool PAD::FlashLayer( int aLayer, bool aOnlyCheckIfPermitted ) const
|
|||
|
||||
int PAD::GetRoundRectCornerRadius() const
|
||||
{
|
||||
return KiROUND( std::min( m_size.x, m_size.y ) * m_roundedCornerScale );
|
||||
return m_padStack.RoundRectRadius();
|
||||
}
|
||||
|
||||
|
||||
void PAD::SetRoundRectCornerRadius( double aRadius )
|
||||
{
|
||||
int min_r = std::min( m_size.x, m_size.y );
|
||||
|
||||
if( min_r > 0 )
|
||||
SetRoundRectRadiusRatio( aRadius / min_r );
|
||||
m_padStack.SetRoundRectRadius( aRadius );
|
||||
}
|
||||
|
||||
|
||||
void PAD::SetRoundRectRadiusRatio( double aRadiusScale )
|
||||
{
|
||||
m_roundedCornerScale = alg::clamp( 0.0, aRadiusScale, 0.5 );
|
||||
m_padStack.SetRoundRectRadiusRatio( alg::clamp( 0.0, aRadiusScale, 0.5 ) );
|
||||
|
||||
SetDirty();
|
||||
}
|
||||
|
@ -505,7 +470,7 @@ void PAD::SetRoundRectRadiusRatio( double aRadiusScale )
|
|||
|
||||
void PAD::SetChamferRectRatio( double aChamferScale )
|
||||
{
|
||||
m_chamferScale = alg::clamp( 0.0, aChamferScale, 0.5 );
|
||||
m_padStack.SetChamferRatio( alg::clamp( 0.0, aChamferScale, 0.5 ) );
|
||||
|
||||
SetDirty();
|
||||
}
|
||||
|
@ -597,6 +562,7 @@ void PAD::BuildEffectiveShapes( PCB_LAYER_ID aLayer ) const
|
|||
|
||||
VECTOR2I shapePos = ShapePos(); // Fetch only once; rotation involves trig
|
||||
PAD_SHAPE effectiveShape = GetShape();
|
||||
const VECTOR2I& size = m_padStack.Size( aLayer );
|
||||
|
||||
if( GetShape() == PAD_SHAPE::CUSTOM )
|
||||
effectiveShape = GetAnchorPadShape();
|
||||
|
@ -604,17 +570,17 @@ void PAD::BuildEffectiveShapes( PCB_LAYER_ID aLayer ) const
|
|||
switch( effectiveShape )
|
||||
{
|
||||
case PAD_SHAPE::CIRCLE:
|
||||
add( new SHAPE_CIRCLE( shapePos, m_size.x / 2 ) );
|
||||
add( new SHAPE_CIRCLE( shapePos, size.x / 2 ) );
|
||||
break;
|
||||
|
||||
case PAD_SHAPE::OVAL:
|
||||
if( m_size.x == m_size.y ) // the oval pad is in fact a circle
|
||||
if( size.x == size.y ) // the oval pad is in fact a circle
|
||||
{
|
||||
add( new SHAPE_CIRCLE( shapePos, m_size.x / 2 ) );
|
||||
add( new SHAPE_CIRCLE( shapePos, size.x / 2 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
VECTOR2I half_size = m_size / 2;
|
||||
VECTOR2I half_size = size / 2;
|
||||
int half_width = std::min( half_size.x, half_size.y );
|
||||
VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
|
||||
RotatePoint( half_len, m_orient );
|
||||
|
@ -628,7 +594,7 @@ void PAD::BuildEffectiveShapes( PCB_LAYER_ID aLayer ) const
|
|||
case PAD_SHAPE::ROUNDRECT:
|
||||
{
|
||||
int r = ( effectiveShape == PAD_SHAPE::ROUNDRECT ) ? GetRoundRectCornerRadius() : 0;
|
||||
VECTOR2I half_size( m_size.x / 2, m_size.y / 2 );
|
||||
VECTOR2I half_size( size.x / 2, size.y / 2 );
|
||||
VECTOR2I trap_delta( 0, 0 );
|
||||
|
||||
if( r )
|
||||
|
@ -647,7 +613,7 @@ void PAD::BuildEffectiveShapes( PCB_LAYER_ID aLayer ) const
|
|||
}
|
||||
else if( effectiveShape == PAD_SHAPE::TRAPEZOID )
|
||||
{
|
||||
trap_delta = m_deltaSize / 2;
|
||||
trap_delta = m_padStack.TrapezoidDeltaSize( aLayer ) / 2;
|
||||
}
|
||||
|
||||
SHAPE_LINE_CHAIN corners;
|
||||
|
@ -735,7 +701,7 @@ void PAD::BuildEffectiveShapes( PCB_LAYER_ID aLayer ) const
|
|||
m_effectiveBoundingBox = m_effectiveShape->BBox();
|
||||
|
||||
// Hole shape
|
||||
VECTOR2I half_size = m_drill / 2;
|
||||
VECTOR2I half_size = m_padStack.Drill().size / 2;
|
||||
int half_width = std::min( half_size.x, half_size.y );
|
||||
VECTOR2I half_len( half_size.x - half_width, half_size.y - half_width );
|
||||
|
||||
|
@ -808,31 +774,33 @@ void PAD::SetAttribute( PAD_ATTRIB aAttribute )
|
|||
{
|
||||
m_attribute = aAttribute;
|
||||
|
||||
LSET& layerMask = m_padStack.LayerSet();
|
||||
|
||||
switch( aAttribute )
|
||||
{
|
||||
case PAD_ATTRIB::PTH:
|
||||
// Plump up to all copper layers
|
||||
m_layerMask |= LSET::AllCuMask();
|
||||
layerMask |= LSET::AllCuMask();
|
||||
break;
|
||||
|
||||
case PAD_ATTRIB::SMD:
|
||||
case PAD_ATTRIB::CONN:
|
||||
{
|
||||
// Trim down to no more than one copper layer
|
||||
LSET copperLayers = m_layerMask & LSET::AllCuMask();
|
||||
LSET copperLayers = layerMask & LSET::AllCuMask();
|
||||
|
||||
if( copperLayers.count() > 1 )
|
||||
{
|
||||
m_layerMask &= ~LSET::AllCuMask();
|
||||
layerMask &= ~LSET::AllCuMask();
|
||||
|
||||
if( copperLayers.test( B_Cu ) )
|
||||
m_layerMask.set( B_Cu );
|
||||
layerMask.set( B_Cu );
|
||||
else
|
||||
m_layerMask.set( copperLayers.Seq().front() );
|
||||
layerMask.set( copperLayers.Seq().front() );
|
||||
}
|
||||
|
||||
// No hole
|
||||
m_drill = VECTOR2I( 0, 0 );
|
||||
m_padStack.Drill().size = VECTOR2I( 0, 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -888,14 +856,14 @@ void PAD::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
|
|||
if( aFlipLeftRight )
|
||||
{
|
||||
MIRROR( m_pos.x, aCentre.x );
|
||||
MIRROR( m_offset.x, 0 );
|
||||
MIRROR( m_deltaSize.x, 0 );
|
||||
MIRROR( m_padStack.Offset().x, 0 );
|
||||
MIRROR( m_padStack.TrapezoidDeltaSize().x, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
MIRROR( m_pos.y, aCentre.y );
|
||||
MIRROR( m_offset.y, 0 );
|
||||
MIRROR( m_deltaSize.y, 0 );
|
||||
MIRROR( m_padStack.Offset().y, 0 );
|
||||
MIRROR( m_padStack.TrapezoidDeltaSize().y, 0 );
|
||||
}
|
||||
|
||||
SetFPRelativeOrientation( -GetFPRelativeOrientation() );
|
||||
|
@ -917,20 +885,24 @@ void PAD::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
|
|||
|
||||
if( aFlipLeftRight )
|
||||
{
|
||||
mirrorBitFlags( m_chamferPositions, RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_TOP_RIGHT );
|
||||
mirrorBitFlags( m_chamferPositions, RECT_CHAMFER_BOTTOM_LEFT, RECT_CHAMFER_BOTTOM_RIGHT );
|
||||
mirrorBitFlags( m_padStack.ChamferPositions(), RECT_CHAMFER_TOP_LEFT,
|
||||
RECT_CHAMFER_TOP_RIGHT );
|
||||
mirrorBitFlags( m_padStack.ChamferPositions(), RECT_CHAMFER_BOTTOM_LEFT,
|
||||
RECT_CHAMFER_BOTTOM_RIGHT );
|
||||
}
|
||||
else
|
||||
{
|
||||
mirrorBitFlags( m_chamferPositions, RECT_CHAMFER_TOP_LEFT, RECT_CHAMFER_BOTTOM_LEFT );
|
||||
mirrorBitFlags( m_chamferPositions, RECT_CHAMFER_TOP_RIGHT, RECT_CHAMFER_BOTTOM_RIGHT );
|
||||
mirrorBitFlags( m_padStack.ChamferPositions(), RECT_CHAMFER_TOP_LEFT,
|
||||
RECT_CHAMFER_BOTTOM_LEFT );
|
||||
mirrorBitFlags( m_padStack.ChamferPositions(), RECT_CHAMFER_TOP_RIGHT,
|
||||
RECT_CHAMFER_BOTTOM_RIGHT );
|
||||
}
|
||||
|
||||
// flip pads layers
|
||||
// PADS items are currently on all copper layers, or
|
||||
// currently, only on Front or Back layers.
|
||||
// So the copper layers count is not taken in account
|
||||
SetLayerSet( FlipLayerMask( m_layerMask ) );
|
||||
SetLayerSet( FlipLayerMask( m_padStack.LayerSet() ) );
|
||||
|
||||
// Flip the basic shapes, in custom pads
|
||||
FlipPrimitives( aFlipLeftRight );
|
||||
|
@ -950,10 +922,10 @@ void PAD::FlipPrimitives( bool aFlipLeftRight )
|
|||
|
||||
VECTOR2I PAD::ShapePos() const
|
||||
{
|
||||
if( m_offset.x == 0 && m_offset.y == 0 )
|
||||
if( m_padStack.Offset().x == 0 && m_padStack.Offset().y == 0 )
|
||||
return m_pos;
|
||||
|
||||
VECTOR2I loc_offset = m_offset;
|
||||
VECTOR2I loc_offset = m_padStack.Offset();
|
||||
|
||||
RotatePoint( loc_offset, m_orient );
|
||||
|
||||
|
@ -973,14 +945,21 @@ bool PAD::IsOnCopperLayer() const
|
|||
switch( GetShape() )
|
||||
{
|
||||
case PAD_SHAPE::CIRCLE:
|
||||
if( m_offset == VECTOR2I( 0, 0 ) && m_size.x <= m_drill.x )
|
||||
if( m_padStack.Offset() == VECTOR2I( 0, 0 )
|
||||
&& m_padStack.Size().x <= m_padStack.Drill().size.x )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PAD_SHAPE::OVAL:
|
||||
if( m_offset == VECTOR2I( 0, 0 ) && m_size.x <= m_drill.x && m_size.y <= m_drill.y )
|
||||
if( m_padStack.Offset() == VECTOR2I( 0, 0 )
|
||||
&& m_padStack.Size().x <= m_padStack.Drill().size.x
|
||||
&& m_padStack.Size().y <= m_padStack.Drill().size.y )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
@ -997,16 +976,16 @@ bool PAD::IsOnCopperLayer() const
|
|||
|
||||
std::optional<int> PAD::GetLocalClearance( wxString* aSource ) const
|
||||
{
|
||||
if( m_clearance.has_value() && aSource )
|
||||
if( m_padStack.Clearance().has_value() && aSource )
|
||||
*aSource = _( "pad" );
|
||||
|
||||
return m_clearance;
|
||||
return m_padStack.Clearance();
|
||||
}
|
||||
|
||||
|
||||
std::optional<int> PAD::GetClearanceOverrides( wxString* aSource ) const
|
||||
{
|
||||
if( m_clearance.has_value() )
|
||||
if( m_padStack.Clearance().has_value() )
|
||||
return GetLocalClearance( aSource );
|
||||
|
||||
if( FOOTPRINT* parentFootprint = GetParentFootprint() )
|
||||
|
@ -1047,10 +1026,10 @@ int PAD::GetSolderMaskExpansion() const
|
|||
// Pads defined only on mask layers (and perhaps on other tech layers) use the shape
|
||||
// defined by the pad settings only. ALL other pads, even those that don't actually have
|
||||
// any copper (such as NPTH pads with holes the same size as the pad) get mask expansion.
|
||||
if( ( m_layerMask & LSET::AllCuMask() ).none() )
|
||||
if( ( m_padStack.LayerSet() & LSET::AllCuMask() ).none() )
|
||||
return 0;
|
||||
|
||||
std::optional<int> margin = m_solderMaskMargin;
|
||||
std::optional<int> margin = m_padStack.SolderMaskMargin();
|
||||
|
||||
if( !margin.has_value() )
|
||||
{
|
||||
|
@ -1069,7 +1048,7 @@ int PAD::GetSolderMaskExpansion() const
|
|||
// ensure mask have a size always >= 0
|
||||
if( marginValue < 0 )
|
||||
{
|
||||
int minsize = -std::min( m_size.x, m_size.y ) / 2;
|
||||
int minsize = -std::min( m_padStack.Size().x, m_padStack.Size().y ) / 2;
|
||||
|
||||
if( marginValue < minsize )
|
||||
marginValue = minsize;
|
||||
|
@ -1084,11 +1063,11 @@ VECTOR2I PAD::GetSolderPasteMargin() const
|
|||
// Pads defined only on mask layers (and perhaps on other tech layers) use the shape
|
||||
// defined by the pad settings only. ALL other pads, even those that don't actually have
|
||||
// any copper (such as NPTH pads with holes the same size as the pad) get paste expansion.
|
||||
if( ( m_layerMask & LSET::AllCuMask() ).none() )
|
||||
if( ( m_padStack.LayerSet() & LSET::AllCuMask() ).none() )
|
||||
return VECTOR2I( 0, 0 );
|
||||
|
||||
std::optional<int> margin = m_solderPasteMargin;
|
||||
std::optional<double> mratio = m_solderPasteMarginRatio;
|
||||
std::optional<int> margin = m_padStack.SolderPasteMargin();
|
||||
std::optional<double> mratio = m_padStack.SolderPasteMarginRatio();
|
||||
|
||||
if( !margin.has_value() )
|
||||
{
|
||||
|
@ -1115,17 +1094,17 @@ VECTOR2I PAD::GetSolderPasteMargin() const
|
|||
}
|
||||
|
||||
VECTOR2I pad_margin;
|
||||
pad_margin.x = margin.value_or( 0 ) + KiROUND( m_size.x * mratio.value_or( 0 ) );
|
||||
pad_margin.y = margin.value_or( 0 ) + KiROUND( m_size.y * mratio.value_or( 0 ) );
|
||||
pad_margin.x = margin.value_or( 0 ) + KiROUND( m_padStack.Size().x * mratio.value_or( 0 ) );
|
||||
pad_margin.y = margin.value_or( 0 ) + KiROUND( m_padStack.Size().y * mratio.value_or( 0 ) );
|
||||
|
||||
// ensure mask have a size always >= 0
|
||||
if( m_padShape != PAD_SHAPE::CUSTOM )
|
||||
if( m_padStack.Shape() != PAD_SHAPE::CUSTOM )
|
||||
{
|
||||
if( pad_margin.x < -m_size.x / 2 )
|
||||
pad_margin.x = -m_size.x / 2;
|
||||
if( pad_margin.x < -m_padStack.Size().x / 2 )
|
||||
pad_margin.x = -m_padStack.Size().x / 2;
|
||||
|
||||
if( pad_margin.y < -m_size.y / 2 )
|
||||
pad_margin.y = -m_size.y / 2;
|
||||
if( pad_margin.y < -m_padStack.Size().y / 2 )
|
||||
pad_margin.y = -m_padStack.Size().y / 2;
|
||||
}
|
||||
|
||||
return pad_margin;
|
||||
|
@ -1134,7 +1113,7 @@ VECTOR2I PAD::GetSolderPasteMargin() const
|
|||
|
||||
ZONE_CONNECTION PAD::GetZoneConnectionOverrides( wxString* aSource ) const
|
||||
{
|
||||
ZONE_CONNECTION connection = m_zoneConnection;
|
||||
ZONE_CONNECTION connection = m_padStack.ZoneConnection().value_or( ZONE_CONNECTION::INHERITED );
|
||||
|
||||
if( connection != ZONE_CONNECTION::INHERITED )
|
||||
{
|
||||
|
@ -1154,19 +1133,19 @@ ZONE_CONNECTION PAD::GetZoneConnectionOverrides( wxString* aSource ) const
|
|||
|
||||
int PAD::GetLocalSpokeWidthOverride( wxString* aSource ) const
|
||||
{
|
||||
if( m_thermalSpokeWidth > 0 && aSource )
|
||||
if( m_padStack.ThermalSpokeWidth().has_value() && aSource )
|
||||
*aSource = _( "pad" );
|
||||
|
||||
return m_thermalSpokeWidth;
|
||||
return m_padStack.ThermalSpokeWidth().value_or( 0 );
|
||||
}
|
||||
|
||||
|
||||
int PAD::GetLocalThermalGapOverride( wxString* aSource ) const
|
||||
{
|
||||
if( m_thermalGap > 0 && aSource )
|
||||
if( m_padStack.ThermalGap().has_value() && aSource )
|
||||
*aSource = _( "pad" );
|
||||
|
||||
return m_thermalGap;
|
||||
return m_padStack.ThermalGap().value_or( 0 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1235,14 +1214,14 @@ void PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>&
|
|||
aList.emplace_back( ShowPadShape(), props );
|
||||
|
||||
if( ( GetShape() == PAD_SHAPE::CIRCLE || GetShape() == PAD_SHAPE::OVAL )
|
||||
&& m_size.x == m_size.y )
|
||||
&& m_padStack.Size().x == m_padStack.Size().y )
|
||||
{
|
||||
aList.emplace_back( _( "Diameter" ), aFrame->MessageTextFromValue( m_size.x ) );
|
||||
aList.emplace_back( _( "Diameter" ), aFrame->MessageTextFromValue( m_padStack.Size().x ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( m_size.x ) );
|
||||
aList.emplace_back( _( "Height" ), aFrame->MessageTextFromValue( m_size.y ) );
|
||||
aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( m_padStack.Size().x ) );
|
||||
aList.emplace_back( _( "Height" ), aFrame->MessageTextFromValue( m_padStack.Size().y ) );
|
||||
}
|
||||
|
||||
EDA_ANGLE fp_orient = parentFootprint ? parentFootprint->GetOrientation() : ANGLE_0;
|
||||
|
@ -1262,20 +1241,22 @@ void PAD::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>&
|
|||
aFrame->MessageTextFromValue( GetPadToDieLength() ) );
|
||||
}
|
||||
|
||||
if( m_drill.x > 0 || m_drill.y > 0 )
|
||||
const VECTOR2I& drill = m_padStack.Drill().size;
|
||||
|
||||
if( drill.x > 0 || drill.y > 0 )
|
||||
{
|
||||
if( GetDrillShape() == PAD_DRILL_SHAPE::CIRCLE )
|
||||
{
|
||||
aList.emplace_back( _( "Hole" ),
|
||||
wxString::Format( wxT( "%s" ),
|
||||
aFrame->MessageTextFromValue( m_drill.x ) ) );
|
||||
aFrame->MessageTextFromValue( drill.x ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
aList.emplace_back( _( "Hole X / Y" ),
|
||||
wxString::Format( wxT( "%s / %s" ),
|
||||
aFrame->MessageTextFromValue( m_drill.x ),
|
||||
aFrame->MessageTextFromValue( m_drill.y ) ) );
|
||||
aFrame->MessageTextFromValue( drill.x ),
|
||||
aFrame->MessageTextFromValue( drill.y ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1354,6 +1335,8 @@ int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
|
|||
{
|
||||
int diff;
|
||||
|
||||
// TODO(JE) move padstack comparision into PADSTACK
|
||||
|
||||
if( ( diff = static_cast<int>( aPadRef->GetShape() ) -
|
||||
static_cast<int>( aPadCmp->GetShape() ) ) != 0 )
|
||||
return diff;
|
||||
|
@ -1362,41 +1345,53 @@ int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
|
|||
static_cast<int>( aPadCmp->m_attribute ) ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = static_cast<int>( aPadRef->m_drillShape ) -
|
||||
static_cast<int>( aPadCmp->m_drillShape ) ) != 0 )
|
||||
if( ( diff = static_cast<int>( aPadRef->GetDrillShape() ) -
|
||||
static_cast<int>( aPadCmp->GetDrillShape() ) ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_drill.x - aPadCmp->m_drill.x ) != 0 )
|
||||
if( ( diff = aPadRef->Padstack().Drill().size.x - aPadCmp->Padstack().Drill().size.x ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_drill.y - aPadCmp->m_drill.y ) != 0 )
|
||||
if( ( diff = aPadRef->Padstack().Drill().size.y - aPadCmp->Padstack().Drill().size.y ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_size.x - aPadCmp->m_size.x ) != 0 )
|
||||
if( ( diff = aPadRef->m_padStack.Size().x - aPadCmp->m_padStack.Size().x ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_size.y - aPadCmp->m_size.y ) != 0 )
|
||||
if( ( diff = aPadRef->m_padStack.Size().y - aPadCmp->m_padStack.Size().y ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_offset.x - aPadCmp->m_offset.x ) != 0 )
|
||||
if( ( diff = aPadRef->m_padStack.Offset().x - aPadCmp->m_padStack.Offset().x ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_offset.y - aPadCmp->m_offset.y ) != 0 )
|
||||
if( ( diff = aPadRef->m_padStack.Offset().y - aPadCmp->m_padStack.Offset().y ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_deltaSize.x - aPadCmp->m_deltaSize.x ) != 0 )
|
||||
if( ( diff = aPadRef->m_padStack.TrapezoidDeltaSize().x
|
||||
- aPadCmp->m_padStack.TrapezoidDeltaSize().x )
|
||||
!= 0 )
|
||||
{
|
||||
return diff;
|
||||
}
|
||||
|
||||
if( ( diff = aPadRef->m_padStack.TrapezoidDeltaSize().y
|
||||
- aPadCmp->m_padStack.TrapezoidDeltaSize().y )
|
||||
!= 0 )
|
||||
{
|
||||
return diff;
|
||||
}
|
||||
|
||||
if( ( diff = aPadRef->m_padStack.RoundRectRadiusRatio()
|
||||
- aPadCmp->m_padStack.RoundRectRadiusRatio() )
|
||||
!= 0 )
|
||||
{
|
||||
return diff;
|
||||
}
|
||||
|
||||
if( ( diff = aPadRef->m_padStack.ChamferPositions() - aPadCmp->m_padStack.ChamferPositions() ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_deltaSize.y - aPadCmp->m_deltaSize.y ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_roundedCornerScale - aPadCmp->m_roundedCornerScale ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_chamferPositions - aPadCmp->m_chamferPositions ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = aPadRef->m_chamferScale - aPadCmp->m_chamferScale ) != 0 )
|
||||
if( ( diff = aPadRef->m_padStack.ChamferRatio() - aPadCmp->m_padStack.ChamferRatio() ) != 0 )
|
||||
return diff;
|
||||
|
||||
if( ( diff = static_cast<int>( aPadRef->m_editPrimitives.size() ) -
|
||||
|
@ -1410,7 +1405,7 @@ int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
|
|||
// Lorenzo: gencad also needs it to implement padstacks!
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
long long d = aPadRef->m_layerMask.to_ullong() - aPadCmp->m_layerMask.to_ullong();
|
||||
long long d = aPadRef->GetLayerSet().to_ullong() - aPadCmp->GetLayerSet().to_ullong();
|
||||
|
||||
if( d < 0 )
|
||||
return -1;
|
||||
|
@ -1420,8 +1415,8 @@ int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
|
|||
return 0;
|
||||
#else
|
||||
// these strings are not typically constructed, since we don't get here often.
|
||||
std::string s1 = aPadRef->m_layerMask.to_string();
|
||||
std::string s2 = aPadCmp->m_layerMask.to_string();
|
||||
std::string s1 = aPadRef->GetLayerSet().to_string();
|
||||
std::string s2 = aPadCmp->GetLayerSet().to_string();
|
||||
return s1.compare( s2 );
|
||||
#endif
|
||||
}
|
||||
|
@ -1687,6 +1682,7 @@ const BOX2I PAD::ViewBBox() const
|
|||
|
||||
void PAD::ImportSettingsFrom( const PAD& aMasterPad )
|
||||
{
|
||||
SetPadstack( aMasterPad.Padstack() );
|
||||
SetShape( aMasterPad.GetShape() );
|
||||
// Layer Set should be updated before calling SetAttribute()
|
||||
SetLayerSet( aMasterPad.GetLayerSet() );
|
||||
|
@ -1717,9 +1713,6 @@ void PAD::ImportSettingsFrom( const PAD& aMasterPad )
|
|||
|
||||
SetOrientation( pad_rot );
|
||||
|
||||
SetRemoveUnconnected( aMasterPad.GetRemoveUnconnected() );
|
||||
SetKeepTopBottom( aMasterPad.GetKeepTopBottom() );
|
||||
|
||||
SetSize( aMasterPad.GetSize() );
|
||||
SetDelta( VECTOR2I( 0, 0 ) );
|
||||
SetOffset( aMasterPad.GetOffset() );
|
||||
|
@ -1813,8 +1806,8 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
|
|||
// This minimal value is mainly for very small pads, like SM0402.
|
||||
// Most of time pads are using the segment count given by aError value.
|
||||
const int pad_min_seg_per_circle_count = 16;
|
||||
int dx = m_size.x / 2;
|
||||
int dy = m_size.y / 2;
|
||||
int dx = m_padStack.Size().x / 2;
|
||||
int dy = m_padStack.Size().y / 2;
|
||||
|
||||
VECTOR2I padShapePos = ShapePos(); // Note: for pad having a shape offset, the pad
|
||||
// position is NOT the shape position
|
||||
|
@ -1846,11 +1839,11 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
|
|||
case PAD_SHAPE::TRAPEZOID:
|
||||
case PAD_SHAPE::RECTANGLE:
|
||||
{
|
||||
int ddx = GetShape() == PAD_SHAPE::TRAPEZOID ? m_deltaSize.x / 2 : 0;
|
||||
int ddy = GetShape() == PAD_SHAPE::TRAPEZOID ? m_deltaSize.y / 2 : 0;
|
||||
int ddx = GetShape() == PAD_SHAPE::TRAPEZOID ? m_padStack.TrapezoidDeltaSize().x / 2 : 0;
|
||||
int ddy = GetShape() == PAD_SHAPE::TRAPEZOID ? m_padStack.TrapezoidDeltaSize().y / 2 : 0;
|
||||
|
||||
SHAPE_POLY_SET outline;
|
||||
TransformTrapezoidToPolygon( outline, padShapePos, m_size, m_orient, ddx, ddy, aClearance,
|
||||
TransformTrapezoidToPolygon( outline, padShapePos, m_padStack.Size(), m_orient, ddx, ddy, aClearance,
|
||||
aMaxError, aErrorLoc );
|
||||
aBuffer.Append( outline );
|
||||
break;
|
||||
|
@ -1862,7 +1855,7 @@ void PAD::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
|
|||
bool doChamfer = GetShape() == PAD_SHAPE::CHAMFERED_RECT;
|
||||
|
||||
SHAPE_POLY_SET outline;
|
||||
TransformRoundChamferedRectToPolygon( outline, padShapePos, m_size, m_orient,
|
||||
TransformRoundChamferedRectToPolygon( outline, padShapePos, m_padStack.Size(), m_orient,
|
||||
GetRoundRectCornerRadius(),
|
||||
doChamfer ? GetChamferRectRatio() : 0,
|
||||
doChamfer ? GetChamferPositions() : 0,
|
||||
|
@ -2129,6 +2122,12 @@ static struct PAD_DESC
|
|||
.Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
|
||||
}
|
||||
|
||||
ENUM_MAP<PADSTACK::UNCONNECTED_LAYER_MODE>::Instance()
|
||||
.Map( PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL, _HKI( "All copper layers" ) )
|
||||
.Map( PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL, _HKI( "Connected layers only" ) )
|
||||
.Map( PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END,
|
||||
_HKI( "Front, back and connected layers" ) );
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
REGISTER_TYPE( PAD );
|
||||
propMgr.InheritsAfter( TYPE_HASH( PAD ), TYPE_HASH( BOARD_CONNECTED_ITEM ) );
|
||||
|
@ -2230,6 +2229,11 @@ static struct PAD_DESC
|
|||
propMgr.AddProperty( new PROPERTY_ENUM<PAD, PAD_PROP>( _HKI( "Fabrication Property" ),
|
||||
&PAD::SetProperty, &PAD::GetProperty ), groupPad );
|
||||
|
||||
auto layerMode = new PROPERTY_ENUM<PAD, PADSTACK::UNCONNECTED_LAYER_MODE>(
|
||||
_HKI( "Copper Layers" ),
|
||||
&PAD::SetUnconnectedLayerMode, &PAD::GetUnconnectedLayerMode );
|
||||
propMgr.AddProperty( layerMode, groupPad );
|
||||
|
||||
auto padToDie = new PROPERTY<PAD, int>( _HKI( "Pad To Die Length" ),
|
||||
&PAD::SetPadToDieLength, &PAD::GetPadToDieLength,
|
||||
PROPERTY_DISPLAY::PT_SIZE );
|
||||
|
|
279
pcbnew/pad.h
279
pcbnew/pad.h
|
@ -40,12 +40,6 @@ class PCB_SHAPE;
|
|||
class SHAPE;
|
||||
class SHAPE_SEGMENT;
|
||||
|
||||
enum CUST_PAD_SHAPE_IN_ZONE
|
||||
{
|
||||
CUST_PAD_SHAPE_IN_ZONE_OUTLINE,
|
||||
CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL
|
||||
};
|
||||
|
||||
class LINE_READER;
|
||||
class EDA_3D_CANVAS;
|
||||
class FOOTPRINT;
|
||||
|
@ -183,14 +177,14 @@ public:
|
|||
*/
|
||||
void SetShape( PAD_SHAPE aShape )
|
||||
{
|
||||
m_padShape = aShape;
|
||||
m_padStack.SetShape( aShape );
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the shape of this pad.
|
||||
*/
|
||||
PAD_SHAPE GetShape() const { return m_padShape; }
|
||||
PAD_SHAPE GetShape() const { return m_padStack.Shape(); }
|
||||
|
||||
void SetPosition( const VECTOR2I& aPos ) override
|
||||
{
|
||||
|
@ -203,14 +197,17 @@ public:
|
|||
/**
|
||||
* @return the shape of the anchor pad shape, for custom shaped pads.
|
||||
*/
|
||||
PAD_SHAPE GetAnchorPadShape() const { return m_anchorPadShape; }
|
||||
PAD_SHAPE GetAnchorPadShape() const
|
||||
{
|
||||
return m_padStack.AnchorShape();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the option for the custom pad shape to use as clearance area in copper zones.
|
||||
*/
|
||||
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
|
||||
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
|
||||
{
|
||||
return m_customShapeClearanceArea;
|
||||
return m_padStack.CustomShapeInZoneMode();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,9 +215,9 @@ public:
|
|||
*
|
||||
* @param aOption is the clearance area shape CUST_PAD_SHAPE_IN_ZONE option
|
||||
*/
|
||||
void SetCustomShapeInZoneOpt( CUST_PAD_SHAPE_IN_ZONE aOption )
|
||||
void SetCustomShapeInZoneOpt( PADSTACK::CUSTOM_SHAPE_ZONE_MODE aOption )
|
||||
{
|
||||
m_customShapeClearanceArea = aOption;
|
||||
m_padStack.SetCustomShapeInZoneMode( aOption );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,7 +228,9 @@ public:
|
|||
*/
|
||||
void SetAnchorPadShape( PAD_SHAPE aShape )
|
||||
{
|
||||
m_anchorPadShape = ( aShape == PAD_SHAPE::RECTANGLE ) ? PAD_SHAPE::RECTANGLE : PAD_SHAPE::CIRCLE;
|
||||
m_padStack.SetAnchorShape( aShape == PAD_SHAPE::RECTANGLE
|
||||
? PAD_SHAPE::RECTANGLE
|
||||
: PAD_SHAPE::CIRCLE );
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
|
@ -243,28 +242,37 @@ public:
|
|||
void SetY( int y ) { m_pos.y = y; SetDirty(); }
|
||||
void SetX( int x ) { m_pos.x = x; SetDirty(); }
|
||||
|
||||
void SetSize( const VECTOR2I& aSize ) { m_size = aSize; SetDirty(); }
|
||||
const VECTOR2I& GetSize() const { return m_size; }
|
||||
void SetSizeX( const int aX ) { if( aX > 0 ) { m_size.x = aX; SetDirty(); } }
|
||||
int GetSizeX() const { return m_size.x; }
|
||||
void SetSizeY( const int aY ) { if( aY > 0 ) { m_size.y = aY; SetDirty(); } }
|
||||
int GetSizeY() const { return m_size.y; }
|
||||
void SetSize( const VECTOR2I& aSize )
|
||||
{
|
||||
m_padStack.Size() = aSize;
|
||||
SetDirty();
|
||||
}
|
||||
const VECTOR2I& GetSize() const { return m_padStack.Size(); }
|
||||
|
||||
void SetDelta( const VECTOR2I& aSize ) { m_deltaSize = aSize; SetDirty(); }
|
||||
const VECTOR2I& GetDelta() const { return m_deltaSize; }
|
||||
void SetSizeX( const int aX ) { if( aX > 0 ) { m_padStack.Size().x = aX; SetDirty(); } }
|
||||
int GetSizeX() const { return m_padStack.Size().x; }
|
||||
void SetSizeY( const int aY ) { if( aY > 0 ) { m_padStack.Size().y = aY; SetDirty(); } }
|
||||
int GetSizeY() const { return m_padStack.Size().y; }
|
||||
|
||||
void SetDrillSize( const VECTOR2I& aSize ) { m_drill = aSize; SetDirty(); }
|
||||
const VECTOR2I& GetDrillSize() const { return m_drill; }
|
||||
void SetDrillSizeX( const int aX ) { m_drill.x = aX; SetDirty(); }
|
||||
int GetDrillSizeX() const { return m_drill.x; }
|
||||
void SetDrillSizeY( const int aY ) { m_drill.y = aY; SetDirty(); }
|
||||
int GetDrillSizeY() const { return m_drill.y; }
|
||||
void SetDelta( const VECTOR2I& aSize ) { m_padStack.TrapezoidDeltaSize() = aSize; SetDirty(); }
|
||||
const VECTOR2I& GetDelta() const { return m_padStack.TrapezoidDeltaSize(); }
|
||||
|
||||
void SetOffset( const VECTOR2I& aOffset ) { m_offset = aOffset; SetDirty(); }
|
||||
const VECTOR2I& GetOffset() const { return m_offset; }
|
||||
void SetDrillSize( const VECTOR2I& aSize ) { m_padStack.Drill().size = aSize; SetDirty(); }
|
||||
const VECTOR2I& GetDrillSize() const { return m_padStack.Drill().size; }
|
||||
void SetDrillSizeX( const int aX ) { m_padStack.Drill().size.x = aX; SetDirty(); }
|
||||
int GetDrillSizeX() const { return m_padStack.Drill().size.x; }
|
||||
void SetDrillSizeY( const int aY ) { m_padStack.Drill().size.y = aY; SetDirty(); }
|
||||
int GetDrillSizeY() const { return m_padStack.Drill().size.y; }
|
||||
|
||||
void SetOffset( const VECTOR2I& aOffset ) { m_padStack.Offset() = aOffset; SetDirty(); }
|
||||
const VECTOR2I& GetOffset() const { return m_padStack.Offset(); }
|
||||
|
||||
VECTOR2I GetCenter() const override { return GetPosition(); }
|
||||
|
||||
const PADSTACK& Padstack() const { return m_padStack; }
|
||||
PADSTACK& Padstack() { return m_padStack; }
|
||||
void SetPadstack( const PADSTACK& aPadstack ) { m_padStack = aPadstack; }
|
||||
|
||||
/**
|
||||
* Has meaning only for custom shape pads.
|
||||
* add a free shape to the shape list.
|
||||
|
@ -355,8 +363,12 @@ public:
|
|||
return m_orient.AsDegrees();
|
||||
}
|
||||
|
||||
void SetDrillShape( PAD_DRILL_SHAPE aShape ) { m_drillShape = aShape; m_shapesDirty = true; }
|
||||
PAD_DRILL_SHAPE GetDrillShape() const { return m_drillShape; }
|
||||
void SetDrillShape( PAD_DRILL_SHAPE aShape )
|
||||
{
|
||||
m_padStack.Drill().shape = aShape;
|
||||
m_shapesDirty = true;
|
||||
}
|
||||
PAD_DRILL_SHAPE GetDrillShape() const { return m_padStack.Drill().shape; }
|
||||
|
||||
bool IsDirty() const
|
||||
{
|
||||
|
@ -370,8 +382,8 @@ public:
|
|||
m_polyDirty[ERROR_OUTSIDE] = true;
|
||||
}
|
||||
|
||||
void SetLayerSet( LSET aLayers ) override { m_layerMask = aLayers; }
|
||||
LSET GetLayerSet() const override { return m_layerMask; }
|
||||
void SetLayerSet( LSET aLayers ) override { m_padStack.SetLayerSet( aLayers ); }
|
||||
LSET GetLayerSet() const override { return m_padStack.LayerSet(); }
|
||||
|
||||
void SetAttribute( PAD_ATTRIB aAttribute );
|
||||
PAD_ATTRIB GetAttribute() const { return m_attribute; }
|
||||
|
@ -383,26 +395,41 @@ public:
|
|||
// format, so for now just infer a copper-less pad to be an APERTURE pad.
|
||||
bool IsAperturePad() const
|
||||
{
|
||||
return ( m_layerMask & LSET::AllCuMask() ).none();
|
||||
return ( m_padStack.LayerSet() & LSET::AllCuMask() ).none();
|
||||
}
|
||||
|
||||
void SetPadToDieLength( int aLength ) { m_lengthPadToDie = aLength; }
|
||||
int GetPadToDieLength() const { return m_lengthPadToDie; }
|
||||
|
||||
std::optional<int> GetLocalClearance() const override { return m_clearance; }
|
||||
void SetLocalClearance( std::optional<int> aClearance ) { m_clearance = aClearance; }
|
||||
std::optional<int> GetLocalClearance() const override { return m_padStack.Clearance(); }
|
||||
void SetLocalClearance( std::optional<int> aClearance ) { m_padStack.Clearance() = aClearance; }
|
||||
|
||||
std::optional<int> GetLocalSolderMaskMargin() const { return m_solderMaskMargin; }
|
||||
void SetLocalSolderMaskMargin( std::optional<int> aMargin ) { m_solderMaskMargin = aMargin; }
|
||||
std::optional<int> GetLocalSolderMaskMargin() const { return m_padStack.SolderMaskMargin(); }
|
||||
void SetLocalSolderMaskMargin( std::optional<int> aMargin )
|
||||
{
|
||||
m_padStack.SolderMaskMargin() = aMargin;
|
||||
}
|
||||
|
||||
std::optional<int> GetLocalSolderPasteMargin() const { return m_solderPasteMargin; }
|
||||
void SetLocalSolderPasteMargin( std::optional<int> aMargin ) { m_solderPasteMargin = aMargin; }
|
||||
std::optional<int> GetLocalSolderPasteMargin() const { return m_padStack.SolderPasteMargin(); }
|
||||
void SetLocalSolderPasteMargin( std::optional<int> aMargin )
|
||||
{
|
||||
m_padStack.SolderPasteMargin() = aMargin;
|
||||
}
|
||||
|
||||
std::optional<double> GetLocalSolderPasteMarginRatio() const { return m_solderPasteMarginRatio; }
|
||||
void SetLocalSolderPasteMarginRatio( std::optional<double> aRatio ) { m_solderPasteMarginRatio = aRatio; }
|
||||
std::optional<double> GetLocalSolderPasteMarginRatio() const
|
||||
{
|
||||
return m_padStack.SolderPasteMarginRatio();
|
||||
}
|
||||
void SetLocalSolderPasteMarginRatio( std::optional<double> aRatio )
|
||||
{
|
||||
m_padStack.SolderPasteMarginRatio() = aRatio;
|
||||
}
|
||||
|
||||
void SetLocalZoneConnection( ZONE_CONNECTION aType ) { m_zoneConnection = aType; }
|
||||
ZONE_CONNECTION GetLocalZoneConnection() const { return m_zoneConnection; }
|
||||
void SetLocalZoneConnection( ZONE_CONNECTION aType ) { m_padStack.ZoneConnection() = aType; }
|
||||
ZONE_CONNECTION GetLocalZoneConnection() const
|
||||
{
|
||||
return m_padStack.ZoneConnection().value_or( ZONE_CONNECTION::INHERITED );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pad's "own" clearance in internal units.
|
||||
|
@ -518,8 +545,8 @@ public:
|
|||
* Set the width of the thermal spokes connecting the pad to a zone. If != 0 this will
|
||||
* override similar settings in the parent footprint and zone.
|
||||
*/
|
||||
void SetThermalSpokeWidth( int aWidth ) { m_thermalSpokeWidth = aWidth; }
|
||||
int GetThermalSpokeWidth() const { return m_thermalSpokeWidth; }
|
||||
void SetThermalSpokeWidth( int aWidth ) { m_padStack.ThermalSpokeWidth() = aWidth; }
|
||||
int GetThermalSpokeWidth() const { return m_padStack.ThermalSpokeWidth().value_or( 0 ); }
|
||||
|
||||
int GetLocalSpokeWidthOverride( wxString* aSource = nullptr ) const;
|
||||
|
||||
|
@ -528,21 +555,27 @@ public:
|
|||
* pads and circular-anchored custom shaped pads), while 90° will produce a + (the default
|
||||
* for all other shapes).
|
||||
*/
|
||||
void SetThermalSpokeAngle( const EDA_ANGLE& aAngle ) { m_thermalSpokeAngle = aAngle; }
|
||||
EDA_ANGLE GetThermalSpokeAngle() const { return m_thermalSpokeAngle; }
|
||||
void SetThermalSpokeAngle( const EDA_ANGLE& aAngle )
|
||||
{
|
||||
m_padStack.SetThermalSpokeAngle( aAngle );
|
||||
}
|
||||
EDA_ANGLE GetThermalSpokeAngle() const
|
||||
{
|
||||
return m_padStack.ThermalSpokeAngle();
|
||||
}
|
||||
|
||||
// For property system
|
||||
void SetThermalSpokeAngleDegrees( double aAngle )
|
||||
{
|
||||
m_thermalSpokeAngle = EDA_ANGLE( aAngle, DEGREES_T );
|
||||
m_padStack.ThermalSpokeAngle() = EDA_ANGLE( aAngle, DEGREES_T );
|
||||
}
|
||||
double GetThermalSpokeAngleDegrees() const
|
||||
{
|
||||
return m_thermalSpokeAngle.AsDegrees();
|
||||
return m_padStack.ThermalSpokeAngle().AsDegrees();
|
||||
}
|
||||
|
||||
void SetThermalGap( int aGap ) { m_thermalGap = aGap; }
|
||||
int GetThermalGap() const { return m_thermalGap; }
|
||||
void SetThermalGap( int aGap ) { m_padStack.ThermalGap() = aGap; }
|
||||
int GetThermalGap() const { return m_padStack.ThermalGap().value_or( 0 ); }
|
||||
|
||||
int GetLocalThermalGapOverride( wxString* aSource = nullptr ) const;
|
||||
|
||||
|
@ -563,7 +596,7 @@ public:
|
|||
* Cannot be > 0.5; the normalized IPC-7351C value is 0.25
|
||||
*/
|
||||
void SetRoundRectRadiusRatio( double aRadiusScale );
|
||||
double GetRoundRectRadiusRatio() const { return m_roundedCornerScale; }
|
||||
double GetRoundRectRadiusRatio() const { return m_padStack.RoundRectRadiusRatio(); }
|
||||
|
||||
/**
|
||||
* Has meaning only for chamfered rectangular pads.
|
||||
|
@ -572,7 +605,7 @@ public:
|
|||
* Cannot be < 0.5.
|
||||
*/
|
||||
void SetChamferRectRatio( double aChamferScale );
|
||||
double GetChamferRectRatio() const { return m_chamferScale; }
|
||||
double GetChamferRectRatio() const { return m_padStack.ChamferRatio(); }
|
||||
|
||||
/**
|
||||
* Has meaning only for chamfered rectangular pads.
|
||||
|
@ -581,8 +614,8 @@ public:
|
|||
*
|
||||
* @param aPositions a bit-set of #RECT_CHAMFER_POSITIONS.
|
||||
*/
|
||||
void SetChamferPositions( int aPositions ) { m_chamferPositions = aPositions; }
|
||||
int GetChamferPositions() const { return m_chamferPositions; }
|
||||
void SetChamferPositions( int aPositions ) { m_padStack.SetChamferPositions( aPositions ); }
|
||||
int GetChamferPositions() const { return m_padStack.ChamferPositions(); }
|
||||
|
||||
/**
|
||||
* @return the netcode.
|
||||
|
@ -591,27 +624,65 @@ public:
|
|||
void SetSubRatsnest( int aSubRatsnest ) { m_subRatsnest = aSubRatsnest; }
|
||||
|
||||
/**
|
||||
* Set the unconnected removal property.
|
||||
*
|
||||
* If true, the copper is removed on zone fill or when specifically requested when the pad
|
||||
* is not connected on a layer. This requires that there be a through hole.
|
||||
* @deprecated - use Padstack().SetUnconnectedLayerMode()
|
||||
* Sets the unconnected removal property. If true, the copper is removed on zone fill
|
||||
* or when specifically requested when the via is not connected on a layer.
|
||||
*/
|
||||
void SetRemoveUnconnected( bool aSet ) { m_removeUnconnectedLayer = aSet; }
|
||||
bool GetRemoveUnconnected() const { return m_removeUnconnectedLayer; }
|
||||
void SetRemoveUnconnected( bool aSet )
|
||||
{
|
||||
m_padStack.SetUnconnectedLayerMode( aSet
|
||||
? PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL
|
||||
: PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL );
|
||||
}
|
||||
|
||||
bool GetRemoveUnconnected() const
|
||||
{
|
||||
return m_padStack.UnconnectedLayerMode() != PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether we keep the top and bottom connections even if they are not connected.
|
||||
* @deprecated - use Padstack().SetUnconnectedLayerMode()
|
||||
* Sets whether we keep the start and end annular rings even if they are not connected
|
||||
*/
|
||||
void SetKeepTopBottom( bool aSet ) { m_keepTopBottomLayer = aSet; }
|
||||
bool GetKeepTopBottom() const { return m_keepTopBottomLayer; }
|
||||
void SetKeepTopBottom( bool aSet )
|
||||
{
|
||||
m_padStack.SetUnconnectedLayerMode( aSet
|
||||
? PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END
|
||||
: PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL );
|
||||
}
|
||||
|
||||
bool GetKeepTopBottom() const
|
||||
{
|
||||
return m_padStack.UnconnectedLayerMode()
|
||||
== PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END;
|
||||
}
|
||||
|
||||
void SetUnconnectedLayerMode( PADSTACK::UNCONNECTED_LAYER_MODE aMode )
|
||||
{
|
||||
m_padStack.SetUnconnectedLayerMode( aMode );
|
||||
}
|
||||
|
||||
PADSTACK::UNCONNECTED_LAYER_MODE GetUnconnectedLayerMode() const
|
||||
{
|
||||
return m_padStack.UnconnectedLayerMode();
|
||||
}
|
||||
|
||||
bool ConditionallyFlashed( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
if( !m_removeUnconnectedLayer )
|
||||
switch( m_padStack.UnconnectedLayerMode() )
|
||||
{
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL:
|
||||
return false;
|
||||
|
||||
if( m_keepTopBottomLayer && ( aLayer == F_Cu || aLayer == B_Cu ) )
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL:
|
||||
return true;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END:
|
||||
{
|
||||
if( aLayer == m_padStack.Drill().start || aLayer == m_padStack.Drill().end )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -620,7 +691,7 @@ public:
|
|||
|
||||
bool IsOnLayer( PCB_LAYER_ID aLayer ) const override
|
||||
{
|
||||
return m_layerMask[aLayer];
|
||||
return m_padStack.LayerSet().test( aLayer );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -761,10 +832,7 @@ private:
|
|||
|
||||
VECTOR2I m_pos; // Pad Position on board
|
||||
|
||||
PAD_SHAPE m_padShape; // Shape: PAD_SHAPE::CIRCLE, PAD_SHAPE::RECTANGLE,
|
||||
// PAD_SHAPE::OVAL, PAD_SHAPE::TRAPEZOID,
|
||||
// PAD_SHAPE::ROUNDRECT, PAD_SHAPE::CHAMFERED_RECT,
|
||||
// PAD_SHAPE::CUSTOM
|
||||
PADSTACK m_padStack;
|
||||
/*
|
||||
* Editing definitions of primitives for custom pad shapes. In local coordinates relative
|
||||
* to m_Pos (NOT shapePos) at orient 0.
|
||||
|
@ -786,36 +854,6 @@ private:
|
|||
int m_subRatsnest; // Variable used to handle subnet (block) number in
|
||||
// ratsnest computations
|
||||
|
||||
VECTOR2I m_drill; // Drill diameter (x == y) or slot dimensions (x != y)
|
||||
VECTOR2I m_size; // X and Y size (relative to orient 0)
|
||||
|
||||
PAD_DRILL_SHAPE m_drillShape; // PAD_DRILL_SHAPE::CIRCLE, PAD_DRILL_SHAPE::OBLONG
|
||||
|
||||
double m_roundedCornerScale; // Scaling factor of min(width, height) to corner
|
||||
// radius, default 0.25
|
||||
double m_chamferScale; // Scaling factor of min(width, height) to chamfer
|
||||
// size, default 0.25
|
||||
int m_chamferPositions; // The positions of the chamfers (at orient 0)
|
||||
|
||||
PAD_SHAPE m_anchorPadShape; // For custom shaped pads: shape of pad anchor,
|
||||
// PAD_SHAPE::RECTANGLE, PAD_SHAPE::CIRCLE
|
||||
|
||||
/*
|
||||
* Most of the time the hole is the center of the shape (m_Offset = 0). But some designers
|
||||
* use oblong/rect pads with a hole moved to one of the oblong/rect pad shape ends.
|
||||
* In all cases the hole is at the pad position. This offset is from the hole to the center
|
||||
* of the pad shape (ie: the copper area around the hole).
|
||||
* ShapePos() returns the board shape position according to the offset and the pad rotation.
|
||||
*/
|
||||
VECTOR2I m_offset;
|
||||
|
||||
LSET m_layerMask; // Bitwise layer: 1 = copper layer, 15 = cmp,
|
||||
// 2..14 = internal layers, 16..31 = technical layers
|
||||
|
||||
VECTOR2I m_deltaSize; // Delta for PAD_SHAPE::TRAPEZOID; half the delta squeezes
|
||||
// one end and half expands the other. It is only valid
|
||||
// to have a single axis be non-0.
|
||||
|
||||
PAD_ATTRIB m_attribute = PAD_ATTRIB::PTH;
|
||||
|
||||
PAD_PROP m_property; // Property in fab files (BGA, FIDUCIAL, TESTPOINT, etc.)
|
||||
|
@ -824,41 +862,6 @@ private:
|
|||
|
||||
int m_lengthPadToDie; // Length net from pad to die, inside the package
|
||||
|
||||
///< If true, the pad copper is removed for layers that are not connected.
|
||||
bool m_removeUnconnectedLayer;
|
||||
|
||||
///< When removing unconnected pads, keep the top and bottom pads.
|
||||
bool m_keepTopBottomLayer;
|
||||
|
||||
/*
|
||||
* Pad clearances, margins, etc. exist in a hierarchy. If a given level is specified then
|
||||
* the remaining levels are NOT consulted.
|
||||
*
|
||||
* LEVEL 1: (highest priority) local overrides (pad, footprint, etc.)
|
||||
* LEVEL 2: Rules
|
||||
* LEVEL 3: Accumulated local settings, netclass settings, & board design settings
|
||||
*
|
||||
* These are the LEVEL 1 settings (overrides) for a pad.
|
||||
*/
|
||||
std::optional<int> m_clearance;
|
||||
std::optional<int> m_solderMaskMargin; // Solder mask margin
|
||||
std::optional<int> m_solderPasteMargin; // Solder paste margin absolute value
|
||||
std::optional<double> m_solderPasteMarginRatio; // Solder mask margin ratio of pad size
|
||||
// The final margin is the sum of these 2 values
|
||||
|
||||
/*
|
||||
* How to build the custom shape in zone, to create the clearance area:
|
||||
* CUST_PAD_SHAPE_IN_ZONE_OUTLINE = use pad shape
|
||||
* CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL = use the convex hull of the pad shape
|
||||
*/
|
||||
CUST_PAD_SHAPE_IN_ZONE m_customShapeClearanceArea;
|
||||
|
||||
ZONE_CONNECTION m_zoneConnection; // No connection, thermal relief, etc.
|
||||
int m_thermalSpokeWidth; // Thermal spoke width.
|
||||
EDA_ANGLE m_thermalSpokeAngle; // Rotation of the spokes. 45° will produce an X,
|
||||
// while 90° will produce a +.
|
||||
int m_thermalGap;
|
||||
|
||||
std::mutex m_zoneLayerOverridesMutex;
|
||||
std::array<ZONE_LAYER_OVERRIDE, MAX_CU_LAYERS> m_zoneLayerOverrides;
|
||||
};
|
||||
|
|
|
@ -18,11 +18,66 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <convert_basic_shapes_to_polygon.h> // RECT_CHAMFER_POSITIONS
|
||||
#include "padstack.h"
|
||||
|
||||
|
||||
PADSTACK::PADSTACK()
|
||||
PADSTACK::PADSTACK() :
|
||||
m_mode( MODE::NORMAL ),
|
||||
m_unconnectedLayerMode( UNCONNECTED_LAYER_MODE::KEEP_ALL ),
|
||||
m_customShapeInZoneMode( CUSTOM_SHAPE_ZONE_MODE::OUTLINE )
|
||||
{
|
||||
m_defaultCopperProps.shape = SHAPE_PROPS();
|
||||
m_defaultCopperProps.zone_connection = ZONE_CONNECTION::INHERITED;
|
||||
m_defaultCopperProps.thermal_spoke_width = std::nullopt;
|
||||
m_defaultCopperProps.thermal_spoke_angle = ANGLE_45;
|
||||
m_defaultCopperProps.thermal_gap = std::nullopt;
|
||||
|
||||
m_drill.shape = PAD_DRILL_SHAPE::CIRCLE;
|
||||
m_drill.start = F_Cu;
|
||||
m_drill.end = B_Cu;
|
||||
|
||||
m_secondaryDrill.start = UNDEFINED_LAYER;
|
||||
m_secondaryDrill.end = UNDEFINED_LAYER;
|
||||
}
|
||||
|
||||
|
||||
PADSTACK::PADSTACK( const PADSTACK& aOther )
|
||||
{
|
||||
*this = aOther;
|
||||
}
|
||||
|
||||
|
||||
PADSTACK& PADSTACK::operator=( const PADSTACK &aOther )
|
||||
{
|
||||
m_mode = aOther.m_mode;
|
||||
m_layerSet = aOther.m_layerSet;
|
||||
m_customName = aOther.m_customName;
|
||||
m_defaultCopperProps = aOther.m_defaultCopperProps;
|
||||
m_defaultOuterProps = aOther.m_defaultOuterProps;
|
||||
m_unconnectedLayerMode = aOther.m_unconnectedLayerMode;
|
||||
m_copperOverrides = aOther.m_copperOverrides;
|
||||
m_topOverrides = aOther.m_topOverrides;
|
||||
m_bottomOverrides = aOther.m_bottomOverrides;
|
||||
m_drill = aOther.m_drill;
|
||||
m_secondaryDrill = aOther.m_secondaryDrill;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool PADSTACK::operator==( const PADSTACK& aOther ) const
|
||||
{
|
||||
return m_mode == aOther.m_mode
|
||||
&& m_layerSet == aOther.m_layerSet
|
||||
&& m_customName == aOther.m_customName
|
||||
&& m_defaultCopperProps == aOther.m_defaultCopperProps
|
||||
&& m_defaultOuterProps == aOther.m_defaultOuterProps
|
||||
&& m_unconnectedLayerMode == aOther.m_unconnectedLayerMode
|
||||
&& m_copperOverrides == aOther.m_copperOverrides
|
||||
&& m_topOverrides == aOther.m_topOverrides
|
||||
&& m_bottomOverrides == aOther.m_bottomOverrides
|
||||
&& m_drill == aOther.m_drill
|
||||
&& m_secondaryDrill == aOther.m_secondaryDrill;
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,5 +94,290 @@ void PADSTACK::Serialize( google::protobuf::Any& aContainer ) const
|
|||
|
||||
wxString PADSTACK::Name() const
|
||||
{
|
||||
// TODO
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
PADSTACK::SHAPE_PROPS::SHAPE_PROPS() :
|
||||
shape( PAD_SHAPE::CIRCLE ),
|
||||
anchor_shape( PAD_SHAPE::CIRCLE ),
|
||||
round_rect_corner_radius( 0 ),
|
||||
round_rect_radius_ratio( 0.25 ),
|
||||
chamfered_rect_ratio( 0.2 ),
|
||||
chamfered_rect_positions( RECT_NO_CHAMFER )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PADSTACK::SHAPE_PROPS::operator==( const SHAPE_PROPS& aOther ) const
|
||||
{
|
||||
return shape == aOther.shape && offset == aOther.offset
|
||||
&& round_rect_corner_radius == aOther.round_rect_corner_radius
|
||||
&& round_rect_radius_ratio == aOther.round_rect_radius_ratio
|
||||
&& chamfered_rect_ratio == aOther.chamfered_rect_ratio
|
||||
&& chamfered_rect_positions == aOther.chamfered_rect_positions;
|
||||
}
|
||||
|
||||
|
||||
bool PADSTACK::COPPER_LAYER_PROPS::operator==( const COPPER_LAYER_PROPS& aOther ) const
|
||||
{
|
||||
return shape == aOther.shape && zone_connection == aOther.zone_connection
|
||||
&& thermal_spoke_width == aOther.thermal_spoke_width
|
||||
&& thermal_spoke_angle == aOther.thermal_spoke_angle
|
||||
&& thermal_gap == aOther.thermal_gap
|
||||
&& custom_shapes == aOther.custom_shapes;
|
||||
}
|
||||
|
||||
|
||||
bool PADSTACK::OUTER_LAYER_PROPS::operator==( const OUTER_LAYER_PROPS& aOther ) const
|
||||
{
|
||||
return solder_mask_margin == aOther.solder_mask_margin
|
||||
&& solder_paste_margin == aOther.solder_paste_margin
|
||||
&& solder_paste_margin_ratio == aOther.solder_paste_margin_ratio
|
||||
&& has_solder_mask == aOther.has_solder_mask
|
||||
&& has_solder_paste == aOther.has_solder_paste;
|
||||
}
|
||||
|
||||
|
||||
bool PADSTACK::DRILL_PROPS::operator==( const DRILL_PROPS& aOther ) const
|
||||
{
|
||||
return size == aOther.size && shape == aOther.shape
|
||||
&& start == aOther.start && end == aOther.end;
|
||||
}
|
||||
|
||||
|
||||
PAD_SHAPE PADSTACK::Shape( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().shape.shape;
|
||||
}
|
||||
|
||||
|
||||
void PADSTACK::SetShape( PAD_SHAPE aShape, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
CopperLayerDefaults().shape.shape = aShape;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I& PADSTACK::Size( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return CopperLayerDefaults().shape.size;
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I& PADSTACK::Size( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().shape.size;
|
||||
}
|
||||
|
||||
|
||||
PAD_DRILL_SHAPE PADSTACK::DrillShape( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return m_drill.shape;
|
||||
}
|
||||
|
||||
|
||||
void PADSTACK::SetDrillShape( PAD_DRILL_SHAPE aShape, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
m_drill.shape = aShape;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I& PADSTACK::Offset( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return CopperLayerDefaults().shape.offset;
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I& PADSTACK::Offset( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().shape.offset;
|
||||
}
|
||||
|
||||
|
||||
PAD_SHAPE PADSTACK::AnchorShape( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().shape.anchor_shape;
|
||||
}
|
||||
|
||||
|
||||
void PADSTACK::SetAnchorShape( PAD_SHAPE aShape, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
CopperLayerDefaults().shape.anchor_shape = aShape;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I& PADSTACK::TrapezoidDeltaSize( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return CopperLayerDefaults().shape.trapezoid_delta_size;
|
||||
}
|
||||
|
||||
|
||||
const VECTOR2I& PADSTACK::TrapezoidDeltaSize( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().shape.trapezoid_delta_size;
|
||||
}
|
||||
|
||||
|
||||
double PADSTACK::RoundRectRadiusRatio( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().shape.round_rect_radius_ratio;
|
||||
}
|
||||
|
||||
|
||||
void PADSTACK::SetRoundRectRadiusRatio( double aRatio, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
CopperLayerDefaults().shape.round_rect_radius_ratio = aRatio;
|
||||
}
|
||||
|
||||
|
||||
int PADSTACK::RoundRectRadius( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
const VECTOR2I& size = Size( aLayer );
|
||||
return KiROUND( std::min( size.x, size.y ) * RoundRectRadiusRatio( aLayer ) );
|
||||
}
|
||||
|
||||
|
||||
void PADSTACK::SetRoundRectRadius( double aRadius, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
const VECTOR2I& size = Size( aLayer );
|
||||
int min_r = std::min( size.x, size.y );
|
||||
|
||||
if( min_r > 0 )
|
||||
SetRoundRectRadiusRatio( aRadius / min_r, aLayer );
|
||||
}
|
||||
|
||||
|
||||
double PADSTACK::ChamferRatio( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().shape.chamfered_rect_ratio;
|
||||
}
|
||||
|
||||
|
||||
void PADSTACK::SetChamferRatio( double aRatio, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
CopperLayerDefaults().shape.chamfered_rect_ratio = aRatio;
|
||||
}
|
||||
|
||||
|
||||
int& PADSTACK::ChamferPositions( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return CopperLayerDefaults().shape.chamfered_rect_positions;
|
||||
}
|
||||
|
||||
|
||||
const int& PADSTACK::ChamferPositions( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().shape.chamfered_rect_positions;
|
||||
}
|
||||
|
||||
|
||||
void PADSTACK::SetChamferPositions( int aPositions, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
CopperLayerDefaults().shape.chamfered_rect_positions = aPositions;
|
||||
}
|
||||
|
||||
|
||||
std::optional<int>& PADSTACK::Clearance( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return CopperLayerDefaults().clearance;
|
||||
}
|
||||
|
||||
|
||||
const std::optional<int>& PADSTACK::Clearance( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().clearance;
|
||||
}
|
||||
|
||||
|
||||
std::optional<int>& PADSTACK::SolderMaskMargin( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return OuterLayerDefaults().solder_mask_margin;
|
||||
}
|
||||
|
||||
|
||||
const std::optional<int>& PADSTACK::SolderMaskMargin( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return OuterLayerDefaults().solder_mask_margin;
|
||||
}
|
||||
|
||||
|
||||
std::optional<int>& PADSTACK::SolderPasteMargin( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return OuterLayerDefaults().solder_paste_margin;
|
||||
}
|
||||
|
||||
|
||||
const std::optional<int>& PADSTACK::SolderPasteMargin( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return OuterLayerDefaults().solder_paste_margin;
|
||||
}
|
||||
|
||||
|
||||
std::optional<double>& PADSTACK::SolderPasteMarginRatio( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return OuterLayerDefaults().solder_paste_margin_ratio;
|
||||
}
|
||||
|
||||
|
||||
const std::optional<double>& PADSTACK::SolderPasteMarginRatio( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return OuterLayerDefaults().solder_paste_margin_ratio;
|
||||
}
|
||||
|
||||
|
||||
std::optional<ZONE_CONNECTION>& PADSTACK::ZoneConnection( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return CopperLayerDefaults().zone_connection;
|
||||
}
|
||||
|
||||
|
||||
const std::optional<ZONE_CONNECTION>& PADSTACK::ZoneConnection( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().zone_connection;
|
||||
}
|
||||
|
||||
|
||||
std::optional<int>& PADSTACK::ThermalSpokeWidth( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return CopperLayerDefaults().thermal_spoke_width;
|
||||
}
|
||||
|
||||
|
||||
const std::optional<int>& PADSTACK::ThermalSpokeWidth( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().thermal_spoke_width;
|
||||
}
|
||||
|
||||
|
||||
std::optional<int>& PADSTACK::ThermalGap( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
return CopperLayerDefaults().thermal_gap;
|
||||
}
|
||||
|
||||
|
||||
const std::optional<int>& PADSTACK::ThermalGap( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
return CopperLayerDefaults().thermal_gap;
|
||||
}
|
||||
|
||||
|
||||
EDA_ANGLE PADSTACK::ThermalSpokeAngle( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
const COPPER_LAYER_PROPS& defaults = CopperLayerDefaults();
|
||||
|
||||
return defaults.thermal_spoke_angle.value_or(
|
||||
( defaults.shape.shape == PAD_SHAPE::CIRCLE
|
||||
|| ( defaults.shape.shape == PAD_SHAPE::CUSTOM
|
||||
&& defaults.shape.anchor_shape == PAD_SHAPE::CIRCLE ) )
|
||||
? ANGLE_45 : ANGLE_90 );
|
||||
}
|
||||
|
||||
|
||||
void PADSTACK::SetThermalSpokeAngle( EDA_ANGLE aAngle, PCB_LAYER_ID aLayer )
|
||||
{
|
||||
CopperLayerDefaults().thermal_spoke_angle = aAngle;
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_ENUM_TO_WXANY( PADSTACK::UNCONNECTED_LAYER_MODE )
|
||||
|
|
|
@ -26,8 +26,14 @@
|
|||
#include <wx/string.h>
|
||||
|
||||
#include <api/serializable.h>
|
||||
#include <geometry/eda_angle.h>
|
||||
#include <layer_ids.h>
|
||||
#include <math/vector2d.h>
|
||||
#include <properties/property.h>
|
||||
#include <zones.h>
|
||||
|
||||
class PCB_SHAPE;
|
||||
|
||||
|
||||
/**
|
||||
* The set of pad shapes, used with PAD::{Set,Get}Shape()
|
||||
|
@ -92,6 +98,19 @@ enum class PAD_PROP
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of
|
||||
* the word. This means that a PCB_PAD has a padstack, but also a PCB_VIA. The padstack for
|
||||
* a pad defines its geometry on copper, soldermask, and paste layers, as well as any drilling
|
||||
* or milling associated with the pad (round or slot hole, back-drilling, etc). Padstacks also
|
||||
* define thermal relief settings for all copper layers, clearance overrides for all copper
|
||||
* layers, and potentially other properties in the future. In other words, the padstack defines
|
||||
* most of the geometric features of a pad on all layers. It does not define electrical properties
|
||||
* or other metadata.
|
||||
*
|
||||
* For padstacks that do not vary between layers, F_Cu is used as the copper layer to store all
|
||||
* padstack properties.
|
||||
*/
|
||||
class PADSTACK : public SERIALIZABLE
|
||||
{
|
||||
public:
|
||||
|
@ -111,35 +130,243 @@ public:
|
|||
CUSTOM ///< Shapes can be defined on arbitrary layers
|
||||
};
|
||||
|
||||
///! Whether or not to remove the copper shape for unconnected layers
|
||||
enum class UNCONNECTED_LAYER_MODE
|
||||
{
|
||||
KEEP_ALL,
|
||||
REMOVE_ALL,
|
||||
REMOVE_EXCEPT_START_AND_END
|
||||
};
|
||||
|
||||
enum class CUSTOM_SHAPE_ZONE_MODE
|
||||
{
|
||||
OUTLINE,
|
||||
CONVEXHULL
|
||||
};
|
||||
|
||||
///! The set of properties that define a pad's shape on a given layer
|
||||
struct SHAPE_PROPS
|
||||
{
|
||||
PAD_SHAPE shape; ///< Shape of the pad
|
||||
PAD_SHAPE anchor_shape; ///< Shape of the anchor when shape == PAD_SHAPE::CUSTOM
|
||||
VECTOR2I size; ///< Size of the shape, or of the anchor pad for custom shape pads
|
||||
|
||||
/*
|
||||
* Most of the time the hole is the center of the shape (m_Offset = 0). But some designers
|
||||
* use oblong/rect pads with a hole moved to one of the oblong/rect pad shape ends.
|
||||
* In all cases the hole is at the pad position. This offset is from the hole to the center
|
||||
* of the pad shape (ie: the copper area around the hole).
|
||||
* ShapePos() returns the board shape position according to the offset and the pad rotation.
|
||||
*/
|
||||
VECTOR2I offset; ///< Offset of the shape center from the pad center
|
||||
|
||||
double round_rect_corner_radius;
|
||||
double round_rect_radius_ratio;
|
||||
double chamfered_rect_ratio; ///< Size of chamfer: ratio of smallest of X,Y size
|
||||
int chamfered_rect_positions; ///< @see RECT_CHAMFER_POSITIONS
|
||||
|
||||
/**
|
||||
* Delta for PAD_SHAPE::TRAPEZOID; half the delta squeezes one end and half expands the
|
||||
* other. It is only valid to have a single axis be non-zero.
|
||||
*/
|
||||
VECTOR2I trapezoid_delta_size;
|
||||
|
||||
SHAPE_PROPS();
|
||||
bool operator==( const SHAPE_PROPS& aOther ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* The features of a padstack that can vary between copper layers
|
||||
* All parameters are optional; leaving them un-set means "use parent/rule defaults"
|
||||
* Pad clearances, margins, etc. exist in a hierarchy. If a given level is specified then
|
||||
* the remaining levels are NOT consulted.
|
||||
*
|
||||
* LEVEL 1: (highest priority) local overrides (pad, footprint, etc.)
|
||||
* LEVEL 2: Rules
|
||||
* LEVEL 3: Accumulated local settings, netclass settings, & board design settings
|
||||
*
|
||||
* These are the LEVEL 1 settings (overrides) for a pad.
|
||||
*/
|
||||
struct COPPER_LAYER_PROPS
|
||||
{
|
||||
SHAPE_PROPS shape;
|
||||
std::optional<ZONE_CONNECTION> zone_connection;
|
||||
std::optional<int> thermal_spoke_width;
|
||||
std::optional<EDA_ANGLE> thermal_spoke_angle;
|
||||
std::optional<int> thermal_gap;
|
||||
std::optional<int> clearance;
|
||||
|
||||
std::vector<std::shared_ptr<PCB_SHAPE>> custom_shapes;
|
||||
|
||||
bool operator==( const COPPER_LAYER_PROPS& aOther ) const;
|
||||
};
|
||||
|
||||
///! The features of a padstack that can vary on outer layers.
|
||||
///! All parameters are optional; leaving them un-set means "use parent/rule defaults"
|
||||
struct OUTER_LAYER_PROPS
|
||||
{
|
||||
std::optional<int> solder_mask_margin;
|
||||
std::optional<int> solder_paste_margin;
|
||||
std::optional<double> solder_paste_margin_ratio;
|
||||
ZONE_CONNECTION zone_connection;
|
||||
std::optional<bool> has_solder_mask; ///< True if this outer layer has mask (is not tented)
|
||||
std::optional<bool> has_solder_paste; ///< True if this outer layer has solder paste
|
||||
|
||||
bool operator==( const OUTER_LAYER_PROPS& aOther ) const;
|
||||
};
|
||||
|
||||
struct INNER_LAYER_PROPS
|
||||
///! The properties of a padstack drill. Drill position is always the pad position (origin).
|
||||
struct DRILL_PROPS
|
||||
{
|
||||
ZONE_CONNECTION zone_connection;
|
||||
VECTOR2I size; ///< Drill diameter (x == y) or slot dimensions (x != y)
|
||||
PAD_DRILL_SHAPE shape;
|
||||
PCB_LAYER_ID start;
|
||||
PCB_LAYER_ID end;
|
||||
|
||||
bool operator==( const DRILL_PROPS& aOther ) const;
|
||||
};
|
||||
|
||||
public:
|
||||
PADSTACK();
|
||||
|
||||
virtual ~PADSTACK() = default;
|
||||
PADSTACK( const PADSTACK& aOther );
|
||||
PADSTACK& operator=( const PADSTACK &aOther );
|
||||
|
||||
bool operator==( const PADSTACK& aOther ) const;
|
||||
bool operator!=( const PADSTACK& aOther ) const { return !operator==( aOther ); }
|
||||
|
||||
void Serialize( google::protobuf::Any &aContainer ) const override;
|
||||
bool Deserialize( const google::protobuf::Any &aContainer ) override;
|
||||
|
||||
const LSET& LayerSet() const { return m_layerSet; }
|
||||
LSET& LayerSet() { return m_layerSet; }
|
||||
void SetLayerSet( const LSET& aSet ) { m_layerSet = aSet; }
|
||||
|
||||
///! Returns the name of this padstack in IPC-7351 format
|
||||
wxString Name() const;
|
||||
|
||||
DRILL_PROPS& Drill() { return m_drill; }
|
||||
const DRILL_PROPS& Drill() const { return m_drill; }
|
||||
|
||||
DRILL_PROPS& SecondaryDrill() { return m_secondaryDrill; }
|
||||
const DRILL_PROPS& SecondaryDrill() const { return m_secondaryDrill; }
|
||||
|
||||
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const { return m_unconnectedLayerMode; }
|
||||
void SetUnconnectedLayerMode( UNCONNECTED_LAYER_MODE aMode ) { m_unconnectedLayerMode = aMode; }
|
||||
|
||||
COPPER_LAYER_PROPS& CopperLayerDefaults() { return m_defaultCopperProps; }
|
||||
const COPPER_LAYER_PROPS& CopperLayerDefaults() const { return m_defaultCopperProps; }
|
||||
|
||||
OUTER_LAYER_PROPS& OuterLayerDefaults() { return m_defaultOuterProps; }
|
||||
const OUTER_LAYER_PROPS& OuterLayerDefaults() const { return m_defaultOuterProps; }
|
||||
|
||||
CUSTOM_SHAPE_ZONE_MODE CustomShapeInZoneMode() const { return m_customShapeInZoneMode; }
|
||||
void SetCustomShapeInZoneMode( CUSTOM_SHAPE_ZONE_MODE aM ) { m_customShapeInZoneMode = aM; }
|
||||
|
||||
// The following section has convenience getters for the padstack properties on a given layer.
|
||||
|
||||
PAD_SHAPE Shape( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
void SetShape( PAD_SHAPE aShape, PCB_LAYER_ID aLayer = F_Cu );
|
||||
|
||||
VECTOR2I& Size( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const VECTOR2I& Size( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
PAD_DRILL_SHAPE DrillShape( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
void SetDrillShape( PAD_DRILL_SHAPE aShape, PCB_LAYER_ID aLayer = F_Cu );
|
||||
|
||||
VECTOR2I& Offset( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const VECTOR2I& Offset( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
PAD_SHAPE AnchorShape( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
void SetAnchorShape( PAD_SHAPE aShape, PCB_LAYER_ID aLayer = F_Cu );
|
||||
|
||||
VECTOR2I& TrapezoidDeltaSize( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const VECTOR2I& TrapezoidDeltaSize( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
double RoundRectRadiusRatio( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
void SetRoundRectRadiusRatio( double aRatio, PCB_LAYER_ID aLayer = F_Cu );
|
||||
|
||||
int RoundRectRadius( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
void SetRoundRectRadius( double aRadius, PCB_LAYER_ID aLayer = F_Cu );
|
||||
|
||||
double ChamferRatio( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
void SetChamferRatio( double aRatio, PCB_LAYER_ID aLayer = F_Cu );
|
||||
|
||||
int& ChamferPositions( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const int& ChamferPositions( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
void SetChamferPositions( int aPositions, PCB_LAYER_ID aLayer = F_Cu );
|
||||
|
||||
std::optional<int>& Clearance( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const std::optional<int>& Clearance( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
std::optional<int>& SolderMaskMargin( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const std::optional<int>& SolderMaskMargin( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
std::optional<int>& SolderPasteMargin( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const std::optional<int>& SolderPasteMargin( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
std::optional<double>& SolderPasteMarginRatio( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const std::optional<double>& SolderPasteMarginRatio( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
std::optional<ZONE_CONNECTION>& ZoneConnection( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const std::optional<ZONE_CONNECTION>& ZoneConnection( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
std::optional<int>& ThermalSpokeWidth( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const std::optional<int>& ThermalSpokeWidth( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
std::optional<int>& ThermalGap( PCB_LAYER_ID aLayer = F_Cu );
|
||||
const std::optional<int>& ThermalGap( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
|
||||
EDA_ANGLE ThermalSpokeAngle( PCB_LAYER_ID aLayer = F_Cu ) const;
|
||||
void SetThermalSpokeAngle( EDA_ANGLE aAngle, PCB_LAYER_ID aLayer = F_Cu );
|
||||
|
||||
private:
|
||||
|
||||
MODE m_mode;
|
||||
|
||||
///! The board layers that this padstack is active on
|
||||
LSET m_layerSet;
|
||||
|
||||
///! An override for the IPC-7351 padstack name
|
||||
wxString m_customName;
|
||||
|
||||
///! The properties applied to copper layers if they aren't overridden
|
||||
COPPER_LAYER_PROPS m_defaultCopperProps;
|
||||
|
||||
///! The properties applied to outer technical layers if they aren't overridden
|
||||
OUTER_LAYER_PROPS m_defaultOuterProps;
|
||||
|
||||
UNCONNECTED_LAYER_MODE m_unconnectedLayerMode;
|
||||
|
||||
/**
|
||||
* How to build the custom shape in zone, to create the clearance area:
|
||||
* CUSTOM_SHAPE_ZONE_MODE::OUTLINE = use pad shape
|
||||
* CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL = use the convex hull of the pad shape
|
||||
*/
|
||||
CUSTOM_SHAPE_ZONE_MODE m_customShapeInZoneMode;
|
||||
|
||||
///! Any entries here override the copper layer settings on the given copper layer.
|
||||
///! If m_mode == MODE::TOP_INNER_BOTTOM, the inner layer setting is always In1_Cu and the only
|
||||
///! keys in this map that are used are F_Cu, In1_Cu, and B_Cu.
|
||||
///! If m_mode == MODE::NORMAL, this map is ignored.
|
||||
std::unordered_map<PCB_LAYER_ID, COPPER_LAYER_PROPS> m_copperOverrides;
|
||||
|
||||
///! Any non-null optional values here override the mask/paste settings for the top layers
|
||||
OUTER_LAYER_PROPS m_topOverrides;
|
||||
|
||||
///! Any non-null optional values here override the mask/paste settings for bottom layers
|
||||
OUTER_LAYER_PROPS m_bottomOverrides;
|
||||
|
||||
///! The primary drill parameters, which also define the start and end layers for through-hole
|
||||
///! vias and pads (F_Cu to B_Cu for normal holes; a subset of layers for blind/buried vias)
|
||||
DRILL_PROPS m_drill;
|
||||
|
||||
///! Secondary drill, used to define back-drilling
|
||||
DRILL_PROPS m_secondaryDrill;
|
||||
};
|
||||
|
||||
#ifndef SWIG
|
||||
DECLARE_ENUM_TO_WXANY( PADSTACK::UNCONNECTED_LAYER_MODE );
|
||||
#endif
|
||||
|
||||
|
||||
#endif //KICAD_PADSTACK_H
|
||||
|
|
|
@ -2568,7 +2568,6 @@ void ALTIUM_PCB::ConvertShapeBasedRegions6ToFootprintItemOnLayer( FOOTPRINT*
|
|||
LSET padLayers;
|
||||
padLayers.set( aLayer );
|
||||
|
||||
pad->SetKeepTopBottom( false ); // TODO: correct? This seems to be KiCad default on import
|
||||
pad->SetAttribute( PAD_ATTRIB::SMD );
|
||||
pad->SetShape( PAD_SHAPE::CUSTOM );
|
||||
pad->SetThermalSpokeAngle( ANGLE_90 );
|
||||
|
@ -3016,8 +3015,6 @@ void ALTIUM_PCB::ConvertPads6ToFootprintItemOnCopper( FOOTPRINT* aFootprint, con
|
|||
{
|
||||
std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
|
||||
|
||||
pad->SetKeepTopBottom( false ); // TODO: correct? This seems to be KiCad default on import
|
||||
|
||||
pad->SetNumber( aElem.name );
|
||||
pad->SetNetCode( GetNetCode( aElem.net ) );
|
||||
|
||||
|
|
|
@ -898,7 +898,6 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryCoppers( const SYMDEF_PCB& aComponen
|
|||
anchorPad = aComponent.ComponentPads.at( compCopper.AssociatedPadIDs.front() );
|
||||
|
||||
std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
|
||||
pad->SetKeepTopBottom( false ); // TODO: correct? This seems to be KiCad default on import
|
||||
pad->SetAttribute( PAD_ATTRIB::SMD );
|
||||
pad->SetLayerSet( copperLayers );
|
||||
pad->SetNumber( anchorPad.Identifier.IsEmpty()
|
||||
|
@ -1342,8 +1341,6 @@ PAD* CADSTAR_PCB_ARCHIVE_LOADER::getKiCadPad( const COMPONENT_PAD& aCadstarPad,
|
|||
m_padcodesTested.insert( csPadcode.ID );
|
||||
}
|
||||
|
||||
pad->SetKeepTopBottom( false ); // TODO: correct? This seems to be KiCad default on import
|
||||
|
||||
return pad.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -2450,8 +2450,6 @@ void PCB_IO_EAGLE::packageHole( FOOTPRINT* aFootprint, wxXmlNode* aTree, bool aC
|
|||
PAD* pad = new PAD( aFootprint );
|
||||
aFootprint->Add( pad );
|
||||
|
||||
pad->SetKeepTopBottom( false ); // TODO: correct? This seems to be KiCad default on import
|
||||
|
||||
pad->SetShape( PAD_SHAPE::CIRCLE );
|
||||
pad->SetAttribute( PAD_ATTRIB::NPTH );
|
||||
|
||||
|
@ -2493,8 +2491,6 @@ void PCB_IO_EAGLE::packageSMD( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
|
|||
aFootprint->Add( pad );
|
||||
transferPad( e, pad );
|
||||
|
||||
pad->SetKeepTopBottom( false ); // TODO: correct? This seems to be KiCad default on import
|
||||
|
||||
pad->SetShape( PAD_SHAPE::RECTANGLE );
|
||||
pad->SetAttribute( PAD_ATTRIB::SMD );
|
||||
|
||||
|
|
|
@ -1697,7 +1697,7 @@ void PCB_IO_KICAD_SEXPR::format( const PAD* aPad, int aNestLevel ) const
|
|||
m_out->Print( 0, "\n");
|
||||
m_out->Print( aNestLevel+1, "(options" );
|
||||
|
||||
if( aPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
if( aPad->GetCustomShapeInZoneOpt() == PADSTACK::CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL )
|
||||
m_out->Print( 0, " (clearance convexhull)" );
|
||||
#if 1 // Set to 1 to output the default option
|
||||
else
|
||||
|
@ -2199,12 +2199,20 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_TRACK* aTrack, int aNestLevel ) const
|
|||
m_out->Quotew( LSET::Name( layer1 ) ).c_str(),
|
||||
m_out->Quotew( LSET::Name( layer2 ) ).c_str() );
|
||||
|
||||
if( via->GetRemoveUnconnected() )
|
||||
switch( via->Padstack().UnconnectedLayerMode() )
|
||||
{
|
||||
KICAD_FORMAT::FormatBool( m_out, 0, "remove_unused_layers",
|
||||
via->GetRemoveUnconnected() );
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL:
|
||||
m_out->Print( 0, "(remove_unused_layers yes)" );
|
||||
m_out->Print( 0, "(keep_end_layers no)" );
|
||||
break;
|
||||
|
||||
KICAD_FORMAT::FormatBool( m_out, 0, "keep_end_layers", via->GetKeepStartEnd() );
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END:
|
||||
m_out->Print( 0, "(remove_unused_layers yes)" );
|
||||
m_out->Print( 0, "(keep_end_layers yes)" );
|
||||
break;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL:
|
||||
break;
|
||||
}
|
||||
|
||||
if( via->IsLocked() )
|
||||
|
|
|
@ -4699,9 +4699,6 @@ PAD* PCB_IO_KICAD_SEXPR_PARSER::parsePAD( FOOTPRINT* aParent )
|
|||
|
||||
std::unique_ptr<PAD> pad = std::make_unique<PAD>( aParent );
|
||||
|
||||
// File only contains a token if KeepTopBottom is true
|
||||
pad->SetKeepTopBottom( false );
|
||||
|
||||
NeedSYMBOLorNUMBER();
|
||||
pad->SetNumber( FromUTF8() );
|
||||
|
||||
|
@ -5286,11 +5283,11 @@ bool PCB_IO_KICAD_SEXPR_PARSER::parsePAD_option( PAD* aPad )
|
|||
switch( token )
|
||||
{
|
||||
case T_outline:
|
||||
aPad->SetCustomShapeInZoneOpt( CUST_PAD_SHAPE_IN_ZONE_OUTLINE );
|
||||
aPad->SetCustomShapeInZoneOpt( PADSTACK::CUSTOM_SHAPE_ZONE_MODE::OUTLINE );
|
||||
break;
|
||||
|
||||
case T_convexhull:
|
||||
aPad->SetCustomShapeInZoneOpt( CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL );
|
||||
aPad->SetCustomShapeInZoneOpt( PADSTACK::CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL );
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -5715,8 +5712,7 @@ PCB_VIA* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_VIA()
|
|||
std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( m_board );
|
||||
|
||||
// File format default is no-token == no-feature.
|
||||
via->SetRemoveUnconnected( false );
|
||||
via->SetKeepStartEnd( false );
|
||||
via->Padstack().SetUnconnectedLayerMode( PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL );
|
||||
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
|
|
|
@ -86,11 +86,11 @@ PCB_VIA::PCB_VIA( BOARD_ITEM* aParent ) :
|
|||
PCB_TRACK( aParent, PCB_VIA_T )
|
||||
{
|
||||
SetViaType( VIATYPE::THROUGH );
|
||||
m_bottomLayer = B_Cu;
|
||||
Padstack().Drill().start = F_Cu;
|
||||
Padstack().Drill().end = B_Cu;
|
||||
SetDrillDefault();
|
||||
|
||||
m_removeUnconnectedLayer = false;
|
||||
m_keepStartEndLayer = true;
|
||||
Padstack().SetUnconnectedLayerMode( PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL );
|
||||
|
||||
m_zoneLayerOverrides.fill( ZLO_NONE );
|
||||
|
||||
|
@ -118,11 +118,8 @@ PCB_VIA& PCB_VIA::operator=( const PCB_VIA &aOther )
|
|||
m_CachedLOD = aOther.m_CachedLOD;
|
||||
m_CachedScale = aOther.m_CachedScale;
|
||||
|
||||
m_bottomLayer = aOther.m_bottomLayer;
|
||||
m_viaType = aOther.m_viaType;
|
||||
m_drill = aOther.m_drill;
|
||||
m_removeUnconnectedLayer = aOther.m_removeUnconnectedLayer;
|
||||
m_keepStartEndLayer = aOther.m_keepStartEndLayer;
|
||||
m_padStack = aOther.m_padStack;
|
||||
m_isFree = aOther.m_isFree;
|
||||
|
||||
return *this;
|
||||
|
@ -249,10 +246,8 @@ bool PCB_VIA::operator==( const BOARD_ITEM& aOther ) const
|
|||
const PCB_VIA& other = static_cast<const PCB_VIA&>( aOther );
|
||||
|
||||
return m_Start == other.m_Start && m_End == other.m_End && m_layer == other.m_layer &&
|
||||
m_bottomLayer == other.m_bottomLayer && m_Width == other.m_Width &&
|
||||
m_viaType == other.m_viaType && m_drill == other.m_drill &&
|
||||
m_removeUnconnectedLayer == other.m_removeUnconnectedLayer &&
|
||||
m_keepStartEndLayer == other.m_keepStartEndLayer &&
|
||||
m_padStack == other.m_padStack && m_Width == other.m_Width &&
|
||||
m_viaType == other.m_viaType &&
|
||||
m_zoneLayerOverrides == other.m_zoneLayerOverrides;
|
||||
}
|
||||
|
||||
|
@ -278,21 +273,12 @@ double PCB_VIA::Similarity( const BOARD_ITEM& aOther ) const
|
|||
if( m_End != other.m_End )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_bottomLayer != other.m_bottomLayer )
|
||||
if( m_padStack != other.m_padStack )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_viaType != other.m_viaType )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_drill != other.m_drill )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_removeUnconnectedLayer != other.m_removeUnconnectedLayer )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_keepStartEndLayer != other.m_keepStartEndLayer )
|
||||
similarity *= 0.9;
|
||||
|
||||
if( m_zoneLayerOverrides != other.m_zoneLayerOverrides )
|
||||
similarity *= 0.9;
|
||||
|
||||
|
@ -389,14 +375,16 @@ void PCB_VIA::Serialize( google::protobuf::Any &aContainer ) const
|
|||
via.mutable_position()->set_x_nm( GetPosition().x );
|
||||
via.mutable_position()->set_y_nm( GetPosition().y );
|
||||
|
||||
const PADSTACK& stack = Padstack();
|
||||
|
||||
kiapi::board::types::PadStack* padstack = via.mutable_pad_stack();
|
||||
padstack->set_type( GetViaType() == VIATYPE::BLIND_BURIED
|
||||
? kiapi::board::types::PadStackType::PST_BLIND_BURIED
|
||||
: kiapi::board::types::PadStackType::PST_THROUGH );
|
||||
padstack->set_start_layer(
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( m_layer ) );
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( stack.Drill().start ) );
|
||||
padstack->set_end_layer(
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( m_bottomLayer ) );
|
||||
ToProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( stack.Drill().end ) );
|
||||
kiapi::common::PackVector2( *padstack->mutable_drill_diameter(),
|
||||
{ GetDrillValue(), GetDrillValue() } );
|
||||
|
||||
|
@ -405,23 +393,12 @@ void PCB_VIA::Serialize( google::protobuf::Any &aContainer ) const
|
|||
kiapi::common::PackVector2( *stackLayer->mutable_size(),
|
||||
{ GetWidth(), GetWidth() } );
|
||||
|
||||
kiapi::board::types::UnconnectedLayerRemoval ulr;
|
||||
|
||||
if( m_removeUnconnectedLayer )
|
||||
{
|
||||
if( m_keepStartEndLayer )
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END;
|
||||
else
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulr = kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP;
|
||||
}
|
||||
|
||||
// TODO: Microvia status is ignored here. Do we still need it?
|
||||
|
||||
padstack->set_unconnected_layer_removal( ulr );
|
||||
padstack->set_unconnected_layer_removal(
|
||||
ToProtoEnum<PADSTACK::UNCONNECTED_LAYER_MODE,
|
||||
kiapi::board::types::UnconnectedLayerRemoval>(
|
||||
Padstack().UnconnectedLayerMode() ) );
|
||||
|
||||
via.set_locked( IsLocked() ? kiapi::common::types::LockedState::LS_LOCKED
|
||||
: kiapi::common::types::LockedState::LS_UNLOCKED );
|
||||
|
@ -466,36 +443,19 @@ bool PCB_VIA::Deserialize( const google::protobuf::Any &aContainer )
|
|||
|
||||
if( GetViaType() != VIATYPE::THROUGH )
|
||||
{
|
||||
m_layer = FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
|
||||
Padstack().Drill().start = FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
|
||||
padstack.start_layer() );
|
||||
|
||||
m_bottomLayer = FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
|
||||
Padstack().Drill().end = FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>(
|
||||
padstack.end_layer() );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_layer = F_Cu;
|
||||
m_bottomLayer = B_Cu;
|
||||
}
|
||||
|
||||
switch( padstack.unconnected_layer_removal() )
|
||||
{
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE:
|
||||
m_removeUnconnectedLayer = true;
|
||||
m_keepStartEndLayer = false;
|
||||
break;
|
||||
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_REMOVE_EXCEPT_START_AND_END:
|
||||
m_removeUnconnectedLayer = true;
|
||||
m_keepStartEndLayer = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
case kiapi::board::types::UnconnectedLayerRemoval::ULR_KEEP:
|
||||
m_removeUnconnectedLayer = false;
|
||||
m_keepStartEndLayer = false;
|
||||
break;
|
||||
Padstack().Drill().start = F_Cu;
|
||||
Padstack().Drill().end = B_Cu;
|
||||
}
|
||||
Padstack().SetUnconnectedLayerMode( FromProtoEnum<PADSTACK::UNCONNECTED_LAYER_MODE>(
|
||||
padstack.unconnected_layer_removal() ) );
|
||||
|
||||
SetNetCode( via.net().code().value() );
|
||||
SetLocked( via.locked() == kiapi::common::types::LockedState::LS_LOCKED );
|
||||
|
@ -599,8 +559,8 @@ int PCB_VIA::GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const
|
|||
|
||||
int PCB_VIA::GetDrillValue() const
|
||||
{
|
||||
if( m_drill > 0 ) // Use the specific value.
|
||||
return m_drill;
|
||||
if( m_padStack.Drill().size.x > 0 ) // Use the specific value.
|
||||
return m_padStack.Drill().size.x;
|
||||
|
||||
// Use the default value from the Netclass
|
||||
NETCLASS* netclass = GetEffectiveNetClass();
|
||||
|
@ -833,7 +793,7 @@ INSPECT_RESULT PCB_TRACK::Visit( INSPECTOR inspector, void* testData,
|
|||
|
||||
std::shared_ptr<SHAPE_SEGMENT> PCB_VIA::GetEffectiveHoleShape() const
|
||||
{
|
||||
return std::make_shared<SHAPE_SEGMENT>( SEG( m_Start, m_Start ), m_drill );
|
||||
return std::make_shared<SHAPE_SEGMENT>( SEG( m_Start, m_Start ), Padstack().Drill().size.x );
|
||||
}
|
||||
|
||||
|
||||
|
@ -862,7 +822,7 @@ bool PCB_VIA::IsOnLayer( PCB_LAYER_ID aLayer ) const
|
|||
return GetLayerSet().test( aLayer );
|
||||
#endif
|
||||
|
||||
if( aLayer >= m_layer && aLayer <= m_bottomLayer )
|
||||
if( aLayer >= Padstack().Drill().start && aLayer <= Padstack().Drill().end )
|
||||
return true;
|
||||
|
||||
if( !IsTented() )
|
||||
|
@ -877,20 +837,32 @@ bool PCB_VIA::IsOnLayer( PCB_LAYER_ID aLayer ) const
|
|||
}
|
||||
|
||||
|
||||
PCB_LAYER_ID PCB_VIA::GetLayer() const
|
||||
{
|
||||
return Padstack().Drill().start;
|
||||
}
|
||||
|
||||
|
||||
void PCB_VIA::SetLayer( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
Padstack().Drill().start = aLayer;
|
||||
}
|
||||
|
||||
|
||||
LSET PCB_VIA::GetLayerSet() const
|
||||
{
|
||||
LSET layermask;
|
||||
|
||||
if( m_layer < PCBNEW_LAYER_ID_START )
|
||||
if( Padstack().Drill().start < PCBNEW_LAYER_ID_START )
|
||||
return layermask;
|
||||
|
||||
if( GetViaType() == VIATYPE::THROUGH )
|
||||
layermask = LSET::AllCuMask();
|
||||
else
|
||||
wxASSERT( m_layer <= m_bottomLayer );
|
||||
wxASSERT( Padstack().Drill().start <= Padstack().Drill().end );
|
||||
|
||||
// PCB_LAYER_IDs are numbered from front to back, this is top to bottom.
|
||||
for( int id = m_layer; id <= m_bottomLayer; ++id )
|
||||
for( int id = Padstack().Drill().start; id <= Padstack().Drill().end; ++id )
|
||||
layermask.set( id );
|
||||
|
||||
if( !IsTented() )
|
||||
|
@ -918,11 +890,11 @@ void PCB_VIA::SetLayerSet( LSET aLayerSet )
|
|||
|
||||
if( first )
|
||||
{
|
||||
m_layer = layer;
|
||||
Padstack().Drill().start = layer;
|
||||
first = false;
|
||||
}
|
||||
|
||||
m_bottomLayer = layer;
|
||||
Padstack().Drill().end = layer;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -930,21 +902,21 @@ void PCB_VIA::SetLayerSet( LSET aLayerSet )
|
|||
void PCB_VIA::SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer )
|
||||
{
|
||||
|
||||
m_layer = aTopLayer;
|
||||
m_bottomLayer = aBottomLayer;
|
||||
Padstack().Drill().start = aTopLayer;
|
||||
Padstack().Drill().end = aBottomLayer;
|
||||
SanitizeLayers();
|
||||
}
|
||||
|
||||
|
||||
void PCB_VIA::SetTopLayer( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
m_layer = aLayer;
|
||||
Padstack().Drill().start = aLayer;
|
||||
}
|
||||
|
||||
|
||||
void PCB_VIA::SetBottomLayer( PCB_LAYER_ID aLayer )
|
||||
{
|
||||
m_bottomLayer = aLayer;
|
||||
Padstack().Drill().end = aLayer;
|
||||
}
|
||||
|
||||
|
||||
|
@ -955,8 +927,8 @@ void PCB_VIA::LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) c
|
|||
|
||||
if( GetViaType() != VIATYPE::THROUGH )
|
||||
{
|
||||
b_layer = m_bottomLayer;
|
||||
t_layer = m_layer;
|
||||
b_layer = Padstack().Drill().end;
|
||||
t_layer = Padstack().Drill().start;
|
||||
|
||||
if( b_layer < t_layer )
|
||||
std::swap( b_layer, t_layer );
|
||||
|
@ -972,13 +944,13 @@ void PCB_VIA::LayerPair( PCB_LAYER_ID* top_layer, PCB_LAYER_ID* bottom_layer ) c
|
|||
|
||||
PCB_LAYER_ID PCB_VIA::TopLayer() const
|
||||
{
|
||||
return m_layer;
|
||||
return Padstack().Drill().start;
|
||||
}
|
||||
|
||||
|
||||
PCB_LAYER_ID PCB_VIA::BottomLayer() const
|
||||
{
|
||||
return m_bottomLayer;
|
||||
return Padstack().Drill().end;
|
||||
}
|
||||
|
||||
|
||||
|
@ -986,12 +958,12 @@ void PCB_VIA::SanitizeLayers()
|
|||
{
|
||||
if( GetViaType() == VIATYPE::THROUGH )
|
||||
{
|
||||
m_layer = F_Cu;
|
||||
m_bottomLayer = B_Cu;
|
||||
Padstack().Drill().start = F_Cu;
|
||||
Padstack().Drill().end = B_Cu;
|
||||
}
|
||||
|
||||
if( m_bottomLayer < m_layer )
|
||||
std::swap( m_bottomLayer, m_layer );
|
||||
if( Padstack().Drill().end < Padstack().Drill().start )
|
||||
std::swap( Padstack().Drill().end, Padstack().Drill().start );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1021,12 +993,28 @@ bool PCB_VIA::FlashLayer( int aLayer ) const
|
|||
if( !IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) ) )
|
||||
return false;
|
||||
|
||||
if( !m_removeUnconnectedLayer || !IsCopperLayer( aLayer ) )
|
||||
if( !IsCopperLayer( aLayer ) )
|
||||
return true;
|
||||
|
||||
if( m_keepStartEndLayer && ( aLayer == m_layer || aLayer == m_bottomLayer ) )
|
||||
switch( Padstack().UnconnectedLayerMode() )
|
||||
{
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL:
|
||||
return true;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END:
|
||||
{
|
||||
if( aLayer == Padstack().Drill().start || aLayer == Padstack().Drill().end )
|
||||
return true;
|
||||
|
||||
// Check for removal below
|
||||
break;
|
||||
}
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL:
|
||||
// Check for removal below
|
||||
break;
|
||||
}
|
||||
|
||||
// Must be static to keep from raising its ugly head in performance profiles
|
||||
static std::initializer_list<KICAD_T> connectedTypes = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T,
|
||||
PCB_PAD_T };
|
||||
|
@ -1736,8 +1724,7 @@ static struct TRACK_VIA_DESC
|
|||
&PCB_VIA::SetWidth, &PCB_VIA::GetWidth, PROPERTY_DISPLAY::PT_SIZE ) );
|
||||
propMgr.AddProperty( new PROPERTY<PCB_VIA, int>( _HKI( "Hole" ),
|
||||
&PCB_VIA::SetDrill, &PCB_VIA::GetDrillValue, PROPERTY_DISPLAY::PT_SIZE ), groupVia );
|
||||
propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ),
|
||||
new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID, BOARD_ITEM>( _HKI( "Layer Top" ),
|
||||
propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Top" ),
|
||||
&PCB_VIA::SetLayer, &PCB_VIA::GetLayer ), groupVia );
|
||||
propMgr.AddProperty( new PROPERTY_ENUM<PCB_VIA, PCB_LAYER_ID>( _HKI( "Layer Bottom" ),
|
||||
&PCB_VIA::SetBottomLayer, &PCB_VIA::BottomLayer ), groupVia );
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <geometry/shape_segment.h>
|
||||
#include <core/minoptmax.h>
|
||||
#include <core/arraydim.h>
|
||||
#include <padstack.h>
|
||||
|
||||
class PCB_TRACK;
|
||||
class PCB_VIA;
|
||||
|
@ -410,6 +411,10 @@ public:
|
|||
VIATYPE GetViaType() const { return m_viaType; }
|
||||
void SetViaType( VIATYPE aViaType ) { m_viaType = aViaType; }
|
||||
|
||||
const PADSTACK& Padstack() const { return m_padStack; }
|
||||
PADSTACK& Padstack() { return m_padStack; }
|
||||
void SetPadstack( const PADSTACK& aPadstack ) { m_padStack = aPadstack; }
|
||||
|
||||
bool HasHole() const override
|
||||
{
|
||||
return true;
|
||||
|
@ -423,6 +428,9 @@ public:
|
|||
bool IsTented() const override;
|
||||
int GetSolderMaskExpansion() const;
|
||||
|
||||
PCB_LAYER_ID GetLayer() const override;
|
||||
void SetLayer( PCB_LAYER_ID aLayer ) override;
|
||||
|
||||
bool IsOnLayer( PCB_LAYER_ID aLayer ) const override;
|
||||
|
||||
virtual LSET GetLayerSet() const override;
|
||||
|
@ -494,25 +502,55 @@ public:
|
|||
int GetMinAnnulus( PCB_LAYER_ID aLayer, wxString* aSource ) const;
|
||||
|
||||
/**
|
||||
* @deprecated - use Padstack().SetUnconnectedLayerMode()
|
||||
* Sets the unconnected removal property. If true, the copper is removed on zone fill
|
||||
* or when specifically requested when the via is not connected on a layer.
|
||||
*/
|
||||
void SetRemoveUnconnected( bool aSet ) { m_removeUnconnectedLayer = aSet; }
|
||||
bool GetRemoveUnconnected() const { return m_removeUnconnectedLayer; }
|
||||
void SetRemoveUnconnected( bool aSet )
|
||||
{
|
||||
m_padStack.SetUnconnectedLayerMode( aSet
|
||||
? PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL
|
||||
: PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL );
|
||||
}
|
||||
|
||||
bool GetRemoveUnconnected() const
|
||||
{
|
||||
return m_padStack.UnconnectedLayerMode() != PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated - use Padstack().SetUnconnectedLayerMode()
|
||||
* Sets whether we keep the start and end annular rings even if they are not connected
|
||||
*/
|
||||
void SetKeepStartEnd( bool aSet ) { m_keepStartEndLayer = aSet; }
|
||||
bool GetKeepStartEnd() const { return m_keepStartEndLayer; }
|
||||
void SetKeepStartEnd( bool aSet )
|
||||
{
|
||||
m_padStack.SetUnconnectedLayerMode( aSet
|
||||
? PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END
|
||||
: PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL );
|
||||
}
|
||||
|
||||
bool GetKeepStartEnd() const
|
||||
{
|
||||
return m_padStack.UnconnectedLayerMode()
|
||||
== PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END;
|
||||
}
|
||||
|
||||
bool ConditionallyFlashed( PCB_LAYER_ID aLayer ) const
|
||||
{
|
||||
if( !m_removeUnconnectedLayer )
|
||||
switch( m_padStack.UnconnectedLayerMode() )
|
||||
{
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::KEEP_ALL:
|
||||
return false;
|
||||
|
||||
if( m_keepStartEndLayer && ( aLayer == m_layer || aLayer == m_bottomLayer ) )
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_ALL:
|
||||
return true;
|
||||
|
||||
case PADSTACK::UNCONNECTED_LAYER_MODE::REMOVE_EXCEPT_START_AND_END:
|
||||
{
|
||||
if( aLayer == m_padStack.Drill().start || aLayer == m_padStack.Drill().end )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -547,14 +585,17 @@ public:
|
|||
*
|
||||
* @param aDrill is the new drill diameter
|
||||
*/
|
||||
void SetDrill( int aDrill ) { m_drill = aDrill; }
|
||||
void SetDrill( int aDrill )
|
||||
{
|
||||
m_padStack.Drill().size = { aDrill, aDrill };
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local drill setting for this PCB_VIA.
|
||||
*
|
||||
* @note Use GetDrillValue() to get the calculated value.
|
||||
*/
|
||||
int GetDrill() const { return m_drill; }
|
||||
int GetDrill() const { return m_padStack.Drill().size.x; }
|
||||
|
||||
/**
|
||||
* Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
|
||||
|
@ -566,7 +607,10 @@ public:
|
|||
/**
|
||||
* Set the drill value for vias to the default value #UNDEFINED_DRILL_DIAMETER.
|
||||
*/
|
||||
void SetDrillDefault() { m_drill = UNDEFINED_DRILL_DIAMETER; }
|
||||
void SetDrillDefault()
|
||||
{
|
||||
m_padStack.Drill().size = { UNDEFINED_DRILL_DIAMETER, UNDEFINED_DRILL_DIAMETER };
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the via is a free via (as opposed to one created on a track by the router).
|
||||
|
@ -611,15 +655,10 @@ protected:
|
|||
wxString layerMaskDescribe() const override;
|
||||
|
||||
private:
|
||||
/// The bottom layer of the via (the top layer is in m_layer)
|
||||
PCB_LAYER_ID m_bottomLayer;
|
||||
|
||||
VIATYPE m_viaType; ///< through, blind/buried or micro
|
||||
|
||||
int m_drill; ///< for vias: via drill (- 1 for default value)
|
||||
PADSTACK m_padStack;
|
||||
|
||||
bool m_removeUnconnectedLayer; ///< Remove annular rings on unconnected layers
|
||||
bool m_keepStartEndLayer; ///< Keep the start and end annular rings
|
||||
bool m_isFree; ///< "Free" vias don't get their nets auto-updated
|
||||
|
||||
std::mutex m_zoneLayerOverridesMutex;
|
||||
|
|
|
@ -773,7 +773,7 @@ void ZONE_FILLER::addKnockout( PAD* aPad, PCB_LAYER_ID aLayer, int aGap, SHAPE_P
|
|||
aPad->TransformShapeToPolygon( poly, aLayer, aGap, m_maxError, ERROR_OUTSIDE );
|
||||
|
||||
// the pad shape in zone can be its convex hull or the shape itself
|
||||
if( aPad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
|
||||
if( aPad->GetCustomShapeInZoneOpt() == PADSTACK::CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL )
|
||||
{
|
||||
std::vector<VECTOR2I> convex_hull;
|
||||
BuildConvexHull( convex_hull, poly );
|
||||
|
|
|
@ -160,4 +160,9 @@ BOOST_AUTO_TEST_CASE( ZoneConnectionStyle )
|
|||
testEnums<ZONE_CONNECTION, kiapi::board::types::ZoneConnectionStyle>();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( UnconnectedLayerRemoval )
|
||||
{
|
||||
testEnums<PADSTACK::UNCONNECTED_LAYER_MODE, kiapi::board::types::UnconnectedLayerRemoval>();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Reference in New Issue