NEW:add step mesh parameters
jira: STUDIO-7415 Change-Id: I5e09a1eb1ad31063ad56d08d5738907a804dc112 (cherry picked from commit ccbe9630076b754ab440e98977c4164afff96250)
This commit is contained in:
parent
4e3893a6e3
commit
84e7063c54
|
@ -34,9 +34,6 @@
|
|||
#include "TopExp_Explorer.hxx"
|
||||
#include "BRep_Tool.hxx"
|
||||
|
||||
const double STEP_TRANS_CHORD_ERROR = 0.003;
|
||||
const double STEP_TRANS_ANGLE_RES = 0.5;
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -220,7 +217,10 @@ static void getNamedSolids(const TopLoc_Location& location, const std::string& p
|
|||
}
|
||||
}
|
||||
|
||||
bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn)
|
||||
bool load_step(const char *path, Model *model, bool& is_cancel,
|
||||
double linear_defletion/*=0.003*/,
|
||||
double angle_defletion/*= 0.5*/,
|
||||
ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn, long& mesh_face_num)
|
||||
{
|
||||
bool cb_cancel = false;
|
||||
if (stepFn) {
|
||||
|
@ -275,7 +275,7 @@ bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgre
|
|||
stl.resize(namedSolids.size());
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, namedSolids.size()), [&](const tbb::blocked_range<size_t> &range) {
|
||||
for (size_t i = range.begin(); i < range.end(); i++) {
|
||||
BRepMesh_IncrementalMesh mesh(namedSolids[i].solid, STEP_TRANS_CHORD_ERROR, false, STEP_TRANS_ANGLE_RES, true);
|
||||
BRepMesh_IncrementalMesh mesh(namedSolids[i].solid, linear_defletion, false, angle_defletion, true);
|
||||
// BBS: calculate total number of the nodes and triangles
|
||||
int aNbNodes = 0;
|
||||
int aNbTriangles = 0;
|
||||
|
@ -348,6 +348,14 @@ bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgre
|
|||
}
|
||||
});
|
||||
|
||||
if (mesh_face_num != -1) {
|
||||
for (size_t i = 0; i < stl.size(); i++) {
|
||||
// Test for overflow
|
||||
mesh_face_num += stl[i].stats.number_of_facets;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ModelObject *new_object = model->add_object();
|
||||
const char * last_slash = strrchr(path, DIR_SEPARATOR);
|
||||
new_object->name.assign((last_slash == nullptr) ? path : last_slash + 1);
|
||||
|
|
|
@ -17,7 +17,13 @@ typedef std::function<void(int load_stage, int current, int total, bool& cancel)
|
|||
typedef std::function<void(bool isUtf8)> StepIsUtf8Fn;
|
||||
|
||||
//BBS: Load an step file into a provided model.
|
||||
extern bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgressFn proFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr);
|
||||
extern bool load_step(const char *path, Model *model,
|
||||
bool& is_cancel,
|
||||
double linear_defletion = 0.003,
|
||||
double angle_defletion = 0.5,
|
||||
ImportStepProgressFn proFn = nullptr,
|
||||
StepIsUtf8Fn isUtf8Fn = nullptr,
|
||||
long& mesh_face_num = *(new long(-1)));
|
||||
|
||||
//BBS: Used to detect what kind of encoded type is used in name field of step
|
||||
// If is encoded in UTF8, the file don't need to be handled, then return the original path directly.
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "SVG.hpp"
|
||||
#include <Eigen/Dense>
|
||||
#include <functional>
|
||||
#include "GCodeWriter.hpp"
|
||||
|
||||
// BBS: for segment
|
||||
|
@ -183,7 +184,8 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
|
|||
StepIsUtf8Fn stepIsUtf8Fn,
|
||||
BBLProject * project,
|
||||
int plate_id,
|
||||
ObjImportColorFn objFn)
|
||||
ObjImportColorFn objFn,
|
||||
std::function<int(double&, double&)> step_mesh_fn)
|
||||
{
|
||||
Model model;
|
||||
|
||||
|
@ -208,9 +210,19 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
|
|||
bool is_cb_cancel = false;
|
||||
std::string message;
|
||||
if (boost::algorithm::iends_with(input_file, ".stp") ||
|
||||
boost::algorithm::iends_with(input_file, ".step"))
|
||||
result = load_step(input_file.c_str(), &model, is_cb_cancel, stepFn, stepIsUtf8Fn);
|
||||
else if (boost::algorithm::iends_with(input_file, ".stl"))
|
||||
boost::algorithm::iends_with(input_file, ".step")) {
|
||||
double linear_defletion = 0.003;
|
||||
double angle_defletion = 0.5;
|
||||
if (step_mesh_fn) {
|
||||
if (step_mesh_fn(linear_defletion, angle_defletion) == -1) {
|
||||
result = false;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
result = load_step(input_file.c_str(), &model, is_cb_cancel, linear_defletion, angle_defletion, stepFn, stepIsUtf8Fn);
|
||||
end:
|
||||
BOOST_LOG_TRIVIAL(info) << "Cancel step mesh dialog";
|
||||
} else if (boost::algorithm::iends_with(input_file, ".stl"))
|
||||
result = load_stl(input_file.c_str(), &model, nullptr, stlFn);
|
||||
else if (boost::algorithm::iends_with(input_file, ".oltp"))
|
||||
result = load_stl(input_file.c_str(), &model, nullptr, stlFn,256);
|
||||
|
|
|
@ -1579,7 +1579,8 @@ public:
|
|||
StepIsUtf8Fn stepIsUtf8Fn = nullptr,
|
||||
BBLProject * project = nullptr,
|
||||
int plate_id = 0,
|
||||
ObjImportColorFn objFn = nullptr
|
||||
ObjImportColorFn objFn = nullptr,
|
||||
std::function<int(double&, double&)> step_mesh_fn = nullptr
|
||||
);
|
||||
// BBS
|
||||
static bool obj_import_vertex_color_deal(const std::vector<unsigned char> &vertex_filament_ids, const unsigned char &first_extruder_id, Model *model);
|
||||
|
|
|
@ -295,6 +295,8 @@ set(SLIC3R_GUI_SOURCES
|
|||
GUI/RemovableDriveManager.hpp
|
||||
GUI/SendSystemInfoDialog.cpp
|
||||
GUI/SendSystemInfoDialog.hpp
|
||||
GUI/StepMeshDialog.cpp
|
||||
GUI/StepMeshDialog.hpp
|
||||
GUI/PlateSettingsDialog.cpp
|
||||
GUI/PlateSettingsDialog.hpp
|
||||
GUI/ImGuiWrapper.hpp
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
#include "PlateSettingsDialog.hpp"
|
||||
#include "DailyTips.hpp"
|
||||
#include "CreatePresetsDialog.hpp"
|
||||
#include "StepMeshDialog.hpp"
|
||||
|
||||
using boost::optional;
|
||||
namespace fs = boost::filesystem;
|
||||
|
@ -3973,7 +3974,20 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
filament_ids.clear();
|
||||
}
|
||||
};
|
||||
model = Slic3r::Model::read_from_file(
|
||||
auto step_mesh = [this, &path, &is_user_cancel](double& linear_value, double& angle_value)-> int {
|
||||
if (boost::iends_with(path.string(), ".step") ||
|
||||
boost::iends_with(path.string(), ".stp")){
|
||||
StepMeshDialog mesh_dlg(nullptr, path);
|
||||
if (mesh_dlg.ShowModal() == wxID_OK) {
|
||||
linear_value = mesh_dlg.get_linear_defletion();
|
||||
angle_value = mesh_dlg.get_angle_defletion();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
is_user_cancel = false;
|
||||
return -1;
|
||||
};
|
||||
model = Slic3r::Model:: read_from_file(
|
||||
path.string(), nullptr, nullptr, strategy, &plate_data, &project_presets, &is_xxx, &file_version, nullptr,
|
||||
[this, &dlg, real_filename, &progress_percent, &file_percent, INPUT_FILES_RATIO, total_files, i, &designer_model_id, &designer_country_code](int current, int total, bool &cancel, std::string &mode_id, std::string &code)
|
||||
{
|
||||
|
@ -4003,7 +4017,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
Slic3r::GUI::show_info(nullptr, _L("Name of components inside step file is not UTF8 format!") + "\n\n" + _L("The name may show garbage characters!"),
|
||||
_L("Attention!"));
|
||||
},
|
||||
nullptr, 0, obj_color_fun);
|
||||
nullptr, 0, obj_color_fun, step_mesh);
|
||||
|
||||
|
||||
if (designer_model_id.empty() && boost::algorithm::iends_with(path.string(), ".stl")) {
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
#include "StepMeshDialog.hpp"
|
||||
#include "BBLStatusBar.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "Widgets/Button.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/slider.h>
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::GUI;
|
||||
|
||||
static int _scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit() / 10; }
|
||||
static int _ITEM_WIDTH() { return _scale(30); }
|
||||
#define MIN_DIALOG_WIDTH FromDIP(400)
|
||||
#define SLIDER_WIDTH FromDIP(150)
|
||||
#define TEXT_CTRL_WIDTH FromDIP(40)
|
||||
#define BUTTON_SIZE wxSize(FromDIP(58), FromDIP(24))
|
||||
#define BUTTON_BORDER FromDIP(int(400 - 58 * 2) / 8)
|
||||
#define SLIDER_SCALE(val) ((val) / 0.001)
|
||||
#define SLIDER_UNSCALE(val) ((val) * 0.001)
|
||||
#define SLIDER_SCALE_10(val) ((val) / 0.01)
|
||||
#define SLIDER_UNSCALE_10(val) ((val) * 0.01)
|
||||
#define LEFT_RIGHT_PADING FromDIP(20)
|
||||
|
||||
void StepMeshDialog::on_dpi_changed(const wxRect& suggested_rect) {
|
||||
};
|
||||
|
||||
bool StepMeshDialog:: validate_number_range(const wxString& value, double min, double max) {
|
||||
double num;
|
||||
if (!value.ToDouble(&num)) {
|
||||
return false;
|
||||
}
|
||||
return (num >= min && num <= max);
|
||||
}
|
||||
|
||||
StepMeshDialog::StepMeshDialog(wxWindow* parent, fs::path file)
|
||||
: DPIDialog(parent ? parent : static_cast<wxWindow *>(wxGetApp().mainframe),
|
||||
wxID_ANY,
|
||||
_(L("Step file import parameters")),
|
||||
wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE /* | wxRESIZE_BORDER*/), m_file(file)
|
||||
{
|
||||
std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico")
|
||||
% Slic3r::resources_dir()).str();
|
||||
SetIcon(wxIcon(Slic3r::encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
|
||||
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
|
||||
wxBoxSizer* bSizer = new wxBoxSizer(wxVERTICAL);
|
||||
bSizer->SetMinSize(wxSize(MIN_DIALOG_WIDTH, -1));
|
||||
|
||||
wxBoxSizer* linear_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
//linear_sizer->SetMinSize(wxSize(MIN_DIALOG_WIDTH, -1));
|
||||
wxStaticText* linear_title = new wxStaticText(this,
|
||||
wxID_ANY,
|
||||
_L("Linear Deflection:"));
|
||||
linear_sizer->Add(linear_title, 0, wxALIGN_LEFT);
|
||||
linear_sizer->AddStretchSpacer(1);
|
||||
wxSlider* linear_slider = new wxSlider(this, wxID_ANY,
|
||||
SLIDER_SCALE(get_linear_defletion()),
|
||||
1, 100, wxDefaultPosition,
|
||||
wxSize(SLIDER_WIDTH, -1),
|
||||
wxSL_HORIZONTAL);
|
||||
linear_sizer->Add(linear_slider, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5));
|
||||
wxTextValidator valid_number(wxFILTER_NUMERIC);
|
||||
wxTextCtrl* linear_textctrl = new wxTextCtrl(this, wxID_ANY,
|
||||
m_linear_last,
|
||||
wxDefaultPosition, wxSize(TEXT_CTRL_WIDTH, -1),
|
||||
0, valid_number);
|
||||
linear_sizer->Add(linear_textctrl, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5));
|
||||
// textctrl loss focus
|
||||
linear_textctrl->Bind(wxEVT_KILL_FOCUS, ([this, linear_textctrl](wxFocusEvent& e) {
|
||||
wxString value = linear_textctrl->GetValue();
|
||||
if(!validate_number_range(value, 0.001, 0.1)) {
|
||||
linear_textctrl->SetValue(m_linear_last);
|
||||
}
|
||||
m_linear_last = value;
|
||||
update_mesh_number_text();
|
||||
e.Skip();
|
||||
}));
|
||||
// slider bind textctrl
|
||||
linear_slider->Bind(wxEVT_SLIDER, ([this, linear_slider, linear_textctrl](wxCommandEvent& e) {
|
||||
double slider_value = SLIDER_UNSCALE(linear_slider->GetValue());
|
||||
linear_textctrl->SetValue(wxString::Format("%.3f", slider_value));
|
||||
m_linear_last = wxString::Format("%.3f", slider_value);
|
||||
update_mesh_number_text();
|
||||
}));
|
||||
// textctrl bind slider
|
||||
linear_textctrl->Bind(wxEVT_TEXT, ([this, linear_textctrl, linear_slider](wxCommandEvent& e) {
|
||||
double slider_value_long;
|
||||
int slider_value;
|
||||
wxString value = linear_textctrl->GetValue();
|
||||
if (value.ToDouble(&slider_value_long)) {
|
||||
slider_value = SLIDER_SCALE(slider_value_long);
|
||||
if (slider_value >= linear_slider->GetMin() && slider_value <= linear_slider->GetMax()) {
|
||||
linear_slider->SetValue(slider_value);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
bSizer->Add(linear_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, LEFT_RIGHT_PADING);
|
||||
|
||||
wxBoxSizer* angle_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxStaticText* angle_title = new wxStaticText(this,
|
||||
wxID_ANY,
|
||||
_L("Angle Deflection:"));
|
||||
angle_sizer->Add(angle_title, 0, wxALIGN_LEFT);
|
||||
angle_sizer->AddStretchSpacer(1);
|
||||
wxSlider* angle_slider = new wxSlider(this, wxID_ANY,
|
||||
SLIDER_SCALE_10(get_angle_defletion()),
|
||||
1, 100, wxDefaultPosition,
|
||||
wxSize(SLIDER_WIDTH, -1),
|
||||
wxSL_HORIZONTAL);
|
||||
angle_sizer->Add(angle_slider, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5));
|
||||
wxTextCtrl* angle_textctrl = new wxTextCtrl(this, wxID_ANY,
|
||||
m_angle_last,
|
||||
wxDefaultPosition, wxSize(TEXT_CTRL_WIDTH, -1),
|
||||
0, valid_number);
|
||||
angle_sizer->Add(angle_textctrl, 0, wxALIGN_RIGHT | wxLEFT, FromDIP(5));
|
||||
// textctrl loss focus
|
||||
angle_textctrl->Bind(wxEVT_KILL_FOCUS, ([this, angle_textctrl](wxFocusEvent& e) {
|
||||
wxString value = angle_textctrl->GetValue();
|
||||
if (!validate_number_range(value, 0.01, 1)) {
|
||||
angle_textctrl->SetValue(m_angle_last);
|
||||
}
|
||||
m_angle_last = value;
|
||||
update_mesh_number_text();
|
||||
e.Skip();
|
||||
}));
|
||||
// slider bind textctrl
|
||||
angle_slider->Bind(wxEVT_SLIDER, ([this, angle_slider, angle_textctrl](wxCommandEvent& e) {
|
||||
double slider_value = SLIDER_UNSCALE_10(angle_slider->GetValue());
|
||||
angle_textctrl->SetValue(wxString::Format("%.2f", slider_value));
|
||||
m_angle_last = wxString::Format("%.2f", slider_value);
|
||||
update_mesh_number_text();
|
||||
}));
|
||||
// textctrl bind slider
|
||||
linear_textctrl->Bind(wxEVT_TEXT, ([this, angle_slider, angle_textctrl](wxCommandEvent& e) {
|
||||
double slider_value_long;
|
||||
int slider_value;
|
||||
wxString value = angle_textctrl->GetValue();
|
||||
if (value.ToDouble(&slider_value_long)) {
|
||||
slider_value = SLIDER_SCALE_10(slider_value_long);
|
||||
if (slider_value >= angle_slider->GetMin() && slider_value <= angle_slider->GetMax()) {
|
||||
angle_slider->SetValue(slider_value);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
bSizer->Add(angle_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, LEFT_RIGHT_PADING);
|
||||
|
||||
|
||||
mesh_face_number_text = new wxStaticText(this, wxID_ANY, _L("Number of generated surfaces: 0"));
|
||||
bSizer->Add(mesh_face_number_text, 1, wxEXPAND | wxLEFT | wxRIGHT, LEFT_RIGHT_PADING);
|
||||
|
||||
wxBoxSizer* bSizer_button = new wxBoxSizer(wxHORIZONTAL);
|
||||
bSizer_button->SetMinSize(wxSize(FromDIP(100), -1));
|
||||
|
||||
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(27, 136, 68), StateColor::Pressed), std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered),
|
||||
std::pair<wxColour, int>(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal));
|
||||
m_button_ok = new Button(this, _L("OK"));
|
||||
m_button_ok->SetBackgroundColor(btn_bg_green);
|
||||
m_button_ok->SetBorderColor(*wxWHITE);
|
||||
m_button_ok->SetTextColor(wxColour(0xFFFFFE));
|
||||
m_button_ok->SetFont(Label::Body_12);
|
||||
m_button_ok->SetSize(BUTTON_SIZE);
|
||||
m_button_ok->SetMinSize(BUTTON_SIZE);
|
||||
m_button_ok->SetCornerRadius(FromDIP(12));
|
||||
bSizer_button->Add(m_button_ok, 0, wxALIGN_RIGHT, BUTTON_BORDER);
|
||||
|
||||
m_button_ok->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { EndModal(wxID_OK); });
|
||||
|
||||
StateColor btn_bg_white(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed), std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered),
|
||||
std::pair<wxColour, int>(*wxWHITE, StateColor::Normal));
|
||||
|
||||
m_button_cancel = new Button(this, _L("Cancel"));
|
||||
m_button_cancel->SetBackgroundColor(btn_bg_white);
|
||||
m_button_cancel->SetBorderColor(wxColour(38, 46, 48));
|
||||
m_button_cancel->SetFont(Label::Body_12);
|
||||
m_button_cancel->SetSize(BUTTON_SIZE);
|
||||
m_button_cancel->SetMinSize(BUTTON_SIZE);
|
||||
m_button_cancel->SetCornerRadius(FromDIP(12));
|
||||
bSizer_button->Add(m_button_cancel, 0, wxALIGN_RIGHT | wxLEFT, BUTTON_BORDER);
|
||||
|
||||
m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { EndModal(wxID_CANCEL); });
|
||||
|
||||
bSizer->Add(bSizer_button, 0, wxALIGN_RIGHT | wxRIGHT| wxBOTTOM, LEFT_RIGHT_PADING);
|
||||
|
||||
this->SetSizer(bSizer);
|
||||
update_mesh_number_text();
|
||||
this->Layout();
|
||||
bSizer->Fit(this);
|
||||
|
||||
this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { });
|
||||
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
}
|
||||
|
||||
long StepMeshDialog::get_mesh_number()
|
||||
{
|
||||
Model model;
|
||||
long number = 0;
|
||||
const std::string file_path = m_file.string();
|
||||
bool is_cb_cancel = false;
|
||||
bool result = load_step(file_path.c_str(), &model, is_cb_cancel, get_linear_defletion(), get_angle_defletion(), nullptr, nullptr, number);
|
||||
return number;
|
||||
}
|
||||
|
||||
void StepMeshDialog::update_mesh_number_text()
|
||||
{
|
||||
long number = get_mesh_number();
|
||||
wxString newText = wxString::Format("Number of generated surfaces: %d", number);
|
||||
mesh_face_number_text->SetLabel(newText);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef _STEP_MESH_DIALOG_H_
|
||||
#define _STEP_MESH_DIALOG_H_
|
||||
|
||||
#include "GUI_Utils.hpp"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <wx/sizer.h>
|
||||
class Button;
|
||||
namespace fs = boost::filesystem;
|
||||
class StepMeshDialog : public Slic3r::GUI::DPIDialog
|
||||
{
|
||||
public:
|
||||
StepMeshDialog(wxWindow* parent, fs::path file);
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
inline double get_linear_defletion() {
|
||||
double value;
|
||||
if (m_linear_last.ToDouble(&value)) {
|
||||
return value;
|
||||
}else {
|
||||
return 0.003;
|
||||
}
|
||||
}
|
||||
inline double get_angle_defletion() {
|
||||
double value;
|
||||
if (m_angle_last.ToDouble(&value)) {
|
||||
return value;
|
||||
} else {
|
||||
return 0.5;
|
||||
}
|
||||
}
|
||||
long get_mesh_number();
|
||||
private:
|
||||
fs::path m_file;
|
||||
Button* m_button_ok = nullptr;
|
||||
Button* m_button_cancel = nullptr;
|
||||
wxString m_linear_last = wxString::Format("%.3f", 0.003);
|
||||
wxString m_angle_last = wxString::Format("%.2f", 0.5);
|
||||
wxStaticText* mesh_face_number_text;
|
||||
bool validate_number_range(const wxString& value, double min, double max);
|
||||
void update_mesh_number_text();
|
||||
};
|
||||
|
||||
#endif // _STEP_MESH_DIALOG_H_
|
Loading…
Reference in New Issue