Step exporter fixes and enhancements:

- fix duplicate code and a few bugs (some are due to changes in code over the years)
- ADDED: option to export tracks and vias on external layers Exporting tracks is *very* time consuming,
and need a bit of optimization.
This commit is contained in:
jean-pierre charras 2023-03-02 19:38:19 +01:00
parent 67ec09c850
commit f569cffa8e
11 changed files with 390 additions and 124 deletions

View File

@ -39,7 +39,9 @@ public:
m_outputFile(),
m_xOrigin( 0.0 ),
m_yOrigin( 0.0 ),
m_minDistance( 0.01 ) // 0.01 mm is a good value to connect 2 items of the board outlines
// max dist to chain 2 items (lines or curves) to build the board outlines
m_BoardOutlinesChainingEpsilon( 0.01 ), // 0.01 mm is a good value
m_exportTracks( false ) // Extremely time consuming if true
{
}
@ -53,7 +55,8 @@ public:
wxString m_outputFile;
double m_xOrigin;
double m_yOrigin;
double m_minDistance;
double m_BoardOutlinesChainingEpsilon;
bool m_exportTracks;
};
#endif

View File

@ -37,6 +37,7 @@
#define ARG_MIN_DISTANCE "--min-distance"
#define ARG_USER_ORIGIN "--user-origin"
#define ARG_BOARD_ONLY "--board-only"
#define ARG_EXPORT_TRACKS "--export-tracks"
#define REGEX_QUANTITY "([\\s]*[+-]?[\\d]*[.]?[\\d]*)"
#define REGEX_DELIMITER "(?:[\\s]*x)"
@ -74,6 +75,11 @@ CLI::EXPORT_PCB_STEP_COMMAND::EXPORT_PCB_STEP_COMMAND() : COMMAND( "step" )
.implicit_value( true )
.default_value( false );
m_argParser.add_argument( ARG_EXPORT_TRACKS )
.help( UTF8STDSTR( _( "Export tracks (extremely time consuming)" ) ) )
.implicit_value( true )
.default_value( false );
m_argParser.add_argument( ARG_MIN_DISTANCE )
.default_value( std::string( "0.01mm" ) )
.help( UTF8STDSTR( _( "Minimum distance between points to treat them as separate ones" ) ) );
@ -101,6 +107,7 @@ int CLI::EXPORT_PCB_STEP_COMMAND::doPerform( KIWAY& aKiway )
step->m_filename = FROM_UTF8( m_argParser.get<std::string>( ARG_INPUT ).c_str() );
step->m_outputFile = FROM_UTF8( m_argParser.get<std::string>( ARG_OUTPUT ).c_str() );
step->m_boardOnly = m_argParser.get<bool>( ARG_BOARD_ONLY );
step->m_exportTracks = m_argParser.get<bool>( ARG_EXPORT_TRACKS );
wxString userOrigin = FROM_UTF8( m_argParser.get<std::string>( ARG_USER_ORIGIN ).c_str() );
@ -142,6 +149,7 @@ int CLI::EXPORT_PCB_STEP_COMMAND::doPerform( KIWAY& aKiway )
}
wxString minDistance = FROM_UTF8( m_argParser.get<std::string>( ARG_MIN_DISTANCE ).c_str() );
if( !minDistance.IsEmpty() )
{
std::regex re_pattern( REGEX_QUANTITY REGEX_UNIT,
@ -149,7 +157,7 @@ int CLI::EXPORT_PCB_STEP_COMMAND::doPerform( KIWAY& aKiway )
std::smatch sm;
std::string str( minDistance.ToUTF8() );
std::regex_search( str, sm, re_pattern );
step->m_minDistance = atof( sm.str( 1 ).c_str() );
step->m_BoardOutlinesChainingEpsilon = atof( sm.str( 1 ).c_str() );
std::string tunit( sm[2] );
@ -157,7 +165,7 @@ int CLI::EXPORT_PCB_STEP_COMMAND::doPerform( KIWAY& aKiway )
{
if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) )
{
step->m_minDistance *= 25.4;
step->m_BoardOutlinesChainingEpsilon *= 25.4;
}
else if( tunit.compare( "mm" ) )
{

View File

@ -107,13 +107,15 @@ private:
double m_userOriginY; // remember last User Origin Y value
int m_originUnits; // remember last units for User Origin
bool m_noVirtual; // remember last preference for No Virtual Component
static bool m_exportTracks; // remember last preference to export tracks
// (stored only for the session)
wxString m_boardPath; // path to the exported board file
static int m_toleranceLastChoice; // Store m_tolerance option during a session
};
int DIALOG_EXPORT_STEP::m_toleranceLastChoice = -1; // Use default
bool DIALOG_EXPORT_STEP::m_exportTracks = false;
DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString& aBoardPath ) :
DIALOG_EXPORT_STEP_BASE( aParent )
@ -172,6 +174,7 @@ DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString&
m_userOriginY = cfg->m_ExportStep.origin_y;
m_noVirtual = cfg->m_ExportStep.no_virtual;
m_cbExportTracks->SetValue( m_exportTracks );
m_cbRemoveVirtual->SetValue( m_noVirtual );
m_cbSubstModels->SetValue( cfg->m_ExportStep.replace_models );
m_cbOverwriteFile->SetValue( cfg->m_ExportStep.overwrite_file );
@ -224,7 +227,7 @@ DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString&
}
if( m_toleranceLastChoice >= 0 )
m_tolerance->SetSelection( m_toleranceLastChoice );
m_choiceTolerance->SetSelection( m_toleranceLastChoice );
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
@ -252,7 +255,8 @@ DIALOG_EXPORT_STEP::~DIALOG_EXPORT_STEP()
cfg->m_ExportStep.no_virtual = m_cbRemoveVirtual->GetValue();
m_toleranceLastChoice = m_tolerance->GetSelection();
m_toleranceLastChoice = m_choiceTolerance->GetSelection();
m_exportTracks = m_cbExportTracks->GetValue();
}
@ -318,9 +322,10 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
m_parent->SetLastPath( LAST_PATH_STEP, m_filePickerSTEP->GetPath() );
double tolerance; // default value in mm
m_toleranceLastChoice = m_tolerance->GetSelection();
m_toleranceLastChoice = m_choiceTolerance->GetSelection();
m_exportTracks = m_cbExportTracks->GetValue();
switch( m_tolerance->GetSelection() )
switch( m_choiceTolerance->GetSelection() )
{
case 0: tolerance = 0.001; break;
default:
@ -394,6 +399,9 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
if( GetSubstOption() )
cmdK2S.Append( wxT( " --subst-models" ) );
if( m_exportTracks )
cmdK2S.Append( wxT( " --export-tracks" ) );
// Note: for some reason, using \" to insert a quote in a format string, under MacOS
// wxString::Format does not work. So use a %c format in string
int quote = '\'';

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 3.10.1-282-g1fa54006)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -120,17 +120,22 @@ DIALOG_EXPORT_STEP_BASE::DIALOG_EXPORT_STEP_BASE( wxWindow* parent, wxWindowID i
m_cbOverwriteFile = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Overwrite old file"), wxDefaultPosition, wxDefaultSize, 0 );
sbOtherOptions->Add( m_cbOverwriteFile, 0, wxBOTTOM|wxRIGHT, 5 );
m_cbExportTracks = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export tracks (time consuming)"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbExportTracks->SetToolTip( _("Export tracks and vias on external copper layers.\nWarning: this is *extremely* time consuming.") );
sbOtherOptions->Add( m_cbExportTracks, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 );
m_staticTextTolerance = new wxStaticText( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Board outline chaining tolerance:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextTolerance->Wrap( -1 );
sbOtherOptions->Add( m_staticTextTolerance, 0, wxLEFT|wxRIGHT|wxTOP, 5 );
wxString m_toleranceChoices[] = { _("Tight (0.001 mm)"), _("Standard (0.01 mm)"), _("Loose (0.1 mm)") };
int m_toleranceNChoices = sizeof( m_toleranceChoices ) / sizeof( wxString );
m_tolerance = new wxChoice( sbOtherOptions->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_toleranceNChoices, m_toleranceChoices, 0 );
m_tolerance->SetSelection( 1 );
m_tolerance->SetToolTip( _("Tolerance sets the distance between two points that are considered joined.") );
wxString m_choiceToleranceChoices[] = { _("Tight (0.001 mm)"), _("Standard (0.01 mm)"), _("Loose (0.1 mm)") };
int m_choiceToleranceNChoices = sizeof( m_choiceToleranceChoices ) / sizeof( wxString );
m_choiceTolerance = new wxChoice( sbOtherOptions->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceToleranceNChoices, m_choiceToleranceChoices, 0 );
m_choiceTolerance->SetSelection( 1 );
m_choiceTolerance->SetToolTip( _("Tolerance sets the distance between two points that are considered joined when building the board outlines.") );
sbOtherOptions->Add( m_tolerance, 0, wxALL|wxEXPAND, 5 );
sbOtherOptions->Add( m_choiceTolerance, 0, wxALL|wxEXPAND, 5 );
bSizer2->Add( sbOtherOptions, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 );

View File

@ -36,6 +36,7 @@
<property name="center">wxBOTH</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="extra_style"></property>
@ -95,6 +96,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -156,6 +158,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -244,6 +247,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -308,6 +312,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -372,6 +377,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -436,6 +442,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -530,6 +537,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -592,6 +600,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -656,6 +665,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -717,6 +727,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -782,6 +793,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -843,6 +855,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -925,6 +938,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -989,6 +1003,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1053,6 +1068,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1091,6 +1107,71 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxTOP|wxBOTTOM|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Export tracks (time consuming)</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbExportTracks</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip">Export tracks and vias on external copper layers.&#x0A;Warning: this is *extremely* time consuming.</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxLEFT|wxRIGHT|wxTOP</property>
@ -1116,6 +1197,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1178,6 +1260,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1192,7 +1275,7 @@
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_tolerance</property>
<property name="name">m_choiceTolerance</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -1206,7 +1289,7 @@
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip">Tolerance sets the distance between two points that are considered joined.</property>
<property name="tooltip">Tolerance sets the distance between two points that are considered joined when building the board outlines.</property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 3.10.1-282-g1fa54006)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -57,8 +57,9 @@ class DIALOG_EXPORT_STEP_BASE : public DIALOG_SHIM
wxCheckBox* m_cbRemoveVirtual;
wxCheckBox* m_cbSubstModels;
wxCheckBox* m_cbOverwriteFile;
wxCheckBox* m_cbExportTracks;
wxStaticText* m_staticTextTolerance;
wxChoice* m_tolerance;
wxChoice* m_choiceTolerance;
wxStdDialogButtonSizer* m_sdbSizer;
wxButton* m_sdbSizerOK;
wxButton* m_sdbSizerCancel;

View File

@ -27,7 +27,10 @@
#include <board.h>
#include <board_design_settings.h>
#include <footprint.h>
#include <pcb_track.h>
#include <pad.h>
#include <fp_lib_table.h>
#include "step_pcb_model.h"
#include <pgm_base.h>
#include <base_units.h>
@ -48,7 +51,6 @@
#include <Message_Messenger.hxx>
#endif
#define DEFAULT_BOARD_THICKNESS 1.6
void ReportMessage( const wxString& aMessage )
{
@ -116,8 +118,7 @@ EXPORTER_STEP::EXPORTER_STEP( BOARD* aBoard, const EXPORTER_STEP_PARAMS& aParams
m_board( aBoard ),
m_pcbModel( nullptr ),
m_pcbName(),
m_minDistance( STEPEXPORT_MIN_DISTANCE ),
m_boardThickness( DEFAULT_BOARD_THICKNESS )
m_boardThickness( DEFAULT_BOARD_THICKNESS_MM )
{
m_solderMaskColor = COLOR4D( 0.08, 0.20, 0.14, 0.83 );
@ -143,6 +144,12 @@ bool EXPORTER_STEP::composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin )
{
if( m_pcbModel->AddPadHole( pad, aOrigin ) )
hasdata = true;
if( ExportTracksAndVias() )
{
if( m_pcbModel->AddPadShape( pad, aOrigin ) )
hasdata = true;
}
}
if( ( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM ) && !m_params.m_includeExcludedBom )
@ -234,6 +241,41 @@ bool EXPORTER_STEP::composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin )
}
bool EXPORTER_STEP::composePCB( PCB_TRACK* aTrack, VECTOR2D aOrigin )
{
if( aTrack->Type() == PCB_VIA_T )
{
PAD dummy( nullptr );
int hole = static_cast<PCB_VIA*>( aTrack )->GetDrillValue();
dummy.SetDrillSize( VECTOR2I( hole, hole ) );
dummy.SetPosition( aTrack->GetStart() );
dummy.SetSize( VECTOR2I( aTrack->GetWidth(), aTrack->GetWidth() ) );
if( m_pcbModel->AddPadHole( &dummy, aOrigin ) )
{
if( m_pcbModel->AddPadShape( &dummy, aOrigin ) )
return false;
}
return true;
}
PCB_LAYER_ID pcblayer = aTrack->GetLayer();
if( pcblayer != F_Cu && pcblayer != B_Cu )
return false;
SHAPE_POLY_SET copper_shapes;
int maxError = m_board->GetDesignSettings().m_MaxError;
aTrack->TransformShapeToPolygon( copper_shapes, pcblayer, 0, maxError, ERROR_INSIDE );
m_pcbModel->AddCopperPolygonShapes( &copper_shapes, pcblayer == F_Cu, aOrigin );
return true;
}
bool EXPORTER_STEP::composePCB()
{
if( m_pcbModel )
@ -264,14 +306,27 @@ bool EXPORTER_STEP::composePCB()
m_pcbModel->SetPCBThickness( m_boardThickness );
// Set the min distance betewenn 2 points for OCC to see these 2 points as merged
double minDistmm = std::max( m_params.m_minDistance, STEPEXPORT_MIN_ACCEPTABLE_DISTANCE );
m_pcbModel->SetMinDistance( minDistmm );
// Note: m_params.m_BoardOutlinesChainingEpsilon is used only to build the board outlines,
// not to set OCC chaining epsilon (much smaller)
//
// Set the min distance between 2 points for OCC to see these 2 points as merged
// OCC_MAX_DISTANCE_TO_MERGE_POINTS is acceptable for OCC, otherwise there are issues
// to handle the shapes chaining on copper layers, because the Z dist is 0.035 mm and the
// min dist must be much smaller (we use 0.001 mm giving good results)
m_pcbModel->OCCSetMergeMaxDistance( OCC_MAX_DISTANCE_TO_MERGE_POINTS );
m_pcbModel->SetMaxError( m_board->GetDesignSettings().m_MaxError );
for( FOOTPRINT* i : m_board->Footprints() )
composePCB( i, origin );
// For copper layers, only pads and tracks are added, because adding everything on copper
// generate unreasonable file sizes and take a unreasonable calculation time.
for( FOOTPRINT* fp : m_board->Footprints() )
composePCB( fp, origin );
if( ExportTracksAndVias() )
{
for( PCB_TRACK* track : m_board->Tracks() )
composePCB( track, origin );
}
ReportMessage( wxT( "Create PCB solid model\n" ) );
@ -291,7 +346,7 @@ bool EXPORTER_STEP::composePCB()
void EXPORTER_STEP::determinePcbThickness()
{
m_boardThickness = DEFAULT_BOARD_THICKNESS;
m_boardThickness = DEFAULT_BOARD_THICKNESS_MM;
const BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();

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-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016-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
@ -30,9 +30,14 @@
#include <geometry/shape_poly_set.h>
#include <gal/color4d.h>
// Default value to chain 2 shapes when creating the board outlines
// from shapes on Edges.Cut layer
#define BOARD_DEFAULT_CHAINING_EPSILON 0.01
class PCBMODEL;
class BOARD;
class FOOTPRINT;
class PCB_TRACK;
class FILENAME_RESOLVER;
class EXPORTER_STEP_PARAMS
@ -45,8 +50,10 @@ public:
m_useDrillOrigin( false ),
m_includeExcludedBom( true ),
m_substModels( true ),
m_minDistance( STEPEXPORT_MIN_DISTANCE ),
m_boardOnly( false ) {};
m_BoardOutlinesChainingEpsilon( BOARD_DEFAULT_CHAINING_EPSILON ),
m_boardOnly( false ),
m_exportTracks( false )
{};
wxString m_outputFile;
@ -57,8 +64,9 @@ public:
bool m_useDrillOrigin;
bool m_includeExcludedBom;
bool m_substModels;
double m_minDistance;
double m_BoardOutlinesChainingEpsilon;
bool m_boardOnly;
bool m_exportTracks;
};
class EXPORTER_STEP
@ -75,9 +83,13 @@ public:
void SetFail() { m_fail = true; }
void SetWarn() { m_warn = true; }
/// Return rue to export tracks and vias on top and bottom copper layers
bool ExportTracksAndVias() { return m_params.m_exportTracks; }
private:
bool composePCB();
bool composePCB( FOOTPRINT* aFootprint, VECTOR2D aOrigin );
bool composePCB( PCB_TRACK* aTrack, VECTOR2D aOrigin );
void determinePcbThickness();
EXPORTER_STEP_PARAMS m_params;
@ -93,9 +105,6 @@ private:
std::unique_ptr<STEP_PCB_MODEL> m_pcbModel;
wxString m_pcbName;
// minimum distance between points to treat them as separate entities (mm)
double m_minDistance;
double m_boardThickness;
KIGFX::COLOR4D m_solderMaskColor;

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-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2016-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
@ -93,21 +93,11 @@
static constexpr double USER_PREC = 1e-4;
static constexpr double USER_ANGLE_PREC = 1e-6;
// minimum PCB thickness in mm (2 microns assumes a very thin polyimide film)
static constexpr double THICKNESS_MIN = 0.002;
// default PCB thickness in mm
static constexpr double THICKNESS_DEFAULT = 1.6;
// nominal offset from the board
static constexpr double BOARD_OFFSET = 0.05;
// min. length**2 below which 2 points are considered coincident
static constexpr double MIN_LENGTH2 = STEPEXPORT_MIN_DISTANCE * STEPEXPORT_MIN_DISTANCE;
// supported file types
enum FormatType
// supported file types for 3D models
enum MODEL3D_FORMAT_TYPE
{
FMT_NONE,
FMT_STEP,
@ -120,7 +110,7 @@ enum FormatType
};
FormatType fileType( const char* aFileName )
MODEL3D_FORMAT_TYPE fileType( const char* aFileName )
{
wxFileName lfile( wxString::FromUTF8Unchecked( aFileName ) );
@ -194,12 +184,13 @@ STEP_PCB_MODEL::STEP_PCB_MODEL( const wxString& aPcbName )
m_components = 0;
m_precision = USER_PREC;
m_angleprec = USER_ANGLE_PREC;
m_thickness = THICKNESS_DEFAULT;
m_minDistance2 = MIN_LENGTH2;
m_boardThickness = BOARD_THICKNESS_DEFAULT_MM;
m_copperThickness = COPPER_THICKNESS_DEFAULT_MM;
m_mergeOCCMaxDist = OCC_MAX_DISTANCE_TO_MERGE_POINTS;
m_minx = 1.0e10; // absurdly large number; any valid PCB X value will be smaller
m_pcbName = aPcbName;
BRepBuilderAPI::Precision( STEPEXPORT_MIN_DISTANCE );
m_maxError = 5000; // 5 microns
BRepBuilderAPI::Precision( m_mergeOCCMaxDist );
m_maxError = pcbIUScale.mmToIU( ARC_TO_SEGMENT_MAX_ERROR_MM );
}
@ -208,22 +199,79 @@ STEP_PCB_MODEL::~STEP_PCB_MODEL()
m_doc->Close();
}
bool STEP_PCB_MODEL::AddPadShape( const PAD* aPad, const VECTOR2D& aOrigin )
{
TopoDS_Shape curr_shape_top;
TopoDS_Shape curr_shape_bottom;
const std::shared_ptr<SHAPE_POLY_SET>& pad_shape = aPad->GetEffectivePolygon();
bool success = true;
if( aPad->IsOnLayer( F_Cu ) )
{
// Make a shape on top copper layer
success = MakeShape( curr_shape_top, pad_shape.get()->COutline(0), m_copperThickness, m_boardThickness, aOrigin );
if( success )
m_board_outlines.push_back( curr_shape_top );
}
if( success && aPad->IsOnLayer( B_Cu ) )
{
success = MakeShape( curr_shape_bottom, pad_shape.get()->COutline(0), m_copperThickness, -m_copperThickness, aOrigin );
if( success )
m_board_outlines.push_back( curr_shape_bottom );
}
if( !success ) // Error
ReportMessage( wxT( "OCC error adding pad/via polygon.\n" ) );
return success;
}
bool STEP_PCB_MODEL::AddCopperPolygonShapes( const SHAPE_POLY_SET* aPolyShapes, bool aOnTop, const VECTOR2D& aOrigin )
{
bool success = true;
for( int ii = 0; ii < aPolyShapes->OutlineCount(); ii++ )
{
TopoDS_Shape copper_shape;
double z_pos = aOnTop ? m_boardThickness : -m_copperThickness;
if( MakeShape( copper_shape, aPolyShapes->COutline( ii ), m_copperThickness, z_pos, aOrigin ) )
{
m_board_outlines.push_back( copper_shape );
}
else
{
ReportMessage( wxString::Format( wxT( "Could not add shape (%d points) to copper layer on %s.\n" ),
aPolyShapes->COutline( ii ).PointCount(),
aOnTop ? wxT( "top" ) : wxT( "bottom" ) ) );
success = false;
}
}
return success;
}
bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin )
{
if( NULL == aPad || !aPad->GetDrillSize().x )
if( aPad == nullptr || !aPad->GetDrillSize().x )
return false;
VECTOR2I pos = aPad->GetPosition();
double holeZsize = m_boardThickness + ( m_copperThickness * 2 );
if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
{
TopoDS_Shape s =
BRepPrimAPI_MakeCylinder( pcbIUScale.IUTomm( aPad->GetDrillSize().x ) * 0.5, m_thickness * 2.0 ).Shape();
BRepPrimAPI_MakeCylinder( pcbIUScale.IUTomm( aPad->GetDrillSize().x ) * 0.5, holeZsize * 2.0 ).Shape();
gp_Trsf shift;
shift.SetTranslation( gp_Vec( pcbIUScale.IUTomm( pos.x - aOrigin.x ),
-pcbIUScale.IUTomm( pos.y - aOrigin.y ),
-m_thickness * 0.5 ) );
-holeZsize * 0.5 ) );
BRepBuilderAPI_Transform hole( s, shift );
m_cutouts.push_back( hole.Shape() );
return true;
@ -231,6 +279,7 @@ bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin )
// slotted hole
SHAPE_POLY_SET holeOutlines;
if( !aPad->TransformHoleToPolygon( holeOutlines, 0, m_maxError, ERROR_INSIDE ) )
{
return false;
@ -240,7 +289,7 @@ bool STEP_PCB_MODEL::AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin )
if( holeOutlines.OutlineCount() > 0 )
{
if( MakeShape( hole, holeOutlines.COutline( 0 ), m_thickness, aOrigin ) )
if( MakeShape( hole, holeOutlines.COutline( 0 ), holeZsize*2, -holeZsize * 0.5, aOrigin ) )
{
m_cutouts.push_back( hole );
}
@ -312,11 +361,11 @@ bool STEP_PCB_MODEL::AddComponent( const std::string& aFileNameUTF8, const std::
void STEP_PCB_MODEL::SetPCBThickness( double aThickness )
{
if( aThickness < 0.0 )
m_thickness = THICKNESS_DEFAULT;
else if( aThickness < THICKNESS_MIN )
m_thickness = THICKNESS_MIN;
m_boardThickness = BOARD_THICKNESS_DEFAULT_MM;
else if( aThickness < BOARD_THICKNESS_MIN_MM )
m_boardThickness = BOARD_THICKNESS_MIN_MM;
else
m_thickness = aThickness;
m_boardThickness = aThickness;
}
@ -328,14 +377,11 @@ void STEP_PCB_MODEL::SetBoardColor( double r, double g, double b )
}
void STEP_PCB_MODEL::SetMinDistance( double aDistance )
void STEP_PCB_MODEL::OCCSetMergeMaxDistance( double aDistance )
{
// Ensure a minimal value (in mm)
aDistance = std::max( aDistance, STEPEXPORT_MIN_ACCEPTABLE_DISTANCE );
// m_minDistance2 keeps a squared distance value
m_minDistance2 = aDistance * aDistance;
BRepBuilderAPI::Precision( aDistance );
m_mergeOCCMaxDist = aDistance;
BRepBuilderAPI::Precision( m_mergeOCCMaxDist );
}
bool STEP_PCB_MODEL::isBoardOutlineValid()
@ -345,7 +391,7 @@ bool STEP_PCB_MODEL::isBoardOutlineValid()
bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aChain,
double aThickness, const VECTOR2D& aOrigin )
double aThickness, double aZposition, const VECTOR2D& aOrigin )
{
if( !aShape.IsNull() )
return false; // there is already data in the shape object
@ -354,11 +400,12 @@ bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aC
return false; // the loop is not closed
BRepBuilderAPI_MakeWire wire;
TopoDS_Edge edge;
bool success = true;
gp_Pnt start = gp_Pnt( pcbIUScale.IUTomm( aChain.CPoint( 0 ).x - aOrigin.x ),
-pcbIUScale.IUTomm( aChain.CPoint( 0 ).y - aOrigin.y ), 0.0 );
-pcbIUScale.IUTomm( aChain.CPoint( 0 ).y - aOrigin.y ), aZposition );
int items_count = 0;
for( int j = 0; j < aChain.PointCount(); j++ )
{
@ -367,38 +414,35 @@ bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aC
gp_Pnt end;
if( next >= aChain.PointCount() )
{
end = gp_Pnt( pcbIUScale.IUTomm( aChain.CPoint( 0 ).x - aOrigin.x ),
-pcbIUScale.IUTomm( aChain.CPoint( 0 ).y - aOrigin.y ), 0.0 );
}
else
{
next = 0;
end = gp_Pnt( pcbIUScale.IUTomm( aChain.CPoint( next ).x - aOrigin.x ),
-pcbIUScale.IUTomm( aChain.CPoint( next ).y - aOrigin.y ), 0.0 );
}
-pcbIUScale.IUTomm( aChain.CPoint( next ).y - aOrigin.y ), aZposition );
// Do not export very small segments: they can create broken outlines
double seg_len = std::abs( end.X() - start.X()) + std::abs(start.Y() - end.Y() );
double min_len = 0.0001; // In mm, i.e. 0.1 micron
// Do not export too short segments: they create broken shape because OCC thinks
// start point and end point are at the same place
double seg_len = std::hypot( end.X() - start.X(), end.Y() - start.Y() );
if( seg_len < min_len )
if( seg_len <= m_mergeOCCMaxDist )
continue;
try
{
TopoDS_Edge edge;
edge = BRepBuilderAPI_MakeEdge( start, end );
wire.Add( edge );
if( BRepBuilderAPI_WireDone != wire.Error() )
if( wire.Error() != BRepBuilderAPI_WireDone )
{
ReportMessage( wxT( "failed to add curve\n" ) );
return false;
}
items_count++;
}
catch( const Standard_Failure& e )
{
ReportMessage(
wxString::Format( wxT( "OCC exception: %s\n" ), e.GetMessageString() ) );
ReportMessage( wxString::Format( wxT( "MakeShape1: OCC exception: %s\n" ),
e.GetMessageString() ) );
success = false;
}
@ -420,7 +464,8 @@ bool STEP_PCB_MODEL::MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& aC
catch( const Standard_Failure& e )
{
ReportMessage(
wxString::Format( wxT( "OCC exception: %s\n" ), e.GetMessageString() ) );
wxString::Format( wxT( "MakeShape2 (items_count %d): OCC exception: %s\n" ),
items_count, e.GetMessageString() ) );
return false;
}
@ -448,9 +493,10 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
m_hasPCB = true; // whether or not operations fail we note that CreatePCB has been invoked
// Support for more than one main outline (more than one board)
std::vector<TopoDS_Shape> board_outlines;
// Number of items having the copper color
int copper_item_count = m_board_outlines.size();
// Support for more than one main outline (more than one board)
for( int cnt = 0; cnt < aOutline.OutlineCount(); cnt++ )
{
const SHAPE_LINE_CHAIN& outline = aOutline.COutline( cnt );
@ -460,7 +506,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
TopoDS_Shape curr_brd;
if( !MakeShape( curr_brd, outline, m_thickness, aOrigin ) )
if( !MakeShape( curr_brd, outline, m_boardThickness, 0.0, aOrigin ) )
{
// Error
ReportMessage( wxString::Format(
@ -468,7 +514,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
cnt+1, outline.PointCount() ) );
}
else
board_outlines.push_back( curr_brd );
m_board_outlines.push_back( curr_brd );
// Generate board cutouts in current main outline:
if( aOutline.HoleCount( cnt ) > 0 )
@ -482,7 +528,8 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
const SHAPE_LINE_CHAIN& holeOutline = aOutline.Hole( cnt, ii );
TopoDS_Shape hole;
if( MakeShape( hole, holeOutline, m_thickness, aOrigin ) )
if( MakeShape( hole, holeOutline, m_boardThickness + (m_copperThickness*4),
-m_copperThickness*2, aOrigin ) )
{
m_cutouts.push_back( hole );
}
@ -501,8 +548,15 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
holelist.Append( hole );
// Remove holes for each board (usually there is only one board
for( TopoDS_Shape& board: board_outlines )
int cnt = 0;
for( TopoDS_Shape& board: m_board_outlines )
{
cnt++;
if( cnt % 10 == 0 )
ReportMessage( wxString::Format( wxT( "added %d/%d shapes\n" ),
cnt, (int)m_board_outlines.size() ) );
BRepAlgoAPI_Cut Cut;
TopTools_ListOfShape mainbrd;
@ -521,7 +575,7 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
ReportMessage( wxT( "\nGenerate board full shape.\n" ) );
// Dont expand the component or else coloring it gets hard
for( TopoDS_Shape& board: board_outlines )
for( TopoDS_Shape& board: m_board_outlines )
{
m_pcb_labels.push_back( m_assy->AddComponent( m_assy_label, board, false ) );
@ -538,13 +592,15 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
// color the PCB
Handle( XCAFDoc_ColorTool ) colorTool = XCAFDoc_DocumentTool::ColorTool( m_doc->Main() );
Quantity_Color 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_TOC_RGB );
Quantity_Color copper_color( 0.7, 0.61, 0.0, Quantity_TOC_RGB );
int pcbIdx = 1;
int copper_objects_cnt = 0;
for( TDF_Label& pcb_label : m_pcb_labels )
{
colorTool->SetColor( pcb_label, color, XCAFDoc_ColorSurf );
colorTool->SetColor( pcb_label, board_color, XCAFDoc_ColorSurf );
Handle( TDataStd_TreeNode ) node;
@ -568,15 +624,21 @@ bool STEP_PCB_MODEL::CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin )
}
}
TopExp_Explorer topex;
// color the PCB
TopExp_Explorer topex;
topex.Init( m_assy->GetShape( pcb_label ), TopAbs_SOLID );
while( topex.More() )
{
colorTool->SetColor( topex.Current(), color, XCAFDoc_ColorSurf );
if( copper_objects_cnt < copper_item_count )
colorTool->SetColor( topex.Current(), copper_color, XCAFDoc_ColorSurf );
else
colorTool->SetColor( topex.Current(), board_color, XCAFDoc_ColorSurf );
topex.Next();
}
copper_objects_cnt++;
}
#if( defined OCC_VERSION_HEX ) && ( OCC_VERSION_HEX > 0x070101 )
@ -711,7 +773,7 @@ bool STEP_PCB_MODEL::getModelLabel( const std::string& aFileNameUTF8, VECTOR3D a
m_app->NewDocument( "MDTV-XCAF", doc );
wxString fileName( wxString::FromUTF8( aFileNameUTF8.c_str() ) );
FormatType modelFmt = fileType( aFileNameUTF8.c_str() );
MODEL3D_FORMAT_TYPE modelFmt = fileType( aFileNameUTF8.c_str() );
switch( modelFmt )
{
@ -944,7 +1006,7 @@ bool STEP_PCB_MODEL::getModelLocation( bool aBottom, VECTOR2D aPosition, double
}
else
{
aOffset.z += m_thickness;
aOffset.z += m_boardThickness;
lRot.SetRotation( gp_Ax1( gp_Pnt( 0.0, 0.0, 0.0 ), gp_Dir( 0.0, 0.0, 1.0 ) ), aRotation );
lPos.Multiply( lRot );
}

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-2022 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
@ -42,9 +42,27 @@
#include <math/vector3.h>
#include <geometry/shape_poly_set.h>
///< Default minimum distance between points to treat them as separate ones (mm)
static constexpr double STEPEXPORT_MIN_DISTANCE = 0.01;
static constexpr double STEPEXPORT_MIN_ACCEPTABLE_DISTANCE = 0.001;
/**
* 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
* merging points that should be different.
* Remember we are a 3D space, so a thin line can be broken if 2 points
* 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
*/
static constexpr double OCC_MAX_DISTANCE_TO_MERGE_POINTS = 0.001;
// default PCB thickness in mm
static constexpr double BOARD_THICKNESS_DEFAULT_MM = 1.6;
// minimum PCB thickness in mm (10 microns assumes a very thin polyimide film)
static constexpr double BOARD_THICKNESS_MIN_MM = 0.01;
// default copper thickness in mm
static constexpr double COPPER_THICKNESS_DEFAULT_MM = 0.035;
// Max error to approximate an arc by segments (in mm)
static constexpr double ARC_TO_SEGMENT_MAX_ERROR_MM = 0.005;
class PAD;
@ -62,6 +80,12 @@ public:
// add a pad hole or slot (must be in final position)
bool AddPadHole( const PAD* aPad, const VECTOR2D& aOrigin );
// add a pad/via shape (must be in final position)
bool AddPadShape( const PAD* aPad, const VECTOR2D& aOrigin );
// add a set of polygons (must be in final position) on top or bottom of the board as copper
bool AddCopperPolygonShapes( const SHAPE_POLY_SET* aPolyShapes, bool aOnTop, const VECTOR2D& aOrigin );
// add a component at the given position and orientation
bool AddComponent( const std::string& aFileName, const std::string& aRefDes, bool aBottom,
VECTOR2D aPosition, double aRotation, VECTOR3D aOffset,
@ -75,8 +99,9 @@ public:
// aThickness > THICKNESS_MIN == use aThickness
void SetPCBThickness( double aThickness );
// Set the minimum distance (in mm) to consider 2 points have the same coordinates
void SetMinDistance( double aDistance );
// Set the max distance (in mm) to consider 2 points have the same coordinates
// and can be merged
void OCCSetMergeMaxDistance( double aDistance = OCC_MAX_DISTANCE_TO_MERGE_POINTS );
void SetMaxError( int aMaxError ) { m_maxError = aMaxError; }
@ -84,7 +109,7 @@ public:
bool CreatePCB( SHAPE_POLY_SET& aOutline, VECTOR2D aOrigin );
bool MakeShape( TopoDS_Shape& aShape, const SHAPE_LINE_CHAIN& chain, double aThickness,
const VECTOR2D& aOrigin );
double aZposition, const VECTOR2D& aOrigin );
#ifdef SUPPORTS_IGES
// write the assembly model in IGES format
@ -142,13 +167,19 @@ private:
double m_precision; // model (length unit) numeric precision
double m_angleprec; // angle numeric precision
double m_boardColor[3]; // RGB values
double m_thickness; // PCB thickness, mm
double m_boardThickness; // PCB thickness, mm
double m_copperThickness; // copper thickness, mm
double m_minx; // leftmost curve point
double m_minDistance2; // minimum squared distance between items (mm)
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;
// Main outlines (more than one board)
std::vector<TopoDS_Shape> m_board_outlines;
/// Name of the PCB, which will most likely be the file name of the path.
wxString m_pcbName;

View File

@ -96,8 +96,9 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob )
}
EXPORTER_STEP_PARAMS params;
params.m_exportTracks = aStepJob->m_exportTracks;
params.m_includeExcludedBom = aStepJob->m_includeExcludedBom;
params.m_minDistance = aStepJob->m_minDistance;
params.m_BoardOutlinesChainingEpsilon = aStepJob->m_BoardOutlinesChainingEpsilon;
params.m_overwrite = aStepJob->m_overwrite;
params.m_substModels = aStepJob->m_substModels;
params.m_origin = VECTOR2D( aStepJob->m_xOrigin, aStepJob->m_yOrigin );