From 8dfad68d6957ed567819cd122710b8fded315a23 Mon Sep 17 00:00:00 2001
From: Alex Shvartzkop <dudesuchamazing@gmail.com>
Date: Sun, 19 Nov 2023 15:21:25 +0300
Subject: [PATCH] ADDED: option to optimize exported STEP files (disable
 pcurves)

---
 common/jobs/job_export_pcb_3d.cpp          |  1 +
 common/jobs/job_export_pcb_3d.h            |  3 +-
 kicad/cli/command_pcb_export_3d.cpp        | 16 ++++-
 pcbnew/dialogs/dialog_export_step.cpp      | 14 +++--
 pcbnew/dialogs/dialog_export_step_base.cpp | 11 +++-
 pcbnew/dialogs/dialog_export_step_base.fbp | 68 +++++++++++++++++++++-
 pcbnew/dialogs/dialog_export_step_base.h   |  3 +-
 pcbnew/exporters/step/exporter_step.cpp    |  2 +-
 pcbnew/exporters/step/exporter_step.h      |  2 +
 pcbnew/exporters/step/step_pcb_model.cpp   |  7 ++-
 pcbnew/exporters/step/step_pcb_model.h     |  2 +-
 pcbnew/pcbnew_jobs_handler.cpp             |  1 +
 12 files changed, 115 insertions(+), 15 deletions(-)

diff --git a/common/jobs/job_export_pcb_3d.cpp b/common/jobs/job_export_pcb_3d.cpp
index 4af9dcf20c..b17c0a3971 100644
--- a/common/jobs/job_export_pcb_3d.cpp
+++ b/common/jobs/job_export_pcb_3d.cpp
@@ -31,6 +31,7 @@ JOB_EXPORT_PCB_3D::JOB_EXPORT_PCB_3D( bool aIsCli ) :
     m_includeUnspecified( false ),
     m_includeDNP( false ),
     m_substModels( false ),
+    m_optimizeStep( false ),
     m_filename(),
     m_outputFile(),
     m_xOrigin( 0.0 ),
diff --git a/common/jobs/job_export_pcb_3d.h b/common/jobs/job_export_pcb_3d.h
index ba9f2c0cbc..f2cdf5cbab 100644
--- a/common/jobs/job_export_pcb_3d.h
+++ b/common/jobs/job_export_pcb_3d.h
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-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 as published by the
@@ -54,6 +54,7 @@ public:
     bool                      m_includeUnspecified;
     bool                      m_includeDNP;
     bool                      m_substModels;
+    bool                      m_optimizeStep;
     wxString                  m_filename;
     wxString                  m_outputFile;
     double                    m_xOrigin;
diff --git a/kicad/cli/command_pcb_export_3d.cpp b/kicad/cli/command_pcb_export_3d.cpp
index d21c04dbca..eb7a11d2d8 100644
--- a/kicad/cli/command_pcb_export_3d.cpp
+++ b/kicad/cli/command_pcb_export_3d.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
- * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-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 as published by the
@@ -39,6 +39,7 @@
 #define ARG_BOARD_ONLY "--board-only"
 #define ARG_INCLUDE_TRACKS "--include-tracks"
 #define ARG_INCLUDE_ZONES "--include-zones"
+#define ARG_NO_OPTIMIZE_STEP "--no-optimize-step"
 #define ARG_FORMAT "--format"
 #define ARG_VRML_UNITS "--units"
 #define ARG_VRML_MODELS_DIR "--models-dir"
@@ -122,6 +123,14 @@ CLI::PCB_EXPORT_3D_COMMAND::PCB_EXPORT_3D_COMMAND( const std::string&        aNa
                 .metavar( "MIN_DIST" );
     }
 
