Altium PCB: support solder/paste mask expansion rules.
- Writes expansion values to board design settings - Imports footprint regions on Cu layers as pads - Adds support for holes in non-Cu polygons in footprints
This commit is contained in:
parent
8e1466a35a
commit
acc03e91f3
|
@ -2,6 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -533,6 +534,13 @@ ARULE6::ARULE6( ALTIUM_PARSER& aReader )
|
|||
else if( rulekind == wxT( "PasteMaskExpansion" ) )
|
||||
{
|
||||
kind = ALTIUM_RULE_KIND::PASTE_MASK_EXPANSION;
|
||||
pastemaskExpansion = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "EXPANSION" ), wxT( "0" ) );
|
||||
}
|
||||
else if( rulekind == wxT( "SolderMaskExpansion" ) )
|
||||
{
|
||||
kind = ALTIUM_RULE_KIND::SOLDER_MASK_EXPANSION;
|
||||
soldermaskExpansion =
|
||||
ALTIUM_PARSER::ReadKicadUnit( props, wxT( "EXPANSION" ), wxT( "4mil" ) );
|
||||
}
|
||||
else if( rulekind == wxT( "PlaneClearance" ) )
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
|
||||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -105,8 +105,9 @@ enum class ALTIUM_RULE_KIND
|
|||
HOLE_TO_HOLE_CLEARANCE = 5,
|
||||
WIDTH = 6,
|
||||
PASTE_MASK_EXPANSION = 7,
|
||||
PLANE_CLEARANCE = 8,
|
||||
POLYGON_CONNECT = 9,
|
||||
SOLDER_MASK_EXPANSION = 8,
|
||||
PLANE_CLEARANCE = 9,
|
||||
POLYGON_CONNECT = 10,
|
||||
};
|
||||
|
||||
enum class ALTIUM_CONNECT_STYLE
|
||||
|
@ -502,6 +503,12 @@ struct ARULE6
|
|||
// ALTIUM_RULE_KIND::PLANE_CLEARANCE
|
||||
int planeclearanceClearance;
|
||||
|
||||
// ALTIUM_RULE_KIND::SOLDER_MASK_EXPANSION
|
||||
int soldermaskExpansion;
|
||||
|
||||
// ALTIUM_RULE_KIND::PASTE_MASK_EXPANSION
|
||||
int pastemaskExpansion;
|
||||
|
||||
// ALTIUM_RULE_KIND::POLYGON_CONNECT
|
||||
int32_t polygonconnectAirgapwidth;
|
||||
int32_t polygonconnectReliefconductorwidth;
|
||||
|
|
|
@ -771,7 +771,7 @@ FOOTPRINT* ALTIUM_PCB::ParseFootprint( const ALTIUM_COMPOUND_FILE& altiumLibFile
|
|||
case ALTIUM_RECORD::REGION:
|
||||
{
|
||||
AREGION6 region( parser, false );
|
||||
ConvertShapeBasedRegions6ToFootprintItem( footprint.get(), region );
|
||||
ConvertShapeBasedRegions6ToFootprintItem( footprint.get(), region, primitiveIndex );
|
||||
break;
|
||||
}
|
||||
case ALTIUM_RECORD::MODEL:
|
||||
|
@ -1866,6 +1866,15 @@ void ALTIUM_PCB::ParseRules6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile
|
|||
} );
|
||||
}
|
||||
|
||||
const ARULE6* soldermaskRule = GetRuleDefault( ALTIUM_RULE_KIND::SOLDER_MASK_EXPANSION );
|
||||
const ARULE6* pastemaskRule = GetRuleDefault( ALTIUM_RULE_KIND::PASTE_MASK_EXPANSION );
|
||||
|
||||
if( soldermaskRule )
|
||||
m_board->GetDesignSettings().m_SolderMaskExpansion = soldermaskRule->soldermaskExpansion;
|
||||
|
||||
if( pastemaskRule )
|
||||
m_board->GetDesignSettings().m_SolderPasteMargin = pastemaskRule->pastemaskExpansion;
|
||||
|
||||
if( reader.GetRemainingBytes() != 0 )
|
||||
THROW_IO_ERROR( wxT( "Rules6 stream is not fully parsed" ) );
|
||||
}
|
||||
|
@ -1894,11 +1903,12 @@ void ALTIUM_PCB::ParseShapeBasedRegions6Data( const ALTIUM_COMPOUND_FILE& aA
|
|||
const CFB::COMPOUND_FILE_ENTRY* aEntry )
|
||||
{
|
||||
if( m_progressReporter )
|
||||
m_progressReporter->Report( _( "Loading zones..." ) );
|
||||
m_progressReporter->Report( _( "Loading polygons..." ) );
|
||||
|
||||
ALTIUM_PARSER reader( aAltiumPcbFile, aEntry );
|
||||
|
||||
while( reader.GetRemainingBytes() >= 4 /* TODO: use Header section of file */ )
|
||||
/* TODO: use Header section of file */
|
||||
for( int primitiveIndex = 0; reader.GetRemainingBytes() >= 4; primitiveIndex++ )
|
||||
{
|
||||
checkpoint();
|
||||
AREGION6 elem( reader, true );
|
||||
|
@ -1912,7 +1922,7 @@ void ALTIUM_PCB::ParseShapeBasedRegions6Data( const ALTIUM_COMPOUND_FILE& aA
|
|||
else
|
||||
{
|
||||
FOOTPRINT* footprint = HelperGetFootprint( elem.component );
|
||||
ConvertShapeBasedRegions6ToFootprintItem( footprint, elem );
|
||||
ConvertShapeBasedRegions6ToFootprintItem( footprint, elem, primitiveIndex );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1974,7 +1984,8 @@ void ALTIUM_PCB::ConvertShapeBasedRegions6ToBoardItem( const AREGION6& aElem )
|
|||
|
||||
|
||||
void ALTIUM_PCB::ConvertShapeBasedRegions6ToFootprintItem( FOOTPRINT* aFootprint,
|
||||
const AREGION6& aElem )
|
||||
const AREGION6& aElem,
|
||||
const int aPrimitiveIndex )
|
||||
{
|
||||
if( aElem.kind == ALTIUM_REGION_KIND::POLYGON_CUTOUT || aElem.is_keepout )
|
||||
{
|
||||
|
@ -2010,7 +2021,8 @@ void ALTIUM_PCB::ConvertShapeBasedRegions6ToFootprintItem( FOOTPRINT* aFoot
|
|||
if( aElem.subpolyindex == ALTIUM_POLYGON_NONE )
|
||||
{
|
||||
for( PCB_LAYER_ID klayer : GetKicadLayersToIterate( aElem.layer ) )
|
||||
ConvertShapeBasedRegions6ToFootprintItemOnLayer( aFootprint, aElem, klayer );
|
||||
ConvertShapeBasedRegions6ToFootprintItemOnLayer( aFootprint, aElem, klayer,
|
||||
aPrimitiveIndex );
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2062,7 +2074,8 @@ void ALTIUM_PCB::ConvertShapeBasedRegions6ToBoardItemOnLayer( const AREGION6& aE
|
|||
|
||||
void ALTIUM_PCB::ConvertShapeBasedRegions6ToFootprintItemOnLayer( FOOTPRINT* aFootprint,
|
||||
const AREGION6& aElem,
|
||||
PCB_LAYER_ID aLayer )
|
||||
PCB_LAYER_ID aLayer,
|
||||
const int aPrimitiveIndex )
|
||||
{
|
||||
SHAPE_LINE_CHAIN linechain;
|
||||
HelperShapeLineChainFromAltiumVertices( linechain, aElem.outline );
|
||||
|
@ -2076,15 +2089,85 @@ void ALTIUM_PCB::ConvertShapeBasedRegions6ToFootprintItemOnLayer( FOOTPRINT*
|
|||
return;
|
||||
}
|
||||
|
||||
FP_SHAPE* shape = new FP_SHAPE( aFootprint, SHAPE_T::POLY );
|
||||
SHAPE_POLY_SET polySet;
|
||||
polySet.AddOutline( linechain );
|
||||
|
||||
shape->SetPolyShape( linechain );
|
||||
shape->SetFilled( true );
|
||||
shape->SetLayer( aLayer );
|
||||
shape->SetStroke( STROKE_PARAMS( 0 ) );
|
||||
for( const std::vector<ALTIUM_VERTICE>& hole : aElem.holes )
|
||||
{
|
||||
SHAPE_LINE_CHAIN hole_linechain;
|
||||
HelperShapeLineChainFromAltiumVertices( hole_linechain, hole );
|
||||
|
||||
HelperShapeSetLocalCoord( shape );
|
||||
aFootprint->Add( shape, ADD_MODE::APPEND );
|
||||
if( hole_linechain.PointCount() < 3 )
|
||||
continue;
|
||||
|
||||
polySet.AddHole( hole_linechain );
|
||||
}
|
||||
|
||||
if( aLayer == F_Cu || aLayer == B_Cu )
|
||||
{
|
||||
PAD* pad = new PAD( aFootprint );
|
||||
|
||||
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 );
|
||||
|
||||
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, ADD_MODE::APPEND );
|
||||
}
|
||||
else
|
||||
{
|
||||
PCB_SHAPE* shape = new PCB_SHAPE( aFootprint, SHAPE_T::POLY );
|
||||
|
||||
shape->SetPolyShape( polySet );
|
||||
shape->SetFilled( true );
|
||||
shape->SetLayer( aLayer );
|
||||
shape->SetStroke( STROKE_PARAMS( 0 ) );
|
||||
|
||||
HelperShapeSetLocalCoord(shape);
|
||||
aFootprint->Add( shape, ADD_MODE::APPEND );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019-2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
|
||||
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -196,11 +197,13 @@ private:
|
|||
void ParseShapeBasedRegions6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
|
||||
const CFB::COMPOUND_FILE_ENTRY* aEntry );
|
||||
void ConvertShapeBasedRegions6ToBoardItem( const AREGION6& aElem );
|
||||
void ConvertShapeBasedRegions6ToFootprintItem( FOOTPRINT* aFootprint, const AREGION6& aElem );
|
||||
void ConvertShapeBasedRegions6ToFootprintItem( FOOTPRINT* aFootprint, const AREGION6& aElem,
|
||||
const int aPrimitiveIndex );
|
||||
void ConvertShapeBasedRegions6ToBoardItemOnLayer( const AREGION6& aElem, PCB_LAYER_ID aLayer );
|
||||
void ConvertShapeBasedRegions6ToFootprintItemOnLayer( FOOTPRINT* aFootprint,
|
||||
const AREGION6& aElem,
|
||||
PCB_LAYER_ID aLayer );
|
||||
PCB_LAYER_ID aLayer,
|
||||
const int aPrimitiveIndex );
|
||||
void ParseExtendedPrimitiveInformationData( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
|
||||
const CFB::COMPOUND_FILE_ENTRY* aEntry );
|
||||
void ParseRegions6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
|
||||
|
|
Loading…
Reference in New Issue