Merge remote-tracking branch 'upstream/main' into belt/baseChanges

Conflicts resolved in src/libslic3r/GCode.cpp and src/slic3r/GUI/GUI_Factories.cpp.

GCode.cpp: combined upstream's air-filtration per-extruder gating
(activate_air_filtration_during_print / _on_completion), the new
extrusion-role-change gcode lambda, ZAA's path.z_contoured arc-fit
disable, raft-aware slow_down_layers branch, and Vec3d/Line3 ZAA
plumbing with the local belt-printer changes (path_on_first_layer,
effective_layer_index_for_point, should_disable_arc_fitting). All
auto-merged m_writer.X() calls converted to m_writer->X() to match
the local unique_ptr<GCodeWriter> refactor.

GUI_Factories.cpp: inserted brim_flow_ratio in the Support category
list and renumbered around the local build_plate_tilt_x/y entries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
harrierpigeon
2026-05-09 16:23:41 -05:00
1592 changed files with 98535 additions and 8652 deletions

View File

@@ -112,7 +112,6 @@
#include "ConfigWizard.hpp"
#include "SyncAmsInfoDialog.hpp"
#include "../Utils/ASCIIFolding.hpp"
#include "../Utils/FixModelByWin10.hpp"
#include "../Utils/UndoRedo.hpp"
#include "../Utils/PresetUpdater.hpp"
#include "../Utils/Process.hpp"
@@ -162,12 +161,16 @@
#include "DailyTips.hpp"
#include "CreatePresetsDialog.hpp"
#include "FileArchiveDialog.hpp"
#include "../Utils/Http.hpp"
#include "../Utils/OrcaCloudServiceAgent.hpp"
#include "StepMeshDialog.hpp"
#include "FilamentMapDialog.hpp"
#include "CloneDialog.hpp"
#include "DeviceCore/DevFilaSystem.h"
#include "DeviceCore/DevManager.h"
#include "DeviceCore/DevConfigUtil.h"
#include "DeviceCore/DevDefs.h"
using boost::optional;
namespace fs = boost::filesystem;
@@ -442,6 +445,7 @@ struct ExtruderGroup : StaticGroup
}
void update_ams();
void SetTitle(const wxString& title);
void sync_ams(MachineObject const *obj, std::vector<DevAms *> const &ams4, std::vector<DevAms *> const &ams1);
@@ -583,7 +587,7 @@ void Sidebar::priv::layout_printer(bool isBBL, bool isDual)
//if (isBBL) {
wxBoxSizer *hsizer = new wxBoxSizer(wxHORIZONTAL);
hsizer->Add(image_printer, 0, wxLEFT | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, FromDIP(10));
hsizer->Add(combo_printer, 1, wxEXPAND | wxALL, FromDIP(2));
hsizer->Add(combo_printer, 1, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(2)); // 1 already triggers wxEXPAND
hsizer->AddSpacer(FromDIP(2));
hsizer->Add(btn_edit_printer, 0, wxRIGHT | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(SidebarProps::IconSpacing()));
//hsizer->Add(btn_connect_printer, 0, wxRIGHT | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(SidebarProps::IconSpacing()));
@@ -1262,6 +1266,16 @@ void ExtruderGroup::sync_ams(MachineObject const *obj, std::vector<DevAms *> con
update_ams();
}
void ExtruderGroup::SetTitle(const wxString& title)
{
m_label = title;
int tW, tH, descent, externalLeading;
GetTextExtent(m_label.IsEmpty() ? "Orca" : m_label, &tW, &tH, &descent, &externalLeading, &m_font);
m_label_height = tH - externalLeading;
m_label_width = tW;
Refresh();
}
bool Sidebar::priv::switch_diameter(bool single)
{
wxString diameter;
@@ -1271,13 +1285,16 @@ bool Sidebar::priv::switch_diameter(bool single)
auto diameter_left = left_extruder->combo_diameter->GetValue();
auto diameter_right = right_extruder->combo_diameter->GetValue();
if (diameter_left != diameter_right) {
std::string printer_type = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle);
auto left_name = _L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::SentenceCase));
auto right_name = _L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::SentenceCase));
MessageDialog dlg(this->plater,
_L("The software does not support using different diameter of nozzles for one print. "
"If the left and right nozzles are inconsistent, we can only proceed with single-head printing. "
"Please confirm which nozzle you would like to use for this project."),
_L("Switch diameter"), wxYES_NO | wxNO_DEFAULT);
dlg.SetButtonLabel(wxID_YES, wxString::Format(_L("Left nozzle: %smm"), diameter_left));
dlg.SetButtonLabel(wxID_NO, wxString::Format(_L("Right nozzle: %smm"), diameter_right));
dlg.SetButtonLabel(wxID_YES, wxString::Format("%s: %smm", left_name, diameter_left));
dlg.SetButtonLabel(wxID_NO, wxString::Format("%s: %smm", right_name, diameter_right));
int result = dlg.ShowModal();
if (result == wxID_YES)
diameter = diameter_left;
@@ -2660,6 +2677,9 @@ void Sidebar::update_presets(Preset::Type preset_type)
};
auto image_path = get_cur_select_bed_image();
if (is_dual_extruder) {
std::string printer_type = printer_preset.get_printer_type(wxGetApp().preset_bundle);
p->left_extruder->SetTitle(_L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase)));
p->right_extruder->SetTitle(_L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase)));
AMSCountPopupWindow::UpdateAMSCount(0, p->left_extruder);
AMSCountPopupWindow::UpdateAMSCount(1, p->right_extruder);
//if (!p->is_switching_diameter) {
@@ -4030,6 +4050,8 @@ void Sidebar::update_printer_thumbnail()
if (printer_thumbnails.find(printer_type) != printer_thumbnails.end()) // Use known cache first
p->image_printer->SetBitmap(create_scaled_bitmap(printer_thumbnails[printer_type], this, PRINTER_THUMBNAIL_SIZE.GetHeight()));
else {
/* ORCA this part check images folder for BBL covers but not checks file existence and causes crash on Linux
* BBL covers already exist on profile folder so no need to use this section
try {
// No cache, try dedicated printer preview
p->image_printer->SetBitmap(create_scaled_bitmap("printer_preview_" + printer_type, this, 48));
@@ -4037,6 +4059,7 @@ void Sidebar::update_printer_thumbnail()
printer_thumbnails[printer_type] = "printer_preview_" + printer_type;
return;
} catch (...) {}
*/
// Orca: try to use the printer model cover as the thumbnail
const auto model_name = selected_preset.config.opt_string("printer_model");
@@ -4728,7 +4751,7 @@ struct Plater::priv
bool can_split_to_volumes() const;
bool can_arrange() const;
bool can_layers_editing() const;
bool can_fix_through_netfabb() const;
bool can_fix_through_cgal() const;
bool can_simplify() const;
bool can_smooth_mesh() const;
bool can_set_instance_to_object() const;
@@ -4876,13 +4899,13 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
"extruder_clearance_radius",
"extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",
"nozzle_height", "skirt_type", "skirt_loops", "skirt_speed","min_skirt_length", "skirt_distance", "skirt_start_angle",
"brim_width", "brim_object_gap", "brim_use_efc_outline", "combine_brims", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation",
"brim_width", "brim_object_gap", "brim_flow_ratio", "brim_use_efc_outline", "combine_brims", "brim_type", "nozzle_diameter", "single_extruder_multi_material", "preferred_orientation",
"enable_prime_tower", "wipe_tower_x", "wipe_tower_y", "prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "prime_tower_enable_framework",
"prime_tower_infill_gap", "prime_volume",
"extruder_colour", "filament_colour", "filament_type", "material_colour", "printable_height", "extruder_printable_height", "printer_model", "printer_technology",
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
"layer_height", "initial_layer_print_height", "min_layer_height", "max_layer_height",
"brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers",
"wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers",
"enable_support", "support_filament", "support_interface_filament",
"support_top_z_distance", "support_bottom_z_distance", "raft_layers",
"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extra_flow", "wipe_tower_max_purge_speed",
@@ -5104,7 +5127,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
this->q->set_prepare_state(Job::PREPARE_STATE_MENU);
this->q->orient(); });
//BBS
view3D_canvas->Bind(EVT_GLCANVAS_SELECT_CURR_PLATE_ALL, [this](SimpleEvent&) {this->q->select_curr_plate_all(); });
view3D_canvas->Bind(EVT_GLCANVAS_SELECT_CURR_PLATE_ALL, [this](SimpleEvent&) {this->q->select_curr_plate_all(); });
view3D_canvas->Bind(EVT_GLCANVAS_PRINTABLE, [this](SimpleEvent& evt) { this->sidebar->obj_list()->toggle_printable_state(); });
view3D_canvas->Bind(EVT_GLCANVAS_SELECT_ALL, [this](SimpleEvent&) { this->q->select_all(); });
view3D_canvas->Bind(EVT_GLCANVAS_QUESTION_MARK, [](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); });
@@ -5951,9 +5975,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (cancel)
is_user_cancel = cancel;
});
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__
<< boost::format(", plate_data.size %1%, project_preset.size %2%, is_bbs_3mf %3%, file_version %4% \n") % plate_data.size() %
project_presets.size() % (en_3mf_file_type == En3mfType::From_BBS) % file_version.to_string();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__
<< boost::format(", plate_data.size %1%, project_preset.size %2%, is_bbs_or_orca_3mf %3%, file_version %4% \n") % plate_data.size() %
project_presets.size() % (en_3mf_file_type == En3mfType::From_BBS || en_3mf_file_type == En3mfType::From_Orca) % file_version.to_string();
// 1. add extruder for prusa model if the number of existing extruders is not enough
// 2. add extruder for BBS or Other model if only import geometry
@@ -5989,97 +6013,154 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// BBS: version check
Semver app_version = *(Semver::parse(SoftFever_VERSION));
const wxString load_3mf_title = _L("Load 3MF");
const wxString newer_3mf_title = _L("Newer 3MF version");
const wxString bambu_project_title = _L("BambuStudio Project");
const wxString msg_unsupported_geometry = _L("The 3MF is not supported by OrcaSlicer, loading geometry data only.");
const wxString msg_old_orca_geometry = _L("The 3MF file was generated by an old OrcaSlicer version, loading geometry data only.");
const wxString msg_older_geometry = _L("The 3MF file was generated by an older version, loading geometry data only.");
const wxString msg_bambu_geometry = _L("The 3MF file was generated by BambuStudio, loading geometry data only.");
auto log_and_show_3mf_info = [&](const wxString& text, const wxString& title) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__
<< " "
<< boost::format("3MF import message [%1%]: %2% | file: %3%") % into_u8(title) % into_u8(text) % path.string();
show_info(q, text, title);
};
if (en_3mf_file_type == En3mfType::From_Prusa) {
// do not reset the model config
load_config = false;
if(load_type != LoadType::LoadGeometry)
show_info(q, _L("The 3MF is not supported by OrcaSlicer, loading geometry data only."), _L("Load 3MF"));
if (load_type != LoadType::LoadGeometry)
log_and_show_3mf_info(msg_unsupported_geometry, load_3mf_title);
}
// else if (load_config && (file_version.maj() != app_version.maj())) {
// // version mismatch, only load geometries
// load_config = false;
// if (!load_model) {
// // only load config case, return directly
// show_info(q, _L("The Config cannot be loaded."), _L("Load 3MF"));
// q->skip_thumbnail_invalid = false;
// return empty_result;
// }
// load_old_project = true;
// // select view to 3D
// q->select_view_3D("3D");
// // select plate 0 as default
// q->select_plate(0);
// if (load_type != LoadType::LoadGeometry) {
// if (en_3mf_file_type == En3mfType::From_BBS)
// show_info(q, _L("The 3MF was generated by an old OrcaSlicer, loading geometry data only."), _L("Load 3MF"));
// else
// show_info(q, _L("The 3MF is not supported by OrcaSlicer, loading geometry data only."), _L("Load 3MF"));
// }
// for (ModelObject *model_object : model.objects) {
// model_object->config.reset();
// // Is there any modifier or advanced config data?
// for (ModelVolume *model_volume : model_object->volumes) model_volume->config.reset();
// }
// }
// Orca: check if the project is created with OrcaSlicer 2.3.1-alpha and use the sparse infill rotation template for non-safe infill patterns
else if (load_config && (file_version < app_version) && file_version == Semver("2.3.1-alpha")) {
if (!config_loaded.opt_string("sparse_infill_rotate_template").empty()) {
const auto _sparse_infill_pattern =
config_loaded.option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
_sparse_infill_pattern == ipLockedZag;
if (!is_safe_to_rotate) {
wxString msg_text = _(
L("This project was created with an OrcaSlicer 2.3.1-alpha and uses "
"infill rotation template settings that may not work properly with your current infill pattern. "
"This could result in weak support or print quality issues."));
msg_text += "\n\n" +
_(L("Would you like OrcaSlicer to automatically fix this by clearing the rotation template settings?"));
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
dialog.SetButtonLabel(wxID_YES, _L("Yes"));
dialog.SetButtonLabel(wxID_NO, _L("No"));
if (dialog.ShowModal() == wxID_YES) {
config_loaded.opt_string("sparse_infill_rotate_template") = "";
else if (en_3mf_file_type == En3mfType::From_Orca) {
// OrcaSlicer file (has OrcaSlicer tag) - compare file_version with SoftFever_VERSION
// Migration fix for OrcaSlicer 2.3.1-alpha sparse infill rotation template
if (load_config && (file_version < app_version) && file_version == Semver("2.3.1-alpha")) {
if (!config_loaded.opt_string("sparse_infill_rotate_template").empty()) {
const auto _sparse_infill_pattern =
config_loaded.option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
_sparse_infill_pattern == ipLockedZag;
if (!is_safe_to_rotate) {
wxString msg_text = _(
L("This project was created with an OrcaSlicer 2.3.1-alpha and uses "
"infill rotation template settings that may not work properly with your current infill pattern. "
"This could result in weak support or print quality issues."));
msg_text += "\n\n" +
_(L("Would you like OrcaSlicer to automatically fix this by clearing the rotation template settings?"));
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
dialog.SetButtonLabel(wxID_YES, _L("Yes"));
dialog.SetButtonLabel(wxID_NO, _L("No"));
if (dialog.ShowModal() == wxID_YES) {
config_loaded.opt_string("sparse_infill_rotate_template") = "";
}
}
}
} else if (load_config && (file_version > app_version)) {
if (config_substitutions.unrecogized_keys.size() > 0) {
wxString text = wxString::Format(_L("The 3MF file version %s is newer than %s's version %s, found the following unrecognized keys:"),
file_version.to_string_sf(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string_sf());
text += "\n";
wxString context = text;
wxString append = _L("You'd better upgrade your software.\n");
context += "\n\n";
context += append;
log_and_show_3mf_info(context, newer_3mf_title);
}
else {
//if the minor version is not matched
if (file_version.min() != app_version.min()) {
wxString text = wxString::Format(_L("The 3MF file version %s is newer than %s's version %s, we suggest to upgrade your software."),
file_version.to_string_sf(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string_sf());
text += "\n";
log_and_show_3mf_info(text, newer_3mf_title);
}
}
}
} else if (load_config && (file_version > app_version)) {
if (config_substitutions.unrecogized_keys.size() > 0) {
wxString text = wxString::Format(_L("The 3MF file version %s is newer than %s's version %s, found the following unrecognized keys:"),
file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string());
text += "\n";
bool first = true;
// std::string context = into_u8(text);
wxString context = text;
// if (wxGetApp().app_config->get("user_mode") == "develop") {
// for (auto &key : config_substitutions.unrecogized_keys) {
// context += " -";
// context += key;
// context += ";\n";
// first = false;
// }
// }
wxString append = _L("You'd better upgrade your software.\n");
context += "\n\n";
// context += into_u8(append);
context += append;
show_info(q, context, _L("Newer 3MF version"));
else if (load_config && config_loaded.empty()) {
load_config = false;
log_and_show_3mf_info(msg_old_orca_geometry, load_3mf_title);
}
else {
//if the minor version is not matched
if (file_version.min() != app_version.min()) {
wxString text = wxString::Format(_L("The 3MF file version %s is newer than %s's version %s, we suggest to upgrade your software."),
file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string());
text += "\n";
show_info(q, text, _L("Newer 3MF version"));
}
else if (en_3mf_file_type == En3mfType::From_BBS) {
// No OrcaSlicer tag - check Bambu/Application version
Semver orca_tag_start_version(2, 3, 2);
if (file_version <= orca_tag_start_version) {
// Compatible old version (before OrcaSlicer tagging was introduced after 2.3.2).
// Any version prior or equal to 2.3.2 is older than the current one, no version warnings needed.
// Still apply migration fixes for known old versions.
if (load_config && (file_version == Semver("2.3.1-alpha"))) {
if (!config_loaded.opt_string("sparse_infill_rotate_template").empty()) {
const auto _sparse_infill_pattern =
config_loaded.option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value;
bool is_safe_to_rotate = _sparse_infill_pattern == ipRectilinear || _sparse_infill_pattern == ipLine ||
_sparse_infill_pattern == ipZigZag || _sparse_infill_pattern == ipCrossZag ||
_sparse_infill_pattern == ipLockedZag;
if (!is_safe_to_rotate) {
wxString msg_text = _(
L("This project was created with an OrcaSlicer 2.3.1-alpha and uses "
"infill rotation template settings that may not work properly with your current infill pattern. "
"This could result in weak support or print quality issues."));
msg_text += "\n\n" +
_(L("Would you like OrcaSlicer to automatically fix this by clearing the rotation template settings?"));
MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO);
dialog.SetButtonLabel(wxID_YES, _L("Yes"));
dialog.SetButtonLabel(wxID_NO, _L("No"));
if (dialog.ShowModal() == wxID_YES) {
config_loaded.opt_string("sparse_infill_rotate_template") = "";
}
}
}
}
else if (load_config && config_loaded.empty()) {
load_config = false;
log_and_show_3mf_info(msg_older_geometry, load_3mf_title);
}
} else {
// BambuStudio project (version > 2.3.2 without OrcaSlicer tag)
// Report that a BambuStudio project is being imported and compare with SLIC3R_VERSION
Semver slic3r_version = *(Semver::parse(SLIC3R_VERSION));
if (load_config && config_loaded.empty()) {
load_config = false;
log_and_show_3mf_info(msg_bambu_geometry, load_3mf_title);
}
else if (load_config && (file_version > slic3r_version)) {
// BambuStudio file version is newer than our compatible SLIC3R_VERSION
if (config_substitutions.unrecogized_keys.size() > 0) {
wxString text = wxString::Format(_L("The 3MF was created by BambuStudio (version %s), which is newer than the compatible version %s. Found unrecognized settings:"),
file_version.to_string(), slic3r_version.to_string());
text += "\n";
wxString context = text;
wxString append = _L("You'd better upgrade your software.\n");
context += "\n\n";
context += append;
log_and_show_3mf_info(context, bambu_project_title);
} else {
wxString text = wxString::Format(_L("The 3MF was created by BambuStudio (version %s), which is newer than the compatible version %s. Some settings may not be fully compatible."),
file_version.to_string(), slic3r_version.to_string());
text += "\n";
log_and_show_3mf_info(text, bambu_project_title);
}
} else if (load_config) {
// BambuStudio version is older or same as our SLIC3R_VERSION
wxString text = _L("The 3MF was created by BambuStudio. Some settings may differ from OrcaSlicer.");
log_and_show_3mf_info(text, bambu_project_title);
}
}
}
}
else if (en_3mf_file_type == En3mfType::From_Other) {
// Generic CAD/other 3MF without slicer metadata: import geometry silently.
if (load_config && config_loaded.empty()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__
<< " "
<< boost::format("3MF has no slicer metadata/project config, importing geometry only: %1%") % path.string();
load_config = false;
}
}
else if (load_config && config_loaded.empty()) {
load_config = false;
show_info(q, _L("The 3MF file was generated by an old OrcaSlicer version, loading geometry data only."), _L("Load 3MF"));
log_and_show_3mf_info(msg_old_orca_geometry, load_3mf_title);
}
else if (!load_config) {
// reset config except color
@@ -6117,7 +6198,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
Semver old_version(1, 5, 9);
if ((en_3mf_file_type == En3mfType::From_BBS) && (file_version < old_version) && load_model && load_config && !config_loaded.empty()) {
if ((en_3mf_file_type == En3mfType::From_BBS || en_3mf_file_type == En3mfType::From_Orca) && (file_version < old_version) && load_model && load_config && !config_loaded.empty()) {
translate_old = true;
partplate_list.get_plate_size(current_width, current_depth, current_height);
}
@@ -6169,9 +6250,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
config += std::move(config_loaded);
std::map<std::string, std::string> validity = config.validate();
if (!validity.empty()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("Param values in 3mf error: ");
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << " " << boost::format("Param values in 3mf error: ");
for (std::map<std::string, std::string>::iterator it=validity.begin(); it!=validity.end(); ++it)
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("%1%: %2%")%it->first %it->second;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << " " << boost::format("%1%: %2%")%it->first %it->second;
//
NotificationManager *notify_manager = q->get_notification_manager();
std::string error_message = L("Invalid values found in the 3MF:");
@@ -6204,7 +6285,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
{
// BBS: modify the prime tower params for old version file
Semver old_version3(2, 0, 0);
if (en_3mf_file_type == En3mfType::From_BBS && file_version < old_version3) {
if ((en_3mf_file_type == En3mfType::From_BBS || en_3mf_file_type == En3mfType::From_Orca) && file_version < old_version3) {
double old_filament_prime_volume = 0.;
int filament_count = 0;
{
@@ -6653,7 +6734,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
model_object->center_around_origin(false);
// BBS
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_LOAD_MODEL_OBJECTS \n");
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << " " << boost::format("import 3mf IMPORT_LOAD_MODEL_OBJECTS \n");
wxString msg = wxString::Format("Loading file: %s", from_path(real_filename));
model_idx++;
dlg_cont = dlg.Update(progress_percent, msg);
@@ -6861,6 +6942,12 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
if (load_model) {
if (!q->m_exported_file && view3D != nullptr) {
// Force a 3D scene refresh after view/plate selection to avoid losing the first load
// on platforms where the GL canvas mapping lags behind model loading.
view3D->reload_scene(true);
view3D->set_as_dirty();
}
if (!silence) wxGetApp().app_config->update_skein_dir(input_files[input_files.size() - 1].parent_path().make_preferred().string());
// XXX: Plater.pm had @loaded_files, but didn't seem to fill them with the filenames...
}
@@ -7736,22 +7823,72 @@ void Plater::priv::process_validation_warning(StringObjectException const &warni
std::string text = warning.string;
auto po = dynamic_cast<PrintObjectBase const *>(warning.object);
auto mo = po ? po->model_object() : dynamic_cast<ModelObject const *>(warning.object);
auto action_fn = (mo || !warning.opt_key.empty()) ? [id = mo ? mo->id() : 0, opt = warning.opt_key](wxEvtHandler *) {
//ORCA: Update process_validation_warning to handle ModelInstance selection and include fallback
auto mi = dynamic_cast<ModelInstance const *>(warning.object);
auto action_fn = (mo || mi || !warning.opt_key.empty()) ? [id = mo ? mo->id() : (mi ? mi->id() : 0),
parent_id = mi ? mi->get_object()->id() : 0,
is_inst = (mi != nullptr),
opt = warning.opt_key](wxEvtHandler *) {
auto & objects = wxGetApp().model().objects;
auto iter = id.id ? std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }) : objects.end();
if (iter != objects.end()) {
wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
wxGetApp().obj_list()->select_items({{*iter, nullptr}});
if (is_inst) {
bool selected = false;
auto iter = std::find_if(objects.begin(), objects.end(), [parent_id](auto o) { return o->id() == parent_id; });
if (iter != objects.end()) {
ModelObject* obj = *iter;
int inst_idx = -1;
for(size_t i=0; i<obj->instances.size(); ++i) {
if (obj->instances[i]->id() == id) {
inst_idx = i;
break;
}
}
wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
if (inst_idx != -1) {
auto* model = wxGetApp().obj_list()->GetModel();
wxDataViewItem item;
wxDataViewItem objItem = model->GetObjectItem(obj);
if (objItem.IsOk()) {
int vm_obj_idx = model->GetIdByItem(objItem);
if (vm_obj_idx != -1) {
item = model->GetItemByInstanceId(vm_obj_idx, inst_idx);
}
}
if (item.IsOk()) {
wxDataViewItemArray sel_items;
sel_items.Add(item);
wxGetApp().obj_list()->select_items(sel_items);
wxGetApp().obj_list()->update_selections_on_canvas();
selected = true;
}
}
if (!selected) {
wxGetApp().obj_list()->select_items({ {obj, nullptr} });
wxGetApp().obj_list()->update_selections_on_canvas();
}
}
} else {
auto iter = id.id ? std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }) : objects.end();
if (iter != objects.end()) {
wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
wxGetApp().obj_list()->select_items({{*iter, nullptr}});
wxGetApp().obj_list()->update_selections_on_canvas();
}
}
if (!opt.empty()) {
if (iter != objects.end())
if ((!is_inst && id.id) || (is_inst && parent_id.id))
wxGetApp().params_panel()->switch_to_object();
wxGetApp().sidebar().jump_to_option(opt, Preset::TYPE_PRINT, L"");
}
return false;
} : std::function<bool(wxEvtHandler *)>();
auto hypertext = (mo || !warning.opt_key.empty()) ? _u8L("Jump to") : "";
auto hypertext = (mo || mi || !warning.opt_key.empty()) ? _u8L("Jump to") : "";
if (mo) hypertext += std::string(" [") + mo->name + "]";
if (mi) hypertext += std::string(" [") + mi->get_object()->name + "]";
if (!warning.opt_key.empty()) hypertext += std::string(" (") + warning.opt_key + ")";
// BBS disable support enforcer
@@ -9018,6 +9155,20 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice)
if (current_panel == panel)
{
if (panel == view3D) {
if (view3D->is_reload_delayed()) {
// Delayed loading of the 3D scene when caller requests the already active tab.
if (printer_technology == ptSLA)
update_restart_background_process(true, false);
else
view3D->reload_scene(true);
}
view3D->set_as_dirty();
view3D->get_canvas3d()->reset_old_size();
if (notification_manager != nullptr)
notification_manager->set_in_preview(false);
}
//BBS: add slice logic when switch to preview page
//BBS: add only gcode mode
if (!q->only_gcode_mode() && (current_panel == preview) && (wxGetApp().is_editor())) {
@@ -9313,12 +9464,17 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
//! instead of
//! combo->GetStringSelection().ToUTF8().data());
wxString wx_name = combo->GetString(selection);
// if (preset_type == Preset::TYPE_PRINTER) {
// wx_name = combo->get_preset_item_name(selection); }
std::string preset_name = wxGetApp().preset_bundle->get_preset_name_by_alias(preset_type,
Preset::remove_suffix_modified(wx_name.ToUTF8().data()));
// Prefer the internal preset name stored per combo item to avoid alias collisions
// (e.g. user preset and bundle preset sharing the same display alias).
wxString wx_stored_name = combo->GetItemAlias(selection);
std::string preset_name;
if (!wx_stored_name.empty()) {
preset_name = Preset::remove_suffix_modified(wx_stored_name.ToUTF8().data());
} else {
wxString wx_name = combo->GetString(selection);
preset_name = wxGetApp().preset_bundle->get_preset_name_by_alias(preset_type,
Preset::remove_suffix_modified(wx_name.ToUTF8().data()));
}
if (preset_type == Preset::TYPE_FILAMENT) {
wxGetApp().preset_bundle->set_filament_preset(idx, preset_name);
@@ -9430,6 +9586,26 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
for (size_t idx = 0; idx < filament_size; ++idx)
wxGetApp().plater()->sidebar().auto_calc_flushing_volumes(idx);
#endif
// Show shared profiles notification for the newly selected printer
if (wxGetApp().app_config->get_bool("show_shared_profiles_notification"))
{
std::string printer_name = wxGetApp().preset_bundle->printers.get_selected_preset_base().name;
std::string encoded_name = Http::url_encode(printer_name);
std::string cloud_url;
if (auto agent = wxGetApp().getAgent()) {
if (auto orca_agent = std::dynamic_pointer_cast<OrcaCloudServiceAgent>(agent->get_cloud_agent())) {
cloud_url = orca_agent->get_cloud_base_url();
}
}
if (cloud_url.empty())
cloud_url = "https://cloud.orcaslicer.com";
std::string explore_url = cloud_url + "/app/bundles/explore?printers=" + encoded_name;
wxGetApp().plater()->get_notification_manager()->push_shared_profiles_notification(explore_url);
}
}
#ifdef __WXMSW__
@@ -10202,10 +10378,10 @@ void Plater::priv::on_object_select(SimpleEvent& evt)
selection_changed();
}
//BBS: repair model through netfabb
//BBS: repair model through cgal
void Plater::priv::on_repair_model(wxCommandEvent &event)
{
wxGetApp().obj_list()->fix_through_netfabb();
wxGetApp().obj_list()->fix_through_cgal();
}
void Plater::priv::on_filament_color_changed(wxCommandEvent &event)
@@ -11270,15 +11446,15 @@ bool Plater::priv::can_delete_plate() const
return q->get_partplate_list().get_plate_count() > 1;
}
bool Plater::priv::can_fix_through_netfabb() const
bool Plater::priv::can_fix_through_cgal() const
{
std::vector<int> obj_idxs, vol_idxs;
sidebar->obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
#if FIX_THROUGH_NETFABB_ALWAYS
#if FIX_THROUGH_CGAL_ALWAYS
// Fixing always.
return ! obj_idxs.empty() || ! vol_idxs.empty();
#else // FIX_THROUGH_NETFABB_ALWAYS
#else // FIX_THROUGH_CGAL_ALWAYS
// Fixing only if the model is not manifold.
if (vol_idxs.empty()) {
for (auto obj_idx : obj_idxs)
@@ -11292,7 +11468,7 @@ bool Plater::priv::can_fix_through_netfabb() const
if (model.objects[obj_idx]->get_repaired_errors_count(vol_idx) > 0)
return true;
return false;
#endif // FIX_THROUGH_NETFABB_ALWAYS
#endif // FIX_THROUGH_CGAL_ALWAYS
}
bool Plater::priv::can_simplify() const
@@ -12477,6 +12653,7 @@ void Plater::calib_pa(const Calib_Params& params)
auto print_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config;
auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
print_config->set_key_value("overhang_reverse", new ConfigOptionBool(false));
print_config->set_key_value("precise_z_height", new ConfigOptionBool(false));
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
switch (params.mode) {
case CalibMode::Calib_PA_Line:
@@ -12823,7 +13000,8 @@ void Plater::_calib_pa_select_added_objects() {
// Adjust settings for flowrate calibration
// For linear mode, pass 1 means normal version while pass 2 mean "for perfectionists" version
void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, int pass)
// ORCA: Add pattern parameter
void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, int pass, InfillPattern pattern)
{
auto print_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config;
auto printerConfig = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
@@ -12886,7 +13064,8 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
_obj->config.set_key_value("sparse_infill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
_obj->config.set_key_value("top_surface_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false));
_obj->config.set_key_value("internal_solid_infill_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false));
_obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum<InfillPattern>(ipArchimedeanChords));
// ORCA: use the pattern parameter
_obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum<InfillPattern>(pattern));
_obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f));
_obj->config.set_key_value("infill_direction", new ConfigOptionFloat(45));
_obj->config.set_key_value("solid_infill_direction", new ConfigOptionFloat(135));
@@ -12937,7 +13116,8 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config();
}
void Plater::calib_flowrate(bool is_linear, int pass) {
// ORCA: Add pattern parameter
void Plater::calib_flowrate(bool is_linear, int pass, InfillPattern pattern) {
if (pass != 1 && pass != 2)
return;
wxString calib_name;
@@ -12969,7 +13149,8 @@ void Plater::calib_flowrate(bool is_linear, int pass) {
(boost::filesystem::path(Slic3r::resources_dir()) / "calib" / "filament_flow" / "flowrate-test-pass2.3mf").string());
}
adjust_settings_for_flowrate_calib(model().objects, is_linear, pass);
// ORCA: pass the pattern
adjust_settings_for_flowrate_calib(model().objects, is_linear, pass, pattern);
wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config();
auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
@@ -12981,6 +13162,10 @@ void Plater::calib_flowrate(bool is_linear, int pass) {
void Plater::calib_temp(const Calib_Params& params) {
constexpr double base_temp_tower_nozzle_diameter = 0.4;
constexpr double base_temp_tower_block_height = 10.0;
constexpr int base_temp_tower_temp_step = 5;
const auto calib_temp_name = wxString::Format(L"Nozzle temperature test");
new_project(false, false, calib_temp_name);
wxGetApp().mainframe->select_tab(size_t(MainFrame::tp3DEditor));
@@ -12991,18 +13176,61 @@ void Plater::calib_temp(const Calib_Params& params) {
auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
auto filament_config = &wxGetApp().preset_bundle->filaments.get_edited_preset().config;
auto start_temp = lround(params.start);
const ConfigOptionFloats* nozzle_diameter_config = printer_config->option<ConfigOptionFloats>("nozzle_diameter");
size_t nozzle_id = static_cast<size_t>(std::max(params.extruder_id, 0));
double nozzle_diameter = base_temp_tower_nozzle_diameter;
if (nozzle_diameter_config && !nozzle_diameter_config->values.empty()) {
nozzle_id = std::min(nozzle_id, nozzle_diameter_config->values.size() - 1);
nozzle_diameter = nozzle_diameter_config->values[nozzle_id];
}
if (nozzle_diameter <= 0.0)
nozzle_diameter = base_temp_tower_nozzle_diameter;
const double nozzle_scale = nozzle_diameter / base_temp_tower_nozzle_diameter;
const double block_height = base_temp_tower_block_height;
// cut upper
auto obj_bb = model().objects[0]->bounding_box_exact();
auto block_count = lround((500 - params.end) / base_temp_tower_temp_step + 1);
if (block_count > 0) {
// subtract EPSILON offset to avoid cutting at the exact location where the flat surface is
auto new_height = block_count * block_height - EPSILON;
if (new_height < obj_bb.size().z()) {
cut_horizontal(0, 0, new_height, ModelObjectCutAttribute::KeepLower);
}
}
// cut bottom
obj_bb = model().objects[0]->bounding_box_exact();
block_count = lround((500 - params.start) / base_temp_tower_temp_step);
if (block_count > 0) {
auto new_height = block_count * block_height + EPSILON;
if (new_height < obj_bb.size().z()) {
cut_horizontal(0, 0, new_height, ModelObjectCutAttribute::KeepUpper);
}
}
if (std::abs(nozzle_scale - 1.0) > EPSILON)
model().objects[0]->scale(nozzle_scale, nozzle_scale, nozzle_scale);
model().objects[0]->ensure_on_bed();
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
filament_config->set_key_value("nozzle_temperature_initial_layer", new ConfigOptionInts(1,(int)start_temp));
filament_config->set_key_value("nozzle_temperature", new ConfigOptionInts(1,(int)start_temp));
model().objects[0]->config.set_key_value("layer_height", new ConfigOptionFloat(nozzle_diameter/2));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(5.0));
model().objects[0]->config.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0));
model().objects[0]->config.set_key_value("alternate_extra_wall", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("seam_slope_type", new ConfigOptionEnum<SeamScarfType>(SeamScarfType::None));
model().objects[0]->config.set_key_value("overhang_reverse", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("precise_z_height", new ConfigOptionBool(false));
auto print_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config;
print_config->set_key_value("enable_wrapping_detection", new ConfigOptionBool(false));
print_config->set_key_value("initial_layer_print_height", new ConfigOptionFloat(nozzle_diameter/2));
changed_objects({ 0 });
wxGetApp().get_tab(Preset::TYPE_PRINT)->update_dirty();
@@ -13010,27 +13238,6 @@ void Plater::calib_temp(const Calib_Params& params) {
wxGetApp().get_tab(Preset::TYPE_PRINT)->reload_config();
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->reload_config();
// cut upper
auto obj_bb = model().objects[0]->bounding_box_exact();
auto block_count = lround((500 - params.end) / 5 + 1);
if(block_count > 0){
// subtract EPSILON offset to avoid cutting at the exact location where the flat surface is
auto new_height = block_count * 10.0 - EPSILON;
if (new_height < obj_bb.size().z()) {
cut_horizontal(0, 0, new_height, ModelObjectCutAttribute::KeepLower);
}
}
// cut bottom
obj_bb = model().objects[0]->bounding_box_exact();
block_count = lround((500 - params.start) / 5);
if(block_count > 0){
auto new_height = block_count * 10.0 + EPSILON;
if (new_height < obj_bb.size().z()) {
cut_horizontal(0, 0, new_height, ModelObjectCutAttribute::KeepUpper);
}
}
p->background_process.fff_print()->set_calib_params(params);
}
@@ -13079,6 +13286,7 @@ void Plater::calib_max_vol_speed(const Calib_Params& params)
obj_cfg.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterAndInner));
obj_cfg.set_key_value("brim_width", new ConfigOptionFloat(5.0));
obj_cfg.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0));
obj_cfg.set_key_value("precise_z_height", new ConfigOptionBool(false));
print_config->set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
print_config->set_key_value("spiral_mode", new ConfigOptionBool(true));
print_config->set_key_value("max_volumetric_extrusion_rate_slope", new ConfigOptionFloat(0));
@@ -13151,6 +13359,7 @@ void Plater::calib_retraction(const Calib_Params& params)
obj->config.set_key_value("seam_position", new ConfigOptionEnum<SeamPosition>(spAligned));
obj->config.set_key_value("wall_sequence", new ConfigOptionEnum<WallSequence>(WallSequence::InnerOuter));
obj->config.set_key_value("overhang_reverse", new ConfigOptionBool(false));
obj->config.set_key_value("precise_z_height", new ConfigOptionBool(false));
changed_objects({ 0 });
@@ -13189,6 +13398,7 @@ void Plater::calib_VFA(const Calib_Params& params)
print_config->set_key_value("detect_thin_wall", new ConfigOptionBool(false));
print_config->set_key_value("spiral_mode", new ConfigOptionBool(true));
print_config->set_key_value("enable_wrapping_detection", new ConfigOptionBool(false));
print_config->set_key_value("precise_z_height", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0));
model().objects[0]->config.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0));
@@ -13256,6 +13466,7 @@ void Plater::calib_input_shaping_freq(const Calib_Params& params)
print_config->set_key_value("outer_wall_speed", new ConfigOptionFloat(200));
print_config->set_key_value("default_acceleration", new ConfigOptionFloat(20000));
print_config->set_key_value("outer_wall_acceleration", new ConfigOptionFloat(20000));
print_config->set_key_value("precise_z_height", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0));
model().objects[0]->config.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0));
@@ -13316,6 +13527,7 @@ void Plater::calib_input_shaping_damp(const Calib_Params& params)
print_config->set_key_value("outer_wall_speed", new ConfigOptionFloat(200));
print_config->set_key_value("default_acceleration", new ConfigOptionFloat(20000));
print_config->set_key_value("outer_wall_acceleration", new ConfigOptionFloat(20000));
print_config->set_key_value("precise_z_height", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0));
model().objects[0]->config.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0));
@@ -13378,6 +13590,7 @@ void Plater::Calib_Cornering(const Calib_Params& params)
print_config->set_key_value("outer_wall_speed", new ConfigOptionFloat(200));
print_config->set_key_value("default_acceleration", new ConfigOptionFloat(2000));
print_config->set_key_value("outer_wall_acceleration", new ConfigOptionFloat(2000));
print_config->set_key_value("precise_z_height", new ConfigOptionBool(false));
model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum<BrimType>(btOuterOnly));
model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0));
model().objects[0]->config.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0));
@@ -18038,15 +18251,13 @@ void Plater::show_object_info()
int non_manifold_edges = 0;
auto mesh_errors = p->sidebar->obj_list()->get_mesh_errors_info(&info_manifold, &non_manifold_edges);
#ifndef __WINDOWS__
if (non_manifold_edges > 0) {
info_manifold += into_u8("\n" + _L("Tips:") + "\n" +_L("\"Fix Model\" feature is currently only on Windows. Please repair the model on Orca Slicer(windows) or CAD softwares."));
}
#endif //APPLE & LINUX
if (non_manifold_edges > 0) {
info_manifold += into_u8("\n" + _L("Tips:") + "\n" + _L("Use \"Fix Model\" to repair the mesh."));
}
info_manifold = "<Error>" + info_manifold + "</Error>";
info_text += into_u8(info_manifold);
notify_manager->bbl_show_objectsinfo_notification(info_text, is_windows10()&&(non_manifold_edges > 0), !(p->current_panel == p->view3D));
notify_manager->bbl_show_objectsinfo_notification(info_text, non_manifold_edges > 0, !(p->current_panel == p->view3D));
}
bool Plater::show_publish_dialog(bool show)
@@ -18223,7 +18434,7 @@ bool Plater::can_delete_plate() const { return p->can_delete_plate(); }
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
bool Plater::can_decrease_instances() const { return p->can_decrease_instances(); }
bool Plater::can_set_instance_to_object() const { return p->can_set_instance_to_object(); }
bool Plater::can_fix_through_netfabb() const { return p->can_fix_through_netfabb(); }
bool Plater::can_fix_through_cgal() const { return p->can_fix_through_cgal(); }
bool Plater::can_simplify() const { return p->can_simplify(); }
bool Plater::can_smooth_mesh() const { return p->can_smooth_mesh(); }
bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); }