Merged with master

This commit is contained in:
bubnikv 2018-09-17 10:38:14 +02:00
commit 38028187b4
70 changed files with 1711 additions and 1163 deletions

View file

@ -11,13 +11,11 @@
#include <ModelArrange.hpp>
#include <slic3r/GUI/PresetBundle.hpp>
#include <Geometry.hpp>
#include <PrintConfig.hpp>
#include <Print.hpp>
#include <PrintExport.hpp>
#include <Geometry.hpp>
#include <Model.hpp>
#include <Utils.hpp>
#include <SLABasePool.hpp>
namespace Slic3r {
@ -45,15 +43,6 @@ namespace GUI {
PresetBundle* get_preset_bundle();
}
static const PrintObjectStep STEP_SLICE = posSlice;
static const PrintObjectStep STEP_PERIMETERS = posPerimeters;
static const PrintObjectStep STEP_PREPARE_INFILL = posPrepareInfill;
static const PrintObjectStep STEP_INFILL = posInfill;
static const PrintObjectStep STEP_SUPPORTMATERIAL = posSupportMaterial;
static const PrintStep STEP_SKIRT = psSkirt;
static const PrintStep STEP_BRIM = psBrim;
static const PrintStep STEP_WIPE_TOWER = psWipeTower;
AppControllerBoilerplate::ProgresIndicatorPtr
AppControllerBoilerplate::global_progress_indicator() {
ProgresIndicatorPtr ret;
@ -73,336 +62,8 @@ void AppControllerBoilerplate::global_progress_indicator(
pri_data_->m.unlock();
}
void PrintController::make_skirt()
{
assert(print_ != nullptr);
// prerequisites
for(auto obj : print_->objects) make_perimeters(obj);
for(auto obj : print_->objects) infill(obj);
for(auto obj : print_->objects) gen_support_material(obj);
if(!print_->state.is_done(STEP_SKIRT)) {
print_->state.set_started(STEP_SKIRT);
print_->skirt.clear();
if(print_->has_skirt()) print_->_make_skirt();
print_->state.set_done(STEP_SKIRT);
}
}
void PrintController::make_brim()
{
assert(print_ != nullptr);
// prerequisites
for(auto obj : print_->objects) make_perimeters(obj);
for(auto obj : print_->objects) infill(obj);
for(auto obj : print_->objects) gen_support_material(obj);
make_skirt();
if(!print_->state.is_done(STEP_BRIM)) {
print_->state.set_started(STEP_BRIM);
// since this method must be idempotent, we clear brim paths *before*
// checking whether we need to generate them
print_->brim.clear();
if(print_->config.brim_width > 0) print_->_make_brim();
print_->state.set_done(STEP_BRIM);
}
}
void PrintController::make_wipe_tower()
{
assert(print_ != nullptr);
// prerequisites
for(auto obj : print_->objects) make_perimeters(obj);
for(auto obj : print_->objects) infill(obj);
for(auto obj : print_->objects) gen_support_material(obj);
make_skirt();
make_brim();
if(!print_->state.is_done(STEP_WIPE_TOWER)) {
print_->state.set_started(STEP_WIPE_TOWER);
// since this method must be idempotent, we clear brim paths *before*
// checking whether we need to generate them
print_->brim.clear();
if(print_->has_wipe_tower()) print_->_make_wipe_tower();
print_->state.set_done(STEP_WIPE_TOWER);
}
}
void PrintController::slice(PrintObject *pobj)
{
assert(pobj != nullptr && print_ != nullptr);
if(pobj->state.is_done(STEP_SLICE)) return;
pobj->state.set_started(STEP_SLICE);
pobj->_slice();
auto msg = pobj->_fix_slicing_errors();
if(!msg.empty()) report_issue(IssueType::WARN, msg);
// simplify slices if required
if (print_->config.resolution)
pobj->_simplify_slices(scale_(print_->config.resolution));
if(pobj->layers.empty())
report_issue(IssueType::ERR,
_(L("No layers were detected. You might want to repair your "
"STL file(s) or check their size or thickness and retry"))
);
pobj->state.set_done(STEP_SLICE);
}
void PrintController::make_perimeters(PrintObject *pobj)
{
assert(pobj != nullptr);
slice(pobj);
if (!pobj->state.is_done(STEP_PERIMETERS)) {
pobj->_make_perimeters();
}
}
void PrintController::infill(PrintObject *pobj)
{
assert(pobj != nullptr);
make_perimeters(pobj);
if (!pobj->state.is_done(STEP_PREPARE_INFILL)) {
pobj->state.set_started(STEP_PREPARE_INFILL);
pobj->_prepare_infill();
pobj->state.set_done(STEP_PREPARE_INFILL);
}
pobj->_infill();
}
void PrintController::gen_support_material(PrintObject *pobj)
{
assert(pobj != nullptr);
// prerequisites
slice(pobj);
if(!pobj->state.is_done(STEP_SUPPORTMATERIAL)) {
pobj->state.set_started(STEP_SUPPORTMATERIAL);
pobj->clear_support_layers();
if((pobj->config.support_material || pobj->config.raft_layers > 0)
&& pobj->layers.size() > 1) {
pobj->_generate_support_material();
}
pobj->state.set_done(STEP_SUPPORTMATERIAL);
}
}
PrintController::PngExportData
PrintController::query_png_export_data(const DynamicPrintConfig& conf)
{
PngExportData ret;
auto zippath = query_destination_path("Output zip file", "*.zip", "out");
ret.zippath = zippath;
ret.width_mm = conf.opt_float("display_width");
ret.height_mm = conf.opt_float("display_height");
ret.width_px = conf.opt_int("display_pixels_x");
ret.height_px = conf.opt_int("display_pixels_y");
auto opt_corr = conf.opt<ConfigOptionFloats>("printer_correction");
if(opt_corr) {
ret.corr_x = opt_corr->values[0];
ret.corr_y = opt_corr->values[1];
ret.corr_z = opt_corr->values[2];
}
ret.exp_time_first_s = conf.opt_float("initial_exposure_time");
ret.exp_time_s = conf.opt_float("exposure_time");
return ret;
}
void PrintController::slice(AppControllerBoilerplate::ProgresIndicatorPtr pri)
{
auto st = pri->state();
Slic3r::trace(3, "Starting the slicing process.");
pri->update(st+20, _(L("Generating perimeters")));
for(auto obj : print_->objects) make_perimeters(obj);
pri->update(st+60, _(L("Infilling layers")));
for(auto obj : print_->objects) infill(obj);
pri->update(st+70, _(L("Generating support material")));
for(auto obj : print_->objects) gen_support_material(obj);
pri->message_fmt(_(L("Weight: %.1fg, Cost: %.1f")),
print_->total_weight, print_->total_cost);
pri->state(st+85);
pri->update(st+88, _(L("Generating skirt")));
make_skirt();
pri->update(st+90, _(L("Generating brim")));
make_brim();
pri->update(st+95, _(L("Generating wipe tower")));
make_wipe_tower();
pri->update(st+100, _(L("Done")));
// time to make some statistics..
Slic3r::trace(3, _(L("Slicing process finished.")));
}
void PrintController::slice()
{
auto pri = global_progress_indicator();
if(!pri) pri = create_progress_indicator(100, L("Slicing"));
slice(pri);
}
void PrintController::slice_to_png()
{
using Pointf3 = Vec3d;
auto presetbundle = GUI::get_preset_bundle();
assert(presetbundle);
auto pt = presetbundle->printers.get_selected_preset().printer_technology();
if(pt != ptSLA) {
report_issue(IssueType::ERR, _("Printer technology is not SLA!"),
_("Error"));
return;
}
auto conf = presetbundle->full_config();
conf.validate();
auto exd = query_png_export_data(conf);
if(exd.zippath.empty()) return;
try {
print_->apply_config(conf);
print_->validate();
} catch(std::exception& e) {
report_issue(IssueType::ERR, e.what(), "Error");
return;
}
// TODO: copy the model and work with the copy only
bool correction = false;
if(exd.corr_x != 1.0 || exd.corr_y != 1.0 || exd.corr_z != 1.0) {
correction = true;
print_->invalidate_all_steps();
for(auto po : print_->objects) {
po->model_object()->scale(
Pointf3(exd.corr_x, exd.corr_y, exd.corr_z)
);
po->model_object()->invalidate_bounding_box();
po->reload_model_instances();
po->invalidate_all_steps();
}
}
// Turn back the correction scaling on the model.
auto scale_back = [this, correction, exd]() {
if(correction) { // scale the model back
print_->invalidate_all_steps();
for(auto po : print_->objects) {
po->model_object()->scale(
Pointf3(1.0/exd.corr_x, 1.0/exd.corr_y, 1.0/exd.corr_z)
);
po->model_object()->invalidate_bounding_box();
po->reload_model_instances();
po->invalidate_all_steps();
}
}
};
auto print_bb = print_->bounding_box();
Vec2d punsc = unscale(print_bb.size());
// If the print does not fit into the print area we should cry about it.
if(px(punsc) > exd.width_mm || py(punsc) > exd.height_mm) {
std::stringstream ss;
ss << _(L("Print will not fit and will be truncated!")) << "\n"
<< _(L("Width needed: ")) << px(punsc) << " mm\n"
<< _(L("Height needed: ")) << py(punsc) << " mm\n";
if(!report_issue(IssueType::WARN_Q, ss.str(), _(L("Warning")))) {
scale_back();
return;
}
}
// std::async(supports_asynch()? std::launch::async : std::launch::deferred,
// [this, exd, scale_back]()
// {
auto pri = create_progress_indicator(
200, _(L("Slicing to zipped png files...")));
try {
pri->update(0, _(L("Slicing...")));
slice(pri);
} catch (std::exception& e) {
pri->cancel();
report_issue(IssueType::ERR, e.what(), _(L("Exception occured")));
scale_back();
return;
}
auto pbak = print_->progressindicator;
print_->progressindicator = pri;
try {
print_to<FilePrinterFormat::PNG>( *print_, exd.zippath,
exd.width_mm, exd.height_mm,
exd.width_px, exd.height_px,
exd.exp_time_s, exd.exp_time_first_s);
} catch (std::exception& e) {
pri->cancel();
report_issue(IssueType::ERR, e.what(), _(L("Exception occured")));
}
print_->progressindicator = pbak;
scale_back();
// });
}
void ProgressIndicator::message_fmt(
const string &fmtstr, ...) {
const std::string &fmtstr, ...) {
std::stringstream ss;
va_list args;
va_start(args, fmtstr);
@ -433,80 +94,77 @@ const PrintConfig &PrintController::config() const
return print_->config;
}
void AppController::arrange_model()
{
using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
auto ftr = std::async(
supports_asynch()? std::launch::async : std::launch::deferred,
[this]()
{
using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
if(arranging_.load()) return;
unsigned count = 0;
for(auto obj : model_->objects) count += obj->instances.size();
// to prevent UI reentrancies
arranging_.store(true);
auto pind = global_progress_indicator();
unsigned count = 0;
for(auto obj : model_->objects) count += obj->instances.size();
float pmax = 1.0;
auto pind = global_progress_indicator();
if(pind) {
pmax = pind->max();
float pmax = 1.0;
// Set the range of the progress to the object count
pind->max(count);
if(pind) {
pmax = pind->max();
}
// Set the range of the progress to the object count
pind->max(count);
auto dist = print_ctl()->config().min_object_distance();
pind->on_cancel([this](){
arranging_.store(false);
});
// Create the arranger config
auto min_obj_distance = static_cast<Coord>(dist/SCALING_FACTOR);
auto& bedpoints = print_ctl()->config().bed_shape.values;
Polyline bed; bed.points.reserve(bedpoints.size());
for(auto& v : bedpoints)
bed.append(Point::new_scale(v(0), v(1)));
if(pind) pind->update(0, L("Arranging objects..."));
try {
arr::BedShapeHint hint;
// TODO: from Sasha from GUI
hint.type = arr::BedShapeType::WHO_KNOWS;
//FIXME merge error
/*
arr::arrange(*model_,
min_obj_distance,
bed,
hint,
false, // create many piles not just one pile
[pind, count](unsigned rem) {
if(pind)
pind->update(count - rem, L("Arranging objects..."));
});
*/
} catch(std::exception& e) {
std::cerr << e.what() << std::endl;
report_issue(IssueType::ERR,
L("Could not arrange model objects! "
"Some geometries may be invalid."),
L("Exception occurred"));
}
// Restore previous max value
if(pind) {
pind->max(pmax);
pind->update(0, L("Arranging done."));
}
});
while( ftr.wait_for(std::chrono::milliseconds(10))
!= std::future_status::ready) {
process_events();
}
auto dist = print_ctl()->config().min_object_distance();
// Create the arranger config
auto min_obj_distance = static_cast<Coord>(dist/SCALING_FACTOR);
auto& bedpoints = print_ctl()->config().bed_shape.values;
Polyline bed; bed.points.reserve(bedpoints.size());
for(auto& v : bedpoints)
bed.append(Point::new_scale(v(0), v(1)));
if(pind) pind->update(0, _(L("Arranging objects...")));
try {
arr::BedShapeHint hint;
// TODO: from Sasha from GUI
hint.type = arr::BedShapeType::WHO_KNOWS;
arr::arrange(*model_,
min_obj_distance,
bed,
hint,
false, // create many piles not just one pile
[this, pind, count](unsigned rem) {
if(pind)
pind->update(count - rem, L("Arranging objects..."));
process_events();
}, [this] () { return !arranging_.load(); });
} catch(std::exception& e) {
std::cerr << e.what() << std::endl;
report_issue(IssueType::ERR,
_(L("Could not arrange model objects! "
"Some geometries may be invalid.")),
_(L("Exception occurred")));
}
// Restore previous max value
if(pind) {
pind->max(pmax);
pind->update(0, arranging_.load() ? L("Arranging done.") :
L("Arranging canceled."));
pind->on_cancel(/*remove cancel function*/);
}
arranging_.store(false);
}
}

View file

@ -16,6 +16,7 @@ class Print;
class PrintObject;
class PrintConfig;
class ProgressStatusBar;
class DynamicPrintConfig;
/**
* @brief A boilerplate class for creating application logic. It should provide
@ -46,7 +47,7 @@ public:
AppControllerBoilerplate();
~AppControllerBoilerplate();
using Path = string;
using Path = std::string;
using PathList = std::vector<Path>;
/// Common runtime issue types
@ -67,20 +68,20 @@ public:
* @return Returns a list of paths choosed by the user.
*/
PathList query_destination_paths(
const string& title,
const std::string& title,
const std::string& extensions) const;
/**
* @brief Same as query_destination_paths but works for directories only.
*/
PathList query_destination_dirs(
const string& title) const;
const std::string& title) const;
/**
* @brief Same as query_destination_paths but returns only one path.
*/
Path query_destination_path(
const string& title,
const std::string& title,
const std::string& extensions,
const std::string& hint = "") const;
@ -95,11 +96,11 @@ public:
* title.
*/
bool report_issue(IssueType issuetype,
const string& description,
const string& brief);
const std::string& description,
const std::string& brief);
bool report_issue(IssueType issuetype,
const string& description);
const std::string& description);
/**
* @brief Return the global progress indicator for the current controller.
@ -150,12 +151,12 @@ protected:
*/
ProgresIndicatorPtr create_progress_indicator(
unsigned statenum,
const string& title,
const string& firstmsg) const;
const std::string& title,
const std::string& firstmsg) const;
ProgresIndicatorPtr create_progress_indicator(
unsigned statenum,
const string& title) const;
const std::string& title) const;
// This is a global progress indicator placeholder. In the Slic3r UI it can
// contain the progress indicator on the statusbar.
@ -167,43 +168,6 @@ protected:
*/
class PrintController: public AppControllerBoilerplate {
Print *print_ = nullptr;
protected:
void make_skirt();
void make_brim();
void make_wipe_tower();
void make_perimeters(PrintObject *pobj);
void infill(PrintObject *pobj);
void gen_support_material(PrintObject *pobj);
// Data structure with the png export input data
struct PngExportData {
std::string zippath; // output zip file
unsigned long width_px = 1440; // resolution - rows
unsigned long height_px = 2560; // resolution columns
double width_mm = 68.0, height_mm = 120.0; // dimensions in mm
double exp_time_first_s = 35.0; // first exposure time
double exp_time_s = 8.0; // global exposure time
double corr_x = 1.0; // offsetting in x
double corr_y = 1.0; // offsetting in y
double corr_z = 1.0; // offsetting in y
};
// Should display a dialog with the input fields for printing to png
PngExportData query_png_export_data(const DynamicPrintConfig&);
// The previous export data, to pre-populate the dialog
PngExportData prev_expdata_;
/**
* @brief Slice one pront object.
* @param pobj The print object.
*/
void slice(PrintObject *pobj);
void slice(ProgresIndicatorPtr pri);
public:
// Must be public for perl to use it
@ -218,15 +182,9 @@ public:
return PrintController::Ptr( new PrintController(print) );
}
/**
* @brief Slice the loaded print scene.
*/
void slice();
/**
* @brief Slice the print into zipped png files.
*/
void slice_to_png();
//FIXME Vojtech: Merging error
void slice() {}
void slice_to_png() {}
const PrintConfig& config() const;
};
@ -237,7 +195,6 @@ public:
class AppController: public AppControllerBoilerplate {
Model *model_ = nullptr;
PrintController::Ptr printctl;
std::atomic<bool> arranging_;
public:
/**
@ -273,14 +230,15 @@ public:
* In perl we have a progress indicating status bar on the bottom of the
* window which is defined and created in perl. We can pass the ID-s of the
* gauge and the statusbar id and make a wrapper implementation of the
* IProgressIndicator interface so we can use this GUI widget from C++.
* ProgressIndicator interface so we can use this GUI widget from C++.
*
* This function should be called from perl.
*
* @param gauge_id The ID of the gague widget of the status bar.
* @param statusbar_id The ID of the status bar.
*/
void set_global_progress_indicator(ProgressStatusBar *prs);
void set_global_progress_indicator(unsigned gauge_id,
unsigned statusbar_id);
void arrange_model();
};

