diff --git a/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.cpp b/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.cpp index 1282448a8b..cbf81d5375 100644 --- a/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.cpp +++ b/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.cpp @@ -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 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 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 } ); diff --git a/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.h b/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.h index ed0e24f0e8..b336fefca9 100644 --- a/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.h +++ b/pcbnew/plugins/cadstar/cadstar_pcb_archive_loader.h @@ -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>; + + /** + * Associated copper pads (if any) for each component library definition + */ + std::map m_librarycopperpads; + std::map m_netMap; ///< Map between Cadstar and KiCad Nets std::map m_netClassMap; ///< Map between Cadstar and KiCad classes std::map 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 );