Added STEP loading dialog (SPE-2723)

This commit is contained in:
YuSanka 2025-03-19 17:22:23 +01:00 committed by Lukas Matena
parent 8d4f86b84a
commit 5b0a81fca4
13 changed files with 429 additions and 16 deletions

View File

@ -88,6 +88,7 @@ src/slic3r/GUI/Jobs/SLAImportDialog.hpp
src/slic3r/GUI/Jobs/SLAImportJob.cpp
src/slic3r/GUI/KBShortcutsDialog.cpp
src/slic3r/GUI/BulkExportDialog.cpp
src/slic3r/GUI/LoadStepDialog.cpp
src/slic3r/GUI/LoginDialog.cpp
src/slic3r/GUI/MainFrame.cpp
src/slic3r/GUI/Mouse3DController.cpp

View File

@ -235,6 +235,15 @@ void AppConfig::set_defaults()
set("sys_menu_enabled", "1");
#endif // _WIN32
if (get("show_step_import_parameters").empty())
set("show_step_import_parameters", "1");
if (get("linear_precision").empty())
set("linear_precision", "0.005");
if (get("angle_precision").empty())
set("angle_precision", "1.");
// Remove legacy window positions/sizes
erase("", "main_frame_maximized");
erase("", "main_frame_pos");

View File