View file

@ -4,7 +4,6 @@
#include <future>
#include <slic3r/GUI/GUI.hpp>
#include <slic3r/GUI/ProgressStatusBar.hpp>
#include <wx/app.h>
#include <wx/filedlg.h>
@ -28,16 +27,16 @@ bool AppControllerBoilerplate::supports_asynch() const
void AppControllerBoilerplate::process_events()
{
wxYieldIfNeeded();
wxSafeYield();
}
AppControllerBoilerplate::PathList
AppControllerBoilerplate::query_destination_paths(
const string &title,
const std::string &title,
const std::string &extensions) const
{
wxFileDialog dlg(wxTheApp->GetTopWindow(), title );
wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) );
dlg.SetWildcard(extensions);
dlg.ShowModal();
@ -53,11 +52,11 @@ AppControllerBoilerplate::query_destination_paths(
AppControllerBoilerplate::Path
AppControllerBoilerplate::query_destination_path(
const string &title,
const std::string &title,
const std::string &extensions,
const std::string& hint) const
{
wxFileDialog dlg(wxTheApp->GetTopWindow(), title );
wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) );
dlg.SetWildcard(extensions);
dlg.SetFilename(hint);
@ -72,8 +71,8 @@ AppControllerBoilerplate::query_destination_path(
}
bool AppControllerBoilerplate::report_issue(IssueType issuetype,
const string &description,
const string &brief)
const std::string &description,
const std::string &brief)
{
auto icon = wxICON_INFORMATION;
auto style = wxOK|wxCENTRE;
@ -85,15 +84,15 @@ bool AppControllerBoilerplate::report_issue(IssueType issuetype,
case IssueType::FATAL: icon = wxICON_ERROR;
}
auto ret = wxMessageBox(description, brief, icon | style);
auto ret = wxMessageBox(_(description), _(brief), icon | style);
return ret != wxCANCEL;
}
bool AppControllerBoilerplate::report_issue(
AppControllerBoilerplate::IssueType issuetype,
const string &description)
const std::string &description)
{
return report_issue(issuetype, description, string());
return report_issue(issuetype, description, std::string());
}
wxDEFINE_EVENT(PROGRESS_STATUS_UPDATE_EVENT, wxCommandEvent);
@ -137,8 +136,8 @@ public:
/// Get the mode of parallel operation.
inline bool asynch() const { return is_asynch_; }
inline GuiProgressIndicator(int range, const string& title,
const string& firstmsg) :
inline GuiProgressIndicator(int range, const wxString& title,
const wxString& firstmsg) :
gauge_(title, firstmsg, range, wxTheApp->GetTopWindow(),
wxPD_APP_MODAL | wxPD_AUTO_HIDE),
message_(firstmsg),
@ -152,11 +151,6 @@ public:
this, id_);
}
virtual void cancel() override {
update(max(), "Abort");
ProgressIndicator::cancel();
}
virtual void state(float val) override {
state(static_cast<unsigned>(val));
}
@ -171,26 +165,28 @@ public:
} else _state(st);
}
virtual void message(const string & msg) override {
message_ = msg;
virtual void message(const std::string & msg) override {
message_ = _(msg);
}
virtual void messageFmt(const string& fmt, ...) {
virtual void messageFmt(const std::string& fmt, ...) {
va_list arglist;
va_start(arglist, fmt);
message_ = wxString::Format(wxString(fmt), arglist);
message_ = wxString::Format(_(fmt), arglist);
va_end(arglist);
}
virtual void title(const string & title) override {
title_ = title;
virtual void title(const std::string & title) override {
title_ = _(title);
}
};
}
AppControllerBoilerplate::ProgresIndicatorPtr
AppControllerBoilerplate::create_progress_indicator(
unsigned statenum, const string& title, const string& firstmsg) const
unsigned statenum,
const std::string& title,
const std::string& firstmsg) const
{
auto pri =
std::make_shared<GuiProgressIndicator>(statenum, title, firstmsg);
@ -203,29 +199,39 @@ AppControllerBoilerplate::create_progress_indicator(
}
AppControllerBoilerplate::ProgresIndicatorPtr
AppControllerBoilerplate::create_progress_indicator(unsigned statenum,
const string &title) const
AppControllerBoilerplate::create_progress_indicator(
unsigned statenum, const std::string &title) const
{
return create_progress_indicator(statenum, title, string());
return create_progress_indicator(statenum, title, std::string());
}
namespace {
// A wrapper progress indicator class around the statusbar created in perl.
class Wrapper: public ProgressIndicator, public wxEvtHandler {
ProgressStatusBar *sbar_;
wxGauge *gauge_;
wxStatusBar *stbar_;
using Base = ProgressIndicator;
std::string message_;
wxString message_;
AppControllerBoilerplate& ctl_;
void showProgress(bool show = true) {
sbar_->show_progress(show);
gauge_->Show(show);
}
void _state(unsigned st) {
if( st <= ProgressIndicator::max() ) {
Base::state(st);
sbar_->set_status_text(message_);
sbar_->set_progress(st);
if(!gauge_->IsShown()) showProgress(true);
stbar_->SetStatusText(message_);
if(static_cast<long>(st) == gauge_->GetRange()) {
gauge_->SetValue(0);
showProgress(false);
} else {
gauge_->SetValue(static_cast<int>(st));
}
}
}
@ -238,12 +244,12 @@ class Wrapper: public ProgressIndicator, public wxEvtHandler {
public:
inline Wrapper(ProgressStatusBar *sbar,
inline Wrapper(wxGauge *gauge, wxStatusBar *stbar,
AppControllerBoilerplate& ctl):
sbar_(sbar), ctl_(ctl)
gauge_(gauge), stbar_(stbar), ctl_(ctl)
{
Base::max(static_cast<float>(sbar_->get_range()));
Base::states(static_cast<unsigned>(sbar_->get_range()));
Base::max(static_cast<float>(gauge->GetRange()));
Base::states(static_cast<unsigned>(gauge->GetRange()));
Bind(PROGRESS_STATUS_UPDATE_EVENT,
&Wrapper::_state,
@ -256,7 +262,7 @@ public:
virtual void max(float val) override {
if(val > 1.0) {
sbar_->set_range(static_cast<int>(val));
gauge_->SetRange(static_cast<int>(val));
ProgressIndicator::max(val);
}
}
@ -271,32 +277,31 @@ public:
}
}
virtual void message(const string & msg) override {
message_ = msg;
virtual void message(const std::string & msg) override {
message_ = _(msg);
}
virtual void message_fmt(const string& fmt, ...) override {
virtual void message_fmt(const std::string& fmt, ...) override {
va_list arglist;
va_start(arglist, fmt);
message_ = wxString::Format(fmt, arglist);
message_ = wxString::Format(_(fmt), arglist);
va_end(arglist);
}
virtual void title(const string & /*title*/) override {}
virtual void on_cancel(CancelFn fn) override {
sbar_->set_cancel_callback(fn);
Base::on_cancel(fn);
}
virtual void title(const std::string & /*title*/) override {}
};
}
void AppController::set_global_progress_indicator(ProgressStatusBar *prsb)
void AppController::set_global_progress_indicator(
unsigned gid,
unsigned sid)
{
if(prsb) {
global_progress_indicator(std::make_shared<Wrapper>(prsb, *this));
wxGauge* gauge = dynamic_cast<wxGauge*>(wxWindow::FindWindowById(gid));
wxStatusBar* sb = dynamic_cast<wxStatusBar*>(wxWindow::FindWindowById(sid));
if(gauge && sb) {
global_progressind_ = std::make_shared<Wrapper>(gauge, sb, *this);
}
}
}

View file

@ -648,7 +648,7 @@ std::vector<int> GLVolumeCollection::load_object(
const ModelVolume *model_volume = model_object->volumes[volume_idx];
int extruder_id = -1;
if (!model_volume->modifier)
if (model_volume->is_model_part())
{
extruder_id = model_volume->config.has("extruder") ? model_volume->config.option("extruder")->getInt() : 0;
if (extruder_id == 0)
@ -661,7 +661,16 @@ std::vector<int> GLVolumeCollection::load_object(
volumes_idx.push_back(int(this->volumes.size()));
float color[4];
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
color[3] = model_volume->modifier ? 0.5f : 1.f;
if (model_volume->is_support_blocker()) {
color[0] = 1.0f;
color[1] = 0.2f;
color[2] = 0.2f;
} else if (model_volume->is_support_enforcer()) {
color[0] = 0.2f;
color[1] = 0.2f;
color[2] = 1.0f;
}
color[3] = model_volume->is_model_part() ? 1.f : 0.5f;
this->volumes.emplace_back(new GLVolume(color));
GLVolume &v = *this->volumes.back();
if (use_VBOs)
@ -675,15 +684,15 @@ std::vector<int> GLVolumeCollection::load_object(
v.composite_id = obj_idx * 1000000 + volume_idx * 1000 + instance_idx;
v.set_select_group_id(select_by);
v.set_drag_group_id(drag_by);
if (!model_volume->modifier)
if (model_volume->is_model_part())
{
v.set_convex_hull(model_volume->get_convex_hull());
v.layer_height_texture = layer_height_texture;
if (extruder_id != -1)
v.extruder_id = extruder_id;
}
v.is_modifier = model_volume->modifier;
v.shader_outside_printer_detection_enabled = !model_volume->modifier;
v.is_modifier = ! model_volume->is_model_part();
v.shader_outside_printer_detection_enabled = model_volume->is_model_part();
#if ENABLE_MODELINSTANCE_3D_OFFSET
v.set_offset(instance->get_offset());
#else

View file

@ -60,6 +60,14 @@ void AppConfig::set_defaults()
if (get("remember_output_path").empty())
set("remember_output_path", "1");
// Remove legacy window positions/sizes
erase("", "main_frame_maximized");
erase("", "main_frame_pos");
erase("", "main_frame_size");
erase("", "object_settings_maximized");
erase("", "object_settings_pos");
erase("", "object_settings_size");
}
void AppConfig::load()

View file

@ -72,6 +72,14 @@ public:
bool has(const std::string &key) const
{ return this->has("", key); }
void erase(const std::string &section, const std::string &key)
{
auto it = m_storage.find(section);
if (it != m_storage.end()) {
it->second.erase(key);
}
}
void clear_section(const std::string &section)
{ m_storage[section].clear(); }

View file

@ -409,11 +409,10 @@ PageFirmware::PageFirmware(ConfigWizard *parent) :
void PageFirmware::apply_custom_config(DynamicPrintConfig &config)
{
ConfigOptionEnum<GCodeFlavor> opt;
auto sel = gcode_picker->GetSelection();
if (sel != wxNOT_FOUND && opt.deserialize(gcode_picker->GetString(sel).ToStdString())) {
config.set_key_value("gcode_flavor", &opt);
if (sel >= 0 && sel < gcode_opt.enum_labels.size()) {
auto *opt = new ConfigOptionEnum<GCodeFlavor>(static_cast<GCodeFlavor>(sel));
config.set_key_value("gcode_flavor", opt);
}
}
@ -871,10 +870,11 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) :
// If the screen is smaller, resize wizrad to match, which will enable scrollbars.
auto wizard_size = GetSize();
unsigned width, height;
GUI::get_current_screen_size(width, height);
wizard_size.SetWidth(std::min(wizard_size.GetWidth(), (int)(width - 2 * DIALOG_MARGIN)));
wizard_size.SetHeight(std::min(wizard_size.GetHeight(), (int)(height - 2 * DIALOG_MARGIN)));
SetMinSize(wizard_size);
if (GUI::get_current_screen_size(this, width, height)) {
wizard_size.SetWidth(std::min(wizard_size.GetWidth(), (int)(width - 2 * DIALOG_MARGIN)));
wizard_size.SetHeight(std::min(wizard_size.GetHeight(), (int)(height - 2 * DIALOG_MARGIN)));
SetMinSize(wizard_size);
}
Fit();
p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); });

View file

@ -367,7 +367,7 @@ void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries)
auto ports = Utils::scan_serial_ports_extended();
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
return port.id_vendor != USB_VID_PRUSA && port.id_product != USB_PID_MMU_BOOT;
return port.id_vendor != USB_VID_PRUSA || port.id_product != USB_PID_MMU_BOOT;
}), ports.end());
if (ports.size() == 1) {
@ -390,23 +390,22 @@ void FirmwareDialog::priv::mmu_reboot(const SerialPortInfo &port)
void FirmwareDialog::priv::lookup_port_mmu()
{
static const auto msg_not_found =
"The Multi Material Control device was not found.\n"
"If the device is connected, please press the Reset button next to the USB connector ...";
BOOST_LOG_TRIVIAL(info) << "Flashing MMU 2.0, looking for VID/PID 0x2c99/3 or 0x2c99/4 ...";
auto ports = Utils::scan_serial_ports_extended();
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
return port.id_vendor != USB_VID_PRUSA &&
return port.id_vendor != USB_VID_PRUSA ||
port.id_product != USB_PID_MMU_BOOT &&
port.id_product != USB_PID_MMU_APP;
}), ports.end());
if (ports.size() == 0) {
BOOST_LOG_TRIVIAL(info) << "MMU 2.0 device not found, asking the user to press Reset and waiting for the device to show up ...";
queue_status(_(L(
"The Multi Material Control device was not found.\n"
"If the device is connected, please press the Reset button next to the USB connector ..."
)));
queue_status(_(L(msg_not_found)));
wait_for_mmu_bootloader(30);
} else if (ports.size() > 1) {
BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found";
@ -417,6 +416,13 @@ void FirmwareDialog::priv::lookup_port_mmu()
BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/4 at `%1%`, rebooting the device ...") % ports[0].port;
mmu_reboot(ports[0]);
wait_for_mmu_bootloader(10);
if (! port) {
// The device in bootloader mode was not found, inform the user and wait some more...
BOOST_LOG_TRIVIAL(info) << "MMU 2.0 bootloader device not found after reboot, asking the user to press Reset and waiting for the device to show up ...";
queue_status(_(L(msg_not_found)));
wait_for_mmu_bootloader(30);
}
} else {
port = ports[0];
}
@ -702,7 +708,8 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) :
panel->SetSizer(vsizer);
auto *label_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:")));
p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY);
p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY, wxEmptyString, wxFileSelectorPromptStr,
"Hex files (*.hex)|*.hex|All files|*.*");
auto *label_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:")));
p->port_picker = new wxComboBox(panel, wxID_ANY);

