mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-25 09:50:59 +00:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ed459e132 | ||
|
|
7cb7465ed8 | ||
|
|
ddf9b85169 | ||
|
|
af52da061f | ||
|
|
87a5d20d4c | ||
|
|
0db1dc6480 | ||
|
|
42009cf385 | ||
|
|
9859d788d4 |
@@ -70,6 +70,9 @@ if (POLICY CMP0092)
|
||||
cmake_policy(SET CMP0092 NEW)
|
||||
endif ()
|
||||
|
||||
# project() reads this, so set it first.
|
||||
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_LIST_DIR}/cmake/modules/ClangClShowIncludes.cmake")
|
||||
|
||||
project(OrcaSlicer)
|
||||
|
||||
# Backward compatibility for old CMake versions
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# ccache does not parse the -clang: arguments CMake uses for clang-cl's gcc-style
|
||||
# depfile, so a cache hit writes the object and no depfile, and Ninja then records
|
||||
# no headers for that object. ccache reproduces /showIncludes output on a hit.
|
||||
foreach (_lang C CXX)
|
||||
if (CMAKE_${_lang}_COMPILER_ID STREQUAL "Clang" AND
|
||||
CMAKE_${_lang}_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
set(CMAKE_DEPFILE_FLAGS_${_lang} "/showIncludes")
|
||||
set(CMAKE_${_lang}_DEPFILE_FORMAT msvc)
|
||||
endif ()
|
||||
endforeach ()
|
||||
Vendored
+10
@@ -38,6 +38,14 @@ if(POLICY CMP0135) # DOWNLOAD_EXTRACT_TIMESTAMP
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
endif()
|
||||
|
||||
# project() reads this, so set it first. scripts/flatpak/make_deps_tar.sh packs deps/
|
||||
# without cmake/, so the file is missing in a Flatpak build.
|
||||
set(_rules_override "${CMAKE_CURRENT_LIST_DIR}/../cmake/modules/ClangClShowIncludes.cmake")
|
||||
if (EXISTS "${_rules_override}")
|
||||
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_rules_override}")
|
||||
endif ()
|
||||
unset(_rules_override)
|
||||
|
||||
project(OrcaSlicer-deps)
|
||||
|
||||
# Backward compatibility for old CMake versions
|
||||
@@ -220,6 +228,7 @@ if (NOT IS_CROSS_COMPILE OR NOT APPLE)
|
||||
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}
|
||||
-DCMAKE_USER_MAKE_RULES_OVERRIDE:STRING=${CMAKE_USER_MAKE_RULES_OVERRIDE}
|
||||
-DCMAKE_TOOLCHAIN_FILE:STRING=${CMAKE_TOOLCHAIN_FILE}
|
||||
-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}
|
||||
-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}
|
||||
@@ -267,6 +276,7 @@ else()
|
||||
-DCMAKE_IGNORE_PREFIX_PATH:STRING=${CMAKE_IGNORE_PREFIX_PATH}
|
||||
-DCMAKE_C_COMPILER_LAUNCHER:STRING=${CMAKE_C_COMPILER_LAUNCHER}
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER:STRING=${CMAKE_CXX_COMPILER_LAUNCHER}
|
||||
-DCMAKE_USER_MAKE_RULES_OVERRIDE:STRING=${CMAKE_USER_MAKE_RULES_OVERRIDE}
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
${_cmake_osx_arch}
|
||||
"${_configs_line}"
|
||||
|
||||
+31
-5
@@ -5527,12 +5527,28 @@ int CLI::run(int argc, char **argv)
|
||||
//add the virtual object into unselect list if has
|
||||
partplate_list.preprocess_exclude_areas(unselected, enable_wrapping_detect);
|
||||
|
||||
if (used_filament_set.size() > 0)
|
||||
// Filament ids given on the command line size the tower for STL input. A project
|
||||
// records its filament use per plate, so count there and keep its tower positions.
|
||||
const int plate_count = partplate_list.get_plate_count();
|
||||
const bool from_project = used_filament_set.empty();
|
||||
std::vector<int> plate_filament_counts(plate_count, static_cast<int>(used_filament_set.size()));
|
||||
if (from_project)
|
||||
for (int plate_index = 0; plate_index < plate_count; ++plate_index)
|
||||
plate_filament_counts[plate_index] = static_cast<int>(partplate_list.get_plate(plate_index)->get_extruders_under_cli(true, m_print_config).size());
|
||||
// A project only gets a tower the slicer will print: the prime tower enabled, and not
|
||||
// a by-object print unless a smooth timelapse needs it, as the per-plate arrange decides.
|
||||
const bool project_tower_allowed = m_print_config.option<ConfigOptionBool>("enable_prime_tower", true)->value &&
|
||||
(is_smooth_timelapse || !arrange_cfg.is_seq_print);
|
||||
const auto plate_needs_wipe_tower = [from_project, project_tower_allowed, is_smooth_timelapse](int filament_count) {
|
||||
if (!from_project)
|
||||
return filament_count > 0;
|
||||
return project_tower_allowed && (filament_count > 1 || (filament_count > 0 && is_smooth_timelapse));
|
||||
};
|
||||
const int max_filament_count = plate_count > 0 ? *std::max_element(plate_filament_counts.begin(), plate_filament_counts.end()) : 0;
|
||||
|
||||
if (plate_needs_wipe_tower(max_filament_count))
|
||||
{
|
||||
//prepare the wipe tower
|
||||
int plate_count = partplate_list.get_plate_count();
|
||||
int extruder_size = used_filament_set.size();
|
||||
|
||||
auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure");
|
||||
// This margin only pre-adjusts the default away from the near edges;
|
||||
// estimate_wipe_tower_polygon below computes the real clamped position.
|
||||
@@ -5568,7 +5584,11 @@ int CLI::run(int argc, char **argv)
|
||||
|
||||
for (int bedid = 0; bedid < MAX_PLATE_COUNT; bedid++) {
|
||||
int plate_index_valid = std::min(bedid, plate_count - 1);
|
||||
if (bedid < plate_count) {
|
||||
// Overflow beds may receive objects from any plate, so size them for the busiest one.
|
||||
const int extruder_size = bedid < plate_count ? plate_filament_counts[bedid] : max_filament_count;
|
||||
if (!plate_needs_wipe_tower(extruder_size))
|
||||
continue;
|
||||
if (bedid < plate_count && !from_project) {
|
||||
wipe_x_option->set_at(&wt_x_opt, plate_index_valid, 0);
|
||||
wipe_y_option->set_at(&wt_y_opt, plate_index_valid, 0);
|
||||
}
|
||||
@@ -7024,6 +7044,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 "<<index+1 << std::endl;
|
||||
boost::nowide::cerr << ex.what() << std::endl;
|
||||
|
||||
+10
-5
@@ -2479,7 +2479,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
|
||||
{
|
||||
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.msg = path;
|
||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||
@@ -2531,7 +2532,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
}
|
||||
{
|
||||
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.msg = std::string(path) + "\n" + err_msg;
|
||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||
@@ -2555,7 +2557,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
boost::nowide::remove(path_tmp.c_str());
|
||||
{
|
||||
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.msg = std::string(path) + "\n" + ex.what();
|
||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||
@@ -2668,7 +2671,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
if (ret) {
|
||||
{
|
||||
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.msg = std::string(path) + "\nFailed to rename the output G-code file: " + ret.message();
|
||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||
@@ -2687,7 +2691,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
|
||||
{
|
||||
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.msg = path;
|
||||
ctx.cancellation_check = [print]() { return print->canceled(); };
|
||||
|
||||
+29
-5
@@ -1705,6 +1705,25 @@ StringObjectException Print::check_multi_filament_valid(const Print& print)
|
||||
|
||||
// Precondition: Print::validate() requires the Print::apply() to be called its invocation.
|
||||
//BBS: refine seq-print validation logic
|
||||
// The exception's own message is just "Errors"; the detail is in the per-object errors,
|
||||
// whose object id is the PrintObject's.
|
||||
std::string Print::slicing_errors_message(const SlicingErrors &errors) const
|
||||
{
|
||||
std::string message;
|
||||
for (const SlicingError &error : errors.errors_) {
|
||||
std::string object_name;
|
||||
for (const PrintObject *object : m_objects)
|
||||
if (object->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<StringObjectException> *warnings, Polygons* collison_polygons, std::vector<std::pair<Polygon, float>>* height_polygons) const
|
||||
{
|
||||
auto add_warning = [warnings](StringObjectException w) {
|
||||
@@ -2697,7 +2716,8 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
|
||||
{
|
||||
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.cancellation_check = [this]() { return canceled(); };
|
||||
fire_lifecycle_event(LifecycleEvent::SliceStarted, ctx);
|
||||
@@ -3324,7 +3344,8 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
|
||||
{
|
||||
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.cancellation_check = [this]() { return canceled(); };
|
||||
fire_lifecycle_event(LifecycleEvent::SliceGeometryFinished, ctx);
|
||||
@@ -4930,7 +4951,8 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
|
||||
{
|
||||
{
|
||||
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.msg = file;
|
||||
ctx.cancellation_check = [this]() { return canceled(); };
|
||||
@@ -4960,7 +4982,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();
|
||||
{
|
||||
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.msg = file + "\n" + ex.what();
|
||||
ctx.cancellation_check = [this]() { return canceled(); };
|
||||
@@ -4974,7 +4997,8 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
|
||||
|
||||
{
|
||||
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.msg = file;
|
||||
ctx.cancellation_check = [this]() { return canceled(); };
|
||||
|
||||
@@ -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<StringObjectException> *warnings = nullptr, Polygons* collison_polygons = nullptr, std::vector<std::pair<Polygon, float>>* 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;
|
||||
|
||||
@@ -2354,6 +2354,13 @@ void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data,
|
||||
render_thumbnail(thumbnail_data, w, h, thumbnail_params, model_objects, m_volumes, camera_type, camera_view_angle_type, for_picking, ban_light);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_set_shown_canvas_current()
|
||||
{
|
||||
// Thumbnails also render outside render(), where another library's GL context (e.g. WebKitGTK's) can be current.
|
||||
// Inside render(), the shown canvas is the one already bound.
|
||||
return wxGetApp().plater()->get_current_canvas3D()->_set_current();
|
||||
}
|
||||
|
||||
void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data,
|
||||
unsigned int w,
|
||||
unsigned int h,
|
||||
@@ -2365,6 +2372,9 @@ void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data,
|
||||
bool for_picking,
|
||||
bool ban_light)
|
||||
{
|
||||
if (!_set_shown_canvas_current())
|
||||
return;
|
||||
|
||||
GLShaderProgram* shader = nullptr;
|
||||
if (for_picking)
|
||||
shader = wxGetApp().get_shader("flat");
|
||||
@@ -2403,6 +2413,9 @@ void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_d
|
||||
bool for_picking,
|
||||
bool ban_light)
|
||||
{
|
||||
if (!_set_shown_canvas_current())
|
||||
return;
|
||||
|
||||
GLShaderProgram *shader = wxGetApp().get_shader("thumbnail");
|
||||
switch (OpenGLManager::get_framebuffers_type()) {
|
||||
case OpenGLManager::EFramebufferType::Arb: {
|
||||
|
||||
@@ -1320,6 +1320,7 @@ private:
|
||||
bool _init_collapse_toolbar();
|
||||
|
||||
bool _set_current();
|
||||
bool _set_shown_canvas_current();
|
||||
void _resize(unsigned int w, unsigned int h);
|
||||
|
||||
//BBS: add part plate related logic
|
||||
|
||||
@@ -12801,9 +12801,6 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
||||
this->background_process.stop();
|
||||
notification_manager->set_slicing_progress_export_possible();
|
||||
|
||||
// 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 bool stops showing export finished notification even when process_completed_with_error is false
|
||||
bool has_error = false;
|
||||
@@ -12850,7 +12847,10 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
||||
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = lifecycle_job_name;
|
||||
if (const Print* print = this->background_process.fff_print()) {
|
||||
ctx.id = std::to_string(print->model().id().id);
|
||||
ctx.name = print->get_model_name();
|
||||
}
|
||||
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());
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::SlicingJobComplete, ctx);
|
||||
|
||||
@@ -7184,6 +7184,14 @@ void Tab::activate_selected_page(std::function<void()> throw_if_canceled)
|
||||
if (!m_active_page)
|
||||
return;
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// Builds the page off screen, since GTK crashes when it desensitizes a multiline text view
|
||||
// that was built on screen and hidden before its first size allocation.
|
||||
const bool hide_view = m_active_page->build_pending() && m_page_view->IsShown();
|
||||
if (hide_view)
|
||||
m_page_view->Hide();
|
||||
ScopeGuard show_view([this, hide_view] { if (hide_view) m_page_view->Show(); });
|
||||
#endif
|
||||
m_active_page->activate(m_mode, throw_if_canceled);
|
||||
update_changed_ui();
|
||||
update_description_lines();
|
||||
|
||||
@@ -1098,35 +1098,32 @@ void PresetUpdater::priv::check_installed_vendor_profiles() const
|
||||
const auto enabled_vendors = app_config->vendors();
|
||||
|
||||
std::set<std::string> bundles;
|
||||
// Orca: always install filament library
|
||||
bundles.insert(PresetBundle::ORCA_FILAMENT_LIBRARY);
|
||||
// A vendor is named by its profile or, where the build ships preset caches
|
||||
// instead of the raw profile JSONs, by its cache alone.
|
||||
for (const std::string &vendor_name : vendor_names_in(rsrc_path)) {
|
||||
if (bundles.find(vendor_name) != bundles.end())continue;
|
||||
|
||||
const auto is_vendor_enabled = (vendor_name == PresetBundle::ORCA_DEFAULT_BUNDLE) // always update configs from resource to vendor for ORCA_DEFAULT_BUNDLE
|
||||
// enabled_vendors lists the vendors whose printer models the user picked, and
|
||||
// neither of these two is ever in it.
|
||||
const auto is_vendor_enabled = (vendor_name == PresetBundle::ORCA_DEFAULT_BUNDLE)
|
||||
|| (vendor_name == PresetBundle::ORCA_FILAMENT_LIBRARY)
|
||||
|| (enabled_vendors.find(vendor_name) != enabled_vendors.end());
|
||||
if (is_vendor_installed(vendor_name)) {
|
||||
if (enabled_config_update) {
|
||||
if (is_vendor_enabled) {
|
||||
// Orca: whichever form of the vendor resources ships at the newer
|
||||
// version is the one installing lays down, and the one to judge
|
||||
// what is installed against.
|
||||
Semver resource_ver = resource_vendor_version(vendor_name);
|
||||
// Orca: a vendor installed as a preset cache has no profile
|
||||
// beside it; the version it was installed at is in the cache.
|
||||
Semver vendor_ver = installed_vendor_version(vendor_name);
|
||||
if (is_vendor_enabled) {
|
||||
// Orca: whichever form of the vendor resources ships at the newer
|
||||
// version is the one installing lays down, and the one to judge
|
||||
// what is installed against.
|
||||
Semver resource_ver = resource_vendor_version(vendor_name);
|
||||
// Orca: a vendor installed as a preset cache has no profile
|
||||
// beside it; the version it was installed at is in the cache.
|
||||
Semver vendor_ver = installed_vendor_version(vendor_name);
|
||||
|
||||
if (vendor_ver < resource_ver) {
|
||||
BOOST_LOG_TRIVIAL(info) << "[Orca Updater]:found vendor " << vendor_name << " newer version "
|
||||
<< resource_ver.to_string() << " from resource, old version " << vendor_ver.to_string();
|
||||
bundles.insert(vendor_name);
|
||||
}
|
||||
} else {
|
||||
// need to be removed because not installed
|
||||
remove_installed_vendor(vendor_name);
|
||||
if (vendor_ver < resource_ver) {
|
||||
BOOST_LOG_TRIVIAL(info) << "[Orca Updater]:found vendor " << vendor_name << " newer version "
|
||||
<< resource_ver.to_string() << " from resource, old version " << vendor_ver.to_string();
|
||||
bundles.insert(vendor_name);
|
||||
}
|
||||
} else {
|
||||
// need to be removed because not installed
|
||||
remove_installed_vendor(vendor_name);
|
||||
}
|
||||
} else if (is_vendor_enabled) {
|
||||
bundles.insert(vendor_name);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user