diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 75d73e546e..c9fd0118d0 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -13,6 +13,7 @@ #include "Time.hpp" #include "GCode.hpp" #include "BeltGCode.hpp" +#include "BeltTransform.hpp" #include "GCode/WipeTower.hpp" #include "GCode/WipeTower2.hpp" #include "Utils.hpp" @@ -1430,57 +1431,57 @@ StringObjectException Print::validate(std::vector *warnin return profile; }; - // Checks that the print does not exceed the max print height + // Checks that the print does not exceed the max print height. + // For belt printers the slicing-frame Z spans the sheared X-length and + // is not comparable to printable_height (which is gantry clearance in the + // build-volume frame). Compare against the model's pre-shear Z instead, + // mirroring the bbox computed in PrintObject::update_slicing_parameters. + const bool belt_printer = this->config().belt_printer.value; + const double shrinkage_compensation_z = this->shrinkage_compensation().z(); for (size_t print_object_idx = 0; print_object_idx < m_objects.size(); ++ print_object_idx) { const PrintObject &print_object = *m_objects[print_object_idx]; - // Belt printer: the sliced (virtual) Z is belt travel along the conveyor, not - // build height, so the loop below (which measures the sliced layer stack) is - // meaningless here. The real ceiling is the usable vertical clearance above the - // belt, which printable_height holds directly: the gantry travels up the tilted - // plane, so a part of height z needs gantry reach z / cos(tilt), and the machine's - // gantry-axis range is sized to accommodate that (e.g. IdeaFormer IR3 V2: ~354 mm - // of gantry travel = 250 mm vertical at 45°, and printable_height = 250). So compare - // the upright object height against printable_height directly. - if (m_config.belt_printer.value) { - const double max_h = m_config.printable_height.value; - double obj_top = 0.0; - const ModelObject *mo = print_object.model_object(); - for (const ModelInstance *mi : mo->instances) - obj_top = std::max(obj_top, mo->instance_bounding_box(*mi).max.z()); - if (obj_top > max_h + EPSILON) - return StringObjectException{ - Slic3r::format(_u8L("The object %1% exceeds the maximum printable height " - "above the belt (%2% mm)."), - print_object.model_object()->name, max_h), - print_object.model_object(), "" }; - continue; - } - //FIXME It is quite expensive to generate object layers just to get the print height! - if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx), print_object.config().precise_z_height.value); - !layers.empty()) { - Vec3d test =this->shrinkage_compensation(); - const double shrinkage_compensation_z = this->shrinkage_compensation().z(); - - if (shrinkage_compensation_z != 1. && layers.back() > (this->config().printable_height / shrinkage_compensation_z + EPSILON)) { - // The object exceeds the maximum build volume height because of shrinkage compensation. - return StringObjectException{ - Slic3r::format(_u8L("While the object %1% itself fits the build volume, it exceeds the maximum build volume height because of material shrinkage compensation."), print_object.model_object()->name), - print_object.model_object(), - "" - }; - } else if (layers.back() > this->config().printable_height + EPSILON) { - // Test whether the last slicing plane is below or above the print volume. - return StringObjectException{ - 0.5 * (layers[layers.size() - 2] + layers.back()) > this->config().printable_height + EPSILON ? - Slic3r::format(_u8L("The object %1% exceeds the maximum build volume height."), print_object.model_object()->name) : - Slic3r::format(_u8L("While the object %1% itself fits the build volume, its last layer exceeds the maximum build volume height."), print_object.model_object()->name) + - " " + _u8L("You might want to reduce the size of your model or change current print settings and retry."), - print_object.model_object(), - "" - }; + double effective_max_z = 0; + bool last_layer_below_max = false; + bool have_height = false; + + if (belt_printer) { + double raw_z = print_object.model_object()->max_z(); + if (BeltTransformPipeline::has_preslice_remap(this->config())) + raw_z = BeltTransformPipeline::remap_bbox(*print_object.model_object(), this->config()).size().z(); + effective_max_z = raw_z; + have_height = raw_z > 0; + } else { + //FIXME It is quite expensive to generate object layers just to get the print height! + auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx), print_object.config().precise_z_height.value); + if (!layers.empty()) { + effective_max_z = layers.back(); + last_layer_below_max = layers.size() >= 2 && + 0.5 * (layers[layers.size() - 2] + layers.back()) <= this->config().printable_height + EPSILON; + have_height = true; } } + + if (!have_height) + continue; + + if (shrinkage_compensation_z != 1. && effective_max_z > (this->config().printable_height / shrinkage_compensation_z + EPSILON)) { + // The object exceeds the maximum build volume height because of shrinkage compensation. + return StringObjectException{ + Slic3r::format(_u8L("While the object %1% itself fits the build volume, it exceeds the maximum build volume height because of material shrinkage compensation."), print_object.model_object()->name), + print_object.model_object(), + "" + }; + } else if (effective_max_z > this->config().printable_height + EPSILON) { + return StringObjectException{ + last_layer_below_max ? + Slic3r::format(_u8L("While the object %1% itself fits the build volume, its last layer exceeds the maximum build volume height."), print_object.model_object()->name) + + " " + _u8L("You might want to reduce the size of your model or change current print settings and retry.") : + Slic3r::format(_u8L("The object %1% exceeds the maximum build volume height."), print_object.model_object()->name), + print_object.model_object(), + "" + }; + } } // Some of the objects has variable layer height applied by painting or by a table.