mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-29 03:41:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c71ac0870 | ||
|
|
ec0d8c225f | ||
|
|
3040ebaac1 | ||
|
|
d347a80ef8 | ||
|
|
e340a13c18 | ||
|
|
9e16cdb23b | ||
|
|
58842bab05 | ||
|
|
04204ec0d3 | ||
|
|
9ed459e132 |
@@ -1692,9 +1692,9 @@ void Layer::make_ironing()
|
|||||||
ironing_params.just_infill = false;
|
ironing_params.just_infill = false;
|
||||||
// ORCA: Get filament-specific overrides if configured, otherwise use process values
|
// ORCA: Get filament-specific overrides if configured, otherwise use process values
|
||||||
size_t extruder_idx = ironing_params.extruder - 1;
|
size_t extruder_idx = ironing_params.extruder - 1;
|
||||||
ironing_params.line_spacing = (!config.filament_ironing_spacing.is_nil(extruder_idx)
|
ironing_params.line_spacing = std::max(IRONING_SPACING_MIN, !config.filament_ironing_spacing.is_nil(extruder_idx)
|
||||||
? config.filament_ironing_spacing.get_at(extruder_idx)
|
? config.filament_ironing_spacing.get_at(extruder_idx)
|
||||||
: config.ironing_spacing);
|
: config.ironing_spacing.value);
|
||||||
ironing_params.inset = (!config.filament_ironing_inset.is_nil(extruder_idx)
|
ironing_params.inset = (!config.filament_ironing_inset.is_nil(extruder_idx)
|
||||||
? config.filament_ironing_inset.get_at(extruder_idx)
|
? config.filament_ironing_inset.get_at(extruder_idx)
|
||||||
: config.ironing_inset);
|
: config.ironing_inset);
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ void FillConcentric::_fill_surface_single(
|
|||||||
|
|
||||||
coord_t min_spacing = scale_(this->spacing) * params.multiline;
|
coord_t min_spacing = scale_(this->spacing) * params.multiline;
|
||||||
coord_t distance = coord_t(min_spacing / params.density);
|
coord_t distance = coord_t(min_spacing / params.density);
|
||||||
|
// A non-positive step never shrinks the region, so the inset loop below would not end.
|
||||||
|
if (min_spacing <= 0 || distance <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||||
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
|
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
|
||||||
@@ -108,6 +111,8 @@ void FillConcentric::_fill_surface_single(const FillParams& params,
|
|||||||
// no rotation is supported for this infill pattern
|
// no rotation is supported for this infill pattern
|
||||||
Point bbox_size = expolygon.contour.bounding_box().size();
|
Point bbox_size = expolygon.contour.bounding_box().size();
|
||||||
coord_t min_spacing = scaled<coord_t>(this->spacing);
|
coord_t min_spacing = scaled<coord_t>(this->spacing);
|
||||||
|
if (min_spacing <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||||
coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
|
coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
|
||||||
|
|||||||
+10
-5
@@ -2504,7 +2504,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||||||
|
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(print->model().id().id);
|
ctx.id = std::to_string(print->model().id().id);
|
||||||
|
ctx.name = print->get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Ok;
|
ctx.code = LifecycleEvtCode::Ok;
|
||||||
ctx.msg = path;
|
ctx.msg = path;
|
||||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||||
@@ -2556,7 +2557,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(print->model().id().id);
|
ctx.id = std::to_string(print->model().id().id);
|
||||||
|
ctx.name = print->get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Error;
|
ctx.code = LifecycleEvtCode::Error;
|
||||||
ctx.msg = std::string(path) + "\n" + err_msg;
|
ctx.msg = std::string(path) + "\n" + err_msg;
|
||||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||||
@@ -2580,7 +2582,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||||||
boost::nowide::remove(path_tmp.c_str());
|
boost::nowide::remove(path_tmp.c_str());
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(print->model().id().id);
|
ctx.id = std::to_string(print->model().id().id);
|
||||||
|
ctx.name = print->get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Error;
|
ctx.code = LifecycleEvtCode::Error;
|
||||||
ctx.msg = std::string(path) + "\n" + ex.what();
|
ctx.msg = std::string(path) + "\n" + ex.what();
|
||||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||||
@@ -2693,7 +2696,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||||||
if (ret) {
|
if (ret) {
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(print->model().id().id);
|
ctx.id = std::to_string(print->model().id().id);
|
||||||
|
ctx.name = print->get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Error;
|
ctx.code = LifecycleEvtCode::Error;
|
||||||
ctx.msg = std::string(path) + "\nFailed to rename the output G-code file: " + ret.message();
|
ctx.msg = std::string(path) + "\nFailed to rename the output G-code file: " + ret.message();
|
||||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||||
@@ -2712,7 +2716,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||||||
|
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(print->model().id().id);
|
ctx.id = std::to_string(print->model().id().id);
|
||||||
|
ctx.name = print->get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Ok;
|
ctx.code = LifecycleEvtCode::Ok;
|
||||||
ctx.msg = path;
|
ctx.msg = path;
|
||||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||||
|
|||||||
+10
-5
@@ -2717,7 +2717,8 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
|||||||
|
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(m_model.id().id);
|
ctx.id = std::to_string(m_model.id().id);
|
||||||
|
ctx.name = get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Ok;
|
ctx.code = LifecycleEvtCode::Ok;
|
||||||
ctx.cancellation_check = [this]() { return canceled(); };
|
ctx.cancellation_check = [this]() { return canceled(); };
|
||||||
fire_lifecycle_event(LifecycleEvent::SliceStarted, ctx);
|
fire_lifecycle_event(LifecycleEvent::SliceStarted, ctx);
|
||||||
@@ -3344,7 +3345,8 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
|||||||
|
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(m_model.id().id);
|
ctx.id = std::to_string(m_model.id().id);
|
||||||
|
ctx.name = get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Ok;
|
ctx.code = LifecycleEvtCode::Ok;
|
||||||
ctx.cancellation_check = [this]() { return canceled(); };
|
ctx.cancellation_check = [this]() { return canceled(); };
|
||||||
fire_lifecycle_event(LifecycleEvent::SliceGeometryFinished, ctx);
|
fire_lifecycle_event(LifecycleEvent::SliceGeometryFinished, ctx);
|
||||||
@@ -4950,7 +4952,8 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(m_model.id().id);
|
ctx.id = std::to_string(m_model.id().id);
|
||||||
|
ctx.name = get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Ok;
|
ctx.code = LifecycleEvtCode::Ok;
|
||||||
ctx.msg = file;
|
ctx.msg = file;
|
||||||
ctx.cancellation_check = [this]() { return canceled(); };
|
ctx.cancellation_check = [this]() { return canceled(); };
|
||||||
@@ -4980,7 +4983,8 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
|
|||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": found errors when process gcode file %1%") %file.c_str();
|
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": found errors when process gcode file %1%") %file.c_str();
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(m_model.id().id);
|
ctx.id = std::to_string(m_model.id().id);
|
||||||
|
ctx.name = get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Error;
|
ctx.code = LifecycleEvtCode::Error;
|
||||||
ctx.msg = file + "\n" + ex.what();
|
ctx.msg = file + "\n" + ex.what();
|
||||||
ctx.cancellation_check = [this]() { return canceled(); };
|
ctx.cancellation_check = [this]() { return canceled(); };
|
||||||
@@ -4994,7 +4998,8 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
|
|||||||
|
|
||||||
{
|
{
|
||||||
LifecycleEventContext ctx;
|
LifecycleEventContext ctx;
|
||||||
ctx.name = std::to_string(m_model.id().id);
|
ctx.id = std::to_string(m_model.id().id);
|
||||||
|
ctx.name = get_model_name();
|
||||||
ctx.code = LifecycleEvtCode::Ok;
|
ctx.code = LifecycleEvtCode::Ok;
|
||||||
ctx.msg = file;
|
ctx.msg = file;
|
||||||
ctx.cancellation_check = [this]() { return canceled(); };
|
ctx.cancellation_check = [this]() { return canceled(); };
|
||||||
|
|||||||
@@ -178,6 +178,10 @@ enum class IroningType {
|
|||||||
Count,
|
Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Smallest usable ironing line spacing. Anything tighter yields an unprintable number of lines,
|
||||||
|
// and zero stops the fillers from making progress.
|
||||||
|
constexpr double IRONING_SPACING_MIN = 0.05;
|
||||||
|
|
||||||
//BBS
|
//BBS
|
||||||
enum class WallInfillOrder {
|
enum class WallInfillOrder {
|
||||||
InnerOuterInfill,
|
InnerOuterInfill,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ struct SupportParameters {
|
|||||||
|
|
||||||
this->ironing = object_config.support_ironing;
|
this->ironing = object_config.support_ironing;
|
||||||
this->ironing_flow = support_material_interface_flow.with_height(support_material_interface_flow.height() * 0.01 * object_config.support_ironing_flow.value);
|
this->ironing_flow = support_material_interface_flow.with_height(support_material_interface_flow.height() * 0.01 * object_config.support_ironing_flow.value);
|
||||||
this->ironing_spacing = object_config.support_ironing_spacing;
|
this->ironing_spacing = std::max(IRONING_SPACING_MIN, object_config.support_ironing_spacing.value);
|
||||||
this->ironing_pattern = object_config.support_ironing_pattern;
|
this->ironing_pattern = object_config.support_ironing_pattern;
|
||||||
|
|
||||||
// Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
|
// Calculate a minimum support layer height as a minimum over all extruders, but not smaller than 10um.
|
||||||
|
|||||||
@@ -210,6 +210,30 @@ void ConfigManipulation::check_filament_max_volumetric_speed(DynamicPrintConfig
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigManipulation::check_filament_ironing_spacing(DynamicPrintConfig *config)
|
||||||
|
{
|
||||||
|
const auto *opt = config->option<ConfigOptionFloatsNullable>("filament_ironing_spacing");
|
||||||
|
if (opt == nullptr)
|
||||||
|
return;
|
||||||
|
std::vector<double> values = opt->values;
|
||||||
|
bool reset = false;
|
||||||
|
for (size_t i = 0; i < values.size(); ++i)
|
||||||
|
if (!opt->is_nil(i) && values[i] < IRONING_SPACING_MIN) {
|
||||||
|
values[i] = 0.1;
|
||||||
|
reset = true;
|
||||||
|
}
|
||||||
|
if (!reset)
|
||||||
|
return;
|
||||||
|
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||||
|
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||||
|
DynamicPrintConfig new_conf = *config;
|
||||||
|
is_msg_dlg_already_exist = true;
|
||||||
|
dialog.ShowModal();
|
||||||
|
new_conf.set_key_value("filament_ironing_spacing", new ConfigOptionFloatsNullable(values));
|
||||||
|
apply(config, &new_conf);
|
||||||
|
is_msg_dlg_already_exist = false;
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigManipulation::check_chamber_temperature(DynamicPrintConfig* config)
|
void ConfigManipulation::check_chamber_temperature(DynamicPrintConfig* config)
|
||||||
{
|
{
|
||||||
bool support_chamber_temp_control=GUI::wxGetApp().preset_bundle->printers.get_selected_preset().config.opt_bool("support_chamber_temp_control");
|
bool support_chamber_temp_control=GUI::wxGetApp().preset_bundle->printers.get_selected_preset().config.opt_bool("support_chamber_temp_control");
|
||||||
@@ -332,7 +356,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
//BBS: ironing_spacing shouldn't be too small or equal to zero
|
//BBS: ironing_spacing shouldn't be too small or equal to zero
|
||||||
if (config->opt_float("ironing_spacing") < 0.05)
|
if (config->opt_float("ironing_spacing") < IRONING_SPACING_MIN)
|
||||||
{
|
{
|
||||||
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||||
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||||
@@ -343,7 +367,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
apply(config, &new_conf);
|
apply(config, &new_conf);
|
||||||
is_msg_dlg_already_exist = false;
|
is_msg_dlg_already_exist = false;
|
||||||
}
|
}
|
||||||
if (config->opt_float("support_ironing_spacing") < 0.05)
|
if (config->opt_float("support_ironing_spacing") < IRONING_SPACING_MIN)
|
||||||
{
|
{
|
||||||
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
const wxString msg_text = _(L("Ironing spacing too small\nIt has been reset to 0.1"));
|
||||||
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK);
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ public:
|
|||||||
void check_nozzle_temperature_initial_layer_range(DynamicPrintConfig* config);
|
void check_nozzle_temperature_initial_layer_range(DynamicPrintConfig* config);
|
||||||
void check_adaptive_pressure_advance_model(DynamicPrintConfig* config);
|
void check_adaptive_pressure_advance_model(DynamicPrintConfig* config);
|
||||||
void check_filament_max_volumetric_speed(DynamicPrintConfig *config);
|
void check_filament_max_volumetric_speed(DynamicPrintConfig *config);
|
||||||
|
void check_filament_ironing_spacing(DynamicPrintConfig *config);
|
||||||
void check_chamber_temperature(DynamicPrintConfig* config);
|
void check_chamber_temperature(DynamicPrintConfig* config);
|
||||||
void check_chamber_minimal_temperature(DynamicPrintConfig* config);
|
void check_chamber_minimal_temperature(DynamicPrintConfig* config);
|
||||||
bool check_layer_height(DynamicPrintConfig* config);
|
bool check_layer_height(DynamicPrintConfig* config);
|
||||||
|
|||||||
@@ -12800,8 +12800,6 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||||||
notification_manager->set_slicing_progress_export_possible();
|
notification_manager->set_slicing_progress_export_possible();
|
||||||
|
|
||||||
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
||||||
const std::string lifecycle_job_name = this->background_process.fff_print() ?
|
|
||||||
this->background_process.fff_print()->output_filename() : std::string();
|
|
||||||
this->background_process.reset_export();
|
this->background_process.reset_export();
|
||||||
// This bool stops showing export finished notification even when process_completed_with_error is false
|
// This bool stops showing export finished notification even when process_completed_with_error is false
|
||||||
bool has_error = false;
|
bool has_error = false;
|
||||||
@@ -12848,8 +12846,18 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||||||
|
|
||||||
{
|
{
|
||||||
Slic3r::LifecycleEventContext ctx;
|
Slic3r::LifecycleEventContext ctx;
|
||||||
ctx.name = lifecycle_job_name;
|
if (const PrintBase* print = this->background_process.current_print()) {
|
||||||
ctx.code = evt.cancelled() ? Slic3r::LifecycleEvtCode::Warn : (has_error ? Slic3r::LifecycleEvtCode::Error : Slic3r::LifecycleEvtCode::Ok);
|
const Model& model = print->model();
|
||||||
|
ctx.id = std::to_string(model.id().id);
|
||||||
|
if (model.model_info)
|
||||||
|
ctx.name = model.model_info->model_name;
|
||||||
|
} else {
|
||||||
|
// Realistically Printbase* print will never be null because select_technology already asserts an active print
|
||||||
|
// and the worker thread asserts it before processing.
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": slicing completed without an active print; lifecycle event has no model ID";
|
||||||
|
}
|
||||||
|
ctx.code = evt.cancelled() ? Slic3r::LifecycleEvtCode::Warn :
|
||||||
|
(has_error ? Slic3r::LifecycleEvtCode::Error : Slic3r::LifecycleEvtCode::Ok);
|
||||||
ctx.msg = evt.cancelled() ? "cancelled" : (has_error ? lifecycle_error_msg : std::string());
|
ctx.msg = evt.cancelled() ? "cancelled" : (has_error ? lifecycle_error_msg : std::string());
|
||||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::SlicingJobComplete, ctx);
|
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::SlicingJobComplete, ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4905,6 +4905,7 @@ void TabFilament::update()
|
|||||||
return; // ys_FIXME
|
return; // ys_FIXME
|
||||||
|
|
||||||
m_config_manipulation.check_filament_max_volumetric_speed(m_config);
|
m_config_manipulation.check_filament_max_volumetric_speed(m_config);
|
||||||
|
m_config_manipulation.check_filament_ironing_spacing(m_config);
|
||||||
|
|
||||||
m_update_cnt++;
|
m_update_cnt++;
|
||||||
|
|
||||||
|
|||||||
@@ -747,6 +747,61 @@ TEST_CASE("A region with ironing turned off is never ironed", "[Fill]")
|
|||||||
REQUIRE(Layer::choose_ironing_extruder(cfg, spiral_mode, /*is_topmost_layer=*/true) == -1);
|
REQUIRE(Layer::choose_ironing_extruder(cfg, spiral_mode, /*is_topmost_layer=*/true) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ironing path count and total length in mm, over the whole object.
|
||||||
|
static std::pair<size_t, double> ironing_extent(const Print &print)
|
||||||
|
{
|
||||||
|
size_t paths = 0;
|
||||||
|
double length = 0.;
|
||||||
|
for (const Layer *layer : print.objects().front()->layers())
|
||||||
|
for (const LayerRegion *region : layer->regions())
|
||||||
|
for (const ExtrusionEntity *entity : region->fills.flatten().entities)
|
||||||
|
if (ironing_role(entity->role())) {
|
||||||
|
++paths;
|
||||||
|
length += unscale<double>(entity->length());
|
||||||
|
}
|
||||||
|
return {paths, length};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Ironing spacing below the minimum irons at the minimum spacing", "[Fill]")
|
||||||
|
{
|
||||||
|
const std::string pattern = GENERATE("rectilinear", "concentric");
|
||||||
|
const bool via_filament = GENERATE(false, true);
|
||||||
|
const double spacing = GENERATE(0., 0.001);
|
||||||
|
CAPTURE(pattern, via_filament, spacing);
|
||||||
|
|
||||||
|
auto ironing_for = [&pattern, via_filament](double spacing) {
|
||||||
|
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||||
|
config.set_deserialize_strict({{"ironing_type", "top"},
|
||||||
|
{"ironing_pattern", pattern},
|
||||||
|
{"layer_height", 0.2}});
|
||||||
|
// The filament override replaces the process spacing, which stays at a usable value.
|
||||||
|
if (via_filament)
|
||||||
|
config.set_deserialize_strict({{"ironing_spacing", 0.1}, {"filament_ironing_spacing", spacing}});
|
||||||
|
else
|
||||||
|
config.set_deserialize_strict({{"ironing_spacing", spacing}});
|
||||||
|
Print print;
|
||||||
|
Slic3r::Test::init_and_process_print({Slic3r::Test::cube(20)}, print, config);
|
||||||
|
return ironing_extent(print);
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::pair<size_t, double> clamped = ironing_for(spacing);
|
||||||
|
const std::pair<size_t, double> minimum = ironing_for(IRONING_SPACING_MIN);
|
||||||
|
REQUIRE(minimum.first > 0);
|
||||||
|
CHECK(clamped.first == minimum.first);
|
||||||
|
CHECK_THAT(clamped.second, Catch::Matchers::WithinRel(minimum.second, 1e-9));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Concentric fill at zero spacing returns without paths", "[Fill]")
|
||||||
|
{
|
||||||
|
std::unique_ptr<Fill> filler(Fill::new_from_type(ipConcentric));
|
||||||
|
filler->spacing = 0.;
|
||||||
|
filler->bounding_box = BoundingBox(Point(0, 0), Point::new_scale(10, 10));
|
||||||
|
FillParams params;
|
||||||
|
params.density = 1.f;
|
||||||
|
Surface surface(stTop, ExPolygon({Point(0, 0), Point::new_scale(10, 0), Point::new_scale(10, 10), Point::new_scale(0, 10)}));
|
||||||
|
CHECK(filler->fill_surface(&surface, params).empty());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
||||||
{
|
{
|
||||||
auto angles_for = [](int direction) {
|
auto angles_for = [](int direction) {
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
#include "libslic3r/Layer.hpp"
|
#include "libslic3r/Layer.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/GCodeReader.hpp"
|
#include "libslic3r/GCodeReader.hpp"
|
||||||
|
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||||
|
#include "libslic3r/Exception.hpp"
|
||||||
|
#include "libslic3r/LifecycleEvents.hpp"
|
||||||
|
|
||||||
#include "test_helpers.hpp"
|
#include "test_helpers.hpp"
|
||||||
#include "test_utils.hpp"
|
#include "test_utils.hpp"
|
||||||
@@ -22,7 +25,10 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::Test;
|
using namespace Slic3r::Test;
|
||||||
@@ -224,8 +230,88 @@ std::string resolved_output_name(Model& model, const std::string& format, const
|
|||||||
return print.output_filename(filename_base);
|
return print.output_filename(filename_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ScopedLifecycleHook
|
||||||
|
{
|
||||||
|
explicit ScopedLifecycleHook(LifecycleHookFn hook) { set_lifecycle_hook_fn(std::move(hook)); }
|
||||||
|
~ScopedLifecycleHook() { set_lifecycle_hook_fn(nullptr); }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
TEST_CASE("Slicing lifecycle events identify the model", "[Print][LifecycleEvents]")
|
||||||
|
{
|
||||||
|
struct ObservedEvent {
|
||||||
|
LifecycleEvent event;
|
||||||
|
std::string id;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
std::vector<ObservedEvent> events;
|
||||||
|
ScopedLifecycleHook hook([&](LifecycleEvent event, const LifecycleEventContext& ctx) {
|
||||||
|
events.push_back({ event, ctx.id, ctx.name });
|
||||||
|
});
|
||||||
|
|
||||||
|
Print print;
|
||||||
|
Model model;
|
||||||
|
ModelInfo info;
|
||||||
|
info.model_name = "Lifecycle test model";
|
||||||
|
model.model_info = std::make_shared<ModelInfo>(std::move(info));
|
||||||
|
init_print({cube(20)}, print, model);
|
||||||
|
|
||||||
|
print.process();
|
||||||
|
ScopedTemporaryFile temp(".gcode");
|
||||||
|
print.export_gcode(temp.string(), nullptr, nullptr);
|
||||||
|
GCodeProcessorResult result;
|
||||||
|
print.export_gcode_from_previous_file(temp.string(), &result);
|
||||||
|
|
||||||
|
const std::string expected_id = std::to_string(print.model().id().id);
|
||||||
|
const std::vector<LifecycleEvent> expected_events = {
|
||||||
|
LifecycleEvent::SliceStarted,
|
||||||
|
LifecycleEvent::SliceGeometryFinished,
|
||||||
|
LifecycleEvent::GCodeExportStarted,
|
||||||
|
LifecycleEvent::GCodeExportFinished,
|
||||||
|
LifecycleEvent::GCodeExportStarted,
|
||||||
|
LifecycleEvent::GCodeExportFinished,
|
||||||
|
};
|
||||||
|
REQUIRE(events.size() == expected_events.size());
|
||||||
|
for (size_t i = 0; i < expected_events.size(); ++i) {
|
||||||
|
CHECK(events[i].event == expected_events[i]);
|
||||||
|
CHECK(events[i].id == expected_id);
|
||||||
|
CHECK(events[i].name == "Lifecycle test model");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Slicing lifecycle event name is empty without model metadata", "[Print][LifecycleEvents]")
|
||||||
|
{
|
||||||
|
std::string event_id;
|
||||||
|
std::string event_name = "unset";
|
||||||
|
ScopedLifecycleHook hook([&](LifecycleEvent event, const LifecycleEventContext& ctx) {
|
||||||
|
if (event == LifecycleEvent::SliceStarted) {
|
||||||
|
event_id = ctx.id;
|
||||||
|
event_name = ctx.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Print print;
|
||||||
|
Model model;
|
||||||
|
init_print({cube(20)}, print, model);
|
||||||
|
print.process();
|
||||||
|
|
||||||
|
CHECK(event_id == std::to_string(print.model().id().id));
|
||||||
|
CHECK(event_name.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Output filenames with numeric statistics fail before slicing finishes", "[Print][Regression]")
|
||||||
|
{
|
||||||
|
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||||
|
config.set_key_value("filename_format", new ConfigOptionString("{int(total_weight*10) / 10.0}"));
|
||||||
|
|
||||||
|
Print print;
|
||||||
|
Model model;
|
||||||
|
init_print({cube(20)}, print, model, config);
|
||||||
|
|
||||||
|
CHECK_THROWS_AS(print.output_filename(), PlaceholderParserError);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Print: {first_object_name} names the first printable object on the plate", "[Print]")
|
TEST_CASE("Print: {first_object_name} names the first printable object on the plate", "[Print]")
|
||||||
{
|
{
|
||||||
Model model;
|
Model model;
|
||||||
|
|||||||
Reference in New Issue
Block a user