mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-29 17:44:36 +08:00
Merge branch 'lm_230beta3_fixes'
This commit is contained in:
commit
4d459f37de
@ -413,14 +413,11 @@ namespace Slic3r {
|
|||||||
|
|
||||||
std::string WipeTowerIntegration::prime(GCode& gcodegen)
|
std::string WipeTowerIntegration::prime(GCode& gcodegen)
|
||||||
{
|
{
|
||||||
assert(m_layer_idx == 0);
|
|
||||||
std::string gcode;
|
std::string gcode;
|
||||||
|
|
||||||
for (const WipeTower::ToolChangeResult& tcr : m_priming) {
|
for (const WipeTower::ToolChangeResult& tcr : m_priming) {
|
||||||
if (! tcr.extrusions.empty())
|
if (! tcr.extrusions.empty())
|
||||||
gcode += append_tcr(gcodegen, tcr, tcr.new_tool);
|
gcode += append_tcr(gcodegen, tcr, tcr.new_tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1243,18 +1240,30 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz));
|
bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz));
|
||||||
BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print));
|
BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print));
|
||||||
bbox_prime.offset(0.5f);
|
bbox_prime.offset(0.5f);
|
||||||
// Beep for 500ms, tone 800Hz. Yet better, play some Morse.
|
bool overlap = bbox_prime.overlap(bbox_print);
|
||||||
_write(file, this->retract());
|
|
||||||
_write(file, "M300 S800 P500\n");
|
if (print.config().gcode_flavor == gcfMarlin) {
|
||||||
if (bbox_prime.overlap(bbox_print)) {
|
_write(file, this->retract());
|
||||||
// Wait for the user to remove the priming extrusions, otherwise they would
|
_write(file, "M300 S800 P500\n"); // Beep for 500ms, tone 800Hz.
|
||||||
// get covered by the print.
|
if (overlap) {
|
||||||
_write(file, "M1 Remove priming towers and click button.\n");
|
// Wait for the user to remove the priming extrusions.
|
||||||
}
|
_write(file, "M1 Remove priming towers and click button.\n");
|
||||||
else {
|
} else {
|
||||||
// Just wait for a bit to let the user check, that the priming succeeded.
|
// Just wait for a bit to let the user check, that the priming succeeded.
|
||||||
//TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
|
//TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
|
||||||
_write(file, "M1 S10\n");
|
_write(file, "M1 S10\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is not Marlin, M1 command is probably not supported.
|
||||||
|
// (See https://github.com/prusa3d/PrusaSlicer/issues/5441.)
|
||||||
|
if (overlap) {
|
||||||
|
print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
|
||||||
|
L("Your print is very close to the priming regions. "
|
||||||
|
"Make sure there is no collision."));
|
||||||
|
} else {
|
||||||
|
// Just continue printing, no action necessary.
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
|
@ -1042,8 +1042,6 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial
|
|||||||
int vol_idx = 0;
|
int vol_idx = 0;
|
||||||
for (ModelVolume* volume : volumes)
|
for (ModelVolume* volume : volumes)
|
||||||
{
|
{
|
||||||
volume->supported_facets.clear();
|
|
||||||
volume->seam_facets.clear();
|
|
||||||
if (!volume->mesh().empty()) {
|
if (!volume->mesh().empty()) {
|
||||||
TriangleMesh mesh(volume->mesh());
|
TriangleMesh mesh(volume->mesh());
|
||||||
mesh.require_shared_vertices();
|
mesh.require_shared_vertices();
|
||||||
@ -1060,6 +1058,9 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial
|
|||||||
vol->source.object_idx = (int)new_objects.size();
|
vol->source.object_idx = (int)new_objects.size();
|
||||||
vol->source.volume_idx = vol_idx;
|
vol->source.volume_idx = vol_idx;
|
||||||
|
|
||||||
|
vol->supported_facets.assign(volume->supported_facets);
|
||||||
|
vol->seam_facets.assign(volume->seam_facets);
|
||||||
|
|
||||||
// Perform conversion only if the target "imperial" state is different from the current one.
|
// Perform conversion only if the target "imperial" state is different from the current one.
|
||||||
// This check supports conversion of "mixed" set of volumes, each with different "imperial" state.
|
// This check supports conversion of "mixed" set of volumes, each with different "imperial" state.
|
||||||
if (//vol->source.is_converted_from_inches != from_imperial &&
|
if (//vol->source.is_converted_from_inches != from_imperial &&
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <regex>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
@ -1272,7 +1273,7 @@ bool GUI_App::switch_language()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux
|
#ifdef __linux__
|
||||||
static const wxLanguageInfo* linux_get_existing_locale_language(const wxLanguageInfo* language,
|
static const wxLanguageInfo* linux_get_existing_locale_language(const wxLanguageInfo* language,
|
||||||
const wxLanguageInfo* system_language)
|
const wxLanguageInfo* system_language)
|
||||||
{
|
{
|
||||||
@ -1281,6 +1282,9 @@ static const wxLanguageInfo* linux_get_existing_locale_language(const wxLanguage
|
|||||||
std::vector<std::string> locales;
|
std::vector<std::string> locales;
|
||||||
const std::string lang_prefix = into_u8(language->CanonicalName.BeforeFirst('_'));
|
const std::string lang_prefix = into_u8(language->CanonicalName.BeforeFirst('_'));
|
||||||
|
|
||||||
|
// Call locale -a so we can parse the output to get the list of available locales
|
||||||
|
// We expect lines such as "en_US.utf8". Pick ones starting with the language code
|
||||||
|
// we are switching to. Lines with different formatting will be removed later.
|
||||||
FILE* fp = popen("locale -a", "r");
|
FILE* fp = popen("locale -a", "r");
|
||||||
if (fp != NULL) {
|
if (fp != NULL) {
|
||||||
while (fgets(path, max_len, fp) != NULL) {
|
while (fgets(path, max_len, fp) != NULL) {
|
||||||
@ -1293,34 +1297,51 @@ static const wxLanguageInfo* linux_get_existing_locale_language(const wxLanguage
|
|||||||
}
|
}
|
||||||
|
|
||||||
// locales now contain all candidates for this language.
|
// locales now contain all candidates for this language.
|
||||||
// Sort them so ones containing anything about UTF-8 are at the beginning.
|
// Sort them so ones containing anything about UTF-8 are at the end.
|
||||||
std::sort(locales.begin(), locales.end(), [](const std::string& a, const std::string& b)
|
std::sort(locales.begin(), locales.end(), [](const std::string& a, const std::string& b)
|
||||||
{
|
{
|
||||||
auto has_utf8 = [](const std::string & s) {
|
auto has_utf8 = [](const std::string & s) {
|
||||||
return boost::to_upper_copy(s).find("UTF") != std::string::npos
|
auto S = boost::to_upper_copy(s);
|
||||||
&& s.find("8") != std::string::npos;
|
return S.find("UTF8") != std::string::npos || S.find("UTF-8") != std::string::npos;
|
||||||
};
|
};
|
||||||
return (has_utf8(a) && ! has_utf8(b));
|
return ! has_utf8(a) && has_utf8(b);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove the suffix.
|
// Remove the suffix behind a dot, if there is one.
|
||||||
for (std::string& s : locales)
|
for (std::string& s : locales)
|
||||||
s = s.substr(0, s.find("."));
|
s = s.substr(0, s.find("."));
|
||||||
|
|
||||||
// Is there a candidate matching a country code of a system language? Put it at the beginning
|
// We just hope that dear Linux "locale -a" returns country codes
|
||||||
// (duplicates do not matter). Check backwards so the utf8 one ends up first if there are more.
|
// in ISO 3166-1 alpha-2 code (two letter) format.
|
||||||
|
// https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
|
||||||
|
// To be sure, remove anything not looking as expected
|
||||||
|
// (any number of lowercase letters, underscore, two uppercase letters).
|
||||||
|
locales.erase(std::remove_if(locales.begin(),
|
||||||
|
locales.end(),
|
||||||
|
[](const std::string& s) {
|
||||||
|
return ! std::regex_match(s,
|
||||||
|
std::regex("^[a-z]+_[A-Z]{2}$"));
|
||||||
|
}),
|
||||||
|
locales.end());
|
||||||
|
|
||||||
|
// Is there a candidate matching a country code of a system language? Move it to the end,
|
||||||
|
// while maintaining the order of matches, so that the best match ends up at the very end.
|
||||||
std::string system_country = "_" + into_u8(system_language->CanonicalName.AfterFirst('_')).substr(0, 2);
|
std::string system_country = "_" + into_u8(system_language->CanonicalName.AfterFirst('_')).substr(0, 2);
|
||||||
int cnt = locales.size();
|
int cnt = locales.size();
|
||||||
for (int i=0; i<cnt; ++i)
|
for (int i=0; i<cnt; ++i)
|
||||||
if (locales[locales.size()-i-1].find(system_country) != std::string::npos)
|
if (locales[i].find(system_country) != std::string::npos) {
|
||||||
locales.insert(locales.begin(), locales[locales.size()-i-1]);
|
locales.emplace_back(std::move(locales[i]));
|
||||||
|
locales[i].clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Now try them one by one.
|
// Now try them one by one.
|
||||||
for (const std::string& locale : locales) {
|
for (auto it = locales.rbegin(); it != locales.rend(); ++ it)
|
||||||
const wxLanguageInfo* lang = wxLocale::FindLanguageInfo(locale.substr(0, locale.find(".")));
|
if (! it->empty()) {
|
||||||
if (wxLocale::IsAvailable(lang->Language))
|
const std::string &locale = *it;
|
||||||
return lang;
|
const wxLanguageInfo* lang = wxLocale::FindLanguageInfo(from_u8(locale));
|
||||||
}
|
if (wxLocale::IsAvailable(lang->Language))
|
||||||
|
return lang;
|
||||||
|
}
|
||||||
return language;
|
return language;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1011,7 +1011,13 @@ void NotificationManager::push_notification(const std::string& text, int timesta
|
|||||||
{
|
{
|
||||||
push_notification_data({ NotificationType::CustomNotification, NotificationLevel::RegularNotification, 10, text }, timestamp);
|
push_notification_data({ NotificationType::CustomNotification, NotificationLevel::RegularNotification, 10, text }, timestamp);
|
||||||
}
|
}
|
||||||
void NotificationManager::push_notification(const std::string& text, NotificationManager::NotificationLevel level, int timestamp)
|
|
||||||
|
void NotificationManager::push_notification(NotificationType type,
|
||||||
|
NotificationLevel level,
|
||||||
|
const std::string& text,
|
||||||
|
const std::string& hypertext,
|
||||||
|
std::function<bool(wxEvtHandler*)> callback,
|
||||||
|
int timestamp)
|
||||||
{
|
{
|
||||||
int duration = 0;
|
int duration = 0;
|
||||||
switch (level) {
|
switch (level) {
|
||||||
@ -1022,7 +1028,7 @@ void NotificationManager::push_notification(const std::string& text, Notificatio
|
|||||||
assert(false);
|
assert(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
push_notification_data({ NotificationType::CustomNotification, level, duration, text }, timestamp);
|
push_notification_data({ type, level, duration, text, hypertext, callback }, timestamp);
|
||||||
}
|
}
|
||||||
void NotificationManager::push_slicing_error_notification(const std::string& text)
|
void NotificationManager::push_slicing_error_notification(const std::string& text)
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,9 @@ enum class NotificationType
|
|||||||
// Progress bar instead of text.
|
// Progress bar instead of text.
|
||||||
ProgressBar,
|
ProgressBar,
|
||||||
// Notification, when Color Change G-code is empty and user try to add color change on DoubleSlider.
|
// Notification, when Color Change G-code is empty and user try to add color change on DoubleSlider.
|
||||||
EmptyColorChangeCode
|
EmptyColorChangeCode,
|
||||||
|
// Notification that custom supports/seams were deleted after mesh repair.
|
||||||
|
CustomSupportsAndSeamRemovedAfterRepair
|
||||||
};
|
};
|
||||||
|
|
||||||
class NotificationManager
|
class NotificationManager
|
||||||
@ -97,7 +99,8 @@ public:
|
|||||||
void push_notification(const std::string& text, int timestamp = 0);
|
void push_notification(const std::string& text, int timestamp = 0);
|
||||||
// Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotification.
|
// Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotification.
|
||||||
// ErrorNotification and ImportantNotification are never faded out.
|
// ErrorNotification and ImportantNotification are never faded out.
|
||||||
void push_notification(const std::string& text, NotificationLevel level, int timestamp = 0);
|
void push_notification(NotificationType type, NotificationLevel level, const std::string& text, const std::string& hypertext = "",
|
||||||
|
std::function<bool(wxEvtHandler*)> callback = std::function<bool(wxEvtHandler*)>(), int timestamp = 0);
|
||||||
// Creates Slicing Error notification with a custom text and no fade out.
|
// Creates Slicing Error notification with a custom text and no fade out.
|
||||||
void push_slicing_error_notification(const std::string& text);
|
void push_slicing_error_notification(const std::string& text);
|
||||||
// Creates Slicing Warning notification with a custom text and no fade out.
|
// Creates Slicing Warning notification with a custom text and no fade out.
|
||||||
|
@ -2124,11 +2124,15 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||||||
if (evt.data.second) {
|
if (evt.data.second) {
|
||||||
this->show_action_buttons(this->ready_to_slice);
|
this->show_action_buttons(this->ready_to_slice);
|
||||||
notification_manager->close_notification_of_type(NotificationType::ExportFinished);
|
notification_manager->close_notification_of_type(NotificationType::ExportFinished);
|
||||||
notification_manager->push_notification(format(_L("Successfully unmounted. The device %s(%s) can now be safely removed from the computer."), evt.data.first.name, evt.data.first.path),
|
notification_manager->push_notification(NotificationType::CustomNotification,
|
||||||
NotificationManager::NotificationLevel::RegularNotification);
|
NotificationManager::NotificationLevel::RegularNotification,
|
||||||
|
format(_L("Successfully unmounted. The device %s(%s) can now be safely removed from the computer."), evt.data.first.name, evt.data.first.path)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
notification_manager->push_notification(format(_L("Ejecting of device %s(%s) has failed."), evt.data.first.name, evt.data.first.path),
|
notification_manager->push_notification(NotificationType::CustomNotification,
|
||||||
NotificationManager::NotificationLevel::ErrorNotification);
|
NotificationManager::NotificationLevel::ErrorNotification,
|
||||||
|
format(_L("Ejecting of device %s(%s) has failed."), evt.data.first.name, evt.data.first.path)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this, q](RemovableDrivesChangedEvent &) {
|
this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this, q](RemovableDrivesChangedEvent &) {
|
||||||
@ -3361,10 +3365,38 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* =
|
|||||||
if (obj_idx < 0)
|
if (obj_idx < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Plater::TakeSnapshot snapshot(q, _L("Fix Throught NetFabb"));
|
size_t snapshot_time = undo_redo_stack().active_snapshot_time();
|
||||||
|
Plater::TakeSnapshot snapshot(q, _L("Fix through NetFabb"));
|
||||||
|
|
||||||
fix_model_by_win10_sdk_gui(*model.objects[obj_idx], vol_idx);
|
ModelObject* mo = model.objects[obj_idx];
|
||||||
sla::reproject_points_and_holes(model.objects[obj_idx]);
|
|
||||||
|
// If there are custom supports/seams, remove them. Fixed mesh
|
||||||
|
// may be different and they would make no sense.
|
||||||
|
bool paint_removed = false;
|
||||||
|
for (ModelVolume* mv : mo->volumes) {
|
||||||
|
paint_removed |= ! mv->supported_facets.empty() || ! mv->seam_facets.empty();
|
||||||
|
mv->supported_facets.clear();
|
||||||
|
mv->seam_facets.clear();
|
||||||
|
}
|
||||||
|
if (paint_removed) {
|
||||||
|
// snapshot_time is captured by copy so the lambda knows where to undo/redo to.
|
||||||
|
notification_manager->push_notification(
|
||||||
|
NotificationType::CustomSupportsAndSeamRemovedAfterRepair,
|
||||||
|
NotificationManager::NotificationLevel::RegularNotification,
|
||||||
|
_u8L("Custom supports and seams were removed after repairing the mesh."),
|
||||||
|
_u8L("Undo the repair"),
|
||||||
|
[this, snapshot_time](wxEvtHandler*){
|
||||||
|
if (undo_redo_stack().has_undo_snapshot(snapshot_time))
|
||||||
|
undo_redo_to(snapshot_time);
|
||||||
|
else
|
||||||
|
notification_manager->push_notification(
|
||||||
|
_u8L("Cannot undo to before the mesh repair!"));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fix_model_by_win10_sdk_gui(*mo, vol_idx);
|
||||||
|
sla::reproject_points_and_holes(mo);
|
||||||
this->update();
|
this->update();
|
||||||
this->object_list_changed();
|
this->object_list_changed();
|
||||||
this->schedule_background_process();
|
this->schedule_background_process();
|
||||||
|
@ -36,6 +36,15 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace UndoRedo {
|
namespace UndoRedo {
|
||||||
|
|
||||||
|
#ifdef SLIC3R_UNDOREDO_DEBUG
|
||||||
|
static inline std::string ptr_to_string(const void* ptr)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
sprintf(buf, "%p", ptr);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0), layer_range_idx(-1)
|
SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0), layer_range_idx(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -368,15 +377,6 @@ private:
|
|||||||
MutableHistoryInterval& operator=(const MutableHistoryInterval &rhs);
|
MutableHistoryInterval& operator=(const MutableHistoryInterval &rhs);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef SLIC3R_UNDOREDO_DEBUG
|
|
||||||
static inline std::string ptr_to_string(const void* ptr)
|
|
||||||
{
|
|
||||||
char buf[64];
|
|
||||||
sprintf(buf, "%p", ptr);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Smaller objects (Model, ModelObject, ModelInstance, ModelVolume, DynamicPrintConfig)
|
// Smaller objects (Model, ModelObject, ModelInstance, ModelVolume, DynamicPrintConfig)
|
||||||
// are mutable and there is not tracking of the changes, therefore a snapshot needs to be
|
// are mutable and there is not tracking of the changes, therefore a snapshot needs to be
|
||||||
// taken every time and compared to the previous data at the Undo / Redo stack.
|
// taken every time and compared to the previous data at the Undo / Redo stack.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user