Step exporter: code cleaning and merge connected tracks in polygons

This commit is contained in:
jean-pierre charras 2023-03-06 11:47:29 +01:00
parent d96598c87c
commit eeee3adb94
4 changed files with 84 additions and 32 deletions

View File

@ -121,6 +121,7 @@ EXPORTER_STEP::EXPORTER_STEP( BOARD* aBoard, const EXPORTER_STEP_PARAMS& aParams
m_boardThickness( DEFAULT_BOARD_THICKNESS_MM ) m_boardThickness( DEFAULT_BOARD_THICKNESS_MM )
{ {
m_solderMaskColor = COLOR4D( 0.08, 0.20, 0.14, 0.83 ); m_solderMaskColor = COLOR4D( 0.08, 0.20, 0.14, 0.83 );
m_copperColor = COLOR4D( 0.7, 0.61, 0.0, 1.0 );
m_resolver = std::make_unique<FILENAME_RESOLVER>(); m_resolver = std::make_unique<FILENAME_RESOLVER>();
m_resolver->Set3DConfigDir( wxT( "" ) ); m_resolver->Set3DConfigDir( wxT( "" ) );
@ -135,7 +136,7 @@ EXPORTER_STEP::~EXPORTER_STEP()
} }
bool EXPORTER_STEP::composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin ) bool EXPORTER_STEP::buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOrigin )
{ {
bool hasdata = false; bool hasdata = false;
@ -152,6 +153,20 @@ bool EXPORTER_STEP::composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin )
} }
} }
// Build 3D shapes of the footprint graphic items on external layers:
if( ExportTracksAndVias() )
{
int maxError = m_board->GetDesignSettings().m_MaxError;
aFootprint->TransformFPShapesToPolySet( m_top_copper_shapes, F_Cu, 0, maxError, ERROR_INSIDE,
false, /* include text */
true, /* include shapes */
false /* include private items */ );
aFootprint->TransformFPShapesToPolySet( m_bottom_copper_shapes, B_Cu, 0, maxError, ERROR_INSIDE,
false, /* include text */
true, /* include shapes */
false /* include private items */ );
}
if( ( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM ) && !m_params.m_includeExcludedBom ) if( ( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM ) && !m_params.m_includeExcludedBom )
{ {
return hasdata; return hasdata;
@ -241,7 +256,7 @@ bool EXPORTER_STEP::composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin )
} }
bool EXPORTER_STEP::composePCB( PCB_TRACK* aTrack, VECTOR2D aOrigin ) bool EXPORTER_STEP::buildTrack3DShape( PCB_TRACK* aTrack, VECTOR2D aOrigin )
{ {
if( aTrack->Type() == PCB_VIA_T ) if( aTrack->Type() == PCB_VIA_T )
{ {
@ -268,15 +283,18 @@ bool EXPORTER_STEP::composePCB( PCB_TRACK* aTrack, VECTOR2D aOrigin )
SHAPE_POLY_SET copper_shapes; SHAPE_POLY_SET copper_shapes;
int maxError = m_board->GetDesignSettings().m_MaxError; int maxError = m_board->GetDesignSettings().m_MaxError;
aTrack->TransformShapeToPolygon( copper_shapes, pcblayer, 0, maxError, ERROR_INSIDE ); if( pcblayer == F_Cu )
aTrack->TransformShapeToPolygon( m_top_copper_shapes, pcblayer, 0, maxError, ERROR_INSIDE );
else
aTrack->TransformShapeToPolygon( m_bottom_copper_shapes, pcblayer, 0, maxError, ERROR_INSIDE );
m_pcbModel->AddCopperPolygonShapes( &copper_shapes, pcblayer == F_Cu, aOrigin ); //m_pcbModel->AddCopperPolygonShapes( &copper_shapes, pcblayer == F_Cu, aOrigin );
return true; return true;
} }
bool EXPORTER_STEP::composePCB() bool EXPORTER_STEP::buildBoard3DShapes()
{ {
if( m_pcbModel ) if( m_pcbModel )
return true; return true;
@ -303,6 +321,7 @@ bool EXPORTER_STEP::composePCB()
// TODO: Handle when top & bottom soldermask colours are different... // TODO: Handle when top & bottom soldermask colours are different...
m_pcbModel->SetBoardColor( m_solderMaskColor.r, m_solderMaskColor.g, m_solderMaskColor.b ); m_pcbModel->SetBoardColor( m_solderMaskColor.r, m_solderMaskColor.g, m_solderMaskColor.b );
m_pcbModel->SetCopperColor( m_copperColor.r, m_copperColor.g, m_copperColor.b );
m_pcbModel->SetPCBThickness( m_boardThickness ); m_pcbModel->SetPCBThickness( m_boardThickness );
@ -320,14 +339,20 @@ bool EXPORTER_STEP::composePCB()
// For copper layers, only pads and tracks are added, because adding everything on copper // For copper layers, only pads and tracks are added, because adding everything on copper
// generate unreasonable file sizes and take a unreasonable calculation time. // generate unreasonable file sizes and take a unreasonable calculation time.
for( FOOTPRINT* fp : m_board->Footprints() ) for( FOOTPRINT* fp : m_board->Footprints() )
composePCB( fp, origin ); buildFootprint3DShapes( fp, origin );
if( ExportTracksAndVias() ) if( ExportTracksAndVias() )
{ {
for( PCB_TRACK* track : m_board->Tracks() ) for( PCB_TRACK* track : m_board->Tracks() )
composePCB( track, origin ); buildTrack3DShape( track, origin );
} }
m_top_copper_shapes.Fracture( SHAPE_POLY_SET::PM_FAST );
m_bottom_copper_shapes.Fracture( SHAPE_POLY_SET::PM_FAST );
m_pcbModel->AddCopperPolygonShapes( &m_top_copper_shapes, true, origin );
m_pcbModel->AddCopperPolygonShapes( &m_bottom_copper_shapes, false, origin );
ReportMessage( wxT( "Create PCB solid model\n" ) ); ReportMessage( wxT( "Create PCB solid model\n" ) );
wxString msg; wxString msg;
@ -344,7 +369,7 @@ bool EXPORTER_STEP::composePCB()
} }
void EXPORTER_STEP::determinePcbThickness() void EXPORTER_STEP::calculatePcbThickness()
{ {
m_boardThickness = DEFAULT_BOARD_THICKNESS_MM; m_boardThickness = DEFAULT_BOARD_THICKNESS_MM;
@ -389,7 +414,7 @@ bool EXPORTER_STEP::Export()
Message::DefaultMessenger()->AddPrinter( new KiCadPrinter( this ) ); Message::DefaultMessenger()->AddPrinter( new KiCadPrinter( this ) );
ReportMessage( _( "Determining PCB data\n" ) ); ReportMessage( _( "Determining PCB data\n" ) );
determinePcbThickness(); calculatePcbThickness();
wxString msg; wxString msg;
msg.Printf( _( "Board Thickness from stackup: %.3f mm\n" ), m_boardThickness ); msg.Printf( _( "Board Thickness from stackup: %.3f mm\n" ), m_boardThickness );
ReportMessage( msg ); ReportMessage( msg );
@ -398,7 +423,7 @@ bool EXPORTER_STEP::Export()
{ {
ReportMessage( _( "Build STEP data\n" ) ); ReportMessage( _( "Build STEP data\n" ) );
if( !composePCB() ) if( !buildBoard3DShapes() )
{ {
ReportMessage( _( "\n** Error building STEP board model. Export aborted. **\n" ) ); ReportMessage( _( "\n** Error building STEP board model. Export aborted. **\n" ) );
return false; return false;

View File

@ -87,10 +87,10 @@ public:
bool ExportTracksAndVias() { return m_params.m_exportTracks; } bool ExportTracksAndVias() { return m_params.m_exportTracks; }
private: private:
bool composePCB(); bool buildBoard3DShapes();
bool composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin ); bool buildFootprint3DShapes( FOOTPRINT* aFootprint, VECTOR2D aOrigin );
bool composePCB( PCB_TRACK* aTrack, VECTOR2D aOrigin ); bool buildTrack3DShape( PCB_TRACK* aTrack, VECTOR2D aOrigin );
void determinePcbThickness(); void calculatePcbThickness();
EXPORTER_STEP_PARAMS m_params; EXPORTER_STEP_PARAMS m_params;
std::unique_ptr<FILENAME_RESOLVER> m_resolver; std::unique_ptr<FILENAME_RESOLVER> m_resolver;
@ -107,7 +107,11 @@ private:
double m_boardThickness; double m_boardThickness;
SHAPE_POLY_SET m_top_copper_shapes;
SHAPE_POLY_SET m_bottom_copper_shapes;
KIGFX::COLOR4D m_solderMaskColor; KIGFX::COLOR4D m_solderMaskColor;
KIGFX::COLOR4D m_copperColor;
}; };
#endif #endif

View File

@ -178,7 +178,7 @@ STEP_PCB_MODEL::STEP_PCB_MODEL( const wxString& aPcbName )
{ {
m_app = XCAFApp_Application::GetApplication(); m_app = XCAFApp_Application::GetApplication();
m_app->NewDocument( "MDTV-XCAF", m_doc ); m_app->NewDocument( "MDTV-XCAF", m_doc );
m_assy = XCAFDoc_DocumentTool::ShapeTool ( m_doc->Main() ); m_assy = XCAFDoc_DocumentTool::ShapeTool( m_doc->Main() );
m_assy_label = m_assy->NewShape(); m_assy_label = m_assy->NewShape();
m_hasPCB = false; m_hasPCB = false;
m_components = 0; m_components = 0;
@ -277,16 +277,19 @@ bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin )
return false; return false;
VECTOR2I pos = aPad->GetPosition(); VECTOR2I pos = aPad->GetPosition();
double holeZsize = m_boardThickness + ( m_copperThickness * 2 ); 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
double holeZsize = m_boardThickness + ( m_copperThickness * 2 ) + ( margin * 2 );
if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE ) if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
{ {
TopoDS_Shape s = TopoDS_Shape s =
BRepPrimAPI_MakeCylinder( pcbIUScale.IUTomm( aPad->GetDrillSize().x ) * 0.5, holeZsize * 2.0 ).Shape(); BRepPrimAPI_MakeCylinder( pcbIUScale.IUTomm( aPad->GetDrillSize().x ) * 0.5, holeZsize ).Shape();
gp_Trsf shift; gp_Trsf shift;
shift.SetTranslation( gp_Vec( pcbIUScale.IUTomm( pos.x - aOrigin.x ), shift.SetTranslation( gp_Vec( pcbIUScale.IUTomm( pos.x - aOrigin.x ),
-pcbIUScale.IUTomm( pos.y - aOrigin.y ), -pcbIUScale.IUTomm( pos.y - aOrigin.y ),
-holeZsize * 0.5 ) ); -m_copperThickness - margin ) );
BRepBuilderAPI_Transform hole( s, shift ); BRepBuilderAPI_Transform hole( s, shift );
m_cutouts.push_back( hole.Shape() ); m_cutouts.push_back( hole.Shape() );
return true; return true;
@ -304,7 +307,7 @@ bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin )
if( holeOutlines.OutlineCount() > 0 ) if( holeOutlines.OutlineCount() > 0 )
{ {
if( MakeShape( hole, holeOutlines.COutline( 0 ), holeZsize*2, -holeZsize * 0.5, aOrigin ) ) if( MakeShape( hole, holeOutlines.COutline( 0 ), holeZsize, -m_copperThickness - margin, aOrigin ) )
{ {
m_cutouts.push_back( hole ); m_cutouts.push_back( hole );
} }
@ -392,6 +395,14 @@ void STEP_PCB_MODEL::SetBoardColor( double r, double g, double b )
} }
void STEP_PCB_MODEL::SetCopperColor( double r, double g, double b )
{
m_copperColor[0] = r;
m_copperColor[1] = g;
m_copperColor[2] = b;
}
void STEP_PCB_MODEL::OCCSetMergeMaxDistance( double aDistance ) void STEP_PCB_MODEL::OCCSetMergeMaxDistance( double aDistance )
{ {
// Ensure a minimal value (in mm) // Ensure a minimal value (in mm)
@ -562,7 +573,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
for( TopoDS_Shape& hole : m_cutouts ) for( TopoDS_Shape& hole : m_cutouts )
holelist.Append( hole ); holelist.Append( hole );
// Remove holes for each board (usually there is only one board // Remove holes for each board (usually there is only one board)
int cnt = 0; int cnt = 0;
for( TopoDS_Shape& board: m_board_outlines ) for( TopoDS_Shape& board: m_board_outlines )
{ {
@ -605,18 +616,18 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
// identically named assemblies. So we want to avoid having the PCB be generally defaulted // identically named assemblies. So we want to avoid having the PCB be generally defaulted
// to "Component" or "Assembly". // to "Component" or "Assembly".
// color the PCB // Init colors for the board body and the copper items (if any)
Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main() ); Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main() );
Quantity_Color board_color( m_boardColor[0], m_boardColor[1], m_boardColor[2], Quantity_TOC_RGB ); Quantity_Color board_color( m_boardColor[0], m_boardColor[1], m_boardColor[2],
Quantity_Color copper_color( 0.7, 0.61, 0.0, Quantity_TOC_RGB ); Quantity_TOC_RGB );
Quantity_Color copper_color( m_copperColor[0], m_copperColor[1], m_copperColor[2],
Quantity_TOC_RGB );
int pcbIdx = 1; int pcbIdx = 1;
int copper_objects_cnt = 0; int copper_objects_cnt = 0;
for( TDF_Label& pcb_label : m_pcb_labels ) for( TDF_Label& pcb_label : m_pcb_labels )
{ {
colorTool->SetColor( pcb_label, board_color, XCAFDoc_ColorSurf );
Handle( TDataStd_TreeNode ) node; Handle( TDataStd_TreeNode ) node;
if( pcb_label.FindAttribute( XCAFDoc::ShapeRefGUID(), node ) ) if( pcb_label.FindAttribute( XCAFDoc::ShapeRefGUID(), node ) )
@ -628,10 +639,17 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
{ {
wxString pcbName; wxString pcbName;
if( m_pcb_labels.size() == 1 ) if( copper_objects_cnt < copper_item_count )
pcbName = wxT( "PCB" ); {
pcbName = wxString::Format( wxT( "Copper_Item%d" ), copper_objects_cnt+1 );
}
else else
pcbName = wxString::Format( wxT( "PCB%d" ), pcbIdx++ ); {
if( m_pcb_labels.size() == 1 )
pcbName = wxT( "PCB" );
else
pcbName = wxString::Format( wxT( "PCB%d" ), pcbIdx++ );
}
std::string pcbNameStdString( pcbName.ToUTF8() ); std::string pcbNameStdString( pcbName.ToUTF8() );
TCollection_ExtendedString partname( pcbNameStdString.c_str() ); TCollection_ExtendedString partname( pcbNameStdString.c_str() );
@ -641,10 +659,11 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
// color the PCB // color the PCB
TopExp_Explorer topex; TopExp_Explorer topex;
topex.Init( m_assy->GetShape( pcb_label ), TopAbs_SOLID ); topex.Init( m_assy->GetShape( pcb_label ), TopAbs_COMPOUND /*TopAbs_SOLID*/ );
while( topex.More() ) while( topex.More() )
{ {
// First objects are copper objects, last(s) is the board body
if( copper_objects_cnt < copper_item_count ) if( copper_objects_cnt < copper_item_count )
colorTool->SetColor( topex.Current(), copper_color, XCAFDoc_ColorSurf ); colorTool->SetColor( topex.Current(), copper_color, XCAFDoc_ColorSurf );
else else

View File

@ -44,9 +44,9 @@
/** /**
* Default distance between points to treat them as separate ones (mm) * Default distance between points to treat them as separate ones (mm)
* 0.001 mm is a reasonable value. A too large value creates issues by * 0.001 mm or less is a reasonable value. A too large value creates issues by
* merging points that should be different. * merging points that should be different.
* Remember we are a 3D space, so a thin line can be broken if 2 points * Remember we are a 3D space, so a thin shape can be broken if 2 points
* are merged (in X, Y, Z coords) when they should not. * are merged (in X, Y, Z coords) when they should not.
* round shapes converted to polygon can also be not good with a to large value * round shapes converted to polygon can also be not good with a to large value
*/ */
@ -56,9 +56,11 @@ static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS = 0.001;
static constexpr double BOARD_THICKNESS_DEFAULT_MM = 1.6; static constexpr double BOARD_THICKNESS_DEFAULT_MM = 1.6;
// minimum PCB thickness in mm (10 microns assumes a very thin polyimide film) // minimum PCB thickness in mm (10 microns assumes a very thin polyimide film)
// must be > OCC_MAX_DISTANCE_TO_MERGE_POINTS
static constexpr double BOARD_THICKNESS_MIN_MM = 0.01; static constexpr double BOARD_THICKNESS_MIN_MM = 0.01;
// default copper thickness in mm // default copper thickness in mm
// must be > OCC_MAX_DISTANCE_TO_MERGE_POINTS
static constexpr double COPPER_THICKNESS_DEFAULT_MM = 0.035; static constexpr double COPPER_THICKNESS_DEFAULT_MM = 0.035;
// Max error to approximate an arc by segments (in mm) // Max error to approximate an arc by segments (in mm)
@ -92,6 +94,7 @@ public:
VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels = true ); VECTOR3D aOrientation, VECTOR3D aScale, bool aSubstituteModels = true );
void SetBoardColor( double r, double g, double b ); void SetBoardColor( double r, double g, double b );
void SetCopperColor( double r, double g, double b );
// set the thickness of the PCB (mm); the top of the PCB shall be at Z = aThickness // set the thickness of the PCB (mm); the top of the PCB shall be at Z = aThickness
// aThickness < 0.0 == use default thickness // aThickness < 0.0 == use default thickness
@ -166,7 +169,8 @@ private:
int m_components; // number of successfully loaded components; int m_components; // number of successfully loaded components;
double m_precision; // model (length unit) numeric precision double m_precision; // model (length unit) numeric precision
double m_angleprec; // angle numeric precision double m_angleprec; // angle numeric precision
double m_boardColor[3]; // RGB values double m_boardColor[3]; // board body, RGB values
double m_copperColor[3]; // copper, RGB values
double m_boardThickness; // PCB thickness, mm double m_boardThickness; // PCB thickness, mm
double m_copperThickness; // copper thickness, mm double m_copperThickness; // copper thickness, mm