diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 0c9bd0b1ee..7f65ba0fb9 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -7015,6 +7015,12 @@ int CLI::run(int argc, char **argv) } } sliced_info.sliced_plates.push_back(sliced_plate_info); + } catch (const Slic3r::SlicingErrors &exs) { + const std::string message = print_fff ? print_fff->slicing_errors_message(exs) : std::string(exs.what()); + BOOST_LOG_TRIVIAL(error) << "found slicing or export error for partplate " << index+1 << ": " << message; + boost::nowide::cerr << message << std::endl; + record_exit_reson(outfile_dir, CLI_SLICING_ERROR, index+1, message, sliced_info); + flush_and_exit(CLI_SLICING_ERROR); } catch (const std::exception &ex) { BOOST_LOG_TRIVIAL(error) << "found slicing or export error for partplate "<id().id == error.objectId()) { + object_name = object->model_object()->name; + break; + } + if (!message.empty()) + message += "\n"; + message += object_name.empty() ? std::string(error.what()) : object_name + ": " + error.what(); + } + return message; +} + StringObjectException Print::validate(std::vector *warnings, Polygons* collison_polygons, std::vector>* height_polygons) const { auto add_warning = [warnings](StringObjectException w) { diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 9c1782e047..12be35ea3c 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -30,6 +30,8 @@ namespace Slic3r { +class SlicingErrors; + class GCode; class Layer; class ModelObject; @@ -967,6 +969,8 @@ public: // Returns an empty string if valid, otherwise returns an error message. StringObjectException validate(std::vector *warnings = nullptr, Polygons* collison_polygons = nullptr, std::vector>* height_polygons = nullptr) const override; + // The per-object messages of a SlicingErrors, each prefixed with its object's name. + std::string slicing_errors_message(const SlicingErrors &errors) const; double skirt_first_layer_height() const; Flow brim_flow() const; Flow skirt_flow() const; diff --git a/tests/fff_print/test_print.cpp b/tests/fff_print/test_print.cpp index d7cd965343..383a7165d5 100644 --- a/tests/fff_print/test_print.cpp +++ b/tests/fff_print/test_print.cpp @@ -505,3 +505,29 @@ TEST_CASE("Sequential printing publishes the nozzle group result", "[Print][Mult CHECK(gcode.find("; SEQ-ND-OK") != std::string::npos); } } + +TEST_CASE("Slicing errors are reported per object with the object's name", "[Print]") +{ + Print print; + Model model; + init_print({Slic3r::Test::cube(20.)}, print, model); + // Lift the cube off the bed: its first layer is empty, which G-code export reports per object. + ModelObject *object = model.objects.front(); + object->name = "floating cube"; + object->instances.front()->set_offset(object->instances.front()->get_offset() + Vec3d(0., 0., 2.)); + print.apply(model, DynamicPrintConfig::full_print_config()); + print.set_status_silent(); + + ScopedTemporaryFile temp(".gcode"); + std::string message; + try { + print.process(); + print.export_gcode(temp.string(), nullptr, nullptr); + FAIL("slicing did not report the empty first layer"); + } catch (const SlicingErrors &errors) { + REQUIRE(errors.errors_.size() == 1); + message = print.slicing_errors_message(errors); + } + CHECK(message.rfind("floating cube: ", 0) == 0); + CHECK(message.find("empty first layer") != std::string::npos); +}