View file

@ -7,6 +7,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#if __APPLE__
#import <IOKit/pwr_mgt/IOPMLib.h>
@ -1226,12 +1227,63 @@ int get_export_option(wxFileDialog* dlg)
}
void get_current_screen_size(unsigned &width, unsigned &height)
bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height)
{
wxDisplay display(wxDisplay::GetFromWindow(g_wxMainFrame));
const auto idx = wxDisplay::GetFromWindow(window);
if (idx == wxNOT_FOUND) {
return false;
}
wxDisplay display(idx);
const auto disp_size = display.GetClientArea();
width = disp_size.GetWidth();
height = disp_size.GetHeight();
return true;
}
void save_window_size(wxTopLevelWindow *window, const std::string &name)
{
const wxSize size = window->GetSize();
const wxPoint pos = window->GetPosition();
const auto maximized = window->IsMaximized() ? "1" : "0";
g_AppConfig->set((boost::format("window_%1%_size") % name).str(), (boost::format("%1%;%2%") % size.GetWidth() % size.GetHeight()).str());
g_AppConfig->set((boost::format("window_%1%_maximized") % name).str(), maximized);
}
void restore_window_size(wxTopLevelWindow *window, const std::string &name)
{
// XXX: This still doesn't behave nicely in some situations (mostly on Linux).
// The problem is that it's hard to obtain window position with respect to screen geometry reliably
// from wxWidgets. Sometimes wxWidgets claim a window is located on a different screen than on which
// it's actually visible. I suspect this has something to do with window initialization (maybe we
// restore window geometry too early), but haven't yet found a workaround.
const auto display_idx = wxDisplay::GetFromWindow(window);
if (display_idx == wxNOT_FOUND) { return; }
const auto display = wxDisplay(display_idx).GetClientArea();
std::vector<std::string> pair;
try {
const auto key_size = (boost::format("window_%1%_size") % name).str();
if (g_AppConfig->has(key_size)) {
if (unescape_strings_cstyle(g_AppConfig->get(key_size), pair) && pair.size() == 2) {
auto width = boost::lexical_cast<int>(pair[0]);
auto height = boost::lexical_cast<int>(pair[1]);
window->SetSize(width, height);
}
}
} catch(const boost::bad_lexical_cast &) {}
// Maximizing should be the last thing to do.
// This ensure the size and position are sane when the user un-maximizes the window.
const auto key_maximized = (boost::format("window_%1%_maximized") % name).str();
if (g_AppConfig->get(key_maximized) == "1") {
window->Maximize(true);
}
}
void enable_action_buttons(bool enable)

