CADSTAR PCB: Fix loading of thermal pads

- Create a pad if a component copper is associated with any other pads
  in the footprint.
- Rename/renumber 'PCB Only' pads that are associated with a component
  copper and make them all use the same pad name/number.
This commit is contained in:
Roberto Fernandez Bautista 2021-04-10 19:14:43 +01:00
parent 2eb96279a2
commit b5edd5f6a5
2 changed files with 131 additions and 11 deletions

View File

@ -661,9 +661,10 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadComponentLibrary()
footprint->SetFPID( libID );
loadLibraryFigures( component, footprint );
loadLibraryCoppers( component, footprint );
loadLibraryAreas( component, footprint );
loadLibraryPads( component, footprint );
loadLibraryCoppers( component, footprint ); // Load coppers after pads to ensure correct
// ordering of pads in footprint->Pads()
m_libraryMap.insert( std::make_pair( key, footprint ) );
}
@ -690,15 +691,94 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryFigures( const SYMDEF_PCB& aComponen
void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryCoppers( const SYMDEF_PCB& aComponent, FOOTPRINT* aFootprint )
{
int totalCopperPads = 0;
for( COMPONENT_COPPER compCopper : aComponent.ComponentCoppers )
{
int lineThickness = getKiCadLength( getCopperCode( compCopper.CopperCodeID ).CopperWidth );
PCB_LAYER_ID copperLayer = getKiCadLayer( compCopper.LayerID );
drawCadstarShape( compCopper.Shape, getKiCadLayer( compCopper.LayerID ), lineThickness,
wxString::Format( "Component %s:%s -> Copper element",
aComponent.ReferenceName,
aComponent.Alternate ),
aFootprint );
if( compCopper.AssociatedPadIDs.size() > 0 && LSET::AllCuMask().Contains( copperLayer )
&& compCopper.Shape.Type == SHAPE_TYPE::SOLID )
{
// The copper is associated with pads and in an electrical layer which means it can
// have a net associated with it. Load as a pad instead.
// Note: we can only handle SOLID copper shapes. If the copper shape is an outline or
// hatched or outline, then we give up and load as a graphical shape instead.
// Find the first non-PCB-only pad. If there are none, use the first one
COMPONENT_PAD anchorPad;
bool found = false;
for( PAD_ID padID : compCopper.AssociatedPadIDs )
{
anchorPad = aComponent.ComponentPads.at( padID );
if( !anchorPad.PCBonlyPad )
{
found = true;
break;
}
}
if( !found )
anchorPad = aComponent.ComponentPads.at( compCopper.AssociatedPadIDs.front() );
PAD* pad = new PAD( aFootprint );
pad->SetAttribute( PAD_ATTR_T::PAD_ATTRIB_SMD );
pad->SetLayerSet( LSET( 1, copperLayer ) );
pad->SetName( anchorPad.Identifier.IsEmpty()
? wxString::Format( wxT( "%ld" ), anchorPad.ID )
: anchorPad.Identifier );
// Custom pad shape with an anchor at the position of one of the associated
// pads and same size as the pad. Shape circle as it fits inside a rectangle
// but not the other way round
PADCODE anchorpadcode = getPadCode( anchorPad.PadCodeID );
int anchorSize = getKiCadLength( anchorpadcode.Shape.Size );
wxPoint anchorPos = getKiCadPoint( anchorPad.Position );
pad->SetShape( PAD_SHAPE_T::PAD_SHAPE_CUSTOM );
pad->SetAnchorPadShape( PAD_SHAPE_CIRCLE );
pad->SetSize( { anchorSize, anchorSize } );
pad->SetPosition( anchorPos );
pad->SetLocalCoord();
pad->SetLocked( true ); // Cadstar pads are always locked with respect to the footprint
SHAPE_POLY_SET shapePolys = getPolySetFromCadstarShape( compCopper.Shape,
lineThickness,
aFootprint );
shapePolys.Move( aFootprint->GetPosition() - anchorPos );
pad->AddPrimitivePoly( shapePolys, 0, true );
aFootprint->Add( pad, ADD_MODE::APPEND ); // Append so that we get the correct behaviour
// when finding pads by PAD_ID. See loadNets()
m_librarycopperpads[aComponent.ID][anchorPad.ID].push_back( aFootprint->Pads().size() );
totalCopperPads++;
// Now renumber all the associated pads if they are PCB Only
COMPONENT_PAD associatedPad;
for( PAD_ID padID : compCopper.AssociatedPadIDs )
{
associatedPad = aComponent.ComponentPads.at( padID );
if( associatedPad.PCBonlyPad )
{
PAD* assocPad = getPadReference( aFootprint, padID );
assocPad->SetName( pad->GetName() );
}
}
}
else
{
drawCadstarShape( compCopper.Shape, copperLayer, lineThickness,
wxString::Format( "Component %s:%s -> Copper element",
aComponent.ReferenceName, aComponent.Alternate ),
aFootprint );
}
}
}
@ -755,7 +835,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadLibraryPads( const SYMDEF_PCB& aComponent,
for( std::pair<PAD_ID, COMPONENT_PAD> padPair : aComponent.ComponentPads )
{
PAD* pad = getKiCadPad( padPair.second, aFootprint );
aFootprint->Add( pad, ADD_MODE::INSERT ); // insert so that we get correct behaviour
aFootprint->Add( pad, ADD_MODE::APPEND ); // Append so that we get correct behaviour
// when finding pads by PAD_ID - see loadNets()
}
}
@ -1086,6 +1166,13 @@ PAD* CADSTAR_PCB_ARCHIVE_LOADER::getKiCadPad( const COMPONENT_PAD& aCadstarPad,
}
PAD*& CADSTAR_PCB_ARCHIVE_LOADER::getPadReference( FOOTPRINT* aFootprint,
const PAD_ID aCadstarPadID )
{
return aFootprint->Pads().at( aCadstarPadID - (long long) 1 );
}
void CADSTAR_PCB_ARCHIVE_LOADER::loadGroups()
{
for( std::pair<GROUP_ID, GROUP> groupPair : Layout.Groups )
@ -1506,7 +1593,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadComponents()
if( pinName.empty() )
pinName = wxString::Format( wxT( "%ld" ), pin.ID );
footprint->Pads().at( pin.ID - (long long) 1 )->SetName( pinName );
getPadReference( footprint, pin.ID )->SetName( pinName );
}
}
}
@ -1534,7 +1621,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadComponents()
csPad.Side = padEx.Side;
// Find the pad in the footprint definition
PAD* kiPad = footprint->Pads().at( padEx.ID - (long long) 1 );
PAD* kiPad = getPadReference( footprint, padEx.ID );
wxString padName = kiPad->GetName();
if( kiPad )
@ -1542,7 +1629,9 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadComponents()
kiPad = getKiCadPad( csPad, footprint );
kiPad->SetName( padName );
footprint->Pads().at( padEx.ID - (long long) 1 ) = kiPad;
// Change the pointer in the footprint to the newly created pad
getPadReference( footprint, padEx.ID ) = kiPad;
}
}
@ -2034,9 +2123,27 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadNets()
{
// The below works because we have added the pads in the correct order to the
// footprint and the PAD_ID in Cadstar is a sequential, numerical ID
PAD* pad = footprint->Pads().at( pin.PadID - (long) 1 );
PAD* pad = getPadReference( footprint, pin.PadID );
pad->SetNet( getKiCadNet( net.ID ) );
// also set the net to any copper pads (i.e. copper elements that we have imported
// as pads instead:
SYMDEF_ID symdefid = Layout.Components.at( pin.ComponentID ).SymdefID;
if( m_librarycopperpads.find( symdefid ) != m_librarycopperpads.end() )
{
ASSOCIATED_COPPER_PADS assocPads = m_librarycopperpads.at( symdefid );
if( assocPads.find( pin.PadID ) != assocPads.end() )
{
for( PAD_ID copperPadID : assocPads.at( pin.PadID ) )
{
PAD* copperpad = getPadReference( footprint, copperPadID );
copperpad->SetNet( getKiCadNet( net.ID ) );
}
}
}
// padsize is used for calculating route offset (as done in CADSTAR post processor)
int padsize = std::min( pad->GetSizeX(), pad->GetSizeY() );
netelementSizes.insert( { pinPair.first, padsize } );

View File

@ -96,6 +96,18 @@ private:
///< components on the board. Does NOT own
///< the FOOTPRINT objects (these should
///< have been loaded to m_board).
/**
* Map of pad anchor points (first) to copper pads (second). In the vast majority
* of designs there is only one copper pad, but just in case, making it a vector
*/
using ASSOCIATED_COPPER_PADS = std::map<PAD_ID, std::vector<PAD_ID>>;
/**
* Associated copper pads (if any) for each component library definition
*/
std::map<SYMDEF_ID, ASSOCIATED_COPPER_PADS> m_librarycopperpads;
std::map<NET_ID, NETINFO_ITEM*> m_netMap; ///< Map between Cadstar and KiCad Nets
std::map<ROUTECODE_ID, NETCLASSPTR> m_netClassMap; ///< Map between Cadstar and KiCad classes
std::map<TEMPLATE_ID, ZONE*> m_zonesMap; ///< Map between Cadstar and KiCad zones
@ -394,6 +406,7 @@ private:
// Helper Functions for obtaining individual elements as KiCad elements:
double getHatchCodeAngleDegrees( const HATCHCODE_ID& aCadstarHatchcodeID );
PAD* getKiCadPad( const COMPONENT_PAD& aCadstarPad, FOOTPRINT* aParent );
PAD*& getPadReference( FOOTPRINT* aFootprint, const PAD_ID aCadstarPadID );
FOOTPRINT* getFootprintFromCadstarID( const COMPONENT_ID& aCadstarComponentID );
int getKiCadHatchCodeThickness( const HATCHCODE_ID& aCadstarHatchcodeID );
int getKiCadHatchCodeGap( const HATCHCODE_ID& aCadstarHatchcodeID );