STEP: export copper plating for vias/pads (25 micrometers).
Fixes https://gitlab.com/kicad/code/kicad/-/issues/16694
This commit is contained in:
parent
a485a4815c
commit
4a1245e85a
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
|
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
|
||||||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* 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;
|
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
|
if( !success ) // Error
|
||||||
ReportMessage( wxT( "OCC error adding pad/via polygon.\n" ) );
|
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 )
|
if( aPad == nullptr || !aPad->GetDrillSize().x )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
VECTOR2I pos = aPad->GetPosition();
|
// TODO: make configurable
|
||||||
const double margin = 0.01; // a small margin on the Z axix to be sure the hole
|
int platingThickness = aPad->GetAttribute() == PAD_ATTRIB::PTH ? pcbIUScale.mmToIU( 0.025 ) : 0;
|
||||||
// is bigget than the board with copper
|
|
||||||
// must be > OCC_MAX_DISTANCE_TO_MERGE_POINTS
|
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 );
|
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();
|
std::shared_ptr<SHAPE_SEGMENT> seg_hole = aPad->GetEffectiveHoleShape();
|
||||||
double width = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
|
|
||||||
|
|
||||||
if( MakeShapeAsThickSegment( hole,
|
double boardDrill = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y );
|
||||||
seg_hole->GetSeg().A, seg_hole->GetSeg().B,
|
double copperDrill = boardDrill - platingThickness * 2;
|
||||||
width, holeZsize, -m_copperThickness - margin,
|
|
||||||
aOrigin ) )
|
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
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -915,76 +911,89 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
|
||||||
BRepBndLib::Add( brdShape, brdBndBox );
|
BRepBndLib::Add( brdShape, brdBndBox );
|
||||||
|
|
||||||
// subtract cutouts (if any)
|
// subtract cutouts (if any)
|
||||||
if( m_cutouts.size() )
|
ReportMessage( wxString::Format( wxT( "Build board cutouts and holes (%d hole(s)).\n" ),
|
||||||
{
|
(int) ( m_boardCutouts.size() + m_copperCutouts.size() ) ) );
|
||||||
ReportMessage( wxString::Format( wxT( "Build board cutouts and holes (%d hole(s)).\n" ),
|
|
||||||
(int) m_cutouts.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,
|
// We need to encompass every location we'll need to test in the global bbox,
|
||||||
// otherwise Bnd_BoundSortBox doesn't work near the boundaries.
|
// otherwise Bnd_BoundSortBox doesn't work near the boundaries.
|
||||||
Bnd_Box brdWithHolesBndBox = brdBndBox;
|
Bnd_Box brdWithHolesBndBox = brdBndBox;
|
||||||
Bnd_BoundSortBox bsbHoles;
|
|
||||||
|
|
||||||
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;
|
Bnd_Box bbox;
|
||||||
BRepBndLib::Add( m_cutouts[i], bbox );
|
BRepBndLib::Add( input[i], bbox );
|
||||||
brdWithHolesBndBox.Add( bbox );
|
brdWithHolesBndBox.Add( bbox );
|
||||||
( *holeBoxSet )[i] = bbox;
|
( *holeBoxSet )[i] = bbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
bsbHoles.Initialize( brdWithHolesBndBox, holeBoxSet );
|
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)
|
Bnd_Box shapeBbox;
|
||||||
int cnt = 0;
|
BRepBndLib::Add( shape, shapeBbox );
|
||||||
for( TopoDS_Shape& shape : aShapesList )
|
|
||||||
{
|
|
||||||
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 )
|
for( const Standard_Integer& index : indices )
|
||||||
holelist.Append( m_cutouts[index] );
|
holelist.Append( aHolesList[index] );
|
||||||
|
|
||||||
if( cnt == 0 )
|
if( cnt == 0 )
|
||||||
ReportMessage( wxString::Format( _( "Build holes for %s\n" ), aWhat ) );
|
ReportMessage( wxString::Format( _( "Build holes for %s\n" ), aWhat ) );
|
||||||
|
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
||||||
if( cnt % 10 == 0 )
|
if( cnt % 10 == 0 )
|
||||||
ReportMessage( wxString::Format( _( "Cutting %d/%d %s\n" ), cnt,
|
ReportMessage( wxString::Format( _( "Cutting %d/%d %s\n" ), cnt,
|
||||||
(int) aShapesList.size(), aWhat ) );
|
(int) aShapesList.size(), aWhat ) );
|
||||||
|
|
||||||
if( holelist.IsEmpty() )
|
if( holelist.IsEmpty() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
TopTools_ListOfShape cutArgs;
|
TopTools_ListOfShape cutArgs;
|
||||||
cutArgs.Append( shape );
|
cutArgs.Append( shape );
|
||||||
|
|
||||||
BRepAlgoAPI_Cut cut;
|
BRepAlgoAPI_Cut cut;
|
||||||
|
|
||||||
// This helps cutting circular holes in zones where a hole is already cut in Clipper
|
// This helps cutting circular holes in zones where a hole is already cut in Clipper
|
||||||
cut.SetFuzzyValue( 0.0005 );
|
cut.SetFuzzyValue( 0.0005 );
|
||||||
cut.SetArguments( cutArgs );
|
cut.SetArguments( cutArgs );
|
||||||
|
|
||||||
cut.SetTools( holelist );
|
cut.SetTools( holelist );
|
||||||
cut.Build();
|
cut.Build();
|
||||||
|
|
||||||
shape = cut.Shape();
|
shape = cut.Shape();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
subtractShapes( _( "pads" ), m_board_copper_pads );
|
if( m_boardCutouts.size() )
|
||||||
subtractShapes( _( "shapes" ), m_board_outlines );
|
{
|
||||||
subtractShapes( _( "tracks" ), m_board_copper_tracks );
|
Bnd_BoundSortBox bsbHoles;
|
||||||
subtractShapes( _( "zones" ), m_board_copper_zones );
|
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
|
// push the board to the data structure
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* 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) 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* 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
|
double m_mergeOCCMaxDist; // minimum distance (mm) below which two
|
||||||
// points are considered coincident by OCC
|
// points are considered coincident by OCC
|
||||||
|
|
||||||
// Holes in main outlines (more than one board)
|
// Holes in copper and main outlines
|
||||||
std::vector<TopoDS_Shape> m_cutouts;
|
std::vector<TopoDS_Shape> m_copperCutouts;
|
||||||
|
std::vector<TopoDS_Shape> m_boardCutouts;
|
||||||
|
|
||||||
// Main outlines (more than one board)
|
// Main outlines (more than one board)
|
||||||
std::vector<TopoDS_Shape> m_board_outlines;
|
std::vector<TopoDS_Shape> m_board_outlines;
|
||||||
|
|
Loading…
Reference in New Issue