STEP: export copper plating for vias/pads (25 micrometers).

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16694
This commit is contained in:
Alex Shvartzkop 2024-02-02 00:29:03 +03:00
parent a485a4815c
commit 4a1245e85a
2 changed files with 105 additions and 95 deletions

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016-2024 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
@ -250,6 +250,26 @@ bool STEP_PCB_MODEL::AddPadShape( const PAD* aPad, const VECTOR2D& aOrigin )
break;
}
if( aPad->GetAttribute() == PAD_ATTRIB::PTH && aPad->IsOnLayer( F_Cu )
&& aPad->IsOnLayer( B_Cu ) )
{
TopoDS_Shape plating;
std::shared_ptr<SHAPE_SEGMENT> seg_hole = aPad->GetEffectiveHoleShape();
double width = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
if( MakeShapeAsThickSegment( plating, seg_hole->GetSeg().A, seg_hole->GetSeg().B, width,
m_boardThickness + m_copperThickness * 2, -m_copperThickness,
aOrigin ) )
{
m_board_copper_pads.push_back( plating );
}
else
{
success = false;
}
}
if( !success ) // Error
ReportMessage( wxT( "OCC error adding pad/via polygon.\n" ) );
@ -324,64 +344,40 @@ bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin )
if( aPad == nullptr || !aPad->GetDrillSize().x )
return false;
VECTOR2I pos = aPad->GetPosition();
const double margin = 0.01; // a small margin on the Z axix to be sure the hole
// is bigget than the board with copper
// must be > OCC_MAX_DISTANCE_TO_MERGE_POINTS
// TODO: make configurable
int platingThickness = aPad->GetAttribute() == PAD_ATTRIB::PTH ? pcbIUScale.mmToIU( 0.025 ) : 0;
const double margin = 0.01; // a small margin on the Z axix to be sure the hole
// is bigger than the board with copper
// must be > OCC_MAX_DISTANCE_TO_MERGE_POINTS
double holeZsize = m_boardThickness + ( m_copperThickness * 2 ) + ( margin * 2 );
if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
{
TopoDS_Shape s =
BRepPrimAPI_MakeCylinder( pcbIUScale.IUTomm( aPad->GetDrillSize().x ) * 0.5, holeZsize ).Shape();
gp_Trsf shift;
shift.SetTranslation( gp_Vec( pcbIUScale.IUTomm( pos.x - aOrigin.x ),
-pcbIUScale.IUTomm( pos.y - aOrigin.y ),
-m_copperThickness - margin ) );
BRepBuilderAPI_Transform hole( s, shift );
m_cutouts.push_back( hole.Shape() );
return true;
}
// slotted hole
TopoDS_Shape hole;
#if 0 // set to 1 to export oblong hole as polygon
SHAPE_POLY_SET holeOutlines;
if( !aPad->TransformHoleToPolygon( holeOutlines, 0, m_maxError, ERROR_INSIDE ) )
{
return false;
}
if( holeOutlines.OutlineCount() > 0 )
{
if( MakeShape( hole, holeOutlines.COutline( 0 ), holeZsize, -m_copperThickness - margin, aOrigin ) )
{
m_cutouts.push_back( hole );
}
}
else
{
return false;
}
#else
std::shared_ptr<SHAPE_SEGMENT> seg_hole = aPad->GetEffectiveHoleShape();
double width = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
if( MakeShapeAsThickSegment( hole,
seg_hole->GetSeg().A, seg_hole->GetSeg().B,
width, holeZsize, -m_copperThickness - margin,
aOrigin ) )
double boardDrill = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
double copperDrill = boardDrill - platingThickness * 2;
TopoDS_Shape copperHole, boardHole;
if( MakeShapeAsThickSegment( copperHole, seg_hole->GetSeg().A, seg_hole->GetSeg().B,
copperDrill, holeZsize, -m_copperThickness - margin, aOrigin ) )
{
m_cutouts.push_back( hole );
m_copperCutouts.push_back( copperHole );
}
else
{
return false;
}
if( MakeShapeAsThickSegment( boardHole, seg_hole->GetSeg().A, seg_hole->GetSeg().B, boardDrill,
holeZsize, -m_copperThickness - margin, aOrigin ) )
{
m_boardCutouts.push_back( boardHole );
}
else
{
return false;
}
#endif
return true;
}
@ -915,76 +911,89 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
BRepBndLib::Add( brdShape, brdBndBox );
// subtract cutouts (if any)
if( m_cutouts.size() )
{
ReportMessage( wxString::Format( wxT( "Build board cutouts and holes (%d hole(s)).\n" ),
(int) m_cutouts.size() ) );
ReportMessage( wxString::Format( wxT( "Build board cutouts and holes (%d hole(s)).\n" ),
(int) ( m_boardCutouts.size() + m_copperCutouts.size() ) ) );
auto buildBSB = [&brdBndBox]( std::vector<TopoDS_Shape>& input, Bnd_BoundSortBox& bsbHoles )
{
// We need to encompass every location we'll need to test in the global bbox,
// otherwise Bnd_BoundSortBox doesn't work near the boundaries.
Bnd_Box brdWithHolesBndBox = brdBndBox;
Bnd_BoundSortBox bsbHoles;
Bnd_Box brdWithHolesBndBox = brdBndBox;
Handle( Bnd_HArray1OfBox ) holeBoxSet = new Bnd_HArray1OfBox( 0, m_cutouts.size() - 1 );
Handle( Bnd_HArray1OfBox ) holeBoxSet = new Bnd_HArray1OfBox( 0, input.size() - 1 );
for( size_t i = 0; i < m_cutouts.size(); i++ )
for( size_t i = 0; i < input.size(); i++ )
{
Bnd_Box bbox;
BRepBndLib::Add( m_cutouts[i], bbox );
BRepBndLib::Add( input[i], bbox );
brdWithHolesBndBox.Add( bbox );
( *holeBoxSet )[i] = bbox;
}
bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
};
auto subtractShapes = [&]( const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList )
auto subtractShapes = []( const wxString& aWhat, std::vector<TopoDS_Shape>& aShapesList,
std::vector<TopoDS_Shape>& aHolesList, Bnd_BoundSortBox& aBSBHoles )
{
// Remove holes for each item (board body or bodies, one can have more than one board)
int cnt = 0;
for( TopoDS_Shape& shape : aShapesList )
{
// Remove holes for each item (board body or bodies, one can have more than one board)
int cnt = 0;
for( TopoDS_Shape& shape : aShapesList )
{
Bnd_Box shapeBbox;
BRepBndLib::Add( shape, shapeBbox );
Bnd_Box shapeBbox;
BRepBndLib::Add( shape, shapeBbox );
const TColStd_ListOfInteger& indices = bsbHoles.Compare( shapeBbox );
const TColStd_ListOfInteger& indices = aBSBHoles.Compare( shapeBbox );
TopTools_ListOfShape holelist;
TopTools_ListOfShape holelist;
for( const Standard_Integer& index : indices )
holelist.Append( m_cutouts[index] );
for( const Standard_Integer& index : indices )
holelist.Append( aHolesList[index] );
if( cnt == 0 )
ReportMessage( wxString::Format( _( "Build holes for %s\n" ), aWhat ) );
if( cnt == 0 )
ReportMessage( wxString::Format( _( "Build holes for %s\n" ), aWhat ) );
cnt++;
cnt++;
if( cnt % 10 == 0 )
ReportMessage( wxString::Format( _( "Cutting %d/%d %s\n" ), cnt,
(int) aShapesList.size(), aWhat ) );
if( cnt % 10 == 0 )
ReportMessage( wxString::Format( _( "Cutting %d/%d %s\n" ), cnt,
(int) aShapesList.size(), aWhat ) );
if( holelist.IsEmpty() )
continue;
if( holelist.IsEmpty() )
continue;
TopTools_ListOfShape cutArgs;
cutArgs.Append( shape );
TopTools_ListOfShape cutArgs;
cutArgs.Append( shape );
BRepAlgoAPI_Cut cut;
BRepAlgoAPI_Cut cut;
// This helps cutting circular holes in zones where a hole is already cut in Clipper
cut.SetFuzzyValue( 0.0005 );
cut.SetArguments( cutArgs );
// This helps cutting circular holes in zones where a hole is already cut in Clipper
cut.SetFuzzyValue( 0.0005 );
cut.SetArguments( cutArgs );
cut.SetTools( holelist );
cut.Build();
cut.SetTools( holelist );
cut.Build();
shape = cut.Shape();
}
};
shape = cut.Shape();
}
};
subtractShapes( _( "pads" ), m_board_copper_pads );
subtractShapes( _( "shapes" ), m_board_outlines );
subtractShapes( _( "tracks" ), m_board_copper_tracks );
subtractShapes( _( "zones" ), m_board_copper_zones );
if( m_boardCutouts.size() )
{
Bnd_BoundSortBox bsbHoles;
buildBSB( m_boardCutouts, bsbHoles );
subtractShapes( _( "shapes" ), m_board_outlines, m_boardCutouts, bsbHoles );
}
if( m_copperCutouts.size() )
{
Bnd_BoundSortBox bsbHoles;
buildBSB( m_copperCutouts, bsbHoles );
subtractShapes( _( "pads" ), m_board_copper_pads, m_copperCutouts, bsbHoles );
subtractShapes( _( "tracks" ), m_board_copper_tracks, m_copperCutouts, bsbHoles );
subtractShapes( _( "zones" ), m_board_copper_zones, m_copperCutouts, bsbHoles );
}
// push the board to the data structure

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2021-2024 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
@ -240,8 +240,9 @@ private:
double m_mergeOCCMaxDist; // minimum distance (mm) below which two
// points are considered coincident by OCC
// Holes in main outlines (more than one board)
std::vector<TopoDS_Shape> m_cutouts;
// Holes in copper and main outlines
std::vector<TopoDS_Shape> m_copperCutouts;
std::vector<TopoDS_Shape> m_boardCutouts;
// Main outlines (more than one board)
std::vector<TopoDS_Shape> m_board_outlines;