@ -37,7 +37,7 @@ bool is_project_file(const std::string& input_file)
}
// Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well.
static Model read_model_from_file(const std::string& input_file, LoadAttributes options)
static Model read_model_from_file(const std::string& input_file, LoadAttributes options, const std::optional<std::pair<double, double>>& step_deflections = std::nullopt)
{
Model model;
@ -49,8 +49,9 @@ static Model read_model_from_file(const std::string& input_file, LoadAttributes
result = load_stl(input_file.c_str(), &model);
else if (boost::algorithm::iends_with(input_file, ".obj"))
result = load_obj(input_file.c_str(), &model);
else if (boost::algorithm::iends_with(input_file, ".step") || boost::algorithm::iends_with(input_file, ".stp"))
result = load_step(input_file.c_str(), &model);
else if (boost::algorithm::iends_with(input_file, ".step") || boost::algorithm::iends_with(input_file, ".stp")) {
result = load_step(input_file.c_str(), &model, step_deflections);
}
else if (boost::algorithm::iends_with(input_file, ".amf") || boost::algorithm::iends_with(input_file, ".amf.xml"))
//? result = load_amf(input_file.c_str(), &temp_config, &temp_config_substitutions_context, &model, options & LoadAttribute::CheckVersion);
//? LoadAttribute::CheckVersion is needed here, when we loading just a geometry
@ -216,9 +217,10 @@ static int removed_objects_with_zero_volume(Model& model)
Model load_model(const std::string& input_file,
LoadAttributes options/* = LoadAttribute::AddDefaultInstances*/,
LoadStats* stats/*= nullptr*/)
LoadStats* stats/*= nullptr*/,
std::optional<std::pair<double, double>> step_deflections/* = std::nullopt*/)
{
Model model = read_model_from_file(input_file, options);
Model model = read_model_from_file(input_file, options, step_deflections);
for (auto obj : model.objects)
if (obj->name.empty())

View File

@ -14,6 +14,8 @@
#include "PrintConfig.hpp"
#include "enum_bitmask.hpp"
#include <utility>
#include <optional>
namespace Slic3r {
@ -46,7 +48,8 @@ namespace FileReader
// Exceptions don't catched inside
Model load_model(const std::string& input_file,
LoadAttributes options = LoadAttribute::AddDefaultInstances,
LoadStats* statistics = nullptr);
LoadStats* statistics = nullptr,
std::optional<std::pair<double, double>> step_deflections = std::nullopt);
// Load model, config and config substitutions from input file and fill statistics if it's required.
// Exceptions don't catched inside

View File

@ -27,9 +27,12 @@
namespace Slic3r {
#if __APPLE__
extern "C" bool load_step_internal(const char *path, OCCTResult* res);
extern "C" bool load_step_internal(const char *path, OCCTResult* res, std::optional<std::pair<double, double>> deflections /*= std::nullopt*/);
#endif
// Inside deflections pair:
// * first value is linear deflection
// * second value is angle deflection
LoadStepFn get_load_step_fn()
{
static LoadStepFn load_step_fn = nullptr;
@ -80,7 +83,7 @@ LoadStepFn get_load_step_fn()
return load_step_fn;
}
bool load_step(const char *path, Model *model /*BBS:, ImportStepProgressFn proFn*/)
bool load_step(const char *path, Model *model /*BBS:, ImportStepProgressFn proFn*/, std::optional<std::pair<double, double>> deflections)
{
OCCTResult occt_object;
@ -89,7 +92,7 @@ bool load_step(const char *path, Model *model /*BBS:, ImportStepProgressFn proFn
if (!load_step_fn)
return false;
load_step_fn(path, &occt_object);
load_step_fn(path, &occt_object, deflections);
assert(! occt_object.volumes.empty());

View File

@ -9,6 +9,9 @@
#ifndef slic3r_Format_STEP_hpp_
#define slic3r_Format_STEP_hpp_
#include <utility>
#include <optional>
namespace Slic3r {
class Model;
@ -16,7 +19,10 @@ class Model;
//typedef std::function<void(int load_stage, int current, int total, bool& cancel)> ImportStepProgressFn;
// Load a step file into a provided model.
extern bool load_step(const char *path_str, Model *model /*LMBBS:, ImportStepProgressFn proFn = nullptr*/);
// Inside deflections pair:
// * first value is linear deflection
// * second value is angle deflection
extern bool load_step(const char *path_str, Model *model /*LMBBS:, ImportStepProgressFn proFn = nullptr*/, std::optional<std::pair<double, double>> deflections = std::nullopt);
}; // namespace Slic3r

View File

@ -79,7 +79,7 @@ static void getNamedSolids(const TopLoc_Location& location, const Handle(XCAFDoc
}
}
extern "C" OCCTWRAPPER_EXPORT bool load_step_internal(const char *path, OCCTResult* res /*BBS:, ImportStepProgressFn proFn*/)
extern "C" OCCTWRAPPER_EXPORT bool load_step_internal(const char *path, OCCTResult* res /*BBS:, ImportStepProgressFn proFn*/, std::optional<std::pair<double, double>> deflections /*= std::nullopt*/)
{
try {
//bool cb_cancel = false;
@ -129,7 +129,9 @@ try {
res->object_name = obj_name;
for (const NamedSolid &namedSolid : namedSolids) {
BRepMesh_IncrementalMesh mesh(namedSolid.solid, STEP_TRANS_CHORD_ERROR, false, STEP_TRANS_ANGLE_RES, true);
BRepMesh_IncrementalMesh mesh(namedSolid.solid,
deflections.has_value() ? deflections.value().first : STEP_TRANS_CHORD_ERROR, false,
deflections.has_value() ? deflections.value().second : STEP_TRANS_ANGLE_RES, true);
res->volumes.emplace_back();
std::vector<Vec3f> vertices;

View File

@ -5,6 +5,8 @@
#include <array>
#include <string>
#include <vector>
#include <utility>
#include <optional>
struct stl_facet;
@ -21,7 +23,7 @@ struct OCCTResult {
std::vector<OCCTVolume> volumes;
};
using LoadStepFn = bool (*)(const char *path, OCCTResult* occt_result);
using LoadStepFn = bool (*)(const char *path, OCCTResult* occt_result, std::optional<std::pair<double, double>> deflections);
}; // namespace Slic3r

View File

@ -143,6 +143,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Sidebar.hpp
GUI/Plater.cpp
GUI/Plater.hpp
GUI/LoadStepDialog.cpp
GUI/LoadStepDialog.hpp
GUI/PresetComboBoxes.hpp
GUI/PresetComboBoxes.cpp
GUI/BitmapComboBox.hpp

View File

@ -0,0 +1,247 @@
///|/ Copyright (c) Prusa Research 2018 - 2023 Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, David Kocík @kocikdav, Lukáš Hejl @hejllukas, Pavel Mikuš @Godrak, Filip Sykala @Jony01, Vojtěch Král @vojtechkral
///|/ Copyright (c) 2022 Michael Kirsch
///|/ Copyright (c) 2021 Boleslaw Ciesielski
///|/ Copyright (c) 2019 John Drake @foxox
///|/
///|/ ported from lib/Slic3r/GUI/Plater.pm:
///|/ Copyright (c) Prusa Research 2016 - 2019 Vojtěch Bubník @bubnikv, Vojtěch Král @vojtechkral, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Tomáš Mészáros @tamasmeszaros
///|/ Copyright (c) 2018 Martin Loidl @LoidlM
///|/ Copyright (c) 2017 Matthias Gazzari @qtux
///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel
///|/ Copyright (c) 2017 Joseph Lenox @lordofhyphens
///|/ Copyright (c) 2015 Daren Schwenke
///|/ Copyright (c) 2014 Mark Hindess
///|/ Copyright (c) 2012 Mike Sheldrake @mesheldrake
///|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen
///|/ Copyright (c) 2012 Sam Wong
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include "LoadStepDialog.hpp"
#include <wx/window.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/radiobut.h>
#include <wx/slider.h>
#include <vector>
#include <utility>
#include "GUI_App.hpp"
#include "format.hpp"
#include "MsgDialog.hpp"
#include "Widgets/CheckBox.hpp"
namespace Slic3r::GUI {
static std::vector<std::pair<std::string, PrecisionParams>> default_step_import_params = {
{"Low" , {0.1, 1. }},
{"Medium" , {0.05, 0.5 }},
{"High" , {0.001, 0.03}},
};
LoadStepDialog::LoadStepDialog(wxWindow* parent, const std::string& filename, double linear_precision, double angle_precision, bool multiple_loading)
: DPIDialog(parent, wxID_ANY, format_wxstr(_L("STEP import quality (%1%)"), filename), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
m_params({ linear_precision, angle_precision })
{
#ifdef _WIN32
wxGetApp().UpdateDarkUI(this);
#else
//SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif
const wxFont& font = wxGetApp().normal_font();
SetFont(font);
// Call your custom function manually after constructing base
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); // Get the sizer
add_params(main_sizer);
main_sizer->Add(new StaticLine(this), 0, wxEXPAND | wxLEFT | wxRIGHT, em_unit());
wxBoxSizer* bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
m_remember_chb = new ::CheckBox(this, _L("Remember my choice"));
bottom_sizer->Add(m_remember_chb, 0, wxEXPAND | wxRIGHT, 5);
bottom_sizer->AddStretchSpacer();
auto buttons_sizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
if (multiple_loading) {
auto apply_btn = new wxButton(this, wxID_APPLY, "Apply to all");
apply_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) {
m_apply_to_all = true;
EndModal(wxID_OK);
});
buttons_sizer->Insert(0, apply_btn, 0, wxRIGHT, 5);
}
bottom_sizer->Add(buttons_sizer, 0, wxEXPAND | wxLEFT, 5);
main_sizer->Add(bottom_sizer, 0, wxEXPAND | wxALL, 10);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
m_custom_sizer->ShowItems(!m_default);
// Update DarkUi just for buttons
wxGetApp().UpdateDlgDarkUI(this, true);
}
void LoadStepDialog::add_params(wxSizer* sizer)
{
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->Add(new wxStaticText(this, wxID_ANY, _L("Select requested quality of the mesh after import: ")));
// add radio buttons for selection default parameters
for (const auto& [name, params] : default_step_import_params) {
wxRadioButton* radio_def = new wxRadioButton(this, wxID_ANY, format_wxstr("%1%", _L(name)));
radio_def->Bind(wxEVT_RADIOBUTTON, [params_copy = params, this](wxEvent&) {
m_params.linear = params_copy.linear;
m_params.angle = params_copy.angle;
m_custom_sizer->ShowItems(false);
});
bool is_selected = m_params.linear == params.linear && params.angle == params.angle;
radio_def->SetValue(is_selected);
m_default |= is_selected;
main_sizer->Add(radio_def, 0, wxLEFT | wxTOP, em_unit());
}
// add radio buttons for set custom parameters
wxRadioButton* radio_custom = new wxRadioButton(this, wxID_ANY, _L("Custom"));
radio_custom->Bind(wxEVT_RADIOBUTTON, [&, this](wxEvent&) {
m_custom_sizer->ShowItems(true);
#ifdef __linux__
this->Fit();
#endif // __linux__
m_params.linear = string_to_double_decimal_point(m_linear_precision_val->GetValue().ToStdString());
m_params.angle = string_to_double_decimal_point(m_angle_precision_val->GetValue().ToStdString());
});
main_sizer->Add(radio_custom, 0, wxLEFT | wxTOP, em_unit());
radio_custom->SetValue(!m_default);
long slyder_style = wxSL_HORIZONTAL | wxSL_TICKS;
long text_ctrl_style = wxTE_PROCESS_ENTER;
#ifdef _WIN32
text_ctrl_style |= wxBORDER_SIMPLE;
#endif
const wxSize def_slider_size = wxSize(15 * em_unit(), wxDefaultCoord);
const wxSize def_editor_size = wxSize(5 * em_unit(), wxDefaultCoord);
const int hgap = 5;
wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(4, em_unit(), hgap);
grid_sizer->SetFlexibleDirection(wxBOTH);
grid_sizer->AddGrowableCol(1, 1);
grid_sizer->AddGrowableRow(0, 1);
grid_sizer->AddGrowableRow(1, 1);
wxBoxSizer* labels_sizer = new wxBoxSizer(wxHORIZONTAL);
{
const wxString left_text = _L("Lower quality");
const int left_text_gap = std::max(GetTextExtent(_L("Linear precision")).x, GetTextExtent(_L("Angle precision")).x) + 4 * hgap - GetTextExtent(left_text).x * 0.5;
const wxString right_text = _L("Higher quality");
const int right_text_gap = GetTextExtent(_L("mm")).x + def_editor_size.x + 4 * hgap - GetTextExtent(right_text).x * 0.5;
labels_sizer->Add(new wxStaticText(this, wxID_ANY, left_text), 0, wxLEFT, left_text_gap);
labels_sizer->Add(new wxStaticText(this, wxID_ANY, wxEmptyString), 1, wxEXPAND);
labels_sizer->Add(new wxStaticText(this, wxID_ANY, right_text), 0, wxRIGHT, right_text_gap);
}
auto high_vals = std::find_if(default_step_import_params.begin(), default_step_import_params.end(),
[](const std::pair<std::string, PrecisionParams>& val) { return val.first == "High"; });
auto low_vals = std::find_if(default_step_import_params.begin(), default_step_import_params.end(),
[](const std::pair<std::string, PrecisionParams>& val) { return val.first == "Low"; });
assert(high_vals != default_step_import_params.end() && low_vals != default_step_import_params.end());
m_linear_precision_sl.init(high_vals->second.linear, low_vals->second.linear, 0.001);
m_angle_precision_sl.init(high_vals->second.angle, low_vals->second.angle, 0.01);
auto process_value_change = [](double& precision, wxTextCtrl* text_ctrl, wxSlider* slider, const SliderHelper& sl_helper) -> void {
wxString str_val = text_ctrl->GetValue();
double val = string_to_double_decimal_point(str_val.ToStdString());
precision = sl_helper.adjust_to_region(val);
slider->SetValue(sl_helper.get_pos(precision));
if (wxString str_precision = format_wxstr("%1%", precision); str_precision != str_val)
text_ctrl->SetValue(str_precision);
};
// Add "Linear precision"
m_linear_precision_slider = new wxSlider(this, wxID_ANY, m_linear_precision_sl.get_pos(m_params.linear), m_linear_precision_sl.beg_sl_pos, m_linear_precision_sl.end_sl_pos, wxDefaultPosition, def_slider_size, slyder_style);
m_linear_precision_slider->SetTickFreq(10);
m_linear_precision_slider->Bind(wxEVT_SLIDER, [this](wxCommandEvent e) {
m_params.linear = m_linear_precision_sl.get_value(m_linear_precision_slider->GetValue());
m_linear_precision_val->SetValue(format_wxstr("%1%", m_params.linear));
});
m_linear_precision_val = new wxTextCtrl(this, wxID_ANY, format_wxstr("%1%", m_linear_precision_sl.adjust_to_region(m_params.linear)), wxDefaultPosition, def_editor_size, text_ctrl_style);
m_linear_precision_val->SetToolTip(format_wxstr("Set value from the range [%1%; %2%] with %3% step",
m_linear_precision_sl.min_val, m_linear_precision_sl.max_val, m_linear_precision_sl.val_step));
m_linear_precision_val->Bind(wxEVT_TEXT_ENTER, [process_value_change, this](wxCommandEvent& e) {
process_value_change(m_params.linear, m_linear_precision_val, m_linear_precision_slider, m_linear_precision_sl);
});
m_linear_precision_val->Bind(wxEVT_KILL_FOCUS, [process_value_change, this](wxFocusEvent& e) {
process_value_change(m_params.linear, m_linear_precision_val, m_linear_precision_slider, m_linear_precision_sl);
e.Skip();
});
grid_sizer->Add(new wxStaticText(this, wxID_ANY, _L("Linear precision") + ": "), 0, wxALIGN_CENTER_VERTICAL);
grid_sizer->Add(m_linear_precision_slider, 1, wxEXPAND);
grid_sizer->Add(m_linear_precision_val, 0, wxALIGN_CENTER_VERTICAL);
grid_sizer->Add(new wxStaticText(this, wxID_ANY, _L("mm")), 0, wxALIGN_CENTER_VERTICAL);
// Add "Angle precision"
m_angle_precision_slider = new wxSlider(this, wxID_ANY, m_angle_precision_sl.get_pos(m_params.angle), m_angle_precision_sl.beg_sl_pos, m_angle_precision_sl.end_sl_pos, wxDefaultPosition, def_slider_size, slyder_style);
m_angle_precision_slider->SetTickFreq(10);
m_angle_precision_slider->Bind(wxEVT_SLIDER, [this](wxCommandEvent e) {
m_params.angle = m_angle_precision_sl.get_value(m_angle_precision_slider->GetValue());
m_angle_precision_val->SetValue(format_wxstr("%1%", m_params.angle));
});
m_angle_precision_val = new wxTextCtrl(this, wxID_ANY, format_wxstr("%1%", m_angle_precision_sl.adjust_to_region(m_params.angle)), wxDefaultPosition, def_editor_size, text_ctrl_style);
m_angle_precision_val->SetToolTip(format_wxstr("Set value from the range [%1%; %2%] with %3% step",
m_angle_precision_sl.min_val, m_angle_precision_sl.max_val, m_angle_precision_sl.val_step));
m_angle_precision_val->Bind(wxEVT_TEXT_ENTER, [process_value_change, this](wxCommandEvent& e) {
process_value_change(m_params.angle, m_angle_precision_val, m_angle_precision_slider, m_angle_precision_sl);
});
m_angle_precision_val->Bind(wxEVT_KILL_FOCUS, [process_value_change, this](wxFocusEvent& e) {
process_value_change(m_params.angle, m_angle_precision_val, m_angle_precision_slider, m_angle_precision_sl);
e.Skip();
});
grid_sizer->Add(new wxStaticText(this, wxID_ANY, _L("Angle precision") + ": "), 0, wxALIGN_CENTER_VERTICAL);
grid_sizer->Add(m_angle_precision_slider, 1, wxEXPAND);
grid_sizer->Add(m_angle_precision_val, 0, wxALIGN_CENTER_VERTICAL);
grid_sizer->Add(new wxStaticText(this, wxID_ANY, _L("°")), 0, wxALIGN_CENTER_VERTICAL);
m_custom_sizer = new wxBoxSizer(wxVERTICAL);
m_custom_sizer->Add(labels_sizer, 0, wxEXPAND | wxBOTTOM | wxTOP, em_unit());
m_custom_sizer->Add(grid_sizer, 1, wxEXPAND);
main_sizer->Add(m_custom_sizer, 1, wxEXPAND | wxLEFT, 3 * em_unit());
sizer->Add(main_sizer, 1, wxEXPAND | wxALL, em_unit());
}
bool LoadStepDialog::IsCheckBoxChecked()
{
return m_remember_chb && m_remember_chb->GetValue();
}
bool LoadStepDialog::IsApplyToAllClicked()
{
return m_apply_to_all;
}
} // namespace Slic3r::GUI

View File

@ -0,0 +1,99 @@
///|/ Copyright (c) Prusa Research 2018 - 2025 Oleksandra Iushchenko @YuSanka
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#ifndef slic3r_LoadStepDialog_hpp_
#define slic3r_LoadStepDialog_hpp_
#include <string>
#include <wx/dialog.h>
#include "GUI_Utils.hpp"
class wxBoxSizer;
class wxTextCtrl;
class wxSlider;
class CheckBox;
namespace Slic3r::GUI {
struct PrecisionParams
{
double linear;
double angle;
};
struct SliderHelper
{
double min_val;
double max_val;
double val_step;
int beg_sl_pos;
int end_sl_pos;
void init(double min, double max, double step, int beg_pos = 1) {
assert(val_step != 0.);
min_val = min;
max_val = max;
val_step = step;
beg_sl_pos = beg_pos;
end_sl_pos = beg_sl_pos + int(double(max_val - min_val) / val_step);
}
double get_value(int pos) const {
return max_val - val_step * (pos - beg_sl_pos);
}
int get_pos(double value) const {
return beg_sl_pos + int((max_val - value) / val_step);
}
double adjust_to_region(double value) const {
return std::max(std::min(value, max_val), min_val);
}
};
class LoadStepDialog : public DPIDialog
{
public:
LoadStepDialog(wxWindow* parent, const std::string& filename, double linear_precision, double angle_precision, bool multiple_loading);
~LoadStepDialog() = default;
bool IsCheckBoxChecked();
bool IsApplyToAllClicked();
double get_linear_precision() { return m_params.linear; }
double get_angle_precision() { return m_params.angle; }
protected:
void on_dpi_changed(const wxRect& suggested_rect) override {}
void on_sys_color_changed() override {};
private:
void add_params(wxSizer* sizer);
private:
PrecisionParams m_params;
::CheckBox* m_remember_chb { nullptr };
wxTextCtrl* m_linear_precision_val { nullptr };
wxTextCtrl* m_angle_precision_val { nullptr };
wxSlider* m_linear_precision_slider { nullptr };
wxSlider* m_angle_precision_slider { nullptr };
wxBoxSizer* m_custom_sizer { nullptr };
bool m_default { false };
bool m_apply_to_all { false };
SliderHelper m_linear_precision_sl;
SliderHelper m_angle_precision_sl;
};
} // namespace Slic3r::GUI
#endif

View File

@ -30,6 +30,7 @@
#include <string>
#include <regex>
#include <future>
#include <utility>
#include <boost/algorithm/string.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/optional.hpp>
@ -138,6 +139,7 @@
#include "ConfigWizardWebViewPage.hpp"
#include "PresetArchiveDatabase.hpp"
#include "BulkExportDialog.hpp"
#include "LoadStepDialog.hpp"
#include "libslic3r/ArrangeHelper.hpp"
@ -325,6 +327,7 @@ struct Plater::priv
static const std::regex pattern_prusa;
static const std::regex pattern_zip;
static const std::regex pattern_printRequest;
static const std::regex pattern_step;
priv(Plater *q, MainFrame *main_frame);
~priv();
@ -615,11 +618,13 @@ private:
bool show_warning_dialog { false };
};
// FIXME: Some of the regex patterns are wrong (missing [.] before file extension).
const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|3mf)", std::regex::icase);
const std::regex Plater::priv::pattern_3mf(".*3mf", std::regex::icase);
const std::regex Plater::priv::pattern_any_amf(".*[.](amf|amf[.]xml|zip[.]amf)", std::regex::icase);
const std::regex Plater::priv::pattern_zip(".*zip", std::regex::icase);
const std::regex Plater::priv::pattern_printRequest(".*printRequest", std::regex::icase);
const std::regex Plater::priv::pattern_step(".*[.](step|stp)", std::regex::icase);
Plater::priv::priv(Plater* q, MainFrame* main_frame)
: q(q)
@ -1288,6 +1293,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
int answer_convert_from_meters = wxOK_DEFAULT;
int answer_convert_from_imperial_units = wxOK_DEFAULT;
int answer_consider_as_multi_part_objects = wxOK_DEFAULT;
bool apply_step_import_parameters_to_all { false };
bool in_temp = false;
const fs::path temp_path = wxStandardPaths::Get().GetTempDir().utf8_str().data();
@ -1303,7 +1309,26 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
const auto &path = input_files[i];
#endif // _WIN32
in_temp = (path.parent_path() == temp_path);
const auto filename = path.filename();
const boost::filesystem::path filename = path.filename();
const bool type_step = std::regex_match(path.string(), pattern_step);
if (type_step && !apply_step_import_parameters_to_all &&
wxGetApp().app_config->get_bool("show_step_import_parameters")) {
double linear_precision = string_to_double_decimal_point(wxGetApp().app_config->get("linear_precision"));
double angle_precision = string_to_double_decimal_point(wxGetApp().app_config->get("angle_precision"));
LoadStepDialog dlg(q, filename.string(), linear_precision, angle_precision, (input_files_size - i) > 1);
if (dlg.ShowModal() == wxID_OK) {
wxGetApp().app_config->set("linear_precision", float_to_string_decimal_point(dlg.get_linear_precision()));
wxGetApp().app_config->set("angle_precision", float_to_string_decimal_point(dlg.get_angle_precision()));
if (dlg.IsCheckBoxChecked())
wxGetApp().app_config->set("show_step_import_parameters", "0");
apply_step_import_parameters_to_all = dlg.IsApplyToAllClicked();
} else
continue;
}
if (progress_dlg) {
progress_dlg->Update(static_cast<int>(100.0f * static_cast<float>(i) / static_cast<float>(input_files.size())), _L("Loading file") + ": " + from_path(filename));
progress_dlg->Fit();
@ -1352,7 +1377,14 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
model = FileReader::load_model_with_config(path.string(), &config_loaded, &config_substitutions, prusaslicer_generator_version, FileReader::LoadAttribute::CheckVersion, &load_stats);
}
else if (load_model) {
model = FileReader::load_model(path.string(), FileReader::LoadAttributes{}, &load_stats);
if (type_step) {
double linear_precision = string_to_double_decimal_point(wxGetApp().app_config->get("linear_precision"));
double angle_precision = string_to_double_decimal_point(wxGetApp().app_config->get("angle_precision"));
model = FileReader::load_model(path.string(), FileReader::LoadAttributes{}, &load_stats,
std::make_pair(linear_precision, angle_precision));
}
else
model = FileReader::load_model(path.string(), FileReader::LoadAttributes{}, &load_stats);
}
} catch (const ConfigurationError &e) {
std::string message = GUI::format(_L("Failed loading file \"%1%\" due to an invalid configuration."), filename.string()) + "\n\n" + e.what();

View File

@ -135,7 +135,7 @@ void PreferencesDialog::show(const std::string& highlight_opt_key /*= std::strin
downloader->set_path_name(app_config->get("url_downloader_dest"));
downloader->allow(!app_config->has("downloader_url_registered") || app_config->get_bool("downloader_url_registered"));
for (const std::string opt_key : {"suppress_hyperlinks", "downloader_url_registered", "show_login_button"})
for (const std::string opt_key : {"suppress_hyperlinks", "downloader_url_registered", "show_login_button", "show_step_import_parameters"})
m_optgroup_other->set_value(opt_key, app_config->get_bool(opt_key));
// by default "Log in" button is visible
if (!app_config->has("show_login_button"))
@ -629,6 +629,11 @@ void PreferencesDialog::build()
// "If disabled, the descriptions of configuration parameters in settings tabs will work as hyperlinks."),
app_config->get_bool("suppress_hyperlinks"));
append_bool_option(m_optgroup_other, "show_step_import_parameters",
L("Show STEP file import parameters"),
L("If enabled, PrusaSlicer will show dialog with quality selection when importing STEP file."),
app_config->get_bool("show_step_import_parameters"));
append_bool_option(m_optgroup_other, "show_login_button",
L("Show \"Log in\" button in application top bar"),
L("If enabled, PrusaSlicer will show up \"Log in\" button in application top bar."),