7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 19:13:44 +00:00

Move custom shapes to PADSTACK; support in API

This commit is contained in:
Jon Evans 2024-06-07 19:18:34 -04:00
parent b20a32f2fd
commit f5e7c705db
11 changed files with 492 additions and 27 deletions

View File

@ -206,6 +206,9 @@ message PadStackLayer
ChamferedRectCorners chamfered_corners = 6;
repeated GraphicShape custom_shapes = 7;
// If shape == PSS_CUSTOM, defines the shape of the anchor (only PSS_CIRCLE and PSS_RECTANGLE supported at present)
PadStackShape custom_anchor_shape = 8;
}
// A pad stack definition for a multilayer pad or via.

View File

@ -160,7 +160,7 @@ VIATYPE FromProtoEnum( types::ViaType aValue )
case types::ViaType::VT_MICRO: return VIATYPE::MICROVIA;
default:
wxCHECK_MSG( false, VIATYPE::THROUGH,
wxCHECK_MSG( false, VIATYPE::THROUGH,
"Unhandled case in FromProtoEnum<types::ViaType>" );
}
}

View File

@ -67,7 +67,8 @@ using KIGFX::PCB_RENDER_SETTINGS;
PAD::PAD( FOOTPRINT* parent ) :
BOARD_CONNECTED_ITEM( parent, PCB_PAD_T )
BOARD_CONNECTED_ITEM( parent, PCB_PAD_T ),
m_padStack( this )
{
VECTOR2I& drill = m_padStack.Drill().size;
VECTOR2I& size = m_padStack.Size();
@ -105,7 +106,8 @@ PAD::PAD( FOOTPRINT* parent ) :
PAD::PAD( const PAD& aOther ) :
BOARD_CONNECTED_ITEM( aOther.GetParent(), PCB_PAD_T )
BOARD_CONNECTED_ITEM( aOther.GetParent(), PCB_PAD_T ),
m_padStack( this )
{
PAD::operator=( aOther );
@ -655,7 +657,7 @@ void PAD::BuildEffectiveShapes( PCB_LAYER_ID aLayer ) const
if( GetShape() == PAD_SHAPE::CUSTOM )
{
for( const std::shared_ptr<PCB_SHAPE>& primitive : m_editPrimitives )
for( const std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives() )
{
if( !primitive->IsProxyItem() )
{
@ -882,7 +884,7 @@ void PAD::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
void PAD::FlipPrimitives( bool aFlipLeftRight )
{
for( std::shared_ptr<PCB_SHAPE>& primitive : m_editPrimitives )
for( std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives() )
primitive->Flip( VECTOR2I( 0, 0 ), aFlipLeftRight );
SetDirty();
@ -1363,8 +1365,8 @@ int PAD::Compare( const PAD* aPadRef, const PAD* aPadCmp )
if( ( diff = aPadRef->m_padStack.ChamferRatio() - aPadCmp->m_padStack.ChamferRatio() ) != 0 )
return diff;
if( ( diff = static_cast<int>( aPadRef->m_editPrimitives.size() ) -
static_cast<int>( aPadCmp->m_editPrimitives.size() ) ) != 0 )
if( ( diff = static_cast<int>( aPadRef->m_padStack.Primitives().size() ) -
static_cast<int>( aPadCmp->m_padStack.Primitives().size() ) ) != 0 )
return diff;
// @todo: Compare custom pad primitives for pads that have the same number of primitives
@ -2175,7 +2177,7 @@ bool PAD::operator==( const BOARD_ITEM& aOther ) const
for( size_t ii = 0; ii < GetPrimitives().size(); ii++ )
{
if( GetPrimitives()[ii] != other.GetPrimitives()[ii] )
if( *GetPrimitives()[ii] != *other.GetPrimitives()[ii] )
return false;
}

View File

@ -316,7 +316,7 @@ public:
*/
const std::vector<std::shared_ptr<PCB_SHAPE>>& GetPrimitives() const
{
return m_editPrimitives;
return m_padStack.Primitives();
}
void Flip( const VECTOR2I& VECTOR2I, bool aFlipLeftRight ) override;
@ -842,11 +842,6 @@ private:
VECTOR2I m_pos; // Pad Position on board
PADSTACK m_padStack;
/*
* Editing definitions of primitives for custom pad shapes. In local coordinates relative
* to m_Pos (NOT shapePos) at orient 0.
*/
std::vector<std::shared_ptr<PCB_SHAPE>> m_editPrimitives;
// Must be set to true to force rebuild shapes to draw (after geometry change for instance)
mutable bool m_shapesDirty;

View File

@ -57,7 +57,7 @@ void PAD::AddPrimitivePoly( const SHAPE_POLY_SET& aPoly, int aThickness, bool aF
item->SetPolyShape( poly_outline );
item->SetStroke( STROKE_PARAMS( aThickness, LINE_STYLE::SOLID ) );
item->SetParent( this );
m_editPrimitives.emplace_back( item );
m_padStack.AddPrimitive( item );
}
SetDirty();
@ -71,7 +71,7 @@ void PAD::AddPrimitivePoly( const std::vector<VECTOR2I>& aPoly, int aThickness,
item->SetPolyPoints( aPoly );
item->SetStroke( STROKE_PARAMS( aThickness, LINE_STYLE::SOLID ) );
item->SetParent( this );
m_editPrimitives.emplace_back( item );
m_padStack.AddPrimitive( item );
SetDirty();
}
@ -102,7 +102,7 @@ void PAD::AppendPrimitives( const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrim
void PAD::AddPrimitive( PCB_SHAPE* aPrimitive )
{
aPrimitive->SetParent( this );
m_editPrimitives.emplace_back( aPrimitive );
m_padStack.AddPrimitive( aPrimitive );
SetDirty();
}
@ -111,8 +111,7 @@ void PAD::AddPrimitive( PCB_SHAPE* aPrimitive )
// clear the basic shapes list and associated data
void PAD::DeletePrimitivesList()
{
m_editPrimitives.clear();
m_padStack.ClearPrimitives();
SetDirty();
}
@ -122,7 +121,7 @@ void PAD::addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError,
{
SHAPE_POLY_SET polyset;
for( const std::shared_ptr<PCB_SHAPE>& primitive : m_editPrimitives )
for( const std::shared_ptr<PCB_SHAPE>& primitive : m_padStack.Primitives() )
{
if( !primitive->IsProxyItem() )
primitive->TransformShapeToPolygon( polyset, UNDEFINED_LAYER, 0, aError, aErrorLoc );

View File

@ -24,9 +24,11 @@
#include <api/api_utils.h>
#include <api/api_pcb_utils.h>
#include <api/board/board_types.pb.h>
#include <pcb_shape.h>
PADSTACK::PADSTACK() :
PADSTACK::PADSTACK( BOARD_ITEM* aParent ) :
m_parent( aParent ),
m_mode( MODE::NORMAL ),
m_orientation( ANGLE_0 ),
m_unconnectedLayerMode( UNCONNECTED_LAYER_MODE::KEEP_ALL ),
@ -112,6 +114,7 @@ bool PADSTACK::Deserialize( const google::protobuf::Any& aContainer )
Size() = kiapi::common::UnpackVector2( layer.size() );
SetLayerSet( kiapi::board::UnpackLayerSet( layer.layers() ) );
SetShape( FromProtoEnum<PAD_SHAPE>( layer.shape() ) );
SetAnchorShape( FromProtoEnum<PAD_SHAPE>( layer.custom_anchor_shape() ) );
SHAPE_PROPS& props = CopperLayerDefaults().shape;
props.chamfered_rect_ratio = layer.chamfer_ratio();
@ -128,6 +131,18 @@ bool PADSTACK::Deserialize( const google::protobuf::Any& aContainer )
if( layer.chamfered_corners().bottom_right() )
props.chamfered_rect_positions |= RECT_CHAMFER_BOTTOM_RIGHT;
ClearPrimitives();
google::protobuf::Any a;
for( const GraphicShape& shapeProto : layer.custom_shapes() )
{
a.PackFrom( shapeProto );
std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( m_parent );
if( shape->Deserialize( a ) )
AddPrimitive( shape.release() );
}
}
SetUnconnectedLayerMode(
@ -152,9 +167,19 @@ void PADSTACK::Serialize( google::protobuf::Any& aContainer ) const
kiapi::board::PackLayerSet( *stackLayer->mutable_layers(), LayerSet() );
kiapi::common::PackVector2( *stackLayer->mutable_size(), Size() );
stackLayer->set_shape( ToProtoEnum<PAD_SHAPE, PadStackShape>( Shape() ) );
stackLayer->set_custom_anchor_shape( ToProtoEnum<PAD_SHAPE, PadStackShape>( AnchorShape() ) );
stackLayer->set_chamfer_ratio( CopperLayerDefaults().shape.chamfered_rect_ratio );
stackLayer->set_corner_rounding_ratio( CopperLayerDefaults().shape.round_rect_radius_ratio );
google::protobuf::Any a;
for( const std::shared_ptr<PCB_SHAPE>& shape : Primitives() )
{
shape->Serialize( a );
GraphicShape* s = stackLayer->add_custom_shapes();
a.UnpackTo( s );
}
const int& corners = CopperLayerDefaults().shape.chamfered_rect_positions;
stackLayer->mutable_chamfered_corners()->set_top_left( corners & RECT_CHAMFER_TOP_LEFT );
stackLayer->mutable_chamfered_corners()->set_top_right( corners & RECT_CHAMFER_TOP_RIGHT );
@ -468,4 +493,46 @@ void PADSTACK::SetThermalSpokeAngle( EDA_ANGLE aAngle, PCB_LAYER_ID aLayer )
}
std::vector<std::shared_ptr<PCB_SHAPE>>& PADSTACK::Primitives( PCB_LAYER_ID aLayer )
{
return CopperLayerDefaults().custom_shapes;
}
const std::vector<std::shared_ptr<PCB_SHAPE>>& PADSTACK::Primitives( PCB_LAYER_ID aLayer ) const
{
return CopperLayerDefaults().custom_shapes;
}
void PADSTACK::AddPrimitive( PCB_SHAPE* aShape, PCB_LAYER_ID aLayer )
{
CopperLayerDefaults().custom_shapes.emplace_back( aShape );
}
void PADSTACK::AppendPrimitives( const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList,
PCB_LAYER_ID aLayer )
{
for( const std::shared_ptr<PCB_SHAPE>& prim : aPrimitivesList )
AddPrimitive( new PCB_SHAPE( *prim ) );
}
void PADSTACK::ReplacePrimitives( const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList,
PCB_LAYER_ID aLayer )
{
ClearPrimitives( aLayer );
if( aPrimitivesList.size() )
AppendPrimitives( aPrimitivesList, aLayer );
}
void PADSTACK::ClearPrimitives( PCB_LAYER_ID aLayer )
{
CopperLayerDefaults().custom_shapes.clear();
}
IMPLEMENT_ENUM_TO_WXANY( PADSTACK::UNCONNECTED_LAYER_MODE )

View File

@ -32,6 +32,7 @@
#include <properties/property.h>
#include <zones.h>
class BOARD_ITEM;
class PCB_SHAPE;
@ -196,6 +197,10 @@ public:
std::optional<int> thermal_gap;
std::optional<int> clearance;
/*
* Editing definitions of primitives for custom pad shapes. In local coordinates relative
* to m_Pos (NOT shapePos) at orient 0.
*/
std::vector<std::shared_ptr<PCB_SHAPE>> custom_shapes;
bool operator==( const COPPER_LAYER_PROPS& aOther ) const;
@ -226,7 +231,7 @@ public:
};
public:
PADSTACK();
PADSTACK( BOARD_ITEM* aParent );
virtual ~PADSTACK() = default;
PADSTACK( const PADSTACK& aOther );
PADSTACK& operator=( const PADSTACK &aOther );
@ -332,8 +337,40 @@ public:
EDA_ANGLE ThermalSpokeAngle( PCB_LAYER_ID aLayer = F_Cu ) const;
void SetThermalSpokeAngle( EDA_ANGLE aAngle, PCB_LAYER_ID aLayer = F_Cu );
private:
std::vector<std::shared_ptr<PCB_SHAPE>>& Primitives( PCB_LAYER_ID aLayer = F_Cu );
const std::vector<std::shared_ptr<PCB_SHAPE>>& Primitives( PCB_LAYER_ID aLayer = F_Cu ) const;
/**
* Adds a custom shape primitive to the padstack.
* @param aShape is a shape to add as a custom primitive. Ownership is passed to this PADSTACK.
* @param aLayer is the padstack layer to add to.
*/
void AddPrimitive( PCB_SHAPE* aShape, PCB_LAYER_ID aLayer = F_Cu );
/**
* Appends a copy of each shape in the given list to this padstack's custom shape list
* @param aPrimitivesList is a list of shapes to add copies of to this PADSTACK
* @param aLayer is the padstack layer to add to.
*/
void AppendPrimitives( const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList,
PCB_LAYER_ID aLayer = F_Cu );
/**
* Clears the existing primitive list (freeing the owned shapes) and adds copies of the given
* shapes to the padstack for the given layer.
* @param aPrimitivesList is a list of shapes to add copies of to this PADSTACK
* @param aLayer is the padstack layer to add to.
*/
void ReplacePrimitives( const std::vector<std::shared_ptr<PCB_SHAPE>>& aPrimitivesList,
PCB_LAYER_ID aLayer = F_Cu );
void ClearPrimitives( PCB_LAYER_ID aLayer = F_Cu );
private:
///! The BOARD_ITEM this PADSTACK belongs to; will be used as the parent for owned shapes
BOARD_ITEM* m_parent;
///! The copper layer variation mode this padstack is in
MODE m_mode;
///! The board layers that this padstack is active on

View File

@ -83,7 +83,8 @@ EDA_ITEM* PCB_ARC::Clone() const
PCB_VIA::PCB_VIA( BOARD_ITEM* aParent ) :
PCB_TRACK( aParent, PCB_VIA_T )
PCB_TRACK( aParent, PCB_VIA_T ),
m_padStack( this )
{
SetViaType( VIATYPE::THROUGH );
Padstack().Drill().start = F_Cu;
@ -105,7 +106,8 @@ PCB_VIA::PCB_VIA( BOARD_ITEM* aParent ) :
PCB_VIA::PCB_VIA( const PCB_VIA& aOther ) :
PCB_TRACK( aOther.GetParent(), PCB_VIA_T )
PCB_TRACK( aOther.GetParent(), PCB_VIA_T ),
m_padStack( this )
{
PCB_VIA::operator=( aOther );

View File

LOADING design file

View File

@ -73,6 +73,7 @@
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_near_hole": "error",
"hole_to_hole": "warning",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",

View File

@ -34,6 +34,7 @@
// Board-specific
#include <padstack.h>
#include <pcb_track.h>
#include <zones.h>
using namespace kiapi::common;
@ -160,9 +161,26 @@ BOOST_AUTO_TEST_CASE( ZoneConnectionStyle )
testEnums<ZONE_CONNECTION, kiapi::board::types::ZoneConnectionStyle>();
}
BOOST_AUTO_TEST_CASE( PadType )
{
testEnums<PAD_ATTRIB, kiapi::board::types::PadType>();
}
BOOST_AUTO_TEST_CASE( PadStackType )
{
testEnums<PADSTACK::MODE, kiapi::board::types::PadStackType>();
}
BOOST_AUTO_TEST_CASE( UnconnectedLayerRemoval )
{
testEnums<PADSTACK::UNCONNECTED_LAYER_MODE, kiapi::board::types::UnconnectedLayerRemoval>();
}
BOOST_AUTO_TEST_CASE( ViaType )
{
// VIATYPE::NOT_DEFINED is not mapped
testEnums<VIATYPE, kiapi::board::types::ViaType>( true );
}
BOOST_AUTO_TEST_SUITE_END()