mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 05:36:03 +08:00
SPE-2491: Allow using supports with different nozzle diameters.
Printing supports with different nozzle diameters is experimental, so the user is notified that it requires caution. When automatic calculation of extrusion width is used, then the extrusion width of supports is calculated from the nozzle diameter of the smallest extruder.
This commit is contained in:
parent
a718a7606a
commit
091bf7d8e3
@ -230,37 +230,64 @@ double Flow::mm3_per_mm() const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float min_nozzle_diameter(const PrintObject &print_object)
|
||||||
|
{
|
||||||
|
const ConfigOptionFloats &nozzle_diameters = print_object.print()->config().nozzle_diameter;
|
||||||
|
float min_nozzle_diameter = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
|
for (const double nozzle_diameter : nozzle_diameters.values) {
|
||||||
|
min_nozzle_diameter = std::min(min_nozzle_diameter, static_cast<float>(nozzle_diameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
return min_nozzle_diameter;
|
||||||
|
}
|
||||||
|
|
||||||
Flow support_material_flow(const PrintObject *object, float layer_height)
|
Flow support_material_flow(const PrintObject *object, float layer_height)
|
||||||
{
|
{
|
||||||
|
const PrintConfig &print_config = object->print()->config();
|
||||||
|
const int extruder = object->config().support_material_extruder - 1;
|
||||||
|
|
||||||
|
// If object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter.
|
||||||
|
const float nozzle_diameter = extruder >= 0 ? static_cast<float>(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object);
|
||||||
|
|
||||||
return Flow::new_from_config_width(
|
return Flow::new_from_config_width(
|
||||||
frSupportMaterial,
|
frSupportMaterial,
|
||||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||||
(object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
|
(object->config().support_material_extrusion_width.value > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
|
||||||
// if object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
|
nozzle_diameter,
|
||||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
|
|
||||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
|
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
|
||||||
{
|
{
|
||||||
const PrintConfig &print_config = object->print()->config();
|
const PrintConfig &print_config = object->print()->config();
|
||||||
const auto &width = (print_config.first_layer_extrusion_width.value > 0) ? print_config.first_layer_extrusion_width : object->config().support_material_extrusion_width;
|
const int extruder = object->config().support_material_extruder - 1;
|
||||||
|
|
||||||
|
// If object->config().support_material_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter.
|
||||||
|
const float nozzle_diameter = extruder >= 0 ? static_cast<float>(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object);
|
||||||
|
const auto &width = (print_config.first_layer_extrusion_width.value > 0) ? print_config.first_layer_extrusion_width : object->config().support_material_extrusion_width;
|
||||||
|
|
||||||
return Flow::new_from_config_width(
|
return Flow::new_from_config_width(
|
||||||
frSupportMaterial,
|
frSupportMaterial,
|
||||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||||
(width.value > 0) ? width : object->config().extrusion_width,
|
(width.value > 0) ? width : object->config().extrusion_width,
|
||||||
float(print_config.nozzle_diameter.get_at(object->config().support_material_extruder-1)),
|
nozzle_diameter,
|
||||||
(layer_height > 0.f) ? layer_height : float(print_config.first_layer_height.get_abs_value(object->config().layer_height.value)));
|
(layer_height > 0.f) ? layer_height : float(print_config.first_layer_height.get_abs_value(object->config().layer_height.value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Flow support_material_interface_flow(const PrintObject *object, float layer_height)
|
Flow support_material_interface_flow(const PrintObject *object, float layer_height)
|
||||||
{
|
{
|
||||||
|
const PrintConfig &print_config = object->print()->config();
|
||||||
|
const int extruder = object->config().support_material_interface_extruder - 1;
|
||||||
|
|
||||||
|
// If object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), use the smallest nozzle diameter.
|
||||||
|
const float nozzle_diameter = extruder >= 0 ? static_cast<float>(print_config.nozzle_diameter.get_at(extruder)) : min_nozzle_diameter(*object);
|
||||||
|
|
||||||
return Flow::new_from_config_width(
|
return Flow::new_from_config_width(
|
||||||
frSupportMaterialInterface,
|
frSupportMaterialInterface,
|
||||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||||
(object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
|
(object->config().support_material_extrusion_width > 0) ? object->config().support_material_extrusion_width : object->config().extrusion_width,
|
||||||
// if object->config().support_material_interface_extruder == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
|
nozzle_diameter,
|
||||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_interface_extruder-1)),
|
|
||||||
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,13 +744,11 @@ std::string Print::validate(std::vector<std::string>* warnings) const
|
|||||||
};
|
};
|
||||||
for (PrintObject *object : m_objects) {
|
for (PrintObject *object : m_objects) {
|
||||||
if (object->has_support_material()) {
|
if (object->has_support_material()) {
|
||||||
if ((object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) {
|
if (warnings != nullptr && (object->config().support_material_extruder == 0 || object->config().support_material_interface_extruder == 0) && max_nozzle_diameter - min_nozzle_diameter > EPSILON) {
|
||||||
// The object has some form of support and either support_material_extruder or support_material_interface_extruder
|
// The object has some form of support and either support_material_extruder or support_material_interface_extruder
|
||||||
// will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles
|
// will be printed with the current tool without a forced tool change.
|
||||||
// are of the same diameter.
|
// Notify the user that printing supports with different nozzle diameters is experimental and requires caution.
|
||||||
return _u8L("Printing with multiple extruders of differing nozzle diameters. "
|
warnings->emplace_back("_SUPPORT_NOZZLE_DIAMETER_DIFFER");
|
||||||
"If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), "
|
|
||||||
"all nozzles have to be of the same diameter.");
|
|
||||||
}
|
}
|
||||||
if (this->has_wipe_tower() && object->config().support_material_style != smsOrganic) {
|
if (this->has_wipe_tower() && object->config().support_material_style != smsOrganic) {
|
||||||
if (object->config().support_material_contact_distance == 0) {
|
if (object->config().support_material_contact_distance == 0) {
|
||||||
|
@ -133,7 +133,7 @@ void NotificationManager::NotificationIDProvider::release_id(int) {}
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//------PopNotification--------
|
//------PopNotification--------
|
||||||
NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler) :
|
NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler, const bool multiline) :
|
||||||
m_data (n)
|
m_data (n)
|
||||||
, m_id_provider (id_provider)
|
, m_id_provider (id_provider)
|
||||||
, m_text1 (n.text1)
|
, m_text1 (n.text1)
|
||||||
@ -141,6 +141,7 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n,
|
|||||||
, m_text2 (n.text2)
|
, m_text2 (n.text2)
|
||||||
, m_evt_handler (evt_handler)
|
, m_evt_handler (evt_handler)
|
||||||
, m_notification_start (GLCanvas3D::timestamp_now())
|
, m_notification_start (GLCanvas3D::timestamp_now())
|
||||||
|
, m_multiline (multiline)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width)
|
void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width)
|
||||||
@ -2157,10 +2158,11 @@ void NotificationManager::push_notification(NotificationType type,
|
|||||||
const std::string& hypertext,
|
const std::string& hypertext,
|
||||||
std::function<bool(wxEvtHandler*)> callback,
|
std::function<bool(wxEvtHandler*)> callback,
|
||||||
const std::string& text_after,
|
const std::string& text_after,
|
||||||
int timestamp)
|
const int timestamp,
|
||||||
|
const bool multiline)
|
||||||
{
|
{
|
||||||
int duration = get_standard_duration(level);
|
int duration = get_standard_duration(level);
|
||||||
push_notification_data({ type, level, duration, text, hypertext, callback, text_after }, timestamp);
|
push_notification_data({ type, level, duration, text, hypertext, callback, text_after }, timestamp, multiline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationManager::push_delayed_notification(const NotificationType type, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval)
|
void NotificationManager::push_delayed_notification(const NotificationType type, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval)
|
||||||
@ -2839,9 +2841,9 @@ void NotificationManager::push_updated_item_info_notification(InfoItemType type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp)
|
bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp, const bool multiline)
|
||||||
{
|
{
|
||||||
return push_notification_data(std::make_unique<PopNotification>(notification_data, m_id_provider, m_evt_handler), timestamp);
|
return push_notification_data(std::make_unique<PopNotification>(notification_data, m_id_provider, m_evt_handler, multiline), timestamp);
|
||||||
}
|
}
|
||||||
bool NotificationManager::push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp)
|
bool NotificationManager::push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp)
|
||||||
{
|
{
|
||||||
|
@ -142,6 +142,8 @@ enum class NotificationType
|
|||||||
ShrinkageCompensationsDiffer,
|
ShrinkageCompensationsDiffer,
|
||||||
// Notification about using wipe tower with different nozzle diameters.
|
// Notification about using wipe tower with different nozzle diameters.
|
||||||
WipeTowerNozzleDiameterDiffer,
|
WipeTowerNozzleDiameterDiffer,
|
||||||
|
// Notification about using supports with different nozzle diameters.
|
||||||
|
SupportNozzleDiameterDiffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
class NotificationManager
|
class NotificationManager
|
||||||
@ -181,7 +183,7 @@ public:
|
|||||||
// Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotificationLevel.
|
// Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotificationLevel.
|
||||||
// ErrorNotificationLevel are never faded out.
|
// ErrorNotificationLevel are never faded out.
|
||||||
void push_notification(NotificationType type, NotificationLevel level, const std::string& text, const std::string& hypertext = "",
|
void push_notification(NotificationType type, NotificationLevel level, const std::string& text, const std::string& hypertext = "",
|
||||||
std::function<bool(wxEvtHandler*)> callback = std::function<bool(wxEvtHandler*)>(), const std::string& text_after = "", int timestamp = 0);
|
std::function<bool(wxEvtHandler*)> callback = std::function<bool(wxEvtHandler*)>(), const std::string& text_after = "", int timestamp = 0, bool multiline = false);
|
||||||
// Pushes basic_notification with delay. See push_delayed_notification_data.
|
// Pushes basic_notification with delay. See push_delayed_notification_data.
|
||||||
void push_delayed_notification(const NotificationType type, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval);
|
void push_delayed_notification(const NotificationType type, std::function<bool(void)> condition_callback, int64_t initial_delay, int64_t delay_interval);
|
||||||
// Removes all notifications of type from m_waiting_notifications
|
// Removes all notifications of type from m_waiting_notifications
|
||||||
@ -344,7 +346,7 @@ private:
|
|||||||
Paused
|
Paused
|
||||||
};
|
};
|
||||||
|
|
||||||
PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler);
|
PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler, bool multiline = false);
|
||||||
virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); }
|
virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); }
|
||||||
virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width);
|
virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width);
|
||||||
// close will dissapear notification on next render
|
// close will dissapear notification on next render
|
||||||
@ -855,7 +857,7 @@ private:
|
|||||||
|
|
||||||
//pushes notification into the queue of notifications that are rendered
|
//pushes notification into the queue of notifications that are rendered
|
||||||
//can be used to create custom notification
|
//can be used to create custom notification
|
||||||
bool push_notification_data(const NotificationData& notification_data, int timestamp);
|
bool push_notification_data(const NotificationData& notification_data, int timestamp, bool multiline = false);
|
||||||
bool push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp);
|
bool push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp);
|
||||||
// Delayed notifications goes first to the m_waiting_notifications vector and only after remaining time is <= 0
|
// Delayed notifications goes first to the m_waiting_notifications vector and only after remaining time is <= 0
|
||||||
// and condition callback is success, notification is regular pushed from update function.
|
// and condition callback is success, notification is regular pushed from update function.
|
||||||
|
@ -2098,13 +2098,16 @@ void Plater::priv::process_validation_warning(const std::vector<std::string>& wa
|
|||||||
if (warnings.empty())
|
if (warnings.empty())
|
||||||
notification_manager->close_notification_of_type(NotificationType::ValidateWarning);
|
notification_manager->close_notification_of_type(NotificationType::ValidateWarning);
|
||||||
|
|
||||||
// Always close warnings BedTemperaturesDiffer, ShrinkageCompensationsDiffer and WipeTowerNozzleDiameterDiffer before next processing.
|
// Always close warnings BedTemperaturesDiffer, ShrinkageCompensationsDiffer, WipeTowerNozzleDiameterDiffer and SupportNozzleDiameterDiffer before next processing.
|
||||||
notification_manager->close_notification_of_type(NotificationType::BedTemperaturesDiffer);
|
notification_manager->close_notification_of_type(NotificationType::BedTemperaturesDiffer);
|
||||||
notification_manager->close_notification_of_type(NotificationType::ShrinkageCompensationsDiffer);
|
notification_manager->close_notification_of_type(NotificationType::ShrinkageCompensationsDiffer);
|
||||||
notification_manager->close_notification_of_type(NotificationType::WipeTowerNozzleDiameterDiffer);
|
notification_manager->close_notification_of_type(NotificationType::WipeTowerNozzleDiameterDiffer);
|
||||||
|
notification_manager->close_notification_of_type(NotificationType::SupportNozzleDiameterDiffer);
|
||||||
|
|
||||||
for (std::string text : warnings) {
|
for (std::string text : warnings) {
|
||||||
std::string hypertext = "";
|
std::string hypertext = "";
|
||||||
|
std::string text_after = "";
|
||||||
|
bool multiline = false;
|
||||||
NotificationType notification_type = NotificationType::ValidateWarning;
|
NotificationType notification_type = NotificationType::ValidateWarning;
|
||||||
std::function<bool(wxEvtHandler*)> action_fn = [](wxEvtHandler*){ return false; };
|
std::function<bool(wxEvtHandler*)> action_fn = [](wxEvtHandler*){ return false; };
|
||||||
|
|
||||||
@ -2133,12 +2136,22 @@ void Plater::priv::process_validation_warning(const std::vector<std::string>& wa
|
|||||||
text = _u8L("Using the wipe tower for extruders with different nozzle diameters "
|
text = _u8L("Using the wipe tower for extruders with different nozzle diameters "
|
||||||
"is experimental, so proceed with caution.");
|
"is experimental, so proceed with caution.");
|
||||||
notification_type = NotificationType::WipeTowerNozzleDiameterDiffer;
|
notification_type = NotificationType::WipeTowerNozzleDiameterDiffer;
|
||||||
|
} else if (text == "_SUPPORT_NOZZLE_DIAMETER_DIFFER") {
|
||||||
|
text = _u8L("Printing supports with different nozzle diameters "
|
||||||
|
"is experimental. For best results, switch to Organic supports and");
|
||||||
|
hypertext = _u8L("assign a specific extruder for supports.");
|
||||||
|
multiline = true;
|
||||||
|
notification_type = NotificationType::SupportNozzleDiameterDiffer;
|
||||||
|
action_fn = [](wxEvtHandler*) {
|
||||||
|
GUI::wxGetApp().jump_to_option("support_material_extruder", Preset::Type::TYPE_PRINT, boost::nowide::widen("Multiple Extruders"));
|
||||||
|
return false;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
notification_manager->push_notification(
|
notification_manager->push_notification(
|
||||||
notification_type,
|
notification_type,
|
||||||
NotificationManager::NotificationLevel::WarningNotificationLevel,
|
NotificationManager::NotificationLevel::WarningNotificationLevel,
|
||||||
_u8L("WARNING:") + "\n" + text, hypertext, action_fn
|
_u8L("WARNING:") + "\n" + text, hypertext, action_fn, text_after, 0, multiline
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user