Fixup for Altium pad/fill importer

The previous commit merged pads with copper areas.  This was appealing
but broke when the pad and the area were meant to have different
size/shape technical layers.  Small pads = Small paste.  Instead, we do
not merge the pads but we assign them to have the appropriate nets in
KiCad, allowing the same effective result but keeping the technical
layers correct
This commit is contained in:
Seth Hillbrand 2024-06-27 13:46:16 -07:00
parent cc81ccf79a
commit 51eb7aa5b5
2 changed files with 473 additions and 835 deletions

View File

@ -811,14 +811,39 @@ FOOTPRINT* ALTIUM_PCB::ParseFootprint( ALTIUM_COMPOUND_FILE& altiumLibFile,
}
}
// Loop over this multiple times to catch pads that are jumpered to each other by multiple shapes
for( bool changes = true; changes; )
{
changes = false;
alg::for_all_pairs( footprint->Pads().begin(), footprint->Pads().end(),
[&changes]( PAD* aPad1, PAD* aPad2 )
{
if( !( aPad1->GetNumber().IsEmpty() ^ aPad2->GetNumber().IsEmpty() ) )
return;
for( PCB_LAYER_ID layer : aPad1->GetLayerSet().Seq() )
{
std::shared_ptr<SHAPE> shape1 = aPad1->GetEffectiveShape( layer );
std::shared_ptr<SHAPE> shape2 = aPad2->GetEffectiveShape( layer );
if( shape1->Collide( shape2.get() ) )
{
if( aPad1->GetNumber().IsEmpty() )
aPad1->SetNumber( aPad2->GetNumber() );
else
aPad2->SetNumber( aPad1->GetNumber() );
changes = true;
}
}
} );
}
// Auto-position reference and value
footprint->AutoPositionFields();
for( PAD* pad : footprint->Pads() )
{
pad->Recombine( false, ARC_HIGH_DEF );
}
if( parser.HasParsingError() )
{
THROW_IO_ERROR( wxString::Format( wxT( "%s stream was not parsed correctly" ),
@ -2588,14 +2613,70 @@ void ALTIUM_PCB::ConvertShapeBasedRegions6ToFootprintItemOnLayer( FOOTPRINT*
polySet.AddHole( hole_linechain );
}
std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( aFootprint, SHAPE_T::POLY );
if( aLayer == F_Cu || aLayer == B_Cu )
{
std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
shape->SetPolyShape( polySet );
shape->SetFilled( true );
shape->SetLayer( aLayer );
shape->SetStroke( STROKE_PARAMS( 0 ) );
LSET padLayers;
padLayers.set( aLayer );
aFootprint->Add( shape.release(), ADD_MODE::APPEND );
pad->SetAttribute( PAD_ATTRIB::SMD );
pad->SetShape( PAD_SHAPE::CUSTOM );
pad->SetThermalSpokeAngle( ANGLE_90 );
int anchorSize = 1;
VECTOR2I anchorPos = linechain.CPoint( 0 );
pad->SetShape( PAD_SHAPE::CUSTOM );
pad->SetAnchorPadShape( PAD_SHAPE::CIRCLE );
pad->SetSize( { anchorSize, anchorSize } );
pad->SetPosition( anchorPos );
SHAPE_POLY_SET shapePolys = polySet;
shapePolys.Move( -anchorPos );
pad->AddPrimitivePoly( shapePolys, 0, true );
auto& map = m_extendedPrimitiveInformationMaps[ALTIUM_RECORD::REGION];
auto it = map.find( aPrimitiveIndex );
if( it != map.end() )
{
const AEXTENDED_PRIMITIVE_INFORMATION& info = it->second;
if( info.pastemaskexpansionmode == ALTIUM_MODE::MANUAL )
{
pad->SetLocalSolderPasteMargin(
info.pastemaskexpansionmanual ? info.pastemaskexpansionmanual : 1 );
}
if( info.soldermaskexpansionmode == ALTIUM_MODE::MANUAL )
{
pad->SetLocalSolderMaskMargin(
info.soldermaskexpansionmanual ? info.soldermaskexpansionmanual : 1 );
}
if( info.pastemaskexpansionmode != ALTIUM_MODE::NONE )
padLayers.set( aLayer == F_Cu ? F_Paste : B_Paste );
if( info.soldermaskexpansionmode != ALTIUM_MODE::NONE )
padLayers.set( aLayer == F_Cu ? F_Mask : B_Mask );
}
pad->SetLayerSet( padLayers );
aFootprint->Add( pad.release(), ADD_MODE::APPEND );
}
else
{
std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( aFootprint, SHAPE_T::POLY );
shape->SetPolyShape( polySet );
shape->SetFilled( true );
shape->SetLayer( aLayer );
shape->SetStroke( STROKE_PARAMS( 0 ) );
aFootprint->Add( shape.release(), ADD_MODE::APPEND );
}
}
@ -4368,24 +4449,73 @@ void ALTIUM_PCB::ConvertFills6ToBoardItemOnLayer( const AFILL6& aElem, PCB_LAYER
void ALTIUM_PCB::ConvertFills6ToFootprintItemOnLayer( FOOTPRINT* aFootprint, const AFILL6& aElem,
PCB_LAYER_ID aLayer )
{
std::unique_ptr<PCB_SHAPE> fill = std::make_unique<PCB_SHAPE>( aFootprint, SHAPE_T::RECTANGLE );
fill->SetFilled( true );
fill->SetLayer( aLayer );
fill->SetStroke( STROKE_PARAMS( 0 ) );
fill->SetStart( aElem.pos1 );
fill->SetEnd( aElem.pos2 );
if( aElem.rotation != 0. )
if( aLayer == F_Cu || aLayer == B_Cu )
{
// TODO: Do we need SHAPE_T::POLY for non 90° rotations?
VECTOR2I center( aElem.pos1.x / 2 + aElem.pos2.x / 2,
aElem.pos1.y / 2 + aElem.pos2.y / 2 );
fill->Rotate( center, EDA_ANGLE( aElem.rotation, DEGREES_T ) );
}
std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
aFootprint->Add( fill.release(), ADD_MODE::APPEND );
LSET padLayers;
padLayers.set( aLayer );
pad->SetAttribute( PAD_ATTRIB::SMD );
if( aElem.rotation == 0. )
{
pad->SetShape( PAD_SHAPE::RECTANGLE );
pad->SetSize( { aElem.pos2.x - aElem.pos1.x, aElem.pos2.y - aElem.pos1.y } );
pad->SetPosition( ( aElem.pos1 + aElem.pos2 ) / 2 );
}
else
{
pad->SetShape( PAD_SHAPE::CUSTOM );
int anchorSize = std::min( std::abs( aElem.pos2.x - aElem.pos1.x ),
std::abs( aElem.pos2.y - aElem.pos1.y ) );
VECTOR2I anchorPos = aElem.pos1;
pad->SetAnchorPadShape( PAD_SHAPE::CIRCLE );
pad->SetSize( { anchorSize, anchorSize } );
pad->SetPosition( anchorPos );
SHAPE_POLY_SET shapePolys;
shapePolys.NewOutline();
shapePolys.Append( aElem.pos1.x - anchorPos.x, aElem.pos1.y - anchorPos.y );
shapePolys.Append( aElem.pos2.x - anchorPos.x, aElem.pos1.y - anchorPos.y );
shapePolys.Append( aElem.pos2.x - anchorPos.x, aElem.pos2.y - anchorPos.y );
shapePolys.Append( aElem.pos1.x - anchorPos.x, aElem.pos2.y - anchorPos.y );
shapePolys.Outline( 0 ).SetClosed( true );
VECTOR2I center( ( aElem.pos1.x + aElem.pos2.x ) / 2 - anchorPos.x,
( aElem.pos1.y + aElem.pos2.y ) / 2 - anchorPos.y );
shapePolys.Rotate( EDA_ANGLE( aElem.rotation, DEGREES_T ), center );
pad->AddPrimitivePoly( shapePolys, 0, true );
}
pad->SetThermalSpokeAngle( ANGLE_90 );
pad->SetLayerSet( padLayers );
aFootprint->Add( pad.release(), ADD_MODE::APPEND );
}
else
{
std::unique_ptr<PCB_SHAPE> fill =
std::make_unique<PCB_SHAPE>( aFootprint, SHAPE_T::RECTANGLE );
fill->SetFilled( true );
fill->SetLayer( aLayer );
fill->SetStroke( STROKE_PARAMS( 0 ) );
fill->SetStart( aElem.pos1 );
fill->SetEnd( aElem.pos2 );
if( aElem.rotation != 0. )
{
// TODO: Do we need SHAPE_T::POLY for non 90° rotations?
VECTOR2I center( aElem.pos1.x / 2 + aElem.pos2.x / 2,
aElem.pos1.y / 2 + aElem.pos2.y / 2 );
fill->Rotate( center, EDA_ANGLE( aElem.rotation, DEGREES_T ) );
}
aFootprint->Add( fill.release(), ADD_MODE::APPEND );
}
}