View file

@ -26,6 +26,7 @@ class wxButton;
class wxFileDialog;
class wxStaticBitmap;
class wxFont;
class wxTopLevelWindow;
namespace Slic3r {
@ -223,7 +224,12 @@ void add_export_option(wxFileDialog* dlg, const std::string& format);
int get_export_option(wxFileDialog* dlg);
// Returns the dimensions of the screen on which the main frame is displayed
void get_current_screen_size(unsigned &width, unsigned &height);
bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height);
// Save window size and maximized status into AppConfig
void save_window_size(wxTopLevelWindow *window, const std::string &name);
// Restore the above
void restore_window_size(wxTopLevelWindow *window, const std::string &name);
// Update buttons view according to enable/disable
void enable_action_buttons(bool enable);

View file

@ -1225,7 +1225,7 @@ void load_part( ModelObject* model_object,
for ( auto object : model.objects) {
for (auto volume : object->volumes) {
auto new_volume = model_object->add_volume(*volume);
new_volume->modifier = is_modifier;
new_volume->set_type(is_modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART);
boost::filesystem::path(input_file).filename().string();
new_volume->name = boost::filesystem::path(input_file).filename().string();
@ -1283,7 +1283,8 @@ void load_lambda( ModelObject* model_object,
mesh.repair();
auto new_volume = model_object->add_volume(mesh);
new_volume->modifier = is_modifier;
new_volume->set_type(is_modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART);
new_volume->name = name;
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
@ -1320,7 +1321,8 @@ void load_lambda(const std::string& type_name)
mesh.repair();
auto new_volume = (*m_objects)[m_selected_object_id]->add_volume(mesh);
new_volume->modifier = true;
new_volume->set_type(ModelVolume::PARAMETER_MODIFIER);
new_volume->name = name;
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
@ -1385,9 +1387,9 @@ bool remove_subobject_from_object(const int volume_id)
// if user is deleting the last solid part, throw error
int solid_cnt = 0;
for (auto vol : (*m_objects)[m_selected_object_id]->volumes)
if (!vol->modifier)
if (vol->is_model_part())
++solid_cnt;
if (!volume->modifier && solid_cnt == 1) {
if (volume->is_model_part() && solid_cnt == 1) {
Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from this object.")));
return false;
}
@ -1477,7 +1479,7 @@ void on_btn_split(const bool split_part)
for (auto id = 0; id < model_object->volumes.size(); id++)
m_objects_model->AddChild(parent, model_object->volumes[id]->name,
model_object->volumes[id]->modifier ? m_icon_modifiermesh : m_icon_solidmesh,
model_object->volumes[id]->is_modifier() ? m_icon_modifiermesh : m_icon_solidmesh,
model_object->volumes[id]->config.has("extruder") ?
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
false);

View file

@ -295,7 +295,7 @@ const std::vector<std::string>& Preset::print_options()
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
"bridge_speed", "gap_fill_speed", "travel_speed", "first_layer_speed", "perimeter_acceleration", "infill_acceleration",
"bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height",
"min_skirt_length", "brim_width", "support_material", "support_material_threshold", "support_material_enforce_layers",
"min_skirt_length", "brim_width", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
"raft_layers", "support_material_pattern", "support_material_with_sheath", "support_material_spacing",
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers",
"support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance",

View file

@ -880,6 +880,7 @@ void TabPrint::build()
page = add_options_page(_(L("Support material")), "building.png");
optgroup = page->new_optgroup(_(L("Support material")));
optgroup->append_single_option_line("support_material");
optgroup->append_single_option_line("support_material_auto");
optgroup->append_single_option_line("support_material_threshold");
optgroup->append_single_option_line("support_material_enforce_layers");
@ -1219,13 +1220,15 @@ void TabPrint::update()
bool have_raft = m_config->opt_int("raft_layers") > 0;
bool have_support_material = m_config->opt_bool("support_material") || have_raft;
bool have_support_material_auto = have_support_material && m_config->opt_bool("support_material_auto");
bool have_support_interface = m_config->opt_int("support_material_interface_layers") > 0;
bool have_support_soluble = have_support_material && m_config->opt_float("support_material_contact_distance") == 0;
for (auto el : {"support_material_threshold", "support_material_pattern", "support_material_with_sheath",
for (auto el : {"support_material_pattern", "support_material_with_sheath",
"support_material_spacing", "support_material_angle", "support_material_interface_layers",
"dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance",
"support_material_xy_spacing" })
get_field(el)->toggle(have_support_material);
get_field("support_material_threshold")->toggle(have_support_material_auto);
for (auto el : {"support_material_interface_spacing", "support_material_interface_extruder",
"support_material_interface_speed", "support_material_interface_contact_loops" })

View file

@ -3,7 +3,6 @@
#include <string>
#include <functional>
#include "Strings.hpp"
namespace Slic3r {
@ -43,13 +42,13 @@ public:
}
/// Message shown on the next status update.
virtual void message(const string&) = 0;
virtual void message(const std::string&) = 0;
/// Title of the operation.
virtual void title(const string&) = 0;
virtual void title(const std::string&) = 0;
/// Formatted message for the next status update. Works just like sprintf.
virtual void message_fmt(const string& fmt, ...);
virtual void message_fmt(const std::string& fmt, ...);
/// Set up a cancel callback for the operation if feasible.
virtual void on_cancel(CancelFn func = CancelFn()) { cancelfunc_ = func; }
@ -61,7 +60,7 @@ public:
virtual void cancel() { cancelfunc_(); }
/// Convenience function to call message and status update in one function.
void update(float st, const string& msg) {
void update(float st, const std::string& msg) {
message(msg); state(st);
}
};

View file

@ -1,10 +0,0 @@
#ifndef STRINGS_HPP
#define STRINGS_HPP
#include "GUI/GUI.hpp"
namespace Slic3r {
using string = wxString;
}
#endif // STRINGS_HPP

View file

@ -231,7 +231,12 @@ std::vector<SerialPortInfo> scan_serial_ports_extended()
spi.port = path;
#ifdef __linux__
auto friendly_name = sysfs_tty_prop(name, "product");
spi.friendly_name = friendly_name ? (boost::format("%1% (%2%)") % *friendly_name % path).str() : path;
if (friendly_name) {
spi.is_printer = looks_like_printer(*friendly_name);
spi.friendly_name = (boost::format("%1% (%2%)") % *friendly_name % path).str();
} else {
spi.friendly_name = path;
}
auto vid = sysfs_tty_prop_hex(name, "idVendor");
auto pid = sysfs_tty_prop_hex(name, "idProduct");
if (vid && pid) {