+    if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP )
+    {
+        m_argParser.add_argument( ARG_NO_OPTIMIZE_STEP )
+                .help( UTF8STDSTR( _( "Do not optimize STEP file (enables writing parametric curves)" ) ) )
+                .implicit_value( true )
+                .default_value( false );
+    }
+
     m_argParser.add_argument( ARG_USER_ORIGIN )
             .default_value( std::string() )
             .help( UTF8STDSTR( _( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default unit mm)" ) ) );
@@ -162,6 +171,11 @@ int CLI::PCB_EXPORT_3D_COMMAND::doPerform( KIWAY& aKiway )
         step->m_boardOnly = m_argParser.get<bool>( ARG_BOARD_ONLY );
     }
 
+    if( m_format == JOB_EXPORT_PCB_3D::FORMAT::STEP )
+    {
+        step->m_optimizeStep = !m_argParser.get<bool>( ARG_NO_OPTIMIZE_STEP );
+    }
+
     step->m_overwrite = m_argParser.get<bool>( ARG_FORCE );
     step->m_filename = m_argInput;
     step->m_outputFile = m_argOutput;
diff --git a/pcbnew/dialogs/dialog_export_step.cpp b/pcbnew/dialogs/dialog_export_step.cpp
index 4040851672..70b714229e 100644
--- a/pcbnew/dialogs/dialog_export_step.cpp
+++ b/pcbnew/dialogs/dialog_export_step.cpp
@@ -116,16 +116,16 @@ private:
     int                m_originUnits;    // remember last units for User Origin
     bool               m_noUnspecified;  // remember last preference for No Unspecified Component
     bool               m_noDNP;          // remember last preference for No DNP Component
-    static bool        m_exportTracks;   // remember last preference to export tracks
-                                         // (stored only for the session)
-    static bool        m_exportZones;    // remember last preference to export tracks
-                                         // (stored only for the session)
+    static bool        m_optimizeStep;   // remember last preference for Optimize STEP file (stored only for the session)
+    static bool        m_exportTracks;   // remember last preference to export tracks (stored only for the session)
+    static bool        m_exportZones;    // 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_optimizeStep = true;
 bool DIALOG_EXPORT_STEP::m_exportTracks = false;
 bool DIALOG_EXPORT_STEP::m_exportZones = false;
 
@@ -177,6 +177,7 @@ DIALOG_EXPORT_STEP::DIALOG_EXPORT_STEP( PCB_EDIT_FRAME* aParent, const wxString&
     m_noUnspecified = cfg->m_ExportStep.no_unspecified;
     m_noDNP       = cfg->m_ExportStep.no_dnp;
 
+    m_cbOptimizeStep->SetValue( m_optimizeStep );
     m_cbExportTracks->SetValue( m_exportTracks );
     m_cbExportZones->SetValue( m_exportZones );
     m_cbRemoveUnspecified->SetValue( m_noUnspecified );
@@ -271,6 +272,7 @@ DIALOG_EXPORT_STEP::~DIALOG_EXPORT_STEP()
     }
 
     m_toleranceLastChoice = m_choiceTolerance->GetSelection();
+    m_optimizeStep = m_cbOptimizeStep->GetValue();
     m_exportTracks = m_cbExportTracks->GetValue();
     m_exportZones = m_cbExportZones->GetValue();
 }
@@ -369,6 +371,7 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
 
     double tolerance;   // default value in mm
     m_toleranceLastChoice = m_choiceTolerance->GetSelection();
+    m_optimizeStep = m_cbOptimizeStep->GetValue();
     m_exportTracks = m_cbExportTracks->GetValue();
     m_exportZones = m_cbExportZones->GetValue();
 
@@ -453,6 +456,9 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
     if( GetSubstOption() )
         cmdK2S.Append( wxT( " --subst-models" ) );
 
+    if( !m_optimizeStep )
+        cmdK2S.Append( wxT( " --no-optimize-step" ) );
+
     if( m_exportTracks )
         cmdK2S.Append( wxT( " --include-tracks" ) );
 
diff --git a/pcbnew/dialogs/dialog_export_step_base.cpp b/pcbnew/dialogs/dialog_export_step_base.cpp
index 29a459743f..c214656282 100644
--- a/pcbnew/dialogs/dialog_export_step_base.cpp
+++ b/pcbnew/dialogs/dialog_export_step_base.cpp
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
+// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO *NOT* EDIT THIS FILE!
@@ -132,16 +132,21 @@ 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_cbOptimizeStep = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Optimize STEP file"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_cbOptimizeStep->SetToolTip( _("Disables writing parametric curves. Optimizes file size and write/read times, but may reduce compatibility with other software.") );
+
+	sbOtherOptions->Add( m_cbOptimizeStep, 0, wxBOTTOM|wxRIGHT, 5 );
+
 	m_staticline1 = new wxStaticLine( sbOtherOptions->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
 	sbOtherOptions->Add( m_staticline1, 0, wxEXPAND|wxTOP|wxBOTTOM, 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.") );
+	m_cbExportTracks->SetToolTip( _("Export tracks and vias on external copper layers.") );
 
 	sbOtherOptions->Add( m_cbExportTracks, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 );
 
 	m_cbExportZones = new wxCheckBox( sbOtherOptions->GetStaticBox(), wxID_ANY, _("Export zones (time consuming)"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_cbExportZones->SetToolTip( _("Export zones on external copper layers.\nWarning: this is *extremely* time consuming.") );
+	m_cbExportZones->SetToolTip( _("Export zones on external copper layers.") );
 
 	sbOtherOptions->Add( m_cbExportZones, 0, wxBOTTOM|wxRIGHT, 5 );
 
diff --git a/pcbnew/dialogs/dialog_export_step_base.fbp b/pcbnew/dialogs/dialog_export_step_base.fbp
index 2984f2ae84..842a47ba99 100644
--- a/pcbnew/dialogs/dialog_export_step_base.fbp
+++ b/pcbnew/dialogs/dialog_export_step_base.fbp
@@ -1228,6 +1228,70 @@
                                         <property name="window_style"></property>
                                     </object>
                                 </object>
+                                <object class="sizeritem" expanded="1">
+                                    <property name="border">5</property>
+                                    <property name="flag">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="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">Optimize STEP file</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_cbOptimizeStep</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"></property>
+                                        <property name="toolbar_pane">0</property>
+                                        <property name="tooltip">Disables writing parametric curves. Optimizes file size and write/read times, but may reduce compatibility with other software.</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="1">
                                     <property name="border">5</property>
                                     <property name="flag">wxEXPAND|wxTOP|wxBOTTOM</property>
@@ -1340,7 +1404,7 @@
                                         <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="tooltip">Export tracks and vias on external copper layers.</property>
                                         <property name="validator_data_type"></property>
                                         <property name="validator_style">wxFILTER_NONE</property>
                                         <property name="validator_type">wxDefaultValidator</property>
@@ -1404,7 +1468,7 @@
                                         <property name="style"></property>
                                         <property name="subclass">; ; forward_declare</property>
                                         <property name="toolbar_pane">0</property>
-                                        <property name="tooltip">Export zones on external copper layers.&#x0A;Warning: this is *extremely* time consuming.</property>
+                                        <property name="tooltip">Export zones on external copper layers.</property>
                                         <property name="validator_data_type"></property>
                                         <property name="validator_style">wxFILTER_NONE</property>
                                         <property name="validator_type">wxDefaultValidator</property>
diff --git a/pcbnew/dialogs/dialog_export_step_base.h b/pcbnew/dialogs/dialog_export_step_base.h
index bbe3c417ae..07e17e9df3 100644
--- a/pcbnew/dialogs/dialog_export_step_base.h
+++ b/pcbnew/dialogs/dialog_export_step_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
+// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO *NOT* EDIT THIS FILE!
@@ -64,6 +64,7 @@ class DIALOG_EXPORT_STEP_BASE : public DIALOG_SHIM
 		wxCheckBox* m_cbRemoveUnspecified;
 		wxCheckBox* m_cbSubstModels;
 		wxCheckBox* m_cbOverwriteFile;
+		wxCheckBox* m_cbOptimizeStep;
 		wxStaticLine* m_staticline1;
 		wxCheckBox* m_cbExportTracks;
 		wxCheckBox* m_cbExportZones;
diff --git a/pcbnew/exporters/step/exporter_step.cpp b/pcbnew/exporters/step/exporter_step.cpp
index 2bc9557aed..022b6e23d1 100644
--- a/pcbnew/exporters/step/exporter_step.cpp
+++ b/pcbnew/exporters/step/exporter_step.cpp
@@ -524,7 +524,7 @@ bool EXPORTER_STEP::Export()
 
         bool success = true;
         if( m_params.m_format == EXPORTER_STEP_PARAMS::FORMAT::STEP )
-            success = m_pcbModel->WriteSTEP( m_outputFile );
+            success = m_pcbModel->WriteSTEP( m_outputFile, m_params.m_optimizeStep );
         else if( m_params.m_format == EXPORTER_STEP_PARAMS::FORMAT::GLB )
             success = m_pcbModel->WriteGLTF( m_outputFile );
 
diff --git a/pcbnew/exporters/step/exporter_step.h b/pcbnew/exporters/step/exporter_step.h
index fd3891ec17..202bfc0cc7 100644
--- a/pcbnew/exporters/step/exporter_step.h
+++ b/pcbnew/exporters/step/exporter_step.h
@@ -56,6 +56,7 @@ public:
             m_boardOnly( false ),
             m_exportTracks( false ),
             m_exportZones( false ),
+            m_optimizeStep( true ),
             m_format( FORMAT::STEP )
     {};
 
@@ -79,6 +80,7 @@ public:
     bool     m_boardOnly;
     bool     m_exportTracks;
     bool     m_exportZones;
+    bool     m_optimizeStep;
     FORMAT   m_format;
 
     wxString GetDefaultExportExtension();
diff --git a/pcbnew/exporters/step/step_pcb_model.cpp b/pcbnew/exporters/step/step_pcb_model.cpp
index 1db53a4cb5..318a9fab21 100644
--- a/pcbnew/exporters/step/step_pcb_model.cpp
+++ b/pcbnew/exporters/step/step_pcb_model.cpp
@@ -1079,7 +1079,7 @@ bool STEP_PCB_MODEL::WriteIGES( const wxString& aFileName )
 #endif
 
 
-bool STEP_PCB_MODEL::WriteSTEP( const wxString& aFileName )
+bool STEP_PCB_MODEL::WriteSTEP( const wxString& aFileName, bool aOptimize )
 {
     if( !isBoardOutlineValid() )
     {
@@ -1103,6 +1103,11 @@ bool STEP_PCB_MODEL::WriteSTEP( const wxString& aFileName )
     if( !Interface_Static::SetCVal( "write.step.product.name", fn.GetName().ToAscii() ) )
         ReportMessage( wxT( "Failed to set step product name, but will attempt to continue." ) );
 
+    // Setting write.surfacecurve.mode to 0 reduces file size and write/read times.
+    // But there are reports that this mode might be less compatible in some cases.
+    if( !Interface_Static::SetIVal( "write.surfacecurve.mode", aOptimize ? 0 : 1 ) )
+        ReportMessage( wxT( "Failed to set surface curve mode, but will attempt to continue." ) );
+
     if( Standard_False == writer.Transfer( m_doc, STEPControl_AsIs ) )
         return false;
 
diff --git a/pcbnew/exporters/step/step_pcb_model.h b/pcbnew/exporters/step/step_pcb_model.h
index 62c7e05d34..6406d3178b 100644
--- a/pcbnew/exporters/step/step_pcb_model.h
+++ b/pcbnew/exporters/step/step_pcb_model.h
@@ -166,7 +166,7 @@ public:
 #endif
 
     // write the assembly model in STEP format
-    bool WriteSTEP( const wxString& aFileName );
+    bool WriteSTEP( const wxString& aFileName, bool aOptimize );
 
     /**
      * Write the assembly in binary GLTF Format
diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp
index 764516e065..12eef225a1 100644
--- a/pcbnew/pcbnew_jobs_handler.cpp
+++ b/pcbnew/pcbnew_jobs_handler.cpp
@@ -154,6 +154,7 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob )
         params.m_useDrillOrigin = aStepJob->m_useDrillOrigin;
         params.m_useGridOrigin = aStepJob->m_useGridOrigin;
         params.m_boardOnly = aStepJob->m_boardOnly;
+        params.m_optimizeStep = aStepJob->m_optimizeStep;
 
         switch( aStepJob->m_format )
         {