mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 19:01:02 +00:00
Merge main and resolved conflicts
This commit is contained in:
+12
-1
@@ -33,7 +33,8 @@ if (SLIC3R_GUI)
|
||||
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
|
||||
find_package(wxWidgets 3.3 REQUIRED COMPONENTS base core adv html gl aui net media webview)
|
||||
else ()
|
||||
find_package(wxWidgets 3.3 CONFIG REQUIRED COMPONENTS html adv gl core base webview aui net media)
|
||||
# propgrid is required by wxInspector.
|
||||
find_package(wxWidgets 3.3 CONFIG REQUIRED COMPONENTS html adv gl core base webview aui net media propgrid)
|
||||
endif ()
|
||||
|
||||
if(UNIX)
|
||||
@@ -90,6 +91,16 @@ if (SLIC3R_GUI)
|
||||
# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc)
|
||||
|
||||
find_package(wxInspector REQUIRED)
|
||||
|
||||
# wxInspector's exported interface names the release wxWidgets import
|
||||
# libraries, which a Debug build cannot link. wx is linked above instead.
|
||||
get_target_property(_wxinspector_interface wxInspector::wxInspector INTERFACE_LINK_LIBRARIES)
|
||||
if (_wxinspector_interface)
|
||||
list(FILTER _wxinspector_interface EXCLUDE REGEX "wx(base|msw)3[0-9]u[_.]")
|
||||
set_target_properties(wxInspector::wxInspector PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES "${_wxinspector_interface}")
|
||||
endif ()
|
||||
|
||||
list(APPEND wxWidgets_LIBRARIES "wxInspector::wxInspector")
|
||||
|
||||
message(STATUS "wx libs: ${wxWidgets_LIBRARIES}")
|
||||
|
||||
+172
-17
@@ -100,6 +100,10 @@ using namespace nlohmann;
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
#include "slic3r/GUI/GUI_Init.hpp"
|
||||
// BBLPrinterAgent::from_orca_filament_id(); the map and its lookups live in libslic3r_gui,
|
||||
// which only a SLIC3R_GUI build links (see target_link_libraries(OrcaSlicer libslic3r_gui)
|
||||
// in CMakeLists).
|
||||
#include "slic3r/Utils/BBLPrinterAgent.hpp"
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
using namespace Slic3r;
|
||||
@@ -1793,8 +1797,9 @@ int CLI::run(int argc, char **argv)
|
||||
old_printable_area = config.option<ConfigOptionPoints>("printable_area", true)->values;
|
||||
old_exclude_area = config.option<ConfigOptionPoints>("bed_exclude_area", true)->values;
|
||||
if (old_printable_area.size() >= 4) {
|
||||
old_printable_width = (int)(old_printable_area[2].x() - old_printable_area[0].x());
|
||||
old_printable_depth = (int)(old_printable_area[2].y() - old_printable_area[0].y());
|
||||
BoundingBoxf old_printable_bbox(old_printable_area);
|
||||
old_printable_width = static_cast<int>(old_printable_bbox.size().x());
|
||||
old_printable_depth = static_cast<int>(old_printable_bbox.size().y());
|
||||
}
|
||||
old_printable_height = (int)(config.opt_float("printable_height"));
|
||||
|
||||
@@ -1969,7 +1974,79 @@ int CLI::run(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
auto load_config_file = [](const std::string& file, DynamicPrintConfig& config, std::string& config_type,
|
||||
std::unique_ptr<PresetBundle> cli_preset_bundle;
|
||||
auto ensure_cli_preset_bundle = [&cli_preset_bundle, config_substitution_rule](std::string &error) -> PresetBundle * {
|
||||
if (cli_preset_bundle)
|
||||
return cli_preset_bundle.get();
|
||||
try {
|
||||
AppConfig app_config;
|
||||
const std::string app_config_error = app_config.load_if_exists();
|
||||
if (!app_config_error.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Ignoring invalid app config during CLI preset resolution: " << app_config_error;
|
||||
app_config.reset();
|
||||
}
|
||||
|
||||
auto bundle = std::make_unique<PresetBundle>();
|
||||
std::string load_error;
|
||||
bundle->load_presets(app_config, config_substitution_rule,
|
||||
PresetBundle::PresetPreferences(), &load_error, true);
|
||||
if (!load_error.empty()) {
|
||||
error = "Failed to load presets for inheritance resolution: " + load_error;
|
||||
return nullptr;
|
||||
}
|
||||
cli_preset_bundle = std::move(bundle);
|
||||
return cli_preset_bundle.get();
|
||||
} catch (const std::exception &ex) {
|
||||
error = ex.what();
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
auto resolve_preset = [&ensure_cli_preset_bundle, config_substitution_rule](const std::string &file, DynamicPrintConfig &config,
|
||||
std::string &config_type, const std::string &config_from,
|
||||
bool probe_type, std::string &error) {
|
||||
const auto *inherits = config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS);
|
||||
if (!probe_type && (inherits == nullptr || inherits->value.empty()))
|
||||
return true;
|
||||
|
||||
std::unique_ptr<PresetBundle> source_bundle;
|
||||
PresetBundle *bundle = nullptr;
|
||||
bool allow_source_manifest = false;
|
||||
if (config_from == "system") {
|
||||
source_bundle = std::make_unique<PresetBundle>();
|
||||
bundle = source_bundle.get();
|
||||
allow_source_manifest = true;
|
||||
} else {
|
||||
bundle = ensure_cli_preset_bundle(error);
|
||||
if (bundle == nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (probe_type) {
|
||||
Preset::Type preset_type;
|
||||
if (!bundle->resolve_preset_config_type(config, preset_type, file, config_substitution_rule,
|
||||
error, allow_source_manifest))
|
||||
return false;
|
||||
config_type = Preset::get_type_string(preset_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
Preset::Type preset_type;
|
||||
if (config_type == "process")
|
||||
preset_type = Preset::TYPE_PRINT;
|
||||
else if (config_type == "filament")
|
||||
preset_type = Preset::TYPE_FILAMENT;
|
||||
else if (config_type == "machine")
|
||||
preset_type = Preset::TYPE_PRINTER;
|
||||
else {
|
||||
error = "Unsupported preset type: " + config_type;
|
||||
return false;
|
||||
}
|
||||
return bundle->resolve_preset_config(config, preset_type, file, config_substitution_rule,
|
||||
error, allow_source_manifest);
|
||||
};
|
||||
|
||||
auto load_config_file = [config_substitution_rule, &resolve_preset](const std::string& file, DynamicPrintConfig& config, std::string& config_type,
|
||||
std::string& config_name, std::string& filament_id, std::string& config_from) {
|
||||
if (! boost::filesystem::exists(file)) {
|
||||
boost::nowide::cerr << __FUNCTION__<< ": can not find setting file: " << file << std::endl;
|
||||
@@ -1998,9 +2075,15 @@ int CLI::run(int argc, char **argv)
|
||||
}
|
||||
|
||||
auto type_iter = key_values.find(BBL_JSON_KEY_TYPE);
|
||||
if (type_iter != key_values.end()) {
|
||||
const bool probe_type = type_iter == key_values.end();
|
||||
if (!probe_type)
|
||||
config_type = type_iter->second;
|
||||
|
||||
if (!resolve_preset(file, config, config_type, config_from, probe_type, reason)) {
|
||||
boost::nowide::cerr << __FUNCTION__ << boost::format(": can not resolve preset %1%: %2%") % file % reason << std::endl;
|
||||
return CLI_CONFIG_FILE_ERROR;
|
||||
}
|
||||
|
||||
if (config_type == "machine") {
|
||||
//config.set("printer_settings_id", config_name, true);
|
||||
//printer_inherits = config.option<ConfigOptionString>("inherits", true)->value;
|
||||
@@ -2343,8 +2426,9 @@ int CLI::run(int argc, char **argv)
|
||||
Pointfs orig_printable_area;
|
||||
orig_printable_area = config.option<ConfigOptionPoints>("printable_area", true)->values;
|
||||
if (orig_printable_area.size() >= 4) {
|
||||
orig_printable_width = (int)(orig_printable_area[2].x() - orig_printable_area[0].x());
|
||||
orig_printable_depth = (int)(orig_printable_area[2].y() - orig_printable_area[0].y());
|
||||
BoundingBoxf orig_printable_bbox(orig_printable_area);
|
||||
orig_printable_width = static_cast<int>(orig_printable_bbox.size().x());
|
||||
orig_printable_depth = static_cast<int>(orig_printable_bbox.size().y());
|
||||
}
|
||||
orig_printable_height = (int)(config.opt_float("printable_height"));
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, check printable size: old_printable_width=%2%, orig_printable_width=%3%, old_printable_depth=%4%, orig_printable_depth=%5%, old_printable_height=%6%, orig_printable_height=%7%")
|
||||
@@ -3138,7 +3222,25 @@ int CLI::run(int argc, char **argv)
|
||||
std::vector<int> old_variant_counts(filament_count, 1), new_variant_counts;
|
||||
|
||||
ConfigOptionInts* filament_self_index_opt = m_print_config.option<ConfigOptionInts>("filament_self_index");
|
||||
if (!filament_self_index_opt) {
|
||||
bool need_regenerate_self_index = !filament_self_index_opt;
|
||||
if (filament_self_index_opt) {
|
||||
// a filament_self_index carried over from a stale project can disagree with the
|
||||
// current filament_count. old_start_indice/old_variant_counts below are sized to
|
||||
// filament_count and walked with 1-based group indices, so an index above
|
||||
// filament_count overruns old_start_indice[++k], and a non-positive first index
|
||||
// writes old_variant_counts[-1] - both heap corruption.
|
||||
int max_self_index = 0, min_self_index = 1;
|
||||
for (int v : filament_self_index_opt->values) {
|
||||
max_self_index = std::max(max_self_index, v);
|
||||
min_self_index = std::min(min_self_index, v);
|
||||
}
|
||||
if (max_self_index > filament_count || min_self_index < 1) {
|
||||
BOOST_LOG_TRIVIAL(warning) << boost::format("filament_self_index range [%1%, %2%] is invalid for filament_count %3%, regenerating")
|
||||
% min_self_index % max_self_index % filament_count;
|
||||
need_regenerate_self_index = true;
|
||||
}
|
||||
}
|
||||
if (need_regenerate_self_index) {
|
||||
filament_self_index_opt = m_print_config.option<ConfigOptionInts>("filament_self_index", true);
|
||||
std::vector<int>& filament_self_indice = filament_self_index_opt->values;
|
||||
filament_self_indice.resize(filament_count);
|
||||
@@ -3732,6 +3834,8 @@ int CLI::run(int argc, char **argv)
|
||||
double height_to_lid = m_print_config.opt_float("extruder_clearance_height_to_lid");
|
||||
double height_to_rod = m_print_config.opt_float("extruder_clearance_height_to_rod");
|
||||
double clearance_radius = m_print_config.opt_float("extruder_clearance_radius");
|
||||
double nozzle_height = m_print_config.opt_float("nozzle_height");
|
||||
Vec2d align_center = m_print_config.option<ConfigOptionPoint>("best_object_pos")->value;
|
||||
int shared_printable_width = 0, shared_printable_depth = 0, shared_printable_height = 0, shared_center_x = 0, shared_center_y = 0;
|
||||
//double plate_stride;
|
||||
std::string bed_texture;
|
||||
@@ -3742,8 +3846,11 @@ int CLI::run(int argc, char **argv)
|
||||
if (m_print_config.opt<ConfigOptionFloatsNullable>("extruder_printable_height")) {
|
||||
current_extruder_print_heights = m_print_config.opt<ConfigOptionFloatsNullable>("extruder_printable_height")->values;
|
||||
}
|
||||
current_printable_width = current_printable_area[2].x() - current_printable_area[0].x();
|
||||
current_printable_depth = current_printable_area[2].y() - current_printable_area[0].y();
|
||||
{
|
||||
BoundingBoxf current_printable_bbox(current_printable_area);
|
||||
current_printable_width = static_cast<int>(current_printable_bbox.size().x());
|
||||
current_printable_depth = static_cast<int>(current_printable_bbox.size().y());
|
||||
}
|
||||
current_printable_height = print_height;
|
||||
if (old_printable_width == 0)
|
||||
old_printable_width = current_printable_width;
|
||||
@@ -3944,6 +4051,11 @@ int CLI::run(int argc, char **argv)
|
||||
ConfigOptionFloats *wipe_x_option = dynamic_cast<ConfigOptionFloats *>(print_config.option("wipe_tower_x"));
|
||||
ConfigOptionFloats *wipe_y_option = dynamic_cast<ConfigOptionFloats *>(print_config.option("wipe_tower_y"));
|
||||
|
||||
// get_at() silently clamps an out-of-range index to entry 0 - make the reuse visible
|
||||
if (static_cast<size_t>(plate_index) >= wipe_x_option->values.size() || static_cast<size_t>(plate_index) >= wipe_y_option->values.size()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << boost::format("plate %1%: wipe_tower_x/y only has %2%/%3% entries, reusing entry 0's position")
|
||||
%(plate_index+1) %wipe_x_option->values.size() %wipe_y_option->values.size();
|
||||
}
|
||||
plate_obj_size_info.wipe_x = wipe_x_option->get_at(plate_index);
|
||||
plate_obj_size_info.wipe_y = wipe_y_option->get_at(plate_index);
|
||||
|
||||
@@ -4139,8 +4251,9 @@ int CLI::run(int argc, char **argv)
|
||||
temp_extruder_print_heights = config.option<ConfigOptionFloatsNullable>("extruder_printable_height", true)->values;
|
||||
|
||||
if (temp_printable_area.size() >= 4) {
|
||||
printer_plate.printable_width = (int)(temp_printable_area[2].x() - temp_printable_area[0].x());
|
||||
printer_plate.printable_depth = (int)(temp_printable_area[2].y() - temp_printable_area[0].y());
|
||||
BoundingBoxf temp_printable_bbox(temp_printable_area);
|
||||
printer_plate.printable_width = static_cast<int>(temp_printable_bbox.size().x());
|
||||
printer_plate.printable_depth = static_cast<int>(temp_printable_bbox.size().y());
|
||||
printer_plate.printable_height = (int)(config.opt_float("printable_height"));
|
||||
}
|
||||
if (temp_exclude_area.size() >= 4) {
|
||||
@@ -4788,6 +4901,8 @@ int CLI::run(int argc, char **argv)
|
||||
arrange_cfg.clearance_height_to_rod = height_to_rod;
|
||||
arrange_cfg.clearance_height_to_lid = height_to_lid;
|
||||
arrange_cfg.clearance_radius = clearance_radius;
|
||||
arrange_cfg.nozzle_height = nozzle_height;
|
||||
arrange_cfg.align_center = align_center;
|
||||
arrange_cfg.printable_height = print_height;
|
||||
arrange_cfg.min_obj_distance = 0;
|
||||
if (arrange_cfg.is_seq_print) {
|
||||
@@ -5166,7 +5281,8 @@ int CLI::run(int argc, char **argv)
|
||||
|
||||
Vec3d wipe_tower_size = cur_plate->estimate_wipe_tower_size(m_print_config, w, v, new_extruder_count, filaments_cnt, false, enable_wrapping);
|
||||
Vec3d plate_origin = cur_plate->get_origin();
|
||||
int plate_width, plate_depth, plate_height;
|
||||
int plate_width, plate_depth;
|
||||
double plate_height;
|
||||
partplate_list.get_plate_size(plate_width, plate_depth, plate_height);
|
||||
float depth = wipe_tower_size(1);
|
||||
float margin = 15.f, wp_brim_width = 0.f;
|
||||
@@ -5238,6 +5354,8 @@ int CLI::run(int argc, char **argv)
|
||||
arrange_cfg.clearance_height_to_rod = height_to_rod;
|
||||
arrange_cfg.clearance_height_to_lid = height_to_lid;
|
||||
arrange_cfg.clearance_radius = clearance_radius;
|
||||
arrange_cfg.nozzle_height = nozzle_height;
|
||||
arrange_cfg.align_center = align_center;
|
||||
arrange_cfg.printable_height = print_height;
|
||||
arrange_cfg.min_obj_distance = 0;
|
||||
if (arrange_cfg.is_seq_print) {
|
||||
@@ -6497,13 +6615,26 @@ int CLI::run(int argc, char **argv)
|
||||
bool need_create_thumbnail_group = false, need_create_no_light_group = false, need_create_top_group = false;
|
||||
|
||||
// get type and color for platedata
|
||||
auto* filament_types = dynamic_cast<const ConfigOptionStrings*>(m_print_config.option("filament_type"));
|
||||
const ConfigOptionStrings* filament_color = dynamic_cast<const ConfigOptionStrings *>(m_print_config.option("filament_colour"));
|
||||
auto* filament_id = dynamic_cast<const ConfigOptionStrings*>(m_print_config.option("filament_ids"));
|
||||
const ConfigOptionFloats* nozzle_diameter_option = dynamic_cast<const ConfigOptionFloats *>(m_print_config.option("nozzle_diameter"));
|
||||
std::string nozzle_diameter_str;
|
||||
if (nozzle_diameter_option)
|
||||
nozzle_diameter_str = nozzle_diameter_option->serialize();
|
||||
#ifdef SLIC3R_GUI
|
||||
// A Bambu printer reads slice_info.config and knows only its own catalog ids. The GUI
|
||||
// gates the same translation on PresetBundle::is_bbl_vendor(); the CLI has no
|
||||
// PresetBundle, so reuse the printer_model prefix that already decides
|
||||
// Print::is_BBL_printer() for this same run.
|
||||
auto* printer_model_option = dynamic_cast<const ConfigOptionString*>(m_print_config.option("printer_model"));
|
||||
const bool is_bbl_printer = printer_model_option && printer_model_option->value.compare(0, 9, "Bambu Lab") == 0;
|
||||
// No wxApp on the CLI path, so there is no live agent to ask; the translator is stateless
|
||||
// over a lazily loaded map, so one instance serves every plate and filament below.
|
||||
// ORCA TODO: this assumes Bambu's is the only agent with a catalog of its own. Once another
|
||||
// agent carries one, resolve the agent from the selected printer the way
|
||||
// GUI_App::resolve_printer_agent_id does, rather than hard-coding BBLPrinterAgent here.
|
||||
const BBLPrinterAgent bbl_agent;
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
for (int i = 0; i < plate_data_list.size(); i++) {
|
||||
PlateData *plate_data = plate_data_list[i];
|
||||
@@ -6516,10 +6647,15 @@ int CLI::run(int argc, char **argv)
|
||||
plate_data->nozzle_diameters = nozzle_diameter_str;
|
||||
|
||||
for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) {
|
||||
// get_at() on an empty vector option is UB - these can be unpopulated on a from-scratch slice
|
||||
std::string display_filament_type;
|
||||
it->type = m_print_config.get_filament_type(display_filament_type, it->id);
|
||||
it->color = filament_color ? filament_color->get_at(it->id) : "#FFFFFF";
|
||||
it->filament_id = filament_id?filament_id->get_at(it->id):"";
|
||||
it->color = (filament_color && !filament_color->values.empty()) ? filament_color->get_at(it->id) : "#FFFFFF";
|
||||
it->filament_id = (filament_id && !filament_id->values.empty()) ? filament_id->get_at(it->id) : "";
|
||||
#ifdef SLIC3R_GUI
|
||||
if (is_bbl_printer)
|
||||
it->filament_id = bbl_agent.from_orca_filament_id(it->filament_id);
|
||||
#endif /* SLIC3R_GUI */
|
||||
}
|
||||
|
||||
if (!plate_data->plate_thumbnail.is_valid()) {
|
||||
@@ -7311,6 +7447,10 @@ bool CLI::setup(int argc, char **argv)
|
||||
m_config.option(optdef.first, true);
|
||||
|
||||
set_data_dir(m_config.opt_string("datadir"));
|
||||
if (!data_dir().empty() && !boost::filesystem::exists(data_dir())) {
|
||||
boost::nowide::cerr << "Could not create data directory: " << data_dir() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet.
|
||||
if (!validity.empty()) {
|
||||
@@ -7423,6 +7563,10 @@ bool CLI::export_models(IO::ExportFormat format, std::string path_dir)
|
||||
for (ModelObject* model_object : model.objects)
|
||||
{
|
||||
const std::string path = this->output_filepath(*model_object, index++, format, path_dir);
|
||||
if (path.empty()) {
|
||||
boost::nowide::cerr << "Could not create output directory for STL export" << std::endl;
|
||||
return false;
|
||||
}
|
||||
success = Slic3r::store_stl(path.c_str(), model_object, true);
|
||||
if (success)
|
||||
BOOST_LOG_TRIVIAL(info) << "Model successfully exported to " << path << std::endl;
|
||||
@@ -7548,8 +7692,19 @@ std::string CLI::output_filepath(const ModelObject &object, unsigned int index,
|
||||
output_path = subdir + "/"+file_name;
|
||||
|
||||
boost::filesystem::path subdir_path(subdir);
|
||||
if (!boost::filesystem::exists(subdir_path))
|
||||
boost::filesystem::create_directory(subdir_path);
|
||||
if (!boost::filesystem::exists(subdir_path)) {
|
||||
try {
|
||||
boost::filesystem::create_directories(subdir_path);
|
||||
} catch (const boost::filesystem::filesystem_error &ex) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to create output directory " << subdir_path.string() << ": " << ex.what();
|
||||
}
|
||||
if (!boost::filesystem::exists(subdir_path)) {
|
||||
// Directory creation failed and won't succeed on a retry (same path, same cause) -
|
||||
// signal failure now instead of letting every object in the model repeat the same
|
||||
// doomed attempt and fail with a less specific "export failed" error later.
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
return output_path;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <boost/format.hpp>
|
||||
#include <mutex>
|
||||
|
||||
#include "git_commit_hash.h"
|
||||
#include "libslic3r_version.h"
|
||||
|
||||
static std::string g_log_folder;
|
||||
@@ -39,7 +40,7 @@ CBaseException::CBaseException(HANDLE hProcess, WORD wPID, LPCTSTR lpSymbolPath,
|
||||
output_file->open(log_filename, std::ios::out | std::ios::app);
|
||||
|
||||
// Output app build info in crash log so we could look for the correct PDB files
|
||||
OutputString(_T("%s\n\n"), _T(SLIC3R_APP_NAME " " SoftFever_VERSION " Build " GIT_COMMIT_HASH));
|
||||
OutputString(_T("%s\n\n"), _T(SLIC3R_APP_NAME " " SoftFever_VERSION " Build " GIT_COMMIT_HASH GIT_COMMIT_SUFFIX));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,17 @@ void select_printer_default_presets(PresetBundle &bundle)
|
||||
if (const auto *def_fil = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile");
|
||||
def_fil != nullptr && !def_fil->values.empty())
|
||||
bundle.filaments.select_preset_by_name(def_fil->values.front(), /*force=*/true);
|
||||
// Re-seed the per-slot filament list from that selection, or the sweep's result depends on the
|
||||
// printer sliced before it. Once there are 2+ slots, full_config() builds the filament config from
|
||||
// filament_presets and ignores the selected preset (PresetBundle::full_fff_config), while
|
||||
// update_compatible() only replaces a slot that has gone *incompatible* - and when it does, it ranks
|
||||
// the outgoing preset's alias, then its filament type, above the printer's own default. The sweep
|
||||
// grows every printer to 2 slots and update_multi_material_filament_presets() never shrinks them, so
|
||||
// a material picked up on the first printer rides the whole run. With all vendors loaded the first
|
||||
// printer inherits a TPU (the load-time pick is whichever filament sorts first), the type match
|
||||
// re-resolves it to "Generic TPU @System", and its alias then pins every later printer to that
|
||||
// vendor's own "Generic TPU @..." - which the BBL dual-nozzle profiles rightly refuse to group.
|
||||
bundle.filament_presets.assign(1, bundle.filaments.get_selected_preset_name());
|
||||
}
|
||||
|
||||
// The vendor/printer currently being sliced, stamped onto every engine log record by the sink below so
|
||||
@@ -381,7 +392,7 @@ int main(int argc, char* argv[])
|
||||
("generate_presets,g", po::value<bool>()->default_value(false), "Generate user presets for mock test")
|
||||
("slice,s", po::bool_switch()->default_value(false), "Slice a two-colour cube through every printer to expand all custom g-code (catches placeholder/flow errors that static checks miss). Off unless this flag is present.")
|
||||
("outdir,o", po::value<std::string>()->default_value(""), "With -s, also save each printer's g-code to this folder (as <vendor>__<printer>.gcode) for manual inspection. Optional.")
|
||||
("check_filament_subtypes,f", po::bool_switch()->default_value(false), "Also flag printers with duplicate (ambiguous) filament subtypes. Off unless this flag is present.")
|
||||
("check_filament_subtypes,f", po::bool_switch()->default_value(true), "Also flag printers with duplicate (ambiguous) filament subtypes. Off unless this flag is present.")
|
||||
("log_level,l", po::value<int>()->default_value(2), "Log level. Optional, default is 2 (warning). Higher values produce more detailed logs.");
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1823,4 +1823,9 @@ bool AppConfig::exists()
|
||||
return boost::filesystem::exists(config_path());
|
||||
}
|
||||
|
||||
std::string AppConfig::load_if_exists()
|
||||
{
|
||||
return boost::filesystem::exists(loading_path()) ? load() : std::string();
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
@@ -113,8 +113,10 @@ public:
|
||||
void set_defaults();
|
||||
|
||||
// Load the slic3r.ini from a user profile directory (or a datadir, if configured).
|
||||
// return error string or empty strinf
|
||||
// Return an error string, or an empty string on success.
|
||||
std::string load();
|
||||
// Treat a missing config as default state; otherwise load it normally.
|
||||
std::string load_if_exists();
|
||||
// Store the slic3r.ini into a user profile directory (or a datadir, if configured).
|
||||
void save();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "BlacklistedLibraryCheck.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
@@ -13,7 +13,6 @@ BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double
|
||||
: m_bed_shape(printable_area), m_max_print_height(printable_height), m_extruder_shapes(extruder_areas), m_extruder_printable_height(extruder_printable_heights)
|
||||
{
|
||||
assert(printable_height >= 0);
|
||||
//assert(extruder_printable_heights.size() == extruder_areas.size());
|
||||
|
||||
m_polygon = Polygon::new_scale(printable_area);
|
||||
assert(m_polygon.is_counter_clockwise());
|
||||
@@ -86,6 +85,9 @@ BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double
|
||||
m_shared_volume.data[2] = m_bboxf.max.x();
|
||||
m_shared_volume.data[3] = m_bboxf.max.y();
|
||||
m_shared_volume.zs[1] = m_bboxf.max.z();
|
||||
if (extruder_printable_heights.size() < m_extruder_shapes.size())
|
||||
BOOST_LOG_TRIVIAL(warning) << boost::format("extruder_printable_height has only %1% entries but extruder_printable_area has %2%, falling back to the bed printable_height for the missing ones")
|
||||
% extruder_printable_heights.size() % m_extruder_shapes.size();
|
||||
for (unsigned int index = 0; index < m_extruder_shapes.size(); index++)
|
||||
{
|
||||
std::vector<Vec2d>& extruder_shape = m_extruder_shapes[index];
|
||||
@@ -100,7 +102,9 @@ BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double
|
||||
return;
|
||||
}
|
||||
|
||||
if ((extruder_shape == printable_area)&&(extruder_printable_heights[index] == printable_height)) {
|
||||
const double extruder_height = index < extruder_printable_heights.size() ? extruder_printable_heights[index] : printable_height;
|
||||
|
||||
if ((extruder_shape == printable_area)&&(extruder_height == printable_height)) {
|
||||
extruder_volume.same_with_bed = true;
|
||||
extruder_volume.type = m_type;
|
||||
extruder_volume.bbox = m_bbox;
|
||||
@@ -113,7 +117,7 @@ BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double
|
||||
double poly_area = poly.area();
|
||||
extruder_volume.bbox = get_extents(poly);
|
||||
BoundingBoxf temp_bboxf = get_extents(extruder_shape);
|
||||
extruder_volume.bboxf = BoundingBoxf3{ to_3d(temp_bboxf.min, 0.), to_3d(temp_bboxf.max, extruder_printable_heights[index]) };
|
||||
extruder_volume.bboxf = BoundingBoxf3{ to_3d(temp_bboxf.min, 0.), to_3d(temp_bboxf.max, extruder_height) };
|
||||
|
||||
if (extruder_shape.size() >= 4 && std::abs((poly_area - double(extruder_volume.bbox.size().x()) * double(extruder_volume.bbox.size().y()))) < sqr(SCALED_EPSILON))
|
||||
{
|
||||
|
||||
@@ -147,6 +147,8 @@ set(lisbslic3r_sources
|
||||
Fill/FillBase.hpp
|
||||
Fill/FillConcentric.cpp
|
||||
Fill/FillConcentric.hpp
|
||||
Fill/FillSpiralInset.cpp
|
||||
Fill/FillSpiralInset.hpp
|
||||
Fill/FillConcentricInternal.cpp
|
||||
Fill/FillConcentricInternal.hpp
|
||||
Fill/FillCornerSmoothing.cpp
|
||||
@@ -665,6 +667,13 @@ if(SLIC3R_PROFILE)
|
||||
target_link_libraries(libslic3r PRIVATE Shiny)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
# Public, since BlacklistedLibraryCheck.hpp includes windows.h. Empty
|
||||
# WIN32_LEAN_AND_MEAN matches the sources that define it themselves; bare
|
||||
# NOMINMAX matches the one libigl already passes.
|
||||
target_compile_definitions(libslic3r PUBLIC "WIN32_LEAN_AND_MEAN=" "NOMINMAX")
|
||||
endif ()
|
||||
|
||||
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
|
||||
add_precompiled_header(libslic3r pchheader.hpp FORCEINCLUDE)
|
||||
endif ()
|
||||
|
||||
@@ -1049,7 +1049,8 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
|
||||
std::vector<std::string>& different_settings = this->option<ConfigOptionStrings>("different_settings_to_system", true)->values;
|
||||
size_t size = different_settings.size();
|
||||
if (size == 0) {
|
||||
size = this->option<ConfigOptionStrings>("filament_settings_id")->values.size() + 2;
|
||||
const auto *filament_ids = this->option<ConfigOptionStrings>("filament_settings_id");
|
||||
size = (filament_ids ? filament_ids->values.size() : 0) + 2;
|
||||
different_settings.resize(size);
|
||||
}
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@ void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkin
|
||||
}
|
||||
|
||||
// Thanks Cura developers for this function.
|
||||
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg, bool closed)
|
||||
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, coordf_t layer_height, const FuzzySkinConfig& cfg, bool closed)
|
||||
{
|
||||
|
||||
if (cfg.noise_type == NoiseType::Ripple) {
|
||||
@@ -356,7 +356,9 @@ void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice
|
||||
|
||||
const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
|
||||
const double range_random_point_dist = cfg.point_distance / 2.;
|
||||
const double min_extrusion_width = 0.01; // workaround for many print options. Need overwrite formula with the layer height parameter. The width must more than >>> layer_height * (1 - 0.25 * PI) * 1.05 <<< (last num is the coeff of overlay error case)
|
||||
// ExtrusionJunction::w is a scaled coord_t, so this floor must be scaled too.
|
||||
// Flow::rounded_rectangle_extrusion_spacing() requires width > height * (1 - 0.25 * PI); keep 5% above it.
|
||||
const double min_extrusion_width = scaled<double>(layer_height * (1. - 0.25 * M_PI) * 1.05);
|
||||
double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point
|
||||
|
||||
auto* p0 = &ext_lines.front();
|
||||
@@ -685,12 +687,13 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
|
||||
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, const bool is_contour, const bool closed)
|
||||
{
|
||||
const auto slice_z = perimeter_generator.slice_z;
|
||||
const auto layer_height = perimeter_generator.layer_height;
|
||||
const auto& regions = perimeter_generator.regions_by_fuzzify;
|
||||
if (regions.size() == 1) { // optimization
|
||||
const auto& config = regions.begin()->first;
|
||||
const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, extrusion->inset_idx, is_contour);
|
||||
if (fuzzify)
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, config, closed);
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, perimeter_generator.layer_height, config, closed);
|
||||
} else {
|
||||
// Merge regions that produce identical fuzzy effects (differ only in type).
|
||||
// When the style (e.g. External) and a painted region (All) both fuzzify this loop
|
||||
@@ -701,7 +704,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
|
||||
// Fast path: single merged region — apply directly without splitting
|
||||
if (merged_regions.size() == 1 && merged_regions.front().expolygons.empty()) {
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, *merged_regions.front().config, closed);
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, perimeter_generator.layer_height, *merged_regions.front().config, closed);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -761,7 +764,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
// Fuzzy splitted extrusion
|
||||
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
|
||||
// The entire polygon is fuzzified
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, *r.config, closed);
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, perimeter_generator.layer_height, *r.config, closed);
|
||||
continue;
|
||||
} else {
|
||||
const auto current_ext = extrusion->junctions;
|
||||
@@ -769,12 +772,12 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
segment.reserve(current_ext.size());
|
||||
extrusion->junctions.clear();
|
||||
|
||||
const auto fuzzy_current_segment = [&segment, &extrusion, &r, slice_z]() {
|
||||
const auto fuzzy_current_segment = [&segment, &extrusion, &r, slice_z, layer_height]() {
|
||||
// Orca: non fuzzy points to isolate fuzzy region
|
||||
const auto front = segment.front();
|
||||
const auto back = segment.back();
|
||||
|
||||
fuzzy_extrusion_line(segment, slice_z, *r.config, false);
|
||||
fuzzy_extrusion_line(segment, slice_z, layer_height, *r.config, false);
|
||||
// Orca: only add non fuzzy point if it's not in the extrusion closing point.
|
||||
if (!extrusion->junctions.empty() && extrusion->junctions.front().p != front.p) {
|
||||
extrusion->junctions.push_back(front);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Slic3r::Feature::FuzzySkin {
|
||||
|
||||
void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkinConfig& cfg);
|
||||
|
||||
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg, bool closed = true);
|
||||
void fuzzy_extrusion_line(Arachne::ExtrusionJunctions& ext_lines, coordf_t slice_z, coordf_t layer_height, const FuzzySkinConfig& cfg, bool closed = true);
|
||||
|
||||
void group_region_by_fuzzify(PerimeterGenerator& g);
|
||||
|
||||
|
||||
@@ -950,7 +950,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
|
||||
params.extruder = region_config.internal_solid_filament_id;
|
||||
// Orca: forced fill order applies only to top/bottom surfaces filled with a
|
||||
// center-based pattern; everything else stays at Default to keep batching together.
|
||||
if (params.pattern == ipConcentric || params.pattern == ipArchimedeanChords || params.pattern == ipOctagramSpiral) {
|
||||
if (params.pattern == ipConcentric || params.pattern == ipSpiralInset || params.pattern == ipArchimedeanChords || params.pattern == ipOctagramSpiral) {
|
||||
if (params.extrusion_role == erTopSolidInfill)
|
||||
params.fill_order = region_config.top_surface_fill_order.value;
|
||||
else if (params.extrusion_role == erBottomSurface)
|
||||
@@ -1332,7 +1332,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
params.anchor_length = surface_fill.params.anchor_length;
|
||||
params.anchor_length_max = surface_fill.params.anchor_length_max;
|
||||
params.resolution = resolution;
|
||||
params.use_arachne = surface_fill.params.pattern == ipConcentric || surface_fill.params.pattern == ipConcentricInternal;
|
||||
params.use_arachne = surface_fill.params.pattern == ipConcentric || surface_fill.params.pattern == ipSpiralInset ||
|
||||
surface_fill.params.pattern == ipConcentricInternal;
|
||||
params.layer_height = layerm->layer()->height;
|
||||
params.lateral_lattice_angle_1 = surface_fill.params.lateral_lattice_angle_1;
|
||||
params.lateral_lattice_angle_2 = surface_fill.params.lateral_lattice_angle_2;
|
||||
@@ -1515,6 +1516,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
|
||||
case ipCubic:
|
||||
case ipLine:
|
||||
case ipConcentric:
|
||||
case ipSpiralInset:
|
||||
case ipHoneycomb:
|
||||
case ipLateralHoneycomb:
|
||||
case ip3DHoneycomb:
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "FillBase.hpp"
|
||||
#include "FillConcentric.hpp"
|
||||
#include "FillSpiralInset.hpp"
|
||||
#include "FillHoneycomb.hpp"
|
||||
#include "Fill3DHoneycomb.hpp"
|
||||
#include "FillGyroid.hpp"
|
||||
@@ -41,6 +42,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
||||
{
|
||||
switch (type) {
|
||||
case ipConcentric: return new FillConcentric();
|
||||
case ipSpiralInset: return new FillSpiralInset();
|
||||
case ipHoneycomb: return new FillHoneycomb();
|
||||
case ipLateralHoneycomb: return new FillLateralHoneycomb();
|
||||
case ip3DHoneycomb: return new Fill3DHoneycomb();
|
||||
@@ -2465,9 +2467,11 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
|
||||
#endif // INFILL_DEBUG_OUTPUT
|
||||
|
||||
const std::vector<SupportArcCost> arches = evaluate_support_arches(infill_ordered, graph, spacing, params);
|
||||
static const double cost_low = line_spacing * 1.3;
|
||||
static const double cost_high = line_spacing * 2.;
|
||||
static const double cost_veryhigh = line_spacing * 3.;
|
||||
// Must not be static: line_spacing varies per call (base vs interface fills differ),
|
||||
// and a static here would fix these to whichever call ran first, order depending on thread count.
|
||||
const double cost_low = line_spacing * 1.3;
|
||||
const double cost_high = line_spacing * 2.;
|
||||
const double cost_veryhigh = line_spacing * 3.;
|
||||
|
||||
{
|
||||
std::vector<const SupportArcCost*> selected;
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../ExPolygon.hpp"
|
||||
#include "../Surface.hpp"
|
||||
#include "../VariableWidth.hpp"
|
||||
#include "Arachne/WallToolPaths.hpp"
|
||||
|
||||
#include "FillSpiralInset.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Index of the corner the spiral should start at. Every following loop is split at the point nearest
|
||||
// the end of the one before it, so this choice propagates inwards and decides where the whole spiral
|
||||
// hands over from ring to ring. A tight corner is the worst place for it: there the next ring
|
||||
// retreats along the bisector by spacing/sin(angle), so the spiral has to strike out several spacings
|
||||
// to reach it instead of stepping across to a ring running parallel one spacing away.
|
||||
//
|
||||
// A right angle is taken first when the loop has one. It clips cleanly, since the trimming below
|
||||
// scales with 1/sin(angle) and so is at its shortest and least sensitive there, and it holds its
|
||||
// shape as the loop is offset inwards, which keeps the handover in the same place ring after ring.
|
||||
// Failing that the widest corner is the flattest stretch on offer, which is the next best handover.
|
||||
// A straight point is no corner at all and only turns up as an artefact of the offsetting, so it is
|
||||
// skipped.
|
||||
static int find_spiral_start_corner(const Polygon& loop)
|
||||
{
|
||||
const size_t n = loop.points.size();
|
||||
if (n < 3)
|
||||
return 0;
|
||||
|
||||
// cos(85 deg): a corner within five degrees of square counts as a right angle.
|
||||
static const double right_angle_cos = 0.08716;
|
||||
// cos(179 deg): anything flatter than this counts as a straight point rather than a corner.
|
||||
static const double straight_cos = -0.99985;
|
||||
|
||||
// Only convex corners qualify. A reflex corner spans the same angle between its two edges but
|
||||
// bulges the other way, so the next ring in steps away from it along the bisector instead of
|
||||
// hugging it, and starting there hands over across a long diagonal on every single ring. Loops
|
||||
// arrive counter-clockwise, in which case a convex corner turns left, but check the winding
|
||||
// rather than trust it. A closed loop always has at least one convex corner.
|
||||
const double convex_turn = loop.is_counter_clockwise() ? 1.0 : -1.0;
|
||||
|
||||
double best_right_cos = right_angle_cos;
|
||||
int best_right = -1;
|
||||
double best_wide_cos = 1.0;
|
||||
int best_wide = -1;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const Point& p_prev = loop.points[(i - 1 + n) % n];
|
||||
const Point& p = loop.points[i];
|
||||
const Point& p_next = loop.points[(i + 1) % n];
|
||||
|
||||
Vec2d e_in = (p - p_prev).cast<double>();
|
||||
Vec2d e_out = (p_next - p).cast<double>();
|
||||
double len1 = e_in.norm();
|
||||
double len2 = e_out.norm();
|
||||
if (len1 < 1e-6 || len2 < 1e-6)
|
||||
continue;
|
||||
if (convex_turn * (e_in.x() * e_out.y() - e_in.y() * e_out.x()) <= 0.0)
|
||||
continue;
|
||||
|
||||
// Cosine of the angle the two edges span at the corner: 1 at a spike, 0 square, -1 straight.
|
||||
double cos_val = -e_in.dot(e_out) / (len1 * len2);
|
||||
if (std::abs(cos_val) < best_right_cos) {
|
||||
best_right_cos = std::abs(cos_val);
|
||||
best_right = int(i);
|
||||
}
|
||||
if (cos_val > straight_cos && cos_val < best_wide_cos) {
|
||||
best_wide_cos = cos_val;
|
||||
best_wide = int(i);
|
||||
}
|
||||
}
|
||||
if (best_right >= 0)
|
||||
return best_right;
|
||||
// A loop smooth enough to have no corner at all, a circle say, hands over equally well anywhere.
|
||||
return best_wide < 0 ? 0 : best_wide;
|
||||
}
|
||||
|
||||
// Length to trim off the end of a loop so that it does not overlap the start of the next one.
|
||||
// The theoretical gap is distance/sin(alpha), alpha being the angle between the last segment of the
|
||||
// loop and the first segment of the next one.
|
||||
static double loop_clip_length(const Polyline& loop_path, const double gap)
|
||||
{
|
||||
const Point& p_prev = loop_path.points[loop_path.points.size() - 2];
|
||||
const Point& p_last = loop_path.points.back();
|
||||
const Point& p_next = loop_path.points[1];
|
||||
Vec2d v1 = (p_last - p_prev).cast<double>();
|
||||
Vec2d v2 = (p_next - p_last).cast<double>();
|
||||
if (v1.norm() < 1e-6 || v2.norm() < 1e-6)
|
||||
return gap;
|
||||
|
||||
double alpha = std::atan2(std::abs(v1.x() * v2.y() - v1.y() * v2.x()), v1.dot(v2));
|
||||
// Outside 45deg < alpha < 120deg the 1/sin(alpha) term would clip far too much, so fall back to the plain gap.
|
||||
return (alpha > M_PI / 4 && alpha < 2 * M_PI / 3) ? gap / std::sin(alpha) : gap;
|
||||
}
|
||||
|
||||
// The chaining below drives two kinds of loop: the plain offset polygons of the classic path, and
|
||||
// Arachne's variable width walls. These are the only four steps that differ between them. Widths run
|
||||
// two per segment, so every point added or removed takes a pair with it.
|
||||
static Polyline open_loop(const Polygon& loop, int start_index) { return loop.split_at_index(start_index); }
|
||||
|
||||
static ThickPolyline open_loop(const Arachne::ExtrusionLine& loop, int start_index)
|
||||
{
|
||||
ThickPolyline path = Arachne::to_thick_polyline(loop);
|
||||
// start_at_index() rotates a closed path, and wants it closed with a matching width at both ends.
|
||||
if (path.points.front() != path.points.back()) {
|
||||
const coordf_t w_first = path.width.front(), w_last = path.width.back();
|
||||
path.points.emplace_back(path.points.front());
|
||||
path.width.emplace_back(w_last);
|
||||
path.width.emplace_back(w_first);
|
||||
}
|
||||
path.start_at_index(start_index);
|
||||
return path;
|
||||
}
|
||||
|
||||
static void clip_path_end(Polyline& path, double distance) { path.clip_end(distance); }
|
||||
|
||||
static void clip_path_end(ThickPolyline& path, double distance)
|
||||
{
|
||||
// Polyline::clip_end() knows nothing about the widths, so walk back trimming the two together.
|
||||
while (distance > 0 && path.points.size() >= 2) {
|
||||
const Point last = path.points.back();
|
||||
const coordf_t w_end = path.width.back();
|
||||
path.points.pop_back();
|
||||
path.width.pop_back();
|
||||
const coordf_t w_start = path.width.back();
|
||||
path.width.pop_back();
|
||||
|
||||
const Vec2d v = (path.points.back() - last).cast<double>();
|
||||
const double len = v.norm();
|
||||
if (len > distance) {
|
||||
const double t = distance / len;
|
||||
path.points.emplace_back((last.cast<double>() + v * t).cast<coord_t>());
|
||||
path.width.emplace_back(w_start);
|
||||
path.width.emplace_back(w_start + (w_end - w_start) * (1.0 - t));
|
||||
return;
|
||||
}
|
||||
distance -= len;
|
||||
}
|
||||
path.clear();
|
||||
}
|
||||
|
||||
static void append_path(Polyline& dst, Polyline&& src) { dst.append(std::move(src)); }
|
||||
|
||||
static void append_path(ThickPolyline& dst, ThickPolyline&& src)
|
||||
{
|
||||
if (dst.empty()) {
|
||||
dst = std::move(src);
|
||||
return;
|
||||
}
|
||||
if (dst.points.back() == src.points.front()) {
|
||||
// Carrying straight on from the same point, so there is no run across to give a width to.
|
||||
src.points.erase(src.points.begin());
|
||||
src.width.erase(src.width.begin(), src.width.begin() + 2);
|
||||
} else {
|
||||
// The run across to the next loop tapers between the two ends it joins.
|
||||
const coordf_t w_from = dst.width.back(), w_to = src.width.front();
|
||||
dst.width.emplace_back(w_from);
|
||||
dst.width.emplace_back(w_to);
|
||||
}
|
||||
append(dst.points, std::move(src.points));
|
||||
append(dst.width, std::move(src.width));
|
||||
}
|
||||
|
||||
// The classic loops all carry the same width, so the innermost one of an island can still ring an
|
||||
// unfilled pin hole, which the spiral plugs by running into the middle. Arachne's walls widen to take
|
||||
// up whatever is left over, so there is nothing there to plug and the stub would only double back
|
||||
// over the wall that just filled it.
|
||||
static bool leaves_a_centre_hole(const Polygon&) { return true; }
|
||||
static bool leaves_a_centre_hole(const Arachne::ExtrusionLine&) { return false; }
|
||||
|
||||
static void append_path_point(Polyline& path, const Point& point) { path.points.emplace_back(point); }
|
||||
|
||||
static void append_path_point(ThickPolyline& path, const Point& point)
|
||||
{
|
||||
const coordf_t w = path.width.back();
|
||||
path.points.emplace_back(point);
|
||||
path.width.emplace_back(w);
|
||||
path.width.emplace_back(w);
|
||||
}
|
||||
|
||||
// Chain the loops of one surface into as few continuous spirals as its shape allows. The loops arrive
|
||||
// ordered outside in, depth first, each paired with its outline in loop_outlines; every decision here
|
||||
// is made on those outlines, so the two kinds of loop take exactly the same route.
|
||||
template<class LoopType, class PathType>
|
||||
static std::vector<PathType> generate_spiral_insets(const FillParams& params,
|
||||
const std::vector<const LoopType*>& loops,
|
||||
const Polygons& loop_outlines,
|
||||
const coord_t distance,
|
||||
const ExPolygon& original_expoly)
|
||||
{
|
||||
std::vector<PathType> output;
|
||||
PathType spiral;
|
||||
Point current_pos(0, 0);
|
||||
// Index into loops of the innermost loop appended to the spiral currently being built.
|
||||
int innermost_loop = -1;
|
||||
|
||||
// Whether the spiral can run straight from one point to the other. The run across is extruded,
|
||||
// not travelled, so it has to be a genuine step over to the ring alongside:
|
||||
// - up to a ring spacing and a half it cannot leave the material, and needs no check at all,
|
||||
// which covers all but a few of the loops;
|
||||
// - beyond that it is tested against the surface, which catches the points that are close in a
|
||||
// straight line but separated by a hole or a notch;
|
||||
// - past four spacings it is refused outright. A handover does stretch at a corner, where the
|
||||
// next ring retreats along the bisector by spacing/sin(angle), but four spacings is already a
|
||||
// fifteen degree wedge, and down a wedge that tight the run across would trace the bisector,
|
||||
// which is where the tail is filled from anyway. Anything longer is a traverse across the
|
||||
// surface that prints over what it crosses. Breaking the spiral leaves the G-code to travel it.
|
||||
const double free_hop = 1.5 * double(distance);
|
||||
const double max_hop = 4.0 * double(distance);
|
||||
auto reachable = [&](const Point& from, const Point& to) {
|
||||
const double hop = from.distance_to(to);
|
||||
if (hop > max_hop)
|
||||
return false;
|
||||
return hop <= free_hop || original_expoly.contains(Line(from, to));
|
||||
};
|
||||
|
||||
// The centre point plugs the pin hole left in the middle of an island, it is not meant to
|
||||
// traverse it, so it is only worth adding when the innermost loop has shrunk to about a ring.
|
||||
const double max_center_stub = 2.0 * double(distance);
|
||||
|
||||
// Emit the spiral built so far as one path and start over on a fresh island.
|
||||
auto flush_spiral = [&]() {
|
||||
if (spiral.empty())
|
||||
return;
|
||||
// Run into the middle of the innermost loop so the island's centre is filled instead of being
|
||||
// left as a pin hole. Only where there is a hole to fill: the loop has to still enclose open
|
||||
// space once its own bead is accounted for, or the stub just runs back over that bead. And
|
||||
// the point has to sit inside the loop and be reachable, or it runs off across the surface.
|
||||
if (innermost_loop >= 0 && leaves_a_centre_hole(*loops[innermost_loop])) {
|
||||
const Polygon& innermost = loop_outlines[innermost_loop];
|
||||
const Point centroid = innermost.centroid();
|
||||
if (!offset(innermost, -float(0.5 * double(distance))).empty() && centroid != spiral.last_point() &&
|
||||
spiral.last_point().distance_to(centroid) <= max_center_stub && innermost.contains(centroid) &&
|
||||
reachable(spiral.last_point(), centroid))
|
||||
append_path_point(spiral, centroid);
|
||||
}
|
||||
output.emplace_back(std::move(spiral));
|
||||
spiral.clear();
|
||||
innermost_loop = -1;
|
||||
current_pos = Point(0, 0);
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < loops.size(); ++i) {
|
||||
const Polygon& outline = loop_outlines[i];
|
||||
if (outline.points.empty())
|
||||
continue;
|
||||
|
||||
// The loop is opened into a path with the split point repeated at both ends, so a usable one
|
||||
// has at least 3 points. Both kinds of loop share the outline's indices, hence its start point.
|
||||
PathType loop_path = open_loop(*loops[i], spiral.empty() ? find_spiral_start_corner(outline) :
|
||||
current_pos.nearest_point_index(outline.points));
|
||||
if (loop_path.size() < 3)
|
||||
continue;
|
||||
|
||||
// Island jumping: the loops are ordered by their nesting, depth first, so the next one
|
||||
// continues the current spiral exactly when it lies inside the one just laid down. Distance
|
||||
// cannot stand in for that test: at a sharp corner the next ring retreats along the bisector
|
||||
// by spacing/sin(angle), which leaves it several spacings away while still being the very
|
||||
// next ring in, and the spiral would break off at every spike.
|
||||
const bool same_island = innermost_loop >= 0 && loop_outlines[innermost_loop].contains(loop_path.points.front());
|
||||
if (!spiral.empty() && (!same_island || !reachable(spiral.last_point(), loop_path.points.front()))) {
|
||||
flush_spiral();
|
||||
loop_path = open_loop(*loops[i], find_spiral_start_corner(outline));
|
||||
if (loop_path.size() < 3)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clip the end of the loop to leave room for the run into the next one. The last loop of the
|
||||
// surface has no successor, so it only gives up half of the gap.
|
||||
clip_path_end(loop_path, loop_clip_length(loop_path, (i + 1 == loops.size() ? 0.5 : 1.0) * double(distance)));
|
||||
// Clipping empties the path when the loop is shorter than the clipping length, which happens
|
||||
// on the degenerate slivers that offsetting leaves behind. Such a loop carries no extrusion.
|
||||
if (loop_path.size() < 2)
|
||||
continue;
|
||||
|
||||
append_path(spiral, std::move(loop_path));
|
||||
innermost_loop = int(i);
|
||||
current_pos = spiral.last_point();
|
||||
}
|
||||
|
||||
flush_spiral();
|
||||
|
||||
// An outward fill order runs every spiral from its centre to its outer edge, innermost island first.
|
||||
if (params.fill_order != SurfaceFillOrder::Inward) {
|
||||
for (PathType& path : output)
|
||||
path.reverse();
|
||||
std::reverse(output.begin(), output.end());
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void FillSpiralInset::_fill_surface_single(const FillParams& params,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point>& direction,
|
||||
ExPolygon expolygon,
|
||||
Polylines& polylines_out)
|
||||
{
|
||||
BoundingBox bounding_box = expolygon.contour.bounding_box();
|
||||
|
||||
coord_t min_spacing = scale_(this->spacing);
|
||||
coord_t distance = coord_t(min_spacing / params.density);
|
||||
|
||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
|
||||
this->spacing = unscale<double>(distance);
|
||||
}
|
||||
|
||||
Polygons loops = to_polygons(expolygon);
|
||||
|
||||
ExPolygons last{std::move(expolygon)};
|
||||
while (!last.empty()) {
|
||||
last = offset2_ex(last, -(distance + min_spacing / 2), +min_spacing / 2);
|
||||
append(loops, to_polygons(last));
|
||||
}
|
||||
|
||||
// Orders the loops outside in, depth first, which is the order the chaining below expects.
|
||||
loops = union_pt_chained_outside_in(loops);
|
||||
|
||||
std::vector<const Polygon*> loop_refs;
|
||||
loop_refs.reserve(loops.size());
|
||||
for (const Polygon& loop : loops)
|
||||
loop_refs.emplace_back(&loop);
|
||||
|
||||
Polylines spiral_result = generate_spiral_insets<Polygon, Polyline>(params, loop_refs, loops, distance, expolygon);
|
||||
|
||||
append(polylines_out, spiral_result);
|
||||
}
|
||||
|
||||
void FillSpiralInset::_fill_surface_single(const FillParams& params,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point>& direction,
|
||||
ExPolygon expolygon,
|
||||
ThickPolylines& thick_polylines_out)
|
||||
{
|
||||
assert(params.use_arachne);
|
||||
assert(this->print_config != nullptr && this->print_object_config != nullptr);
|
||||
|
||||
// Only a solid surface is worth the variable width walls; a sparse one falls back to plain loops.
|
||||
if (params.density <= 0.9999f || params.dont_adjust) {
|
||||
Polylines polylines;
|
||||
this->_fill_surface_single(params, thickness_layers, direction, expolygon, polylines);
|
||||
append(thick_polylines_out, to_thick_polylines(std::move(polylines), scaled<coord_t>(this->spacing)));
|
||||
return;
|
||||
}
|
||||
|
||||
// no rotation is supported for this infill pattern
|
||||
Point bbox_size = expolygon.contour.bounding_box().size();
|
||||
coord_t min_spacing = scaled<coord_t>(this->spacing);
|
||||
|
||||
coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
|
||||
Polygons polygons = offset(expolygon, float(min_spacing) / 2.f);
|
||||
|
||||
double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end());
|
||||
Arachne::WallToolPathsParams input_params;
|
||||
input_params.min_bead_width = 0.85 * min_nozzle_diameter;
|
||||
input_params.min_feature_size = 0.25 * min_nozzle_diameter;
|
||||
input_params.wall_transition_length = 1.0 * min_nozzle_diameter;
|
||||
input_params.wall_transition_angle = 10;
|
||||
input_params.wall_transition_filter_deviation = 0.25 * min_nozzle_diameter;
|
||||
input_params.wall_distribution_count = 1;
|
||||
|
||||
Arachne::WallToolPaths wallToolPaths(polygons, min_spacing, min_spacing, loops_count, 0, params.layer_height, input_params);
|
||||
std::vector<Arachne::VariableWidthLines> walls_by_inset = wallToolPaths.getToolPaths();
|
||||
|
||||
// Open walls are the thin features Arachne fits between the closed ones. They cannot join a
|
||||
// spiral, so they go out as they are; leaving them behind is what would put the gaps back.
|
||||
std::vector<const Arachne::ExtrusionLine*> walls;
|
||||
Polygons wall_outlines;
|
||||
ThickPolylines open_walls;
|
||||
for (const Arachne::VariableWidthLines& inset : walls_by_inset)
|
||||
for (const Arachne::ExtrusionLine& wall : inset) {
|
||||
if (wall.empty())
|
||||
continue;
|
||||
if (wall.is_closed) {
|
||||
walls.emplace_back(&wall);
|
||||
wall_outlines.emplace_back(wall.toPolygon());
|
||||
} else {
|
||||
open_walls.emplace_back(Arachne::to_thick_polyline(wall));
|
||||
}
|
||||
}
|
||||
|
||||
// Arachne hands the walls back grouped by inset, which is not their nesting: around a hole the
|
||||
// wall of a given inset lies inside the wall of that same inset around the contour. Nest them by
|
||||
// containment instead, so the spiral follows one island all the way in before starting the next,
|
||||
// the same order union_pt_chained_outside_in gives the classic path above.
|
||||
const size_t wall_count = walls.size();
|
||||
std::vector<int> nesting_depth(wall_count, 0), parent(wall_count, -1);
|
||||
std::vector<char> inside(wall_count * wall_count, 0);
|
||||
for (size_t i = 0; i < wall_count; ++i)
|
||||
for (size_t j = 0; j < wall_count; ++j)
|
||||
if (i != j && wall_outlines[j].contains(walls[i]->junctions.front().p)) {
|
||||
inside[i * wall_count + j] = 1;
|
||||
++nesting_depth[i];
|
||||
}
|
||||
// The innermost of the walls containing this one, which is the deepest of them, is its parent.
|
||||
for (size_t i = 0; i < wall_count; ++i)
|
||||
for (size_t j = 0; j < wall_count; ++j)
|
||||
if (inside[i * wall_count + j] && (parent[i] < 0 || nesting_depth[parent[i]] < nesting_depth[j]))
|
||||
parent[i] = int(j);
|
||||
|
||||
std::vector<const Arachne::ExtrusionLine*> ordered;
|
||||
Polygons outlines;
|
||||
ordered.reserve(wall_count);
|
||||
outlines.reserve(wall_count);
|
||||
std::function<void(int)> descend = [&](int idx) {
|
||||
ordered.emplace_back(walls[idx]);
|
||||
outlines.emplace_back(wall_outlines[idx]);
|
||||
for (size_t k = 0; k < wall_count; ++k)
|
||||
if (parent[k] == idx)
|
||||
descend(int(k));
|
||||
};
|
||||
for (size_t i = 0; i < wall_count; ++i)
|
||||
if (parent[i] < 0)
|
||||
descend(int(i));
|
||||
|
||||
ThickPolylines spiral_result =
|
||||
generate_spiral_insets<Arachne::ExtrusionLine, ThickPolyline>(params, ordered, outlines, min_spacing, expolygon);
|
||||
|
||||
append(thick_polylines_out, std::move(spiral_result));
|
||||
append(thick_polylines_out, std::move(open_walls));
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef slic3r_FillSpiralInset_hpp_
|
||||
#define slic3r_FillSpiralInset_hpp_
|
||||
|
||||
#include "FillBase.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class FillSpiralInset : public Fill
|
||||
{
|
||||
public:
|
||||
~FillSpiralInset() override = default;
|
||||
bool is_self_crossing() override { return false; }
|
||||
|
||||
protected:
|
||||
Fill* clone() const override { return new FillSpiralInset(*this); };
|
||||
void _fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point> &direction,
|
||||
ExPolygon expolygon,
|
||||
Polylines &polylines_out) override;
|
||||
|
||||
// Orca: solid surfaces are filled with Arachne's variable width walls, which widen to take up
|
||||
// whatever the fixed width loops above would have left over as gaps.
|
||||
void _fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
const std::pair<float, Point> &direction,
|
||||
ExPolygon expolygon,
|
||||
ThickPolylines &thick_polylines_out) override;
|
||||
|
||||
bool no_sort() const override { return true; }
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_FillSpiralInset_hpp_
|
||||
@@ -40,8 +40,8 @@ static float DeltaHS_BBS(float h1, float s1, float v1, float h2, float s2, float
|
||||
return std::min(1.2f, dxy);
|
||||
}
|
||||
|
||||
FlushVolCalculator::FlushVolCalculator(int min, int max, int flush_dataset, float multiplier)
|
||||
:m_min_flush_vol(min), m_max_flush_vol(max), m_multiplier(multiplier), m_flush_dataset(flush_dataset)
|
||||
FlushVolCalculator::FlushVolCalculator(int min, int max, int flush_dataset)
|
||||
:m_min_flush_vol(min), m_max_flush_vol(max), m_flush_dataset(flush_dataset)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ extern const int g_max_flush_volume;
|
||||
class FlushVolCalculator
|
||||
{
|
||||
public:
|
||||
FlushVolCalculator(int min, int max, int flush_dataset, float multiplier = 1.0f);
|
||||
FlushVolCalculator(int min, int max, int flush_dataset);
|
||||
~FlushVolCalculator()
|
||||
{
|
||||
}
|
||||
@@ -32,7 +32,6 @@ public:
|
||||
private:
|
||||
int m_min_flush_vol;
|
||||
int m_max_flush_vol;
|
||||
float m_multiplier;
|
||||
int m_flush_dataset;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ class FanMover
|
||||
private:
|
||||
const std::regex regex_fan_speed;
|
||||
const float nb_seconds_delay;
|
||||
const bool with_D_option;
|
||||
// Set from fan_speedup_time at the call site, but nothing here reads it.
|
||||
[[maybe_unused]] const bool with_D_option;
|
||||
const bool relative_e;
|
||||
const bool only_overhangs;
|
||||
const float kickstart;
|
||||
|
||||
@@ -125,7 +125,6 @@ public:
|
||||
/******************************************** Splitting the 128bit number into two 64bit words *********************************************/
|
||||
|
||||
Int128(int64_t lo = 0) : m_lo((uint64_t)lo), m_hi((lo < 0) ? -1 : 0) {}
|
||||
Int128(const Int128 &val) : m_lo(val.m_lo), m_hi(val.m_hi) {}
|
||||
Int128(const int64_t& hi, const uint64_t& lo) : m_lo(lo), m_hi(hi) {}
|
||||
|
||||
Int128& operator = (const int64_t &val)
|
||||
|
||||
@@ -419,6 +419,7 @@ coordf_t Layer::get_sparse_infill_max_void_area()
|
||||
double spacing = flow.scaled_spacing() * (100 - density) / density;
|
||||
switch (pattern) {
|
||||
case ipConcentric:
|
||||
case ipSpiralInset:
|
||||
case ipRectilinear:
|
||||
case ipLine:
|
||||
case ipGyroid:
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
explicit MultiPoint(const Points &_points) : points(_points) {}
|
||||
MultiPoint& operator=(const MultiPoint &other) { points = other.points; return *this; }
|
||||
MultiPoint& operator=(MultiPoint &&other) { points = std::move(other.points); return *this; }
|
||||
virtual ~MultiPoint() = default;
|
||||
void scale(double factor);
|
||||
void scale(double factor_x, double factor_y);
|
||||
void translate(double x, double y) { this->translate(Point(coord_t(x), coord_t(y))); }
|
||||
|
||||
@@ -2127,7 +2127,7 @@ void PerimeterGenerator::process_no_bridge(Surfaces& all_surfaces, coord_t perim
|
||||
bridgeable_filtered = union_ex(offset_ex(remaining, perimeter_spacing), bridgeable_filtered);
|
||||
bridgeable_filtered = offset_ex(bridgeable_filtered, -perimeter_spacing);
|
||||
bridgeable_filtered = diff_ex(bridgeable_filtered, remaining, ApplySafetyOffset::Yes);
|
||||
bridgeable_filtered = opening_ex(bridgeable_filtered, perimeter_spacing); // filter noise from the diff_ex
|
||||
bridgeable_filtered = opening_ex(bridgeable_filtered, ext_perimeter_width / 2); // filter noise from the diff_ex
|
||||
bridgeable_filtered = offset_ex(bridgeable_filtered, perimeter_spacing); // restore the size to the original bridgeable area
|
||||
// Safety measure: Keep the bridge mask from intruding deeper into the
|
||||
// supported anchor region than the explicit anchor overlap.
|
||||
|
||||
+13
-11
@@ -545,7 +545,7 @@ std::string generate_preset_setting_id(const std::string& vendor, const std::str
|
||||
return "";
|
||||
|
||||
// Dedicated namespace for preset setting_ids, distinct from the cloud per-user
|
||||
// namespace (OrcaCloudServiceAgent). Keep in sync with scripts/assign_vendor_setting_ids.py;
|
||||
// namespace (OrcaCloudServiceAgent). Keep in sync with scripts/orca_id_tool.py;
|
||||
// never change this constant.
|
||||
static const boost::uuids::uuid vendor_namespace =
|
||||
boost::uuids::string_generator()("c1f4d9e2-7a3b-5c8d-9e0f-1a2b3c4d5e6f");
|
||||
@@ -1653,7 +1653,7 @@ std::string PresetCollection::canonical_preset_name(const std::string &name, con
|
||||
void PresetCollection::load_presets(
|
||||
const std::string &dir_path, const std::string &subdir,
|
||||
PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule substitution_rule,
|
||||
std::function<void(Preset&)> preset_loaded_fn, const PresetOrigin &load_origin)
|
||||
std::function<void(Preset&)> preset_loaded_fn, const PresetOrigin &load_origin, bool read_only)
|
||||
{
|
||||
// Don't use boost::filesystem::canonical() on Windows, it is broken in regard to reparse points,
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/732
|
||||
@@ -1662,7 +1662,7 @@ void PresetCollection::load_presets(
|
||||
|
||||
// Load custom roots first
|
||||
if (fs::exists(dir / "base")) {
|
||||
load_presets(dir.string(), "base", substitutions, substitution_rule, nullptr, resolved_origin);
|
||||
load_presets(dir.string(), "base", substitutions, substitution_rule, nullptr, resolved_origin, read_only);
|
||||
}
|
||||
|
||||
//BBS: add config related logs
|
||||
@@ -1670,7 +1670,8 @@ void PresetCollection::load_presets(
|
||||
//BBS do not parse folder if not exists
|
||||
m_dir_path = dir.string();
|
||||
if (!fs::exists(dir)) {
|
||||
fs::create_directory(dir);
|
||||
if (!read_only)
|
||||
fs::create_directory(dir);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1720,10 +1721,10 @@ void PresetCollection::load_presets(
|
||||
substitutions.push_back({ preset.name, m_type, PresetConfigSubstitutions::Source::UserFile, preset.file, std::move(config_substitutions) });
|
||||
if (!reason.empty()) {
|
||||
fs::path file_path(preset.file);
|
||||
if (fs::exists(file_path))
|
||||
if (!read_only && fs::exists(file_path))
|
||||
fs::remove(file_path);
|
||||
file_path.replace_extension(".info");
|
||||
if (fs::exists(file_path))
|
||||
if (!read_only && fs::exists(file_path))
|
||||
fs::remove(file_path);
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("parse config %1% failed")%preset.file;
|
||||
++m_errors;
|
||||
@@ -1794,7 +1795,8 @@ void PresetCollection::load_presets(
|
||||
size_t at_pos = name.find('@');
|
||||
if (at_pos != std::string::npos && at_pos + 1 < name.length()) {
|
||||
compatible_printers->values.push_back(name.substr(at_pos + 1));
|
||||
preset.save(nullptr);
|
||||
if (!read_only)
|
||||
preset.save(nullptr);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " added compatible_printers for preset: " << name;
|
||||
}
|
||||
}
|
||||
@@ -1812,10 +1814,10 @@ void PresetCollection::load_presets(
|
||||
++m_errors;
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("The user-config cannot be loaded: %1%. Reason: %2%")%preset.file %err.what();
|
||||
fs::path file_path(preset.file);
|
||||
if (fs::exists(file_path))
|
||||
if (!read_only && fs::exists(file_path))
|
||||
fs::remove(file_path);
|
||||
file_path.replace_extension(".info");
|
||||
if (fs::exists(file_path))
|
||||
if (!read_only && fs::exists(file_path))
|
||||
fs::remove(file_path);
|
||||
//throw Slic3r::RuntimeError(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what());
|
||||
} catch (const std::runtime_error &err) {
|
||||
@@ -1823,10 +1825,10 @@ void PresetCollection::load_presets(
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Failed loading the user-config file: %1%. Reason: %2%")%preset.file %err.what();
|
||||
//throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what());
|
||||
fs::path file_path(preset.file);
|
||||
if (fs::exists(file_path))
|
||||
if (!read_only && fs::exists(file_path))
|
||||
fs::remove(file_path);
|
||||
file_path.replace_extension(".info");
|
||||
if (fs::exists(file_path))
|
||||
if (!read_only && fs::exists(file_path))
|
||||
fs::remove(file_path);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,8 +93,8 @@ class PresetBundle;
|
||||
|
||||
// Deterministic preset setting_id: uuid5(vendor/type/name) -> 16 base62 chars.
|
||||
// Pure function of a system preset's identity, so the value can be assigned by
|
||||
// scripts/assign_vendor_setting_ids.py and recomputed here when a profile ships
|
||||
// without it. MUST stay byte-identical to scripts/assign_vendor_setting_ids.py.
|
||||
// scripts/orca_id_tool.py and recomputed here when a profile ships without it.
|
||||
// MUST stay byte-identical to scripts/orca_id_tool.py.
|
||||
// This is NOT the per-user cloud-sync setting_id
|
||||
// (OrcaCloudServiceAgent::generate_uuid_for_setting_id) - do not conflate them.
|
||||
std::string generate_preset_setting_id(const std::string& vendor,
|
||||
@@ -558,7 +558,7 @@ public:
|
||||
void add_default_preset(const std::vector<std::string> &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &preset_name);
|
||||
|
||||
// Load ini files of the particular type from the provided directory path.
|
||||
void load_presets(const std::string &dir_path, const std::string &subdir, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule, std::function<void(Preset&)> preset_loaded_fn = nullptr, const PresetOrigin &load_origin = PresetOrigin());
|
||||
void load_presets(const std::string &dir_path, const std::string &subdir, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule, std::function<void(Preset&)> preset_loaded_fn = nullptr, const PresetOrigin &load_origin = PresetOrigin(), bool read_only = false);
|
||||
|
||||
//BBS: update user presets directory
|
||||
void update_user_presets_directory(const std::string& dir_path, const std::string& type);
|
||||
|
||||
+285
-32
@@ -474,6 +474,158 @@ PresetBundle::PresetBundle()
|
||||
this->project_config.apply_only(FullPrintConfig::defaults(), s_project_options);
|
||||
}
|
||||
|
||||
bool PresetBundle::resolve_preset_config(DynamicPrintConfig &config, Preset::Type type,
|
||||
const std::string &source_file,
|
||||
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||
std::string &error, bool allow_source_manifest)
|
||||
{
|
||||
if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)
|
||||
compatibility_rule = ForwardCompatibilitySubstitutionRule::EnableSilent;
|
||||
else if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem)
|
||||
compatibility_rule = ForwardCompatibilitySubstitutionRule::Disable;
|
||||
|
||||
auto collection_for_type = [](PresetBundle &bundle, Preset::Type preset_type) -> PresetCollection * {
|
||||
switch (preset_type) {
|
||||
case Preset::TYPE_PRINT: return &bundle.prints;
|
||||
case Preset::TYPE_FILAMENT: return &bundle.filaments;
|
||||
case Preset::TYPE_PRINTER: return &bundle.printers;
|
||||
default: return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
PresetCollection *collection = collection_for_type(*this, type);
|
||||
if (collection == nullptr) {
|
||||
error = "Unsupported preset type";
|
||||
return false;
|
||||
}
|
||||
|
||||
const boost::filesystem::path source_path = boost::filesystem::absolute(source_file).lexically_normal();
|
||||
auto find_loaded = [&](PresetBundle &bundle) -> const Preset * {
|
||||
PresetCollection *loaded_collection = collection_for_type(bundle, type);
|
||||
const Preset *resolved = nullptr;
|
||||
for (const Preset &preset : loaded_collection->get_presets()) {
|
||||
if (preset.file.empty())
|
||||
continue;
|
||||
|
||||
boost::system::error_code ec;
|
||||
const bool same_file = boost::filesystem::equivalent(source_path, boost::filesystem::path(preset.file), ec);
|
||||
if (ec || !same_file)
|
||||
continue;
|
||||
if (resolved != nullptr) {
|
||||
error = "Preset identity is ambiguous";
|
||||
return nullptr;
|
||||
}
|
||||
resolved = &preset;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
|
||||
if (const Preset *resolved = find_loaded(*this)) {
|
||||
config = resolved->config;
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
if (error == "Preset identity is ambiguous")
|
||||
return false;
|
||||
if (!allow_source_manifest) {
|
||||
error = "Preset was not found in the loaded bundle";
|
||||
return false;
|
||||
}
|
||||
|
||||
// A manifest-backed source file can be resolved without requiring the vendor
|
||||
// to have been copied into data_dir()/system. Find the nearest ancestor whose
|
||||
// sibling manifest names it, then let the canonical vendor loader flatten the
|
||||
// complete tree (including nested sub_path entries and library inheritance).
|
||||
for (boost::filesystem::path vendor_dir = source_path.parent_path(); !vendor_dir.empty(); vendor_dir = vendor_dir.parent_path()) {
|
||||
const std::string vendor_id = vendor_dir.filename().string();
|
||||
if (vendor_id.empty())
|
||||
continue;
|
||||
const boost::filesystem::path root_dir = vendor_dir.parent_path();
|
||||
const boost::filesystem::path manifest = root_dir / (vendor_id + ".json");
|
||||
if (!boost::filesystem::is_regular_file(manifest))
|
||||
continue;
|
||||
const boost::filesystem::path manifest_relative = source_path.lexically_relative(vendor_dir);
|
||||
if (manifest_relative.empty() || *manifest_relative.begin() == "..")
|
||||
continue;
|
||||
|
||||
try {
|
||||
PresetBundle library_bundle;
|
||||
const PresetBundle *base_bundle = nullptr;
|
||||
if (vendor_id != ORCA_FILAMENT_LIBRARY &&
|
||||
boost::filesystem::is_regular_file(root_dir / (std::string(ORCA_FILAMENT_LIBRARY) + ".json"))) {
|
||||
library_bundle.m_preserve_vendor_source_paths = true;
|
||||
library_bundle.load_vendor_configs_from_json(root_dir.string(), ORCA_FILAMENT_LIBRARY, LoadSystem,
|
||||
compatibility_rule, nullptr, false);
|
||||
if (library_bundle.error_count() != 0) {
|
||||
error = "OrcaFilamentLibrary contains invalid presets";
|
||||
return false;
|
||||
}
|
||||
base_bundle = &library_bundle;
|
||||
}
|
||||
|
||||
PresetBundle source_bundle;
|
||||
source_bundle.m_preserve_vendor_source_paths = true;
|
||||
source_bundle.load_vendor_configs_from_json(root_dir.string(), vendor_id, LoadSystem,
|
||||
compatibility_rule, base_bundle, false);
|
||||
if (source_bundle.error_count() != 0) {
|
||||
error = "Vendor bundle contains invalid presets";
|
||||
return false;
|
||||
}
|
||||
|
||||
const Preset *resolved = find_loaded(source_bundle);
|
||||
if (resolved == nullptr) {
|
||||
if (error.empty())
|
||||
error = "Source file is not an instantiated preset in its vendor manifest";
|
||||
return false;
|
||||
}
|
||||
config = resolved->config;
|
||||
error.clear();
|
||||
return true;
|
||||
} catch (const std::exception &ex) {
|
||||
error = ex.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
error = "Preset was not found in the loaded bundle";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PresetBundle::resolve_preset_config_type(DynamicPrintConfig &config, Preset::Type &type,
|
||||
const std::string &source_file,
|
||||
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||
std::string &error, bool allow_source_manifest)
|
||||
{
|
||||
std::optional<std::pair<Preset::Type, DynamicPrintConfig>> resolved;
|
||||
for (Preset::Type candidate_type : types_list(ptFFF)) {
|
||||
DynamicPrintConfig candidate_config(config);
|
||||
std::string candidate_error;
|
||||
if (!resolve_preset_config(candidate_config, candidate_type, source_file, compatibility_rule,
|
||||
candidate_error, allow_source_manifest)) {
|
||||
if (candidate_error == "Preset identity is ambiguous") {
|
||||
error = std::move(candidate_error);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (resolved) {
|
||||
error = "Preset type is ambiguous";
|
||||
return false;
|
||||
}
|
||||
resolved.emplace(candidate_type, std::move(candidate_config));
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
error = "Preset type could not be resolved";
|
||||
return false;
|
||||
}
|
||||
|
||||
type = resolved->first;
|
||||
config = std::move(resolved->second);
|
||||
error.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
PresetBundle::PresetBundle(const PresetBundle &rhs)
|
||||
{
|
||||
*this = rhs;
|
||||
@@ -595,7 +747,8 @@ void PresetBundle::copy_files(const std::string& from)
|
||||
}
|
||||
|
||||
PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule,
|
||||
const PresetPreferences& preferred_selection/* = PresetPreferences()*/)
|
||||
const PresetPreferences& preferred_selection/* = PresetPreferences()*/,
|
||||
std::string *errors, bool read_only)
|
||||
{
|
||||
// First load the vendor specific system presets.
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
@@ -606,16 +759,20 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward
|
||||
const auto startup_t0 = std::chrono::steady_clock::now();
|
||||
|
||||
//BBS: change system config to json
|
||||
std::tie(substitutions, errors_cummulative) = this->load_system_presets_from_json(substitution_rule);
|
||||
std::tie(substitutions, errors_cummulative) = this->load_system_presets_from_json(substitution_rule, !read_only);
|
||||
if (errors != nullptr)
|
||||
*errors = errors_cummulative;
|
||||
|
||||
// BBS load preset from user's folder, load system default if
|
||||
// BBS: change directories by design
|
||||
std::string dir_user_presets = config.get("preset_folder");
|
||||
if (dir_user_presets.empty()) {
|
||||
load_user_presets(DEFAULT_USER_FOLDER_NAME, substitution_rule);
|
||||
load_user_presets(DEFAULT_USER_FOLDER_NAME, substitution_rule, read_only);
|
||||
} else {
|
||||
load_user_presets(dir_user_presets, substitution_rule);
|
||||
load_user_presets(dir_user_presets, substitution_rule, read_only);
|
||||
}
|
||||
if (errors != nullptr && errors->empty() && m_errors != 0)
|
||||
*errors = "Preset loading reported " + std::to_string(m_errors) + " error(s)";
|
||||
|
||||
// Rewrite renamed compatible_printers / compatible_prints references before selection. Skipped
|
||||
// in validation mode so the profile validator (has_errors -> check_preset_references) sees the
|
||||
@@ -1031,18 +1188,26 @@ std::string PresetBundle::get_hotend_model_for_printer_model(std::string model_n
|
||||
return out;
|
||||
}
|
||||
|
||||
PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule substitution_rule)
|
||||
PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule substitution_rule, bool read_only)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " entry and user is: " << user;
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string errors_cummulative;
|
||||
|
||||
fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR);
|
||||
if (!fs::exists(user_folder)) fs::create_directory(user_folder);
|
||||
if (!fs::exists(user_folder)) {
|
||||
if (read_only)
|
||||
return substitutions;
|
||||
fs::create_directory(user_folder);
|
||||
}
|
||||
|
||||
std::string dir_user_presets = data_dir() + "/" + PRESET_USER_DIR + "/" + user;
|
||||
fs::path folder(user_folder / user);
|
||||
if (!fs::exists(folder)) fs::create_directory(folder);
|
||||
if (!fs::exists(folder)) {
|
||||
if (read_only)
|
||||
return substitutions;
|
||||
fs::create_directory(folder);
|
||||
}
|
||||
|
||||
bundles.WriteLock();
|
||||
bundles.m_bundles.clear();
|
||||
@@ -1070,13 +1235,13 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, For
|
||||
|
||||
this->prints.load_presets(bundle_dir, PRESET_PRINT_NAME, substitutions, substitution_rule, [&](Preset& preset) {
|
||||
metadata.print_presets.push_back(preset.name);
|
||||
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id));
|
||||
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id), read_only);
|
||||
this->filaments.load_presets(bundle_dir, PRESET_FILAMENT_NAME, substitutions, substitution_rule, [&](Preset& preset) {
|
||||
metadata.filament_presets.push_back(preset.name);
|
||||
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id));
|
||||
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id), read_only);
|
||||
this->printers.load_presets(bundle_dir, PRESET_PRINTER_NAME, substitutions, substitution_rule, [&](Preset& preset) {
|
||||
metadata.printer_presets.push_back(preset.name);
|
||||
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id));
|
||||
}, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id), read_only);
|
||||
metadata.bundle_type = BundleType::Local;
|
||||
metadata.path = metadata_file.string();
|
||||
|
||||
@@ -1106,13 +1271,13 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, For
|
||||
|
||||
this->prints.load_presets(bundle_dir, PRESET_PRINT_NAME, substitutions, substitution_rule, [&](Preset& preset) {
|
||||
metadata.print_presets.push_back(preset.name);
|
||||
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id));
|
||||
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id), read_only);
|
||||
this->filaments.load_presets(bundle_dir, PRESET_FILAMENT_NAME, substitutions, substitution_rule, [&](Preset& preset) {
|
||||
metadata.filament_presets.push_back(preset.name);
|
||||
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id));
|
||||
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id), read_only);
|
||||
this->printers.load_presets(bundle_dir, PRESET_PRINTER_NAME, substitutions, substitution_rule, [&](Preset& preset) {
|
||||
metadata.printer_presets.push_back(preset.name);
|
||||
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id));
|
||||
}, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id), read_only);
|
||||
|
||||
metadata.bundle_type = BundleType::Subscribed;
|
||||
metadata.path = metadata_file.string();
|
||||
@@ -1131,17 +1296,20 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, For
|
||||
const auto json_t0 = std::chrono::steady_clock::now();
|
||||
try {
|
||||
std::string sel = prints.get_selected_preset().name;
|
||||
this->prints.load_presets(dir_user_presets, PRESET_PRINT_NAME, substitutions, substitution_rule);
|
||||
this->prints.load_presets(dir_user_presets, PRESET_PRINT_NAME, substitutions, substitution_rule,
|
||||
nullptr, PresetOrigin(), read_only);
|
||||
prints.select_preset_by_name(sel, false);
|
||||
} catch (const std::runtime_error& err) { errors_cummulative += err.what(); }
|
||||
try {
|
||||
std::string sel = filaments.get_selected_preset().name;
|
||||
this->filaments.load_presets(dir_user_presets, PRESET_FILAMENT_NAME, substitutions, substitution_rule);
|
||||
this->filaments.load_presets(dir_user_presets, PRESET_FILAMENT_NAME, substitutions, substitution_rule,
|
||||
nullptr, PresetOrigin(), read_only);
|
||||
filaments.select_preset_by_name(sel, false);
|
||||
} catch (const std::runtime_error& err) { errors_cummulative += err.what(); }
|
||||
try {
|
||||
std::string sel = printers.get_selected_preset().name;
|
||||
this->printers.load_presets(dir_user_presets, PRESET_PRINTER_NAME, substitutions, substitution_rule);
|
||||
this->printers.load_presets(dir_user_presets, PRESET_PRINTER_NAME, substitutions, substitution_rule,
|
||||
nullptr, PresetOrigin(), read_only);
|
||||
printers.select_preset_by_name(sel, false);
|
||||
} catch (const std::runtime_error& err) { errors_cummulative += err.what(); }
|
||||
if (!errors_cummulative.empty()) throw Slic3r::RuntimeError(errors_cummulative);
|
||||
@@ -2287,7 +2455,8 @@ void PresetBundle::clear_printer_hold_aliases()
|
||||
}
|
||||
|
||||
//BBS: add json related logic, load system presets from json
|
||||
std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_presets_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||
std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_presets_from_json(
|
||||
ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache)
|
||||
{
|
||||
//BBS: add config related logs
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, compatibility_rule %1%")%compatibility_rule;
|
||||
@@ -2309,7 +2478,7 @@ std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_pre
|
||||
// The vendors below are loaded whole and against each other — the filament
|
||||
// library first, then every other vendor with it as the base — so each parse
|
||||
// is complete enough to be worth caching.
|
||||
m_generate_vendor_caches = m_generate_vendor_caches || ! validation_mode;
|
||||
m_generate_vendor_caches = allow_cache && (m_generate_vendor_caches || !validation_mode);
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
std::string errors_cummulative;
|
||||
@@ -2339,7 +2508,8 @@ std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_pre
|
||||
// state into this load.
|
||||
this->clear_printer_hold_aliases();
|
||||
this->m_errors = 0;
|
||||
append(substitutions, this->load_vendor_configs_from_json(dir.string(), orca_lib_vendor, PresetBundle::LoadSystem, compatibility_rule).first);
|
||||
append(substitutions, this->load_vendor_configs_from_json(
|
||||
dir.string(), orca_lib_vendor, PresetBundle::LoadSystem, compatibility_rule, nullptr, allow_cache).first);
|
||||
first = false;
|
||||
} catch (const std::runtime_error &err) {
|
||||
if (validation_mode)
|
||||
@@ -2364,7 +2534,7 @@ std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_pre
|
||||
bundle->set_generate_vendor_caches(m_generate_vendor_caches);
|
||||
try {
|
||||
auto result = bundle->load_vendor_configs_from_json(
|
||||
dir.string(), other_vendors[i], PresetBundle::LoadSystem, compatibility_rule, this);
|
||||
dir.string(), other_vendors[i], PresetBundle::LoadSystem, compatibility_rule, this, allow_cache);
|
||||
parallel_substitutions[i] = std::move(result.first);
|
||||
parallel_bundles[i] = std::move(bundle);
|
||||
} catch (const std::runtime_error &err) {
|
||||
@@ -3404,6 +3574,24 @@ std::vector<size_t> PresetBundle::physical_filament_config_indices() const
|
||||
}
|
||||
|
||||
|
||||
// Orca: the AMS lookups below resolve a tray's filament_id to the FIRST compatible base
|
||||
// preset. When several presets match the same id for the selected printer the pick is
|
||||
// arbitrary (a profile bug - see the validator's check_duplicate_filament_subtypes), so
|
||||
// scan past a successful match and warn about the runners-up. Behavior is unchanged.
|
||||
static void warn_ambiguous_filament_id_match(const PresetCollection &filaments, PresetCollection::ConstIterator match, const std::string &filament_id)
|
||||
{
|
||||
if (match == filaments.end())
|
||||
return;
|
||||
std::string others;
|
||||
for (auto it = std::next(match); it != filaments.end(); ++it)
|
||||
if (it->is_compatible && filaments.get_preset_base(*it) == &*it && it->filament_id == filament_id)
|
||||
others += (others.empty() ? "\"" : ", \"") + it->name + "\"";
|
||||
if (!others.empty())
|
||||
BOOST_LOG_TRIVIAL(warning) << "Ambiguous AMS filament match: filament_id \"" << filament_id
|
||||
<< "\" matches multiple presets compatible with the selected printer; picked \"" << match->name
|
||||
<< "\", also matches " << others;
|
||||
}
|
||||
|
||||
void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info)
|
||||
{
|
||||
combox_info.clear();
|
||||
@@ -3426,6 +3614,7 @@ void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info)
|
||||
}
|
||||
auto iter = std::find_if(filaments.begin(), filaments.end(),
|
||||
[this, &filament_id](auto &f) { return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
|
||||
warn_ambiguous_filament_id_match(filaments, iter, filament_id);
|
||||
if (iter == filaments.end()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
|
||||
auto filament_type = ams.opt_string("filament_type", 0u);
|
||||
@@ -3528,6 +3717,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
||||
auto iter = std::find_if(filaments.begin(), filaments.end(), [this, &filament_id, &has_type, filament_type](auto &f) {
|
||||
has_type |= f.config.opt_string("filament_type", 0u) == filament_type;
|
||||
return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
|
||||
warn_ambiguous_filament_id_match(filaments, iter, filament_id);
|
||||
if (iter == filaments.end()) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
|
||||
if (!filament_type.empty()) {
|
||||
@@ -4040,6 +4230,9 @@ std::vector<std::vector<DynamicPrintConfig>> PresetBundle::get_extruder_filament
|
||||
return filament_infos;
|
||||
}
|
||||
|
||||
// ORCA TODO: currently, this function assumes the printer name follows the pattern of "<printer_model> <nozzle_diameter>", e.g.
|
||||
// printer_type: "Bambu Lab X2D", nozzle_diameter_str: "0.4 nozzle" => printer_name: "Bambu Lab X2D 0.4 nozzle". If the printer name does
|
||||
// not follow this pattern, the function may not work correctly.
|
||||
std::set<std::string> PresetBundle::get_printer_names_by_printer_type_and_nozzle(const std::string &printer_type, std::string nozzle_diameter_str, bool system_only)
|
||||
{
|
||||
std::set<std::string> printer_names;
|
||||
@@ -4070,6 +4263,40 @@ std::set<std::string> PresetBundle::get_printer_names_by_printer_type_and_nozzle
|
||||
return printer_names;
|
||||
}
|
||||
|
||||
std::vector<Preset *> PresetBundle::get_filament_presets_for_machine(const std::string &printer_type,
|
||||
const std::string &nozzle_diameter_str,
|
||||
bool include_user_presets)
|
||||
{
|
||||
// Printer model plus nozzle diameter is expected to resolve to a single system printer preset;
|
||||
// get_printer_names_by_printer_type_and_nozzle asserts as much in debug builds.
|
||||
const std::set<std::string> printer_names = get_printer_names_by_printer_type_and_nozzle(printer_type, nozzle_diameter_str);
|
||||
const Preset *printer = printer_names.empty() ? nullptr : printers.find_preset(*printer_names.begin());
|
||||
if (printer == nullptr)
|
||||
return {};
|
||||
|
||||
// Preset::is_visible is deliberately not consulted: it tracks what the Configuration Wizard
|
||||
// installed, while the caller identifies a physically connected machine the user may never
|
||||
// have installed - gating on it would empty the list for exactly those machines.
|
||||
const PresetWithVendorProfile active_printer = printers.get_preset_with_vendor_profile(*printer);
|
||||
// Loop invariant - the two argument is_compatible_with_printer() would rebuild it per preset.
|
||||
DynamicPrintConfig printer_config;
|
||||
printer_config.set_key_value("printer_preset", new ConfigOptionString(printer->name));
|
||||
if (const ConfigOption *opt = printer->config.option("nozzle_diameter"))
|
||||
printer_config.set_key_value("num_extruders", new ConfigOptionInt((int) static_cast<const ConfigOptionFloats *>(opt)->values.size()));
|
||||
|
||||
std::vector<Preset *> compatible;
|
||||
for (Preset &preset : filaments) {
|
||||
/* The situation where the preset is not offered is as follows:
|
||||
1. Not a root preset
|
||||
2. Not a system preset and the printer firmware does not support user presets */
|
||||
if (filaments.get_preset_base(preset) != &preset || (!preset.is_system && !include_user_presets))
|
||||
continue;
|
||||
if (is_compatible_with_printer(filaments.get_preset_with_vendor_profile(preset), active_printer, &printer_config))
|
||||
compatible.push_back(&preset);
|
||||
}
|
||||
return compatible;
|
||||
}
|
||||
|
||||
bool PresetBundle::check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(
|
||||
const std::string &printer_type, std::string& nozzle_diameter_str, std::string &setting_id, std::string &tag_uid, std::string &nozzle_temp_min, std::string &nozzle_temp_max, std::string& preset_setting_id)
|
||||
{
|
||||
@@ -4078,7 +4305,11 @@ bool PresetBundle::check_filament_temp_equation_by_printer_type_and_nozzle_for_m
|
||||
std::map<std::string, std::vector<Preset const *>> filament_list = filaments.get_filament_presets();
|
||||
std::set<std::string> printer_names = get_printer_names_by_printer_type_and_nozzle(printer_type, nozzle_diameter_str);
|
||||
|
||||
for (const Preset *preset : filament_list.find(setting_id)->second) {
|
||||
auto filament_iter = filament_list.find(setting_id);
|
||||
if (filament_iter == filament_list.end())
|
||||
return is_equation;
|
||||
|
||||
for (const Preset *preset : filament_iter->second) {
|
||||
if (tag_uid == "0" || (tag_uid.size() == 16 && tag_uid.substr(12, 2) == "01")) continue;
|
||||
if (preset && !preset->is_user()) continue;
|
||||
ConfigOption * printer_opt = const_cast<Preset *>(preset)->config.option("compatible_printers");
|
||||
@@ -6511,9 +6742,11 @@ std::string PresetBundle::load_vendor_preset(
|
||||
return reason;
|
||||
}
|
||||
|
||||
auto file_path = (boost::filesystem::path(data_dir()) /PRESET_SYSTEM_DIR/ vendor_name / entry.sub_path).make_preferred();
|
||||
if(validation_mode)
|
||||
auto file_path = (boost::filesystem::path(data_dir()) / PRESET_SYSTEM_DIR / vendor_name / entry.sub_path).make_preferred();
|
||||
if (validation_mode)
|
||||
file_path = (boost::filesystem::path(data_dir()) / vendor_name / entry.sub_path).make_preferred();
|
||||
if (m_preserve_vendor_source_paths)
|
||||
file_path = (boost::filesystem::path(path) / vendor_name / entry.sub_path).make_preferred();
|
||||
|
||||
// Load the preset into the list of presets, save it to disk.
|
||||
Preset &loaded = presets_collection->load_preset(file_path.string(), preset_name, std::move(config), false);
|
||||
@@ -6524,8 +6757,8 @@ std::string PresetBundle::load_vendor_preset(
|
||||
loaded.description = entry.description;
|
||||
loaded.setting_id = entry.setting_id;
|
||||
// Derive the preset setting_id on the fly when a profile ships without one,
|
||||
// matching scripts/assign_vendor_setting_ids.py. Only instantiated presets
|
||||
// carry an id; non-instantiated base profiles return earlier above. This never
|
||||
// matching scripts/orca_id_tool.py. Only instantiated presets carry an id;
|
||||
// non-instantiated base profiles return earlier above. This never
|
||||
// touches the per-user cloud-sync setting_id written into user .info files.
|
||||
if (loaded.setting_id.empty() && entry.instantiation == "true")
|
||||
loaded.setting_id = generate_preset_setting_id(
|
||||
@@ -6579,7 +6812,8 @@ std::string PresetBundle::load_vendor_preset(
|
||||
|
||||
//BBS: Load a config bundle file from json
|
||||
std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_from_json(
|
||||
const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, const PresetBundle* base_bundle)
|
||||
const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags,
|
||||
ForwardCompatibilitySubstitutionRule compatibility_rule, const PresetBundle* base_bundle, bool allow_cache)
|
||||
{
|
||||
// Enable substitutions for user config bundle, throw an exception when loading a system profile.
|
||||
ConfigSubstitutionContext substitution_context { compatibility_rule };
|
||||
@@ -6597,7 +6831,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
|
||||
// Orca: only a whole-vendor load has a cache — the vendor-only and filament-only
|
||||
// scans want a slice of one. Validation reads the JSONs whatever is cached.
|
||||
const boost::filesystem::path dir_path(dir);
|
||||
const bool cacheable = flags.has(LoadConfigBundleAttribute::LoadSystem) && ! flags.has(LoadConfigBundleAttribute::LoadFilamentOnly);
|
||||
const bool cacheable = allow_cache && flags.has(LoadConfigBundleAttribute::LoadSystem) && ! flags.has(LoadConfigBundleAttribute::LoadFilamentOnly);
|
||||
if (cacheable && ! validation_mode && this->load_vendor_cache(dir_path, vendor_name, base_bundle)) {
|
||||
size_t presets_loaded = 0;
|
||||
for (const PresetCollection* coll : std::initializer_list<const PresetCollection*>{
|
||||
@@ -7462,7 +7696,11 @@ bool PresetBundle::check_duplicate_filament_subtypes() const
|
||||
// inherited from its @base at load time), grouped by vendor so we only test a
|
||||
// printer against its own vendor's filaments. A vendor's compatible_printers
|
||||
// only names that vendor's printers, so same-vendor scoping is correctness
|
||||
// preserving and avoids an O(all printers x all filaments) sweep.
|
||||
// preserving and avoids an O(all printers x all filaments) sweep. The one
|
||||
// exception is the Orca Filament Library: its presets have empty
|
||||
// compatible_printers (= compatible with every printer, minus the alias-shadowing
|
||||
// exclusions that is_compatible_with_printer checks via m_excluded_from), so they
|
||||
// are tested against every vendor's printers as well.
|
||||
std::map<std::string, std::vector<const Preset *>> filaments_by_vendor;
|
||||
for (const auto &preset : filaments) {
|
||||
if (!preset.is_system || preset.filament_id.empty() || preset.vendor == nullptr)
|
||||
@@ -7470,20 +7708,29 @@ bool PresetBundle::check_duplicate_filament_subtypes() const
|
||||
filaments_by_vendor[preset.vendor->name].push_back(&preset);
|
||||
}
|
||||
|
||||
const std::vector<const Preset *> no_filaments;
|
||||
const auto library_it = filaments_by_vendor.find(ORCA_FILAMENT_LIBRARY);
|
||||
const std::vector<const Preset *> &library_filaments = library_it == filaments_by_vendor.end() ? no_filaments : library_it->second;
|
||||
|
||||
bool found_duplicates = false;
|
||||
for (const auto &printer : printers) {
|
||||
if (!printer.is_system || printer.vendor == nullptr)
|
||||
continue;
|
||||
auto vendor_it = filaments_by_vendor.find(printer.vendor->name);
|
||||
if (vendor_it == filaments_by_vendor.end())
|
||||
const std::vector<const Preset *> &vendor_filaments = vendor_it == filaments_by_vendor.end() ? no_filaments : vendor_it->second;
|
||||
if (vendor_filaments.empty() && library_filaments.empty())
|
||||
continue;
|
||||
|
||||
const PresetWithVendorProfile active_printer = printers.get_preset_with_vendor_profile(printer);
|
||||
// std::map keeps the reported errors in a deterministic (sorted) order.
|
||||
std::map<std::string, std::vector<const Preset *>> by_filament_id;
|
||||
for (const Preset *fil : vendor_it->second)
|
||||
for (const Preset *fil : vendor_filaments)
|
||||
if (is_compatible_with_printer(filaments.get_preset_with_vendor_profile(*fil), active_printer))
|
||||
by_filament_id[fil->filament_id].push_back(fil);
|
||||
if (&vendor_filaments != &library_filaments)
|
||||
for (const Preset *fil : library_filaments)
|
||||
if (is_compatible_with_printer(filaments.get_preset_with_vendor_profile(*fil), active_printer))
|
||||
by_filament_id[fil->filament_id].push_back(fil);
|
||||
|
||||
for (const auto &entry : by_filament_id) {
|
||||
if (entry.second.size() < 2)
|
||||
@@ -7491,9 +7738,15 @@ bool PresetBundle::check_duplicate_filament_subtypes() const
|
||||
found_duplicates = true;
|
||||
// List each conflicting preset with a clickable file:// URI on its own
|
||||
// line, so the profile author can jump straight to the files to fix.
|
||||
// A preset from another bundle (the Orca Filament Library) is tagged with
|
||||
// its vendor so the source bundle is obvious.
|
||||
std::string presets;
|
||||
for (const Preset *p : entry.second)
|
||||
presets += "\n - " + p->name + "\n " + preset_file_uri(p->file);
|
||||
for (const Preset *p : entry.second) {
|
||||
presets += "\n - " + p->name;
|
||||
if (p->vendor != nullptr && p->vendor->name != printer.vendor->name)
|
||||
presets += " [" + p->vendor->name + "]";
|
||||
presets += "\n " + preset_file_uri(p->file);
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(error)
|
||||
<< "Ambiguous AMS filament match: " << entry.second.size()
|
||||
<< " filament presets share filament_id \"" << entry.first
|
||||
|
||||
@@ -256,7 +256,22 @@ public:
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// select preferred presets, if any exist
|
||||
PresetsConfigSubstitutions load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule,
|
||||
const PresetPreferences& preferred_selection = PresetPreferences());
|
||||
const PresetPreferences& preferred_selection = PresetPreferences(),
|
||||
std::string *errors = nullptr, bool read_only = false);
|
||||
|
||||
// Resolve an explicitly named source file through a canonical flattened
|
||||
// preset. Exact loaded-file identity is preferred; otherwise a manifest-
|
||||
// backed vendor tree is loaded from that source root without using caches.
|
||||
bool resolve_preset_config(DynamicPrintConfig &config, Preset::Type type,
|
||||
const std::string &source_file,
|
||||
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||
std::string &error, bool allow_source_manifest = true);
|
||||
// Resolve a source file whose JSON omits `type`. Succeeds only when exactly
|
||||
// one FFF preset collection owns the file and returns that collection's type.
|
||||
bool resolve_preset_config_type(DynamicPrintConfig &config, Preset::Type &type,
|
||||
const std::string &source_file,
|
||||
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||
std::string &error, bool allow_source_manifest = true);
|
||||
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// This is done just once on application start up.
|
||||
@@ -264,7 +279,7 @@ public:
|
||||
void load_selections(AppConfig &config, const PresetPreferences& preferred_selection = PresetPreferences());
|
||||
|
||||
// BBS Load user presets
|
||||
PresetsConfigSubstitutions load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule rule);
|
||||
PresetsConfigSubstitutions load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule rule, bool read_only = false);
|
||||
PresetsConfigSubstitutions load_user_presets(AppConfig &config, std::map<std::string, std::map<std::string, std::string>>& my_presets, ForwardCompatibilitySubstitutionRule rule);
|
||||
// Orca: Import subscribed bundle presets (load and save to disk in one operation), handles one bundle at a time
|
||||
PresetsConfigSubstitutions update_subscribed_presets(AppConfig& config,
|
||||
@@ -376,6 +391,13 @@ public:
|
||||
std::vector<std::vector<DynamicPrintConfig>> get_extruder_filament_info() const;
|
||||
|
||||
std::set<std::string> get_printer_names_by_printer_type_and_nozzle(const std::string &printer_type, std::string nozzle_diameter_str, bool system_only = true);
|
||||
// Orca: the root filament presets a connected machine can use, resolved with the rule the rest
|
||||
// of the app applies (is_compatible_with_printer): an empty compatible_printers means every
|
||||
// printer, minus the alias shadowing exclusions the Orca Filament Library records in
|
||||
// Preset::m_excluded_from.
|
||||
std::vector<Preset *> get_filament_presets_for_machine(const std::string &printer_type,
|
||||
const std::string &nozzle_diameter_str,
|
||||
bool include_user_presets);
|
||||
bool check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(const std::string &printer_type,
|
||||
std::string & nozzle_diameter_str,
|
||||
std::string & setting_id,
|
||||
@@ -500,10 +522,13 @@ public:
|
||||
//Orca: load config bundle from json, pass the base bundle to support cross vendor inheritance
|
||||
// Orca: `dir` is where the vendor is looked for — its own directory, whether or
|
||||
// not the profile JSONs are still there. A whole-vendor load comes from the
|
||||
// vendor's preset cache whenever one covers the profile on disk, and is parsed
|
||||
// from the JSONs in `dir` only when none does. Nothing here reads resources.
|
||||
// vendor's preset cache whenever one covers the profile on disk and allow_cache
|
||||
// is true, and is parsed from the JSONs in `dir` otherwise. Nothing here reads
|
||||
// resources implicitly.
|
||||
std::pair<PresetsConfigSubstitutions, size_t> load_vendor_configs_from_json(
|
||||
const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, const PresetBundle* base_bundle = nullptr);
|
||||
const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags,
|
||||
ForwardCompatibilitySubstitutionRule compatibility_rule, const PresetBundle* base_bundle = nullptr,
|
||||
bool allow_cache = true);
|
||||
|
||||
// Export a config bundle file containing all the presets and the names of the active presets.
|
||||
//void export_configbundle(const std::string &path, bool export_system_settings = false, bool export_physical_printers = false);
|
||||
@@ -625,6 +650,7 @@ private:
|
||||
|
||||
// Whether to (re)write a per-vendor cache after a JSON parse.
|
||||
bool m_generate_vendor_caches { false };
|
||||
bool m_preserve_vendor_source_paths { false };
|
||||
|
||||
// Orca: validation only - flag any printer with two or more compatible
|
||||
// filament presets sharing one filament_id (ambiguous AMS subtype match).
|
||||
@@ -632,7 +658,7 @@ private:
|
||||
|
||||
//std::pair<PresetsConfigSubstitutions, std::string> load_system_presets(ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||
//BBS: add json related logic
|
||||
std::pair<PresetsConfigSubstitutions, std::string> load_system_presets_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule);
|
||||
std::pair<PresetsConfigSubstitutions, std::string> load_system_presets_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache = true);
|
||||
// Update the multicolor information for filaments.
|
||||
void update_filament_multi_color();
|
||||
// Update renamed_from and alias maps of system profiles.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#ifdef _WIN32
|
||||
// Keep this first. A header below reaches boost/regex, whose w32_regex_traits
|
||||
// needs the Win32 types declared already.
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#include "Config.hpp"
|
||||
#include "Exception.hpp"
|
||||
#include "Print.hpp"
|
||||
|
||||
@@ -275,6 +275,7 @@ static t_config_enum_values s_keys_map_InfillPattern {
|
||||
{ "tpmsfk", ipTpmsFK },
|
||||
{ "gyroid", ipGyroid },
|
||||
{ "concentric", ipConcentric },
|
||||
{ "spiralinset", ipSpiralInset },
|
||||
{ "hilbertcurve", ipHilbertCurve },
|
||||
{ "archimedeanchords", ipArchimedeanChords },
|
||||
{ "octagramspiral", ipOctagramSpiral }
|
||||
@@ -371,6 +372,7 @@ static t_config_enum_values s_keys_map_SupportMaterialInterfacePattern {
|
||||
{ "auto", smipAuto },
|
||||
{ "rectilinear", smipRectilinear },
|
||||
{ "concentric", smipConcentric },
|
||||
{ "spiralinset", smipSpiralInset },
|
||||
{ "rectilinear_interlaced", smipRectilinearInterlaced},
|
||||
{ "grid", smipGrid }
|
||||
};
|
||||
@@ -2292,6 +2294,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("rectilinear");
|
||||
def->enum_values.push_back("alignedrectilinear");
|
||||
def->enum_values.push_back("concentric");
|
||||
def->enum_values.push_back("spiralinset");
|
||||
def->enum_values.push_back("hilbertcurve");
|
||||
def->enum_values.push_back("archimedeanchords");
|
||||
def->enum_values.push_back("octagramspiral");
|
||||
@@ -2300,6 +2303,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Aligned Rectilinear"));
|
||||
def->enum_labels.push_back(L("Concentric"));
|
||||
def->enum_labels.push_back(L("Spiral Inset"));
|
||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||
@@ -2382,7 +2386,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Top surface fill order");
|
||||
def->category = L("Strength");
|
||||
def->tooltip = L("Direction in which top surfaces are filled when using a center-based pattern "
|
||||
"(Concentric, Archimedean Chords, Octagram Spiral).\n"
|
||||
"(Concentric, Spiral Inset, Archimedean Chords, Octagram Spiral).\n"
|
||||
"Outward starts at the center of the surface, so any excess material is pushed "
|
||||
"towards the edge where it is least visible. Inward starts at the edge and ends "
|
||||
"with the tight curves at the center.\n"
|
||||
@@ -2401,7 +2405,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Bottom surface fill order");
|
||||
def->category = L("Strength");
|
||||
def->tooltip = L("Direction in which bottom surfaces are filled when using a center-based pattern "
|
||||
"(Concentric, Archimedean Chords, Octagram Spiral).\n"
|
||||
"(Concentric, Spiral Inset, Archimedean Chords, Octagram Spiral).\n"
|
||||
"Inward starts each surface with the wider outer curves, which improves first layer "
|
||||
"adhesion on build plates where the tight curves at the center may not stick. "
|
||||
"Outward starts at the center, pushing any excess material towards the edge.\n"
|
||||
@@ -6963,11 +6967,13 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("auto");
|
||||
def->enum_values.push_back("rectilinear");
|
||||
def->enum_values.push_back("concentric");
|
||||
def->enum_values.push_back("spiralinset");
|
||||
def->enum_values.push_back("rectilinear_interlaced");
|
||||
def->enum_values.push_back("grid");
|
||||
def->enum_labels.push_back(L("Default"));
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Concentric"));
|
||||
def->enum_labels.push_back(L("Spiral Inset"));
|
||||
def->enum_labels.push_back(L("Rectilinear Interlaced"));
|
||||
def->enum_labels.push_back(L("Grid"));
|
||||
def->mode = comAdvanced;
|
||||
@@ -9865,7 +9871,15 @@ std::string DynamicPrintConfig::get_filament_type(std::string &displayed_filamen
|
||||
auto* filament_type = dynamic_cast<const ConfigOptionStrings*>(this->option("filament_type"));
|
||||
auto* filament_is_support = dynamic_cast<const ConfigOptionBools*>(this->option("filament_is_support"));
|
||||
|
||||
if (!filament_type)
|
||||
// get_at() on an empty vector option is undefined behavior (.front() of an empty vector),
|
||||
// and e.g. filament_id is never populated on a CLI from-scratch slice - treat an empty
|
||||
// option the same as a missing one.
|
||||
if (filament_id && filament_id->values.empty())
|
||||
filament_id = nullptr;
|
||||
if (filament_is_support && filament_is_support->values.empty())
|
||||
filament_is_support = nullptr;
|
||||
|
||||
if (!filament_type || filament_type->values.empty())
|
||||
return "";
|
||||
|
||||
if (!filament_is_support) {
|
||||
|
||||
@@ -113,7 +113,7 @@ enum InfillPattern : int {
|
||||
ipCubic, ipAdaptiveCubic, ipQuarterCubic, ipSupportCubic, ipLightning,
|
||||
ipHoneycomb, ip3DHoneycomb, ipLateralHoneycomb, ipLateralLattice,
|
||||
ipCrossHatch, ipTpmsD, ipTpmsFK, ipGyroid,
|
||||
ipConcentric, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
||||
ipConcentric, ipSpiralInset, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
||||
ipSupportBase, ipConcentricInternal,
|
||||
ipCount,
|
||||
};
|
||||
@@ -271,7 +271,7 @@ enum LongRectrationLevel
|
||||
};
|
||||
|
||||
enum SupportMaterialInterfacePattern {
|
||||
smipAuto, smipRectilinear, smipConcentric, smipRectilinearInterlaced, smipGrid
|
||||
smipAuto, smipRectilinear, smipConcentric, smipSpiralInset, smipRectilinearInterlaced, smipGrid
|
||||
};
|
||||
|
||||
// BBS
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
|
||||
#include <libslic3r/OpenVDBUtils.hpp>
|
||||
|
||||
@@ -65,11 +65,13 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
|
||||
const bool smooth_supports = support_params.support_style != smsGrid;
|
||||
SupportGeneratorLayersPtr &interface_layers = base_and_interface_layers.first;
|
||||
SupportGeneratorLayersPtr &base_interface_layers = base_and_interface_layers.second;
|
||||
// The user-facing interface layer counts include the contact layer. Internally,
|
||||
// contact layers are generated separately, so only the remaining layers are
|
||||
// projected into intermediate interface/base-interface layers here.
|
||||
const size_t num_top_interface_layers = support_params.has_top_contacts ? support_params.num_top_interface_layers - 1 : 0;
|
||||
const size_t num_bottom_interface_layers = support_params.has_bottom_contacts ? support_params.num_bottom_interface_layers - 1 : 0;
|
||||
// Contacts printed separately consume one requested interface layer. Organic
|
||||
// bottom contacts are projection seeds and are not printed separately.
|
||||
const bool organic_tree = support_params.support_style == smsTreeOrganic;
|
||||
const size_t num_top_interface_layers = support_params.has_top_contacts ?
|
||||
support_params.num_top_interface_layers - 1 : 0;
|
||||
const size_t num_bottom_interface_layers = support_params.has_bottom_contacts ?
|
||||
support_params.num_bottom_interface_layers - (organic_tree ? 0 : 1) : 0;
|
||||
const size_t num_top_base_interface_layers = std::min(support_params.num_top_base_interface_layers, num_top_interface_layers);
|
||||
const size_t num_bottom_base_interface_layers = std::min(support_params.num_bottom_base_interface_layers, num_bottom_interface_layers);
|
||||
const size_t num_top_interface_layers_only = num_top_interface_layers - num_top_base_interface_layers;
|
||||
@@ -1652,28 +1654,32 @@ void generate_support_toolpaths(
|
||||
if (top_contact_layer.could_merge(interface_layer) && ! raft_layer)
|
||||
top_contact_layer.merge(std::move(interface_layer));
|
||||
}
|
||||
if (!bottom_interfaces && support_params.can_merge_support_regions) {
|
||||
if (base_layer.could_merge(bottom_contact_layer))
|
||||
base_layer.merge(std::move(bottom_contact_layer));
|
||||
else if (base_layer.empty() && ! bottom_contact_layer.empty() && ! bottom_contact_layer.layer->bridging)
|
||||
base_layer = std::move(bottom_contact_layer);
|
||||
} else if (bottom_contact_layer.could_merge(top_contact_layer) && ! raft_layer) {
|
||||
if (top_interfaces && bottom_interfaces) {
|
||||
top_contact_layer.merge(std::move(bottom_contact_layer));
|
||||
} else if (bottom_interfaces) {
|
||||
top_contact_layer.set_polygons_to_extrude(
|
||||
diff(top_contact_layer.polygons_to_extrude(), bottom_contact_layer.polygons_to_extrude()));
|
||||
} else {
|
||||
bottom_contact_layer.set_polygons_to_extrude(
|
||||
diff(bottom_contact_layer.polygons_to_extrude(), top_contact_layer.polygons_to_extrude()));
|
||||
}
|
||||
} else if (bottom_contact_layer.could_merge(interface_layer) && ! organic_tree) {
|
||||
const bool interface_layer_is_bottom = interface_layer.layer->layer_type == SupporLayerType::BottomInterface;
|
||||
if (bottom_interfaces && interface_layer_is_bottom) {
|
||||
bottom_contact_layer.merge(std::move(interface_layer));
|
||||
} else {
|
||||
bottom_contact_layer.set_polygons_to_extrude(
|
||||
diff(bottom_contact_layer.polygons_to_extrude(), interface_layer.polygons_to_extrude()));
|
||||
// Orca: Organic bottom contacts are projection seeds, not same-layer toolpaths.
|
||||
// Do not merge them into another same-layer support region.
|
||||
if (!organic_tree) {
|
||||
if (!bottom_interfaces && support_params.can_merge_support_regions) {
|
||||
if (base_layer.could_merge(bottom_contact_layer))
|
||||
base_layer.merge(std::move(bottom_contact_layer));
|
||||
else if (base_layer.empty() && ! bottom_contact_layer.empty() && ! bottom_contact_layer.layer->bridging)
|
||||
base_layer = std::move(bottom_contact_layer);
|
||||
} else if (bottom_contact_layer.could_merge(top_contact_layer) && ! raft_layer) {
|
||||
if (top_interfaces && bottom_interfaces) {
|
||||
top_contact_layer.merge(std::move(bottom_contact_layer));
|
||||
} else if (bottom_interfaces) {
|
||||
top_contact_layer.set_polygons_to_extrude(
|
||||
diff(top_contact_layer.polygons_to_extrude(), bottom_contact_layer.polygons_to_extrude()));
|
||||
} else {
|
||||
bottom_contact_layer.set_polygons_to_extrude(
|
||||
diff(bottom_contact_layer.polygons_to_extrude(), top_contact_layer.polygons_to_extrude()));
|
||||
}
|
||||
} else if (bottom_contact_layer.could_merge(interface_layer)) {
|
||||
const bool interface_layer_is_bottom = interface_layer.layer->layer_type == SupporLayerType::BottomInterface;
|
||||
if (bottom_interfaces && interface_layer_is_bottom) {
|
||||
bottom_contact_layer.merge(std::move(interface_layer));
|
||||
} else {
|
||||
bottom_contact_layer.set_polygons_to_extrude(
|
||||
diff(bottom_contact_layer.polygons_to_extrude(), interface_layer.polygons_to_extrude()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -333,8 +333,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
|
||||
m_print_config (&object->print()->config()),
|
||||
m_object_config (&object->config()),
|
||||
m_slicing_params (slicing_params),
|
||||
m_support_params (*object),
|
||||
m_object (object)
|
||||
m_support_params (*object)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ private:
|
||||
*/
|
||||
|
||||
// Following objects are not owned by SupportMaterial class.
|
||||
const PrintObject *m_object;
|
||||
const PrintConfig *m_print_config;
|
||||
const PrintObjectConfig *m_object_config;
|
||||
// Pre-calculated parameters shared between the object slicer and the support generator,
|
||||
|
||||
@@ -141,6 +141,8 @@ struct SupportParameters {
|
||||
this->contact_fill_pattern = ipGrid;
|
||||
else if (object_config.support_interface_pattern == smipRectilinearInterlaced)
|
||||
this->contact_fill_pattern = ipRectilinear;
|
||||
else if (object_config.support_interface_pattern == smipSpiralInset)
|
||||
this->contact_fill_pattern = ipSpiralInset;
|
||||
else
|
||||
this->contact_fill_pattern =
|
||||
(object_config.support_interface_pattern == smipAuto && zero_gap_contact_interface) ||
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Slic3r::TreeSupport3D
|
||||
using namespace std::literals;
|
||||
|
||||
// or warning
|
||||
// had to use a define beacuse the macro processing inside macro BOOST_LOG_TRIVIAL()
|
||||
// had to use a define because the macro processing inside macro BOOST_LOG_TRIVIAL()
|
||||
#define error_level_not_in_cache debug
|
||||
|
||||
//FIXME Machine border is currently ignored.
|
||||
|
||||
@@ -432,7 +432,6 @@ private:
|
||||
size_t m_highest_overhang_layer = 0;
|
||||
std::vector<std::vector<MinimumSpanningTree>> m_spanning_trees;
|
||||
std::vector< std::unordered_map<Line, bool, LineHash>> m_mst_line_x_layer_contour_caches;
|
||||
float DO_NOT_MOVER_UNDER_MM = 0.0;
|
||||
coordf_t base_radius = 0.0;
|
||||
const coordf_t MAX_BRANCH_RADIUS = 10.0;
|
||||
const coordf_t MIN_BRANCH_RADIUS = 0.4;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <deque>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
@@ -607,6 +608,17 @@ static inline std::vector<IntersectionLines> slice_make_lines(
|
||||
}
|
||||
}
|
||||
);
|
||||
// Facet processing above is parallel, so per-layer line order depends on thread scheduling,
|
||||
// and make_loops() derives island order and loop start vertices from it. Sort canonically;
|
||||
// edge_type and flags only break ties, std::sort being unstable.
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, lines.size()),
|
||||
[&lines](const tbb::blocked_range<size_t> &range) {
|
||||
for (size_t i = range.begin(); i < range.end(); ++ i)
|
||||
std::sort(lines[i].begin(), lines[i].end(), [](const IntersectionLine &l, const IntersectionLine &r) {
|
||||
return std::make_tuple(l.edge_a_id, l.edge_b_id, l.a_id, l.b_id, l.a.x(), l.a.y(), l.b.x(), l.b.y(), l.edge_type, l.flags) <
|
||||
std::make_tuple(r.edge_a_id, r.edge_b_id, r.a_id, r.b_id, r.a.x(), r.a.y(), r.b.x(), r.b.y(), r.edge_type, r.flags);
|
||||
});
|
||||
});
|
||||
return lines;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
#define SLIC3R_APP_KEY "@SLIC3R_APP_KEY@"
|
||||
#define SLIC3R_VERSION "@SLIC3R_VERSION@"
|
||||
#define SoftFever_VERSION "@SoftFever_VERSION@"
|
||||
#ifndef GIT_COMMIT_HASH
|
||||
#define GIT_COMMIT_HASH "0000000" // 0000000 means uninitialized
|
||||
#endif
|
||||
#define SLIC3R_BUILD_ID "@SLIC3R_BUILD_ID@"
|
||||
//#define SLIC3R_RC_VERSION "@SLIC3R_VERSION@"
|
||||
#define BBL_INTERNAL_TESTING @BBL_INTERNAL_TESTING@
|
||||
|
||||
@@ -310,7 +310,11 @@ void set_data_dir(const std::string &dir)
|
||||
{
|
||||
g_data_dir = dir;
|
||||
if (!g_data_dir.empty() && !boost::filesystem::exists(g_data_dir)) {
|
||||
boost::filesystem::create_directory(g_data_dir);
|
||||
try {
|
||||
boost::filesystem::create_directories(g_data_dir);
|
||||
} catch (const boost::filesystem::filesystem_error &ex) {
|
||||
BOOST_LOG_TRIVIAL(error) << "set_data_dir: failed to create data directory " << g_data_dir << ": " << ex.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/BitmapComboBox.hpp
|
||||
GUI/BonjourDialog.cpp
|
||||
GUI/BonjourDialog.hpp
|
||||
GUI/BuildCommit.cpp
|
||||
GUI/BuildCommit.hpp
|
||||
GUI/CrealityDiscoveryDialog.cpp
|
||||
GUI/CrealityDiscoveryDialog.hpp
|
||||
GUI/calib_dlg.cpp
|
||||
@@ -849,6 +851,18 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES})
|
||||
|
||||
encoding_check(libslic3r_gui)
|
||||
|
||||
# Only BuildCommit.cpp includes the generated header, plus BaseException.cpp on
|
||||
# Windows. Both build into libslic3r_gui, so the header only has to exist before
|
||||
# that target builds.
|
||||
set(_git_commit_hash_header "${CMAKE_CURRENT_BINARY_DIR}/git_commit_hash.h")
|
||||
add_custom_target(git_commit_hash_header
|
||||
BYPRODUCTS "${_git_commit_hash_header}"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DSOURCE_DIR=${CMAKE_SOURCE_DIR}"
|
||||
"-DOUT_FILE=${_git_commit_hash_header}"
|
||||
-P "${CMAKE_CURRENT_LIST_DIR}/GitCommitHash.cmake"
|
||||
COMMENT "Resolving the git commit hash")
|
||||
add_dependencies(libslic3r_gui git_commit_hash_header)
|
||||
|
||||
if(APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
|
||||
set(_opengl_link_lib "")
|
||||
@@ -906,6 +920,9 @@ endif ()
|
||||
|
||||
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
|
||||
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
|
||||
elseif (MSVC)
|
||||
# Puts the Windows headers first when the PCH is off.
|
||||
target_compile_options(libslic3r_gui PRIVATE "/FIslic3r/win_platform.hpp")
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
@@ -971,10 +988,6 @@ endif ()
|
||||
# Add a definition so that we can tell we are compiling slic3r.
|
||||
target_compile_definitions(libslic3r_gui PRIVATE SLIC3R_CURRENTLY_COMPILING_GUI_MODULE)
|
||||
|
||||
if(ORCA_BUNDLED_UV_EXECUTABLE_CONFIG)
|
||||
target_compile_definitions(libslic3r_gui PRIVATE "ORCA_BUNDLED_UV_EXECUTABLE=\"${ORCA_BUNDLED_UV_EXECUTABLE_CONFIG}\"")
|
||||
endif()
|
||||
|
||||
if (ORCA_BUILD_PYTHON_STUBGEN_MODULE)
|
||||
add_library(orca_stubgen MODULE
|
||||
plugin/PythonPluginBridge.cpp
|
||||
|
||||
@@ -1511,6 +1511,10 @@ void AMSDryCtrWin::update_filament_guide_info(DevAms* dev_ams)
|
||||
m_temperature_input->GetValue().ToLong(&input_temp);
|
||||
bool can_start = true;
|
||||
|
||||
// "GFA00" is Bambu's PLA id; GetFilamentDryingPreset is keyed by our OF ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string pla_filament_id = agent ? agent->to_orca_filament_id("GFA00") : std::string("GFA00");
|
||||
|
||||
int slot_count = 0, empty_count = 0;
|
||||
for (auto& tray_pair : dev_ams->GetTrays()) {
|
||||
if (!tray_pair.second) {
|
||||
@@ -1526,13 +1530,15 @@ void AMSDryCtrWin::update_filament_guide_info(DevAms* dev_ams)
|
||||
wxString filament_type = tray_pair.second->get_display_filament_type();
|
||||
DevFilamentDryingPreset preset;
|
||||
if (filament_type.IsEmpty()) {
|
||||
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
|
||||
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(pla_filament_id);
|
||||
if (!fallback_preset) continue; // no PLA preset (e.g. the id map is missing): skip, don't throw
|
||||
preset = fallback_preset.value();
|
||||
filament_type = "?";
|
||||
} else if (preset_opt.has_value()) {
|
||||
preset = preset_opt.value();
|
||||
} else {
|
||||
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
|
||||
auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(pla_filament_id);
|
||||
if (!fallback_preset) continue;
|
||||
preset = fallback_preset.value();
|
||||
}
|
||||
std::string icon_path = "dev_ams_dry_ctr_enable";
|
||||
@@ -1594,39 +1600,21 @@ int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj)
|
||||
}
|
||||
stream << std::fixed << std::setprecision(1) << obj->GetExtderSystem()->GetNozzleDiameter(extruder_id);
|
||||
std::string nozzle_diameter_str = stream.str();
|
||||
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str);
|
||||
|
||||
for (auto filament_it = filaments.begin(); filament_it != filaments.end(); ++filament_it) {
|
||||
Preset& preset = *filament_it;
|
||||
// Filter by system preset: root preset and (system preset or user preset is supported)
|
||||
if (filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) {
|
||||
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
|
||||
if (!filament_id_set.insert(filament_it->filament_id).second)
|
||||
continue;
|
||||
const std::string filament_alias = filaments.get_preset_alias(*filament_it, true);
|
||||
if (filament_alias.empty())
|
||||
continue;
|
||||
auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id);
|
||||
if (!opt_info.has_value())
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
|
||||
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
|
||||
if (!printer_strs) continue;
|
||||
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_names.find(printer_str) != printer_names.end()) {
|
||||
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filament_id_set.insert(filament_it->filament_id);
|
||||
auto filament_alias = filaments.get_preset_alias(*filament_it, true);
|
||||
if (!filament_alias.empty()) {
|
||||
auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id);
|
||||
if (opt_info.has_value()) {
|
||||
auto real_info = opt_info.value();
|
||||
real_info.filament_name = filament_alias;
|
||||
m_tray_ids.push_back(std::move(real_info));
|
||||
m_trays_combo->Append(wxString::FromUTF8(filament_alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opt_info->filament_name = filament_alias;
|
||||
m_tray_ids.push_back(std::move(*opt_info));
|
||||
m_trays_combo->Append(wxString::FromUTF8(filament_alias));
|
||||
}
|
||||
|
||||
if (m_tray_ids.empty()) {
|
||||
@@ -1701,9 +1689,10 @@ int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj)
|
||||
|
||||
// Select recommended drying temperature and default filament
|
||||
float min_dry_temp = std::numeric_limits<float>::max();
|
||||
std::string default_filament_id = "GFA00";
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
std::string default_filament_id = agent ? agent->to_orca_filament_id("GFA00") : std::string("GFA00"); // compared against m_tray_ids[i].filament_id (our OF ids) below
|
||||
bool has_ready = false;
|
||||
const auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00");
|
||||
const auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset(default_filament_id);
|
||||
for (const auto& tray_pair : dev_ams->GetTrays()) {
|
||||
if (!tray_pair.second || !tray_pair.second->is_tray_info_ready()) continue;
|
||||
has_ready = true;
|
||||
|
||||
@@ -97,12 +97,6 @@ private:
|
||||
wxSimplebook* m_main_simplebook{nullptr};
|
||||
wxPanel* m_original_page{nullptr};
|
||||
|
||||
wxWindow* m_amswin{nullptr};
|
||||
wxBoxSizer* m_sizer_ams_items{nullptr};
|
||||
wxScrolledWindow* m_panel_prv_left {nullptr};
|
||||
wxScrolledWindow* m_panel_prv_right{nullptr};
|
||||
wxBoxSizer* m_sizer_prv_left{nullptr};
|
||||
wxBoxSizer* m_sizer_prv_right{nullptr};
|
||||
|
||||
// left panel related members
|
||||
ScalableBitmap m_humidity_image;
|
||||
|
||||
@@ -681,6 +681,19 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event)
|
||||
}
|
||||
|
||||
|
||||
// Orca: log the tray payload this dialog hands the printer, so the filament_id resolved from the
|
||||
// dropdown selection can be checked against the tray_info_idx the AMS actually receives. A
|
||||
// BBL-tagged (RFID) tray is read-only here, so nothing is published for it.
|
||||
BOOST_LOG_TRIVIAL(info) << "ams_materials_setting: " << (m_is_third ? "sending" : "NOT sending (BBL RFID tray, read-only)")
|
||||
<< ", ams_id = " << ams_id << ", slot_id = " << slot_id
|
||||
<< ", selected = " << m_comboBox_filament->GetValue().ToStdString()
|
||||
<< ", tray_info_idx (filament_id) = " << ams_filament_id
|
||||
<< ", setting_id = " << ams_setting_id
|
||||
<< ", tray_type = " << m_filament_type
|
||||
<< ", tray_color = " << col_buf
|
||||
<< ", nozzle_temp_min = " << nozzle_temp_min_int
|
||||
<< ", nozzle_temp_max = " << nozzle_temp_max_int;
|
||||
|
||||
// set filament
|
||||
if (m_is_third) {
|
||||
obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int);
|
||||
@@ -802,7 +815,10 @@ void AMSMaterialsSetting::set_color(wxColour color)
|
||||
fila_color.m_colors.insert(color);
|
||||
fila_color.EndSet(m_clr_picker->ctype);
|
||||
auto clr_query = GUI::wxGetApp().get_filament_color_code_query();
|
||||
m_clr_name->SetLabelText(clr_query->GetFilaColorName(ams_filament_id, fila_color));
|
||||
// ams_filament_id is our OF id; GetFilaColorName looks up filaments_color_codes.json,
|
||||
// downloaded from Bambu and keyed by the printer's own ids, so translate for this lookup only.
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
m_clr_name->SetLabelText(clr_query->GetFilaColorName(agent ? agent->from_orca_filament_id(ams_filament_id) : ams_filament_id, fila_color));
|
||||
}
|
||||
|
||||
void AMSMaterialsSetting::set_empty_color(wxColour color)
|
||||
@@ -823,7 +839,10 @@ void AMSMaterialsSetting::set_colors(std::vector<wxColour> colors)
|
||||
for (const auto& clr : colors) { fila_color.m_colors.insert(clr); }
|
||||
fila_color.EndSet(m_clr_picker->ctype);
|
||||
auto clr_query = GUI::wxGetApp().get_filament_color_code_query();
|
||||
m_clr_name->SetLabelText(clr_query->GetFilaColorName(ams_filament_id, fila_color));
|
||||
// ams_filament_id is our OF id; GetFilaColorName looks up filaments_color_codes.json,
|
||||
// downloaded from Bambu and keyed by the printer's own ids, so translate for this lookup only.
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
m_clr_name->SetLabelText(clr_query->GetFilaColorName(agent ? agent->from_orca_filament_id(ams_filament_id) : ams_filament_id, fila_color));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -932,7 +951,6 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
m_input_k_val->GetTextCtrl()->SetValue(k);
|
||||
m_input_n_val->GetTextCtrl()->SetValue(n);
|
||||
|
||||
int idx = 0;
|
||||
wxArrayString filament_items;
|
||||
wxString bambu_filament_name;
|
||||
wxString hint_filament_name; // the hint type to be selected
|
||||
@@ -940,6 +958,9 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
std::unordered_map<wxString, wxString> query_filament_types; //
|
||||
|
||||
std::set<std::string> filament_id_set;
|
||||
// The alias keyed map has to start empty: it is a member, so a stale alias left by an earlier
|
||||
// popup (a different printer, a different nozzle) would resolve to that printer's filament_id.
|
||||
map_filament_items.clear();
|
||||
PresetBundle * preset_bundle = wxGetApp().preset_bundle;
|
||||
std::ostringstream stream;
|
||||
// Defensive: this dialog is opened only from StatusPanel (BBL-only) today, so the fallback fires
|
||||
@@ -952,83 +973,48 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
|
||||
}
|
||||
stream << std::fixed << std::setprecision(1) << machine_diameter;
|
||||
std::string nozzle_diameter_str = stream.str();
|
||||
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str);
|
||||
|
||||
if (preset_bundle) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
|
||||
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
|
||||
//filter by system preset
|
||||
Preset& preset = *filament_it;
|
||||
/*The situation where the user preset is not displayed is as follows:
|
||||
1. Not a root preset
|
||||
2. Not system preset and the printer firmware does not support user preset */
|
||||
if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) {
|
||||
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
|
||||
if (!filament_id_set.insert(filament_it->filament_id).second)
|
||||
continue;
|
||||
const std::string alias = preset_bundle->filaments.get_preset_alias(*filament_it, true);
|
||||
if (alias.empty())
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
|
||||
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_names.find(printer_str) != printer_names.end()) {
|
||||
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
|
||||
continue;
|
||||
} else {
|
||||
filament_id_set.insert(filament_it->filament_id);
|
||||
// name matched
|
||||
if (filament_it->is_system) {
|
||||
filament_items.push_back(filament_it->alias);
|
||||
_collect_filament_info(filament_it->alias, preset, query_filament_vendors, query_filament_types);
|
||||
filament_items.push_back(alias);
|
||||
_collect_filament_info(alias, *filament_it, query_filament_vendors, query_filament_types);
|
||||
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[filament_it->alias] = filament_infos;
|
||||
} else {
|
||||
char target = '@';
|
||||
size_t pos = filament_it->name.find(target);
|
||||
if (pos != std::string::npos) {
|
||||
std::string user_preset_alias = filament_it->name.substr(0, pos - 1);
|
||||
wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8);
|
||||
user_preset_alias = wx_user_preset_alias.ToStdString();
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[alias] = filament_infos;
|
||||
|
||||
filament_items.push_back(user_preset_alias);
|
||||
_collect_filament_info(user_preset_alias, preset, query_filament_vendors, query_filament_types);
|
||||
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[user_preset_alias] = filament_infos;
|
||||
}
|
||||
}
|
||||
|
||||
if (filament_it->filament_id == ams_filament_id) {
|
||||
hint_filament_name = from_u8(filament_it->alias);
|
||||
bambu_filament_name = from_u8(filament_it->alias);
|
||||
if (filament_it->filament_id == ams_filament_id) {
|
||||
hint_filament_name = from_u8(alias);
|
||||
bambu_filament_name = from_u8(alias);
|
||||
|
||||
|
||||
// update if nozzle_temperature_range is found
|
||||
ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts *opt_min_ints = dynamic_cast<ConfigOptionInts *>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
}
|
||||
ConfigOption *opt_max = filament_it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts *opt_max_ints = dynamic_cast<ConfigOptionInts *>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
// update if nozzle_temperature_range is found
|
||||
ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts *opt_min_ints = dynamic_cast<ConfigOptionInts *>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
}
|
||||
ConfigOption *opt_max = filament_it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts *opt_max_ints = dynamic_cast<ConfigOptionInts *>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1251,56 +1237,47 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
|
||||
stream << std::fixed << std::setprecision(1) << machine_diameter;
|
||||
}
|
||||
std::string nozzle_diameter_str = stream.str();
|
||||
std::set<std::string> printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(DevPrinterConfigUtil::get_printer_display_name(obj->printer_type),
|
||||
nozzle_diameter_str);
|
||||
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) {
|
||||
if (!m_comboBox_filament->GetValue().IsEmpty()) {
|
||||
auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()];
|
||||
std::string filament_id = filament_item.filament_id;
|
||||
if (it->filament_id.compare(filament_id) == 0) {
|
||||
ConfigOption * printer_opt = it->config.option("compatible_printers");
|
||||
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
|
||||
bool has_compatible_printer = false;
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_names.find(printer_str) != printer_names.end()) {
|
||||
has_compatible_printer = true;
|
||||
break;
|
||||
}
|
||||
// Resolve the selection against the same list Popup() built the dropdown from, so the two
|
||||
// halves of the dialog cannot disagree about which filaments this machine can use.
|
||||
const std::string selected = m_comboBox_filament->GetValue().ToStdString();
|
||||
if (!selected.empty()) {
|
||||
const std::string filament_id = map_filament_items[selected].filament_id;
|
||||
for (Preset *it : preset_bundle->get_filament_presets_for_machine(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
|
||||
if (it->filament_id != filament_id)
|
||||
continue;
|
||||
// ) if nozzle_temperature_range is found
|
||||
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts* opt_min_ints = dynamic_cast<ConfigOptionInts*>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
if (!it->is_system && !has_compatible_printer) continue;
|
||||
// ) if nozzle_temperature_range is found
|
||||
ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low");
|
||||
if (opt_min) {
|
||||
ConfigOptionInts* opt_min_ints = dynamic_cast<ConfigOptionInts*>(opt_min);
|
||||
if (opt_min_ints) {
|
||||
wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0));
|
||||
m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min);
|
||||
}
|
||||
}
|
||||
ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts* opt_max_ints = dynamic_cast<ConfigOptionInts*>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
ConfigOption* opt_type = it->config.option("filament_type");
|
||||
bool found_filament_type = false;
|
||||
if (opt_type) {
|
||||
ConfigOptionStrings* opt_type_strs = dynamic_cast<ConfigOptionStrings*>(opt_type);
|
||||
if (opt_type_strs) {
|
||||
found_filament_type = true;
|
||||
//m_filament_type = opt_type_strs->get_at(0);
|
||||
std::string display_filament_type;
|
||||
m_filament_type = it->config.get_filament_type(display_filament_type);
|
||||
}
|
||||
}
|
||||
if (!found_filament_type)
|
||||
m_filament_type = "";
|
||||
|
||||
break;
|
||||
}
|
||||
ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high");
|
||||
if (opt_max) {
|
||||
ConfigOptionInts* opt_max_ints = dynamic_cast<ConfigOptionInts*>(opt_max);
|
||||
if (opt_max_ints) {
|
||||
wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0));
|
||||
m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max);
|
||||
}
|
||||
}
|
||||
ConfigOption* opt_type = it->config.option("filament_type");
|
||||
bool found_filament_type = false;
|
||||
if (opt_type) {
|
||||
ConfigOptionStrings* opt_type_strs = dynamic_cast<ConfigOptionStrings*>(opt_type);
|
||||
if (opt_type_strs) {
|
||||
found_filament_type = true;
|
||||
//m_filament_type = opt_type_strs->get_at(0);
|
||||
std::string display_filament_type;
|
||||
m_filament_type = it->config.get_filament_type(display_filament_type);
|
||||
}
|
||||
}
|
||||
if (!found_filament_type)
|
||||
m_filament_type = "";
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1938,11 +1915,6 @@ void ColorPickerPopup::paintEvent(wxPaintEvent& evt)
|
||||
|
||||
void ColorPickerPopup::OnDismiss() {}
|
||||
|
||||
void ColorPickerPopup::Popup()
|
||||
{
|
||||
PopupWindow::Popup();
|
||||
}
|
||||
|
||||
bool ColorPickerPopup::ProcessLeftDown(wxMouseEvent& event) {
|
||||
return PopupWindow::ProcessLeftDown(event);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ public:
|
||||
void set_ams_colours(std::vector<wxColour> ams);
|
||||
void set_def_colour(wxColour col);
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
void Popup();
|
||||
virtual void OnDismiss() wxOVERRIDE;
|
||||
virtual bool ProcessLeftDown(wxMouseEvent& event) wxOVERRIDE;
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ void AMSSetting::UpdateByObj(MachineObject* obj)
|
||||
|
||||
update_ams_img(obj);
|
||||
|
||||
m_ams_type->Update(obj);
|
||||
m_ams_type->UpdateInfo(obj);
|
||||
//m_ams_arrange_order->Update(obj);
|
||||
update_insert_material_read_mode(obj);
|
||||
m_sizer_remain_block->Show(obj->is_support_update_remain);
|
||||
@@ -624,7 +624,7 @@ void AMSSettingTypePanel::CreateGui()
|
||||
Fit();
|
||||
}
|
||||
|
||||
void AMSSettingTypePanel::Update(const MachineObject* obj)
|
||||
void AMSSettingTypePanel::UpdateInfo(const MachineObject* obj)
|
||||
{
|
||||
if (!obj) {
|
||||
Show(false);
|
||||
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
~AMSSettingTypePanel();
|
||||
|
||||
public:
|
||||
void Update(const MachineObject* obj);
|
||||
void UpdateInfo(const MachineObject* obj);
|
||||
|
||||
private:
|
||||
void CreateGui();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/Color.hpp"
|
||||
#include "BuildCommit.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
@@ -245,7 +246,7 @@ AboutDialog::AboutDialog()
|
||||
vesizer->Add(0, 0, 1, wxEXPAND, FromDIP(5));
|
||||
auto version_string = std::string(SoftFever_VERSION); // _L("Orca Slicer ") + " " + std::string(SoftFever_VERSION);
|
||||
wxStaticText* version = new wxStaticText(this, wxID_ANY, version_string.c_str(), wxDefaultPosition, wxDefaultSize);
|
||||
wxStaticText* credits_string = new wxStaticText(this, wxID_ANY, wxString::Format("Build %s", std::string(GIT_COMMIT_HASH)), wxDefaultPosition, wxDefaultSize);
|
||||
wxStaticText* credits_string = new wxStaticText(this, wxID_ANY, wxString::Format("Build %s", build_commit_label), wxDefaultPosition, wxDefaultSize);
|
||||
credits_string->SetFont(_build_string_font);
|
||||
wxFont version_font = GetFont();
|
||||
version_font = version_font.Scaled(1.85f); // SetPointSize(20) not works on macOS because it uses a 72 PPI reference
|
||||
|
||||
@@ -457,7 +457,6 @@ private:
|
||||
ScalableBitmap close_img;
|
||||
|
||||
wxStaticBitmap* curr_humidity_img;
|
||||
wxStaticBitmap* m_img;
|
||||
|
||||
Label* m_staticText;;
|
||||
Label* m_staticText_note;
|
||||
|
||||
@@ -93,7 +93,6 @@ private:
|
||||
CenteredTitle* m_title_ctrl { nullptr };
|
||||
wxString m_titleText;
|
||||
|
||||
wxAuiToolBarItem* m_model_store_item;
|
||||
|
||||
//wxAuiToolBarItem *m_publish_item;
|
||||
wxAuiToolBarItem* m_undo_item;
|
||||
|
||||
@@ -65,18 +65,10 @@ private:
|
||||
wxPanel* request_bind_panel;
|
||||
wxPanel* binding_panel;
|
||||
|
||||
wxScrolledWindow* m_sw_bind_failed_info;
|
||||
Label* m_bind_failed_info;
|
||||
Label* m_st_txt_error_code{ nullptr };
|
||||
Label* m_st_txt_error_desc{ nullptr };
|
||||
Label* m_st_txt_extra_info{ nullptr };
|
||||
HyperLink* m_link_network_state{ nullptr };
|
||||
wxString m_result_info;
|
||||
wxString m_result_extra;
|
||||
wxString m_ping_code_wiki;
|
||||
bool m_show_error_info_state = true;
|
||||
|
||||
int m_result_code;
|
||||
std::shared_ptr<BBLStatusBarBind> m_status_bar;
|
||||
|
||||
public:
|
||||
@@ -110,7 +102,6 @@ private:
|
||||
wxBitmap m_bitmap_show_error_close;
|
||||
wxBitmap m_bitmap_show_error_open;
|
||||
wxScrolledWindow* m_sw_bind_failed_info;
|
||||
Label* m_bind_failed_info;
|
||||
Label* m_st_txt_error_code{ nullptr };
|
||||
Label* m_st_txt_error_desc{ nullptr };
|
||||
Label* m_st_txt_extra_info{ nullptr };
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "BuildCommit.hpp"
|
||||
#include "git_commit_hash.h"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
const char *const build_commit_hash = GIT_COMMIT_HASH;
|
||||
const char *const build_commit_label = GIT_COMMIT_HASH GIT_COMMIT_SUFFIX;
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
// Read these rather than including git_commit_hash.h, which changes with every
|
||||
// commit and rebuilds everything that includes it.
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
// The commit alone, safe to use in a commit URL.
|
||||
extern const char *const build_commit_hash;
|
||||
|
||||
// The same, with "-dirty" when the build had uncommitted changes. Use this
|
||||
// wherever the build is shown to a person.
|
||||
extern const char *const build_commit_label;
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
@@ -702,7 +702,6 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject
|
||||
|
||||
wxArrayString filament_items;
|
||||
std::set<std::string> filament_id_set;
|
||||
std::set<std::string> printer_names;
|
||||
std::ostringstream stream;
|
||||
// If the machine didn't report a nozzle diameter (0.0 = unknown), fall back to the currently
|
||||
// selected printer preset so the filament list isn't empty.
|
||||
@@ -714,67 +713,21 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject
|
||||
stream << std::fixed << std::setprecision(1) << machine_diameter;
|
||||
std::string nozzle_diameter_str = stream.str();
|
||||
|
||||
for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) {
|
||||
// filter by system preset
|
||||
if (!printer_it->is_system)
|
||||
continue;
|
||||
// get printer_model
|
||||
ConfigOption * printer_model_opt = printer_it->config.option("printer_model");
|
||||
ConfigOptionString *printer_model_str = dynamic_cast<ConfigOptionString *>(printer_model_opt);
|
||||
if (!printer_model_str)
|
||||
continue;
|
||||
|
||||
// use printer_model as printer type
|
||||
if (printer_model_str->value != DevPrinterConfigUtil::get_printer_display_name(obj->printer_type))
|
||||
continue;
|
||||
|
||||
if (printer_it->name.find(nozzle_diameter_str) != std::string::npos)
|
||||
printer_names.insert(printer_it->name);
|
||||
}
|
||||
|
||||
if (preset_bundle) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
|
||||
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
|
||||
// filter by system preset
|
||||
Preset &preset = *filament_it;
|
||||
/*The situation where the user preset is not displayed is as follows:
|
||||
1. Not a root preset
|
||||
2. Not system preset and the printer firmware does not support user preset */
|
||||
if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && ! obj->is_support_user_preset)) { continue; }
|
||||
for (Preset *filament_it : preset_bundle->get_filament_presets_for_machine(
|
||||
DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str, obj->is_support_user_preset)) {
|
||||
if (!filament_id_set.insert(filament_it->filament_id).second)
|
||||
continue;
|
||||
const std::string alias = preset_bundle->filaments.get_preset_alias(*filament_it, true);
|
||||
if (alias.empty())
|
||||
continue;
|
||||
|
||||
ConfigOption * printer_opt = filament_it->config.option("compatible_printers");
|
||||
ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_names.find(printer_str) != printer_names.end()) {
|
||||
if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) {
|
||||
continue;
|
||||
} else {
|
||||
filament_id_set.insert(filament_it->filament_id);
|
||||
// name matched
|
||||
if (filament_it->is_system) {
|
||||
filament_items.push_back(filament_it->alias);
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[filament_it->alias] = filament_infos;
|
||||
} else {
|
||||
char target = '@';
|
||||
size_t pos = filament_it->name.find(target);
|
||||
if (pos != std::string::npos) {
|
||||
std::string user_preset_alias = filament_it->name.substr(0, pos - 1);
|
||||
wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8);
|
||||
user_preset_alias = wx_user_preset_alias.ToStdString();
|
||||
|
||||
filament_items.push_back(user_preset_alias);
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[user_preset_alias] = filament_infos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
filament_items.push_back(alias);
|
||||
FilamentInfos filament_infos;
|
||||
filament_infos.filament_id = filament_it->filament_id;
|
||||
filament_infos.setting_id = filament_it->setting_id;
|
||||
map_filament_items[alias] = filament_infos;
|
||||
}
|
||||
}
|
||||
return filament_items;
|
||||
|
||||
@@ -70,11 +70,7 @@ public:
|
||||
|
||||
private:
|
||||
int m_my_devices_count{ 0 };
|
||||
int m_other_devices_count{ 0 };
|
||||
bool m_dismiss{ false };
|
||||
wxWindow* m_placeholder_panel { nullptr };
|
||||
wxWindow* m_panel_body{ nullptr };
|
||||
wxBoxSizer* m_sizer_body{ nullptr };
|
||||
wxBoxSizer* m_sizer_my_devices{ nullptr };
|
||||
wxScrolledWindow* m_scrolledWindow{ nullptr };
|
||||
wxTimer* m_refresh_timer{ nullptr };
|
||||
|
||||
@@ -72,8 +72,10 @@ private:
|
||||
SwitchButton* m_switch_recording;
|
||||
wxStaticText* m_text_vcamera;
|
||||
SwitchButton* m_switch_vcamera;
|
||||
#if !BBL_RELEASE_TO_PUBLIC
|
||||
wxStaticText* m_text_liveview_retry;
|
||||
SwitchButton* m_switch_liveview_retry;
|
||||
#endif //BBL_RELEASE_TO_PUBLIC
|
||||
wxStaticText* m_custom_camera_hint;
|
||||
TextInput* m_custom_camera_input;
|
||||
Button* m_custom_camera_input_confirm;
|
||||
|
||||
@@ -62,10 +62,16 @@ std::string decompose_basic_type_from_source(size_t source_config_idx,
|
||||
auto& project_config = wxGetApp().preset_bundle->project_config;
|
||||
if (auto* filament_id_opt = project_config.option<ConfigOptionStrings>("filament_id")) {
|
||||
if (source_config_idx < filament_id_opt->values.size()) {
|
||||
const std::string& filament_id = filament_id_opt->values[source_config_idx];
|
||||
if (filament_id == kDecomposePetgFilamentId)
|
||||
// Dead in practice: "filament_id" is not in PresetBundle's s_project_options, so this
|
||||
// option() lookup (create=false) always returns null and the block never runs. Kept as
|
||||
// found, with the translation the values would need: they would be our OF ids, and the
|
||||
// two constants are the printer's own ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string& orca_filament_id = filament_id_opt->values[source_config_idx];
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(orca_filament_id) : orca_filament_id;
|
||||
if (printer_filament_id == kDecomposePetgFilamentId)
|
||||
return kDecomposePetgBasicType;
|
||||
if (filament_id == kDecomposePlaFilamentId)
|
||||
if (printer_filament_id == kDecomposePlaFilamentId)
|
||||
return kDecomposePlaBasicType;
|
||||
}
|
||||
}
|
||||
@@ -82,9 +88,14 @@ std::string decompose_basic_type_from_source(size_t source_config_idx,
|
||||
|
||||
std::string decompose_basic_filament_id(const std::string& basic_type)
|
||||
{
|
||||
if (basic_type == kDecomposePetgBasicType)
|
||||
return kDecomposePetgFilamentId;
|
||||
return kDecomposePlaFilamentId;
|
||||
// The result becomes DecomposeOfficialComponent::filament_id, which the rest of this file
|
||||
// reads as one of our OF ids (translating back before it compares against the printer's
|
||||
// ids), so translate on the way out; kDecompose*FilamentId itself stays the printer-side
|
||||
// literal. The only place that would carry it further, project_config's "filament_id", is
|
||||
// dead code: that key is not in PresetBundle's s_project_options.
|
||||
const std::string printer_filament_id = basic_type == kDecomposePetgBasicType ? kDecomposePetgFilamentId : kDecomposePlaFilamentId;
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
return agent ? agent->to_orca_filament_id(printer_filament_id) : printer_filament_id;
|
||||
}
|
||||
|
||||
void set_created_standard_component_metadata(size_t config_idx, const DecomposeOfficialComponent& component)
|
||||
@@ -98,8 +109,11 @@ void set_created_standard_component_metadata(size_t config_idx, const DecomposeO
|
||||
}
|
||||
}
|
||||
|
||||
const std::string type = component.filament_id == kDecomposePetgFilamentId ? kDecomposePetgShortType :
|
||||
component.filament_id == kDecomposePlaFilamentId ? kDecomposePlaShortType : "";
|
||||
// component.filament_id is our OF id; the two constants are the printer's own ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(component.filament_id) : component.filament_id;
|
||||
const std::string type = printer_filament_id == kDecomposePetgFilamentId ? kDecomposePetgShortType :
|
||||
printer_filament_id == kDecomposePlaFilamentId ? kDecomposePlaShortType : "";
|
||||
if (!type.empty()) {
|
||||
if (auto* type_opt = project_config.option<ConfigOptionStrings>("filament_type")) {
|
||||
while (type_opt->values.size() <= config_idx)
|
||||
@@ -151,7 +165,12 @@ DecomposeOfficialComponent lookup_decompose_official_component(
|
||||
continue;
|
||||
if (item.contains("fila_color") && item["fila_color"].is_array() && !item["fila_color"].empty())
|
||||
result.color_hex = decompose_normalize_color_hex(item["fila_color"][0].get<std::string>());
|
||||
result.filament_id = item.value("fila_id", result.filament_id);
|
||||
// fila_id from this shipped, Bambu-keyed color table is a printer-side id; translate it so
|
||||
// result.filament_id stays an OF id like the rest of this struct (the fallback default,
|
||||
// result.filament_id, is already OF and passes through unchanged).
|
||||
const std::string fila_id = item.value("fila_id", result.filament_id);
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
result.filament_id = agent ? agent->to_orca_filament_id(fila_id) : fila_id;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -211,8 +230,11 @@ int find_existing_decompose_component(
|
||||
auto* type_opt = project_config.option<ConfigOptionStrings>("filament_type");
|
||||
const PresetBundle& preset_bundle = *wxGetApp().preset_bundle;
|
||||
const size_t num_physical = physical_colors.size();
|
||||
const std::string expected_basic_type = component.filament_id == kDecomposePetgFilamentId ? kDecomposePetgBasicType :
|
||||
component.filament_id == kDecomposePlaFilamentId ? kDecomposePlaBasicType : "";
|
||||
// component.filament_id is our OF id; the two constants are the printer's own ids.
|
||||
auto* agent = wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(component.filament_id) : component.filament_id;
|
||||
const std::string expected_basic_type = printer_filament_id == kDecomposePetgFilamentId ? kDecomposePetgBasicType :
|
||||
printer_filament_id == kDecomposePlaFilamentId ? kDecomposePlaBasicType : "";
|
||||
const std::string expected_short_type = expected_basic_type == kDecomposePetgBasicType ? kDecomposePetgShortType :
|
||||
expected_basic_type == kDecomposePlaBasicType ? kDecomposePlaShortType : "";
|
||||
const std::string expected_preset_part = expected_basic_type.empty() ? "" : std::string(kDecomposeBambuPresetPrefix) + expected_basic_type;
|
||||
|
||||
@@ -741,14 +741,21 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in
|
||||
bool have_infill = config->option<ConfigOptionPercent>("sparse_infill_density")->value > 0;
|
||||
// sparse_infill_filament_id uses the same logic as in Print::extruders()
|
||||
for (auto el : { "sparse_infill_pattern", "infill_combination", "fill_multiline","infill_direction",
|
||||
"minimum_sparse_infill_area", "sparse_infill_filament_id", "infill_anchor", "infill_anchor_max","infill_shift_step","sparse_infill_rotate_template","symmetric_infill_y_axis"})
|
||||
"minimum_sparse_infill_area", "sparse_infill_filament_id","infill_shift_step","sparse_infill_rotate_template","symmetric_infill_y_axis"})
|
||||
toggle_line(el, have_infill);
|
||||
|
||||
InfillPattern pattern = config->opt_enum<InfillPattern>("sparse_infill_pattern");
|
||||
|
||||
// Orca: the concentric patterns follow the surface outline instead of crossing it, so there is
|
||||
// nothing for an infill anchor to attach to. Hide the anchor settings for them.
|
||||
bool have_infill_anchor = have_infill && pattern != ipConcentric && pattern != ipSpiralInset;
|
||||
toggle_line("infill_anchor", have_infill_anchor);
|
||||
toggle_line("infill_anchor_max", have_infill_anchor);
|
||||
|
||||
bool have_combined_infill = config->opt_bool("infill_combination") && have_infill;
|
||||
toggle_line("infill_combination_max_layer_height", have_combined_infill);
|
||||
|
||||
// Infill patterns that support multiline infill.
|
||||
InfillPattern pattern = config->opt_enum<InfillPattern>("sparse_infill_pattern");
|
||||
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ipLateralLattice || pattern == ipLateralHoneycomb || pattern == ipConcentric ||
|
||||
pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic|| pattern == ipTriangles || pattern == ipQuarterCubic|| pattern == ipArchimedeanChords || pattern == ipHilbertCurve || pattern == ipOctagramSpiral;
|
||||
|
||||
@@ -831,7 +838,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in
|
||||
toggle_line("separated_infills", is_internal_infill_separable);
|
||||
|
||||
// Fill order is only meaningful for the center-based surface fill patterns; hide it otherwise.
|
||||
auto is_centered_fill = [](InfillPattern p) { return p == ipConcentric || p == ipArchimedeanChords || p == ipOctagramSpiral; };
|
||||
auto is_centered_fill = [](InfillPattern p) { return p == ipConcentric || p == ipSpiralInset || p == ipArchimedeanChords || p == ipOctagramSpiral; };
|
||||
toggle_line("top_surface_fill_order", has_top_shell && is_centered_fill(config->opt_enum<InfillPattern>("top_surface_pattern")));
|
||||
toggle_line("bottom_surface_fill_order", has_bottom_shell && is_centered_fill(config->opt_enum<InfillPattern>("bottom_surface_pattern")));
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ private:
|
||||
std::unordered_set<std::string> m_system_filament_types_set;
|
||||
std::set<std::string> m_visible_printers;
|
||||
CreateType m_create_type;
|
||||
Button * m_button_cancel = nullptr;
|
||||
ComboBox * m_filament_vendor_combobox = nullptr;
|
||||
::CheckBox * m_can_not_find_vendor_checkbox = nullptr;
|
||||
ComboBox * m_filament_type_combobox = nullptr;
|
||||
|
||||
@@ -245,7 +245,6 @@ DailyTipsPanel::DailyTipsPanel(bool can_expand, DailyTipsLayout layout)
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_can_expand(can_expand),
|
||||
m_layout(layout),
|
||||
m_uid(DailyTipsPanel::uid++),
|
||||
m_dailytips_renderer(std::make_unique<DailyTipsDataRenderer>(layout))
|
||||
{
|
||||
|
||||
@@ -51,7 +51,6 @@ private:
|
||||
int m_uid;
|
||||
bool m_first_enter{ false };
|
||||
bool m_is_dark{ false };
|
||||
DailyTipsLayout m_layout{ DailyTipsLayout::Vertical };
|
||||
float m_fade_opacity{ 1.0f };
|
||||
};
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
void ParseCalibrationConfig(const json& print_json); //cali
|
||||
|
||||
private:
|
||||
MachineObject* m_obj;
|
||||
[[maybe_unused]] MachineObject* m_obj;
|
||||
|
||||
/*configure vals*/
|
||||
// chamber
|
||||
|
||||
@@ -31,7 +31,7 @@ protected:
|
||||
DevExtensionTool(MachineObject* obj);
|
||||
|
||||
private:
|
||||
MachineObject* m_owner = nullptr;
|
||||
[[maybe_unused]] MachineObject* m_owner = nullptr;
|
||||
|
||||
enum MountState
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
void SetAutoRefillEnabled(bool enable) { m_enable_auto_refill = enable; }
|
||||
|
||||
private:
|
||||
DevFilaSystem* m_owner = nullptr;
|
||||
[[maybe_unused]] DevFilaSystem* m_owner = nullptr;
|
||||
|
||||
std::optional<bool> m_enable_detect_on_insert = false;
|
||||
bool m_enable_detect_on_powerup = false;
|
||||
|
||||
@@ -241,8 +241,11 @@ void check_filaments(const DevFilaBlacklist::CheckFilamentInfo& check_info, DevF
|
||||
std::set<std::string> white_fila_ids = filament_item.contains("white_fila_ids") ? filament_item["white_fila_ids"].get<std::set<std::string>>() : std::set<std::string>();
|
||||
if (!white_fila_ids.empty() && !check_info.fila_id.empty())
|
||||
{
|
||||
auto it = std::find_if(white_fila_ids.begin(), white_fila_ids.end(), [&check_info](const std::string& white_fila_id) {
|
||||
return white_fila_id == check_info.fila_id;
|
||||
// check_info.fila_id is our OF id; white_fila_ids in filaments_blacklist.json holds the printer's own.
|
||||
auto* agent = Slic3r::GUI::wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(check_info.fila_id) : check_info.fila_id;
|
||||
auto it = std::find_if(white_fila_ids.begin(), white_fila_ids.end(), [&printer_filament_id](const std::string& white_fila_id) {
|
||||
return white_fila_id == printer_filament_id;
|
||||
});
|
||||
if (it != white_fila_ids.end()) { continue; }
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// TODO: remove this include
|
||||
#include "slic3r/GUI/DeviceManager.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
||||
#include "DevUtil.h"
|
||||
#include "DevUtilBackend.h"
|
||||
@@ -95,7 +96,12 @@ std::string DevAmsTray::get_filament_type()
|
||||
if (m_fila_type == "Sup.ABS") { return "ABS-S"; }
|
||||
if (m_fila_type == "Support W") { return "PLA-S"; }
|
||||
if (m_fila_type == "Support G") { return "PA-S"; }
|
||||
if (m_fila_type == "Support") { if (setting_id == "GFS00") { m_fila_type = "PLA-S"; } else if (setting_id == "GFS01") { m_fila_type = "PA-S"; } else { return "PLA-S"; } }
|
||||
// setting_id is our OF id; GFS00/GFS01 are the printer's own support-filament ids.
|
||||
if (m_fila_type == "Support") {
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(setting_id) : setting_id;
|
||||
if (printer_filament_id == "GFS00") { m_fila_type = "PLA-S"; } else if (printer_filament_id == "GFS01") { m_fila_type = "PA-S"; } else { return "PLA-S"; }
|
||||
}
|
||||
|
||||
return m_fila_type;
|
||||
}
|
||||
@@ -654,11 +660,14 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
|
||||
curr_tray->setting_id = (*tray_it)["tray_info_idx"].get<std::string>();
|
||||
//std::string type = (*tray_it)["tray_type"].get<std::string>();
|
||||
std::string type = MachineObject::setting_id_to_type(curr_tray->setting_id, (*tray_it)["tray_type"].get<std::string>());
|
||||
if (curr_tray->setting_id == "GFS00")
|
||||
// curr_tray->setting_id is our OF id; GFS00/GFS01 are the printer's own support-filament ids.
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(curr_tray->setting_id) : curr_tray->setting_id;
|
||||
if (printer_filament_id == "GFS00")
|
||||
{
|
||||
curr_tray->m_fila_type = "PLA-S";
|
||||
}
|
||||
else if (curr_tray->setting_id == "GFS01")
|
||||
else if (printer_filament_id == "GFS01")
|
||||
{
|
||||
curr_tray->m_fila_type = "PA-S";
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
std::string id;
|
||||
std::string tag_uid; // tag_uid
|
||||
std::string setting_id; // tray_info_idx
|
||||
std::string setting_id; // tray_info_idx, map to the filament_id
|
||||
std::string filament_setting_id; // setting_id
|
||||
std::string m_fila_type;
|
||||
std::string sub_brands;
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
const std::vector<DevHMSItem>& GetHMSItems() const { return m_hms_list; };
|
||||
|
||||
private:
|
||||
MachineObject* m_object = nullptr;
|
||||
[[maybe_unused]] MachineObject* m_object = nullptr;
|
||||
|
||||
// all hms for this machine
|
||||
std::vector<DevHMSItem> m_hms_list;
|
||||
|
||||
@@ -34,7 +34,7 @@ private:
|
||||
//std::string m_connect_type;
|
||||
//std::string m_bind_state;
|
||||
|
||||
MachineObject* m_owner = nullptr;
|
||||
[[maybe_unused]] MachineObject* m_owner = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
void ParseStatus(const nlohmann::json& print_jj);
|
||||
|
||||
private:
|
||||
MachineObject *m_owner = nullptr;
|
||||
[[maybe_unused]] MachineObject *m_owner = nullptr;
|
||||
std::optional<DevJobState> m_job_state; // could be nullopt for some old firmware
|
||||
};
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
bool is_timelapse_storage_low(const std::string& storage) const;
|
||||
|
||||
private:
|
||||
MachineObject *m_owner;
|
||||
[[maybe_unused]] MachineObject *m_owner;
|
||||
SdcardState m_sdcard_state { NO_SDCARD };
|
||||
// timelapse storage space info (from device push cam data)
|
||||
int tl_internal_free_kb{-1};
|
||||
|
||||
@@ -110,7 +110,9 @@ bool Slic3r::is_stringing_prone_filament(const std::string& filament_id, float n
|
||||
if (filament_id.empty()) return false;
|
||||
const auto* set = pick_stringing_set(nozzle_diameter);
|
||||
if (!set) return false;
|
||||
return set->count(filament_id) > 0;
|
||||
// filament_id is one of our content-addressed OF ids; the table above is keyed by the printer's own.
|
||||
auto* agent = Slic3r::GUI::wxGetApp().getAgent();
|
||||
return set->count(agent ? agent->from_orca_filament_id(filament_id) : filament_id) > 0;
|
||||
}
|
||||
|
||||
wxString Slic3r::get_stage_string(int stage)
|
||||
@@ -5048,10 +5050,13 @@ DevAmsTray MachineObject::parse_vt_tray(json vtray)
|
||||
vt_tray.setting_id = vtray["tray_info_idx"].get<std::string>();
|
||||
//std::string type = vtray["tray_type"].get<std::string>();
|
||||
std::string type = setting_id_to_type(vt_tray.setting_id, vtray["tray_type"].get<std::string>());
|
||||
if (vt_tray.setting_id == "GFS00") {
|
||||
// vt_tray.setting_id is our OF id (translated on the way in); the two support ids below are the printer's own.
|
||||
auto* agent = GUI::wxGetApp().getAgent();
|
||||
const std::string printer_filament_id = agent ? agent->from_orca_filament_id(vt_tray.setting_id) : vt_tray.setting_id;
|
||||
if (printer_filament_id == "GFS00") {
|
||||
vt_tray.m_fila_type = "PLA-S";
|
||||
}
|
||||
else if (vt_tray.setting_id == "GFS01") {
|
||||
else if (printer_filament_id == "GFS01") {
|
||||
vt_tray.m_fila_type = "PA-S";
|
||||
}
|
||||
else {
|
||||
@@ -5592,7 +5597,10 @@ void MachineObject::update_filament_list()
|
||||
|
||||
for (auto it = filament_list.begin(); it != filament_list.end(); it++) {
|
||||
if (m_filament_list.find(it->first) != m_filament_list.end()) {
|
||||
assert(it->first.size() == 8 && it->first[0] == 'P');
|
||||
// User roots may legitimately carry adopted system-shaped ids (GF*/OF*/P-hex
|
||||
// system), so a non-'P' id here is expected, not an invariant violation.
|
||||
if (it->first.size() != 8 || it->first[0] != 'P')
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": user-root filament_id is not user-shaped: " << it->first;
|
||||
|
||||
if (it->second.first != m_filament_list[it->first].first) {
|
||||
BOOST_LOG_TRIVIAL(info) << "old min temp is not equal to new min temp and filament id: " << it->first;
|
||||
@@ -5654,6 +5662,17 @@ void MachineObject::update_printer_preset_name()
|
||||
void MachineObject::check_ams_filament_valid()
|
||||
{
|
||||
PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle;
|
||||
// A tray id carried by ANY system filament preset is not a dangling user-preset id
|
||||
// (ten shipped P-hex system ids pass the 'P' shape gates below), so the destructive
|
||||
// tray-wipe / temp-rewrite handling must never fire for it.
|
||||
auto is_system_filament_id = [preset_bundle](const std::string &id) {
|
||||
if (!preset_bundle)
|
||||
return false;
|
||||
for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++)
|
||||
if (it->is_system && it->filament_id == id)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
auto printer_model = DevPrinterConfigUtil::get_printer_display_name(this->printer_type);
|
||||
std::map<std::string, std::set<std::string>> need_checked_filament_id;
|
||||
for (auto &ams_pair : m_fila_system->GetAmsList()) {
|
||||
@@ -5675,6 +5694,8 @@ void MachineObject::check_ams_filament_valid()
|
||||
auto &checked_filament = data.checked_filament;
|
||||
for (const auto &[slot_id, curr_tray] : ams->GetTrays()) {
|
||||
|
||||
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && is_system_filament_id(curr_tray->setting_id))
|
||||
continue;
|
||||
if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && filament_list.find(curr_tray->setting_id) == filament_list.end()) {
|
||||
if (checked_filament.find(curr_tray->setting_id) != checked_filament.end()) {
|
||||
need_checked_filament_id[nozzle_diameter_str].insert(curr_tray->setting_id);
|
||||
@@ -5735,6 +5756,8 @@ void MachineObject::check_ams_filament_valid()
|
||||
auto &data = m_nozzle_filament_data[nozzle_diameter_str];
|
||||
auto &checked_filament = data.checked_filament;
|
||||
auto &filament_list = data.filament_list;
|
||||
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && is_system_filament_id(vt_tray.setting_id))
|
||||
continue;
|
||||
if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && filament_list.find(vt_tray.setting_id) == filament_list.end()) {
|
||||
if (checked_filament.find(vt_tray.setting_id) != checked_filament.end()) {
|
||||
need_checked_filament_id[nozzle_diameter_str].insert(vt_tray.setting_id);
|
||||
|
||||
@@ -705,7 +705,7 @@ ReselectMachineDialog::ReselectMachineDialog(wxWindow* parent)
|
||||
Centre();
|
||||
}
|
||||
|
||||
void ReselectMachineDialog::Update(MachineObject* obj, const std::map<int, int>& best_pos_map, const std::vector<FilamentInfo>& ams_mapping, wxString save_time)
|
||||
void ReselectMachineDialog::UpdateInfo(MachineObject* obj, const std::map<int, int>& best_pos_map, const std::vector<FilamentInfo>& ams_mapping, wxString save_time)
|
||||
{
|
||||
|
||||
if (suggestText)
|
||||
|
||||
@@ -188,7 +188,7 @@ class ReselectMachineDialog : public wxDialog
|
||||
public:
|
||||
ReselectMachineDialog(wxWindow* parent);
|
||||
~ReselectMachineDialog();
|
||||
void Update(MachineObject* obj,
|
||||
void UpdateInfo(MachineObject* obj,
|
||||
const std::map<int, int>& best_pos_map,
|
||||
const std::vector<FilamentInfo>& ams_mapping,
|
||||
wxString save_time);
|
||||
|
||||
@@ -98,7 +98,7 @@ void uiAmsPercentHumidityDryPopup::Create()
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void uiAmsPercentHumidityDryPopup::Update(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature)
|
||||
void uiAmsPercentHumidityDryPopup::UpdateInfo(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature)
|
||||
{
|
||||
if (m_humidity_level != humidiy_level || m_humidity_percent != humidity_percent ||
|
||||
m_left_dry_time != left_dry_time || m_current_temperature != current_temperature)
|
||||
|
||||
@@ -38,14 +38,14 @@ public:
|
||||
~uiAmsPercentHumidityDryPopup() = default;
|
||||
|
||||
public:
|
||||
void Update(uiAmsHumidityInfo *info) { m_ams_id = info->ams_id; Update(info->humidity_display_idx, info->humidity_percent, info->left_dry_time, info->current_temperature); };
|
||||
void UpdateInfo(uiAmsHumidityInfo *info) { m_ams_id = info->ams_id; UpdateInfo(info->humidity_display_idx, info->humidity_percent, info->left_dry_time, info->current_temperature); };
|
||||
|
||||
std::string get_owner_ams_id() const { return m_ams_id; }
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
private:
|
||||
void Update(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature);
|
||||
void UpdateInfo(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature);
|
||||
void UpdateContents();
|
||||
|
||||
void Create();
|
||||
|
||||
@@ -399,7 +399,7 @@ void wgtDeviceNozzleRackArea::UpdateNozzleItems(const std::unordered_map<int, wg
|
||||
{
|
||||
for (auto iter : nozzle_items)
|
||||
{
|
||||
iter.second->Update(nozzle_rack);
|
||||
iter.second->UpdateInfo(nozzle_rack);
|
||||
}
|
||||
|
||||
/*update nozzle possition and background*/
|
||||
@@ -837,7 +837,7 @@ void wgtDeviceNozzleRackNozzleItem::SetSelected(bool selected)
|
||||
}
|
||||
}
|
||||
|
||||
void wgtDeviceNozzleRackNozzleItem::Update(const std::shared_ptr<DevNozzleRack> rack, bool on_rack /*= true*/)
|
||||
void wgtDeviceNozzleRackNozzleItem::UpdateInfo(const std::shared_ptr<DevNozzleRack> rack, bool on_rack /*= true*/)
|
||||
{
|
||||
m_rack = rack;
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ public:
|
||||
wgtDeviceNozzleRackNozzleItem(wxWindow* parent, int nozzle_id);
|
||||
|
||||
public:
|
||||
void Update(const std::shared_ptr<DevNozzleRack> rack, bool on_rack = true); // on_rack is false means extruder nozzle
|
||||
void UpdateInfo(const std::shared_ptr<DevNozzleRack> rack, bool on_rack = true); // on_rack is false means extruder nozzle
|
||||
|
||||
int GetNozzleId() const { return m_nozzle_id; }
|
||||
void SetDisplayIdText(const wxString& text) { m_nozzle_label_id->SetLabel(text);};
|
||||
|
||||
@@ -114,7 +114,7 @@ static void s_update_nozzle_info(wgtDeviceNozzleRackNozzleItem* item,
|
||||
std::shared_ptr<DevNozzleRack> rack,
|
||||
const DevNozzle& nozzle_info)
|
||||
{
|
||||
item->Update(rack, nozzle_info.IsOnRack());
|
||||
item->UpdateInfo(rack, nozzle_info.IsOnRack());
|
||||
if (nozzle_info.IsUnknown()) {
|
||||
if (item->GetToolTipText() != _L("Nozzle information needs to be read")) {
|
||||
item->SetToolTip(_L("Nozzle information needs to be read"));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "wx/bitmap.h"
|
||||
#include "wx/dragimag.h"
|
||||
#include "wx/panel.h"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include <algorithm>
|
||||
#include "I18N.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <wx/dcgraph.h>
|
||||
@@ -599,8 +600,10 @@ void ExtrusionCalibration::update_combobox_filaments()
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
if (preset_bundle && obj) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size();
|
||||
std::string printer_type = obj->printer_type;
|
||||
std::set<std::string> printer_preset_list;
|
||||
double nozzle_value = 0.4;
|
||||
m_comboBox_nozzle_dia->GetValue().ToDouble(&nozzle_value);
|
||||
|
||||
std::vector<PresetWithVendorProfile> printer_profiles;
|
||||
for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) {
|
||||
// only use system printer preset
|
||||
if (!printer_it->is_system) continue;
|
||||
@@ -610,49 +613,42 @@ void ExtrusionCalibration::update_combobox_filaments()
|
||||
ConfigOptionFloats* printer_nozzle_vals = nullptr;
|
||||
if (printer_nozzle_opt)
|
||||
printer_nozzle_vals = dynamic_cast<ConfigOptionFloats*>(printer_nozzle_opt);
|
||||
double nozzle_value = 0.4;
|
||||
wxString nozzle_value_str = m_comboBox_nozzle_dia->GetValue();
|
||||
try {
|
||||
nozzle_value_str.ToDouble(&nozzle_value);
|
||||
} catch(...) {
|
||||
;
|
||||
}
|
||||
if (!model_id.empty() && model_id.compare(obj->printer_type) == 0
|
||||
&& printer_nozzle_vals
|
||||
&& abs(printer_nozzle_vals->get_at(0) - nozzle_value) < 1e-3) {
|
||||
printer_preset_list.insert(printer_it->name);
|
||||
printer_profiles.push_back(preset_bundle->printers.get_preset_with_vendor_profile(*printer_it));
|
||||
BOOST_LOG_TRIVIAL(trace) << "extrusion_cali: printer_model = " << model_id;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "extrusion_cali: printer_model = " << model_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Unlike the AMS dialogs this one offers every matching preset by full name rather than one
|
||||
// root preset per alias, so it filters the collection itself instead of calling
|
||||
// PresetBundle::get_filament_presets_for_machine().
|
||||
for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) {
|
||||
ConfigOption* printer_opt = filament_it->config.option("compatible_printers");
|
||||
ConfigOptionStrings* printer_strs = dynamic_cast<ConfigOptionStrings*>(printer_opt);
|
||||
for (auto printer_str : printer_strs->values) {
|
||||
if (printer_preset_list.find(printer_str) != printer_preset_list.end()) {
|
||||
user_filaments.push_back(&(*filament_it));
|
||||
const PresetWithVendorProfile filament = preset_bundle->filaments.get_preset_with_vendor_profile(*filament_it);
|
||||
if (std::none_of(printer_profiles.begin(), printer_profiles.end(),
|
||||
[&filament](const PresetWithVendorProfile &printer) { return is_compatible_with_printer(filament, printer); }))
|
||||
continue;
|
||||
|
||||
// set default filament id
|
||||
filament_index++;
|
||||
if (filament_it->is_system
|
||||
&& !ams_filament_id.empty()
|
||||
&& filament_it->filament_id == ams_filament_id
|
||||
) {
|
||||
curr_selection = filament_index;
|
||||
}
|
||||
user_filaments.push_back(&(*filament_it));
|
||||
|
||||
if (filament_it->name == obj->extrusion_cali_filament_name && !obj->extrusion_cali_filament_name.empty())
|
||||
{
|
||||
curr_selection = filament_index;
|
||||
}
|
||||
|
||||
wxString filament_name = wxString::FromUTF8(filament_it->name);
|
||||
filament_items.Add(filament_name);
|
||||
break;
|
||||
}
|
||||
// set default filament id
|
||||
filament_index++;
|
||||
if (filament_it->is_system
|
||||
&& !ams_filament_id.empty()
|
||||
&& filament_it->filament_id == ams_filament_id
|
||||
) {
|
||||
curr_selection = filament_index;
|
||||
}
|
||||
|
||||
if (filament_it->name == obj->extrusion_cali_filament_name && !obj->extrusion_cali_filament_name.empty())
|
||||
{
|
||||
curr_selection = filament_index;
|
||||
}
|
||||
|
||||
filament_items.Add(wxString::FromUTF8(filament_it->name));
|
||||
}
|
||||
m_comboBox_filament->Set(filament_items);
|
||||
m_comboBox_filament->SetSelection(curr_selection);
|
||||
|
||||
@@ -642,19 +642,12 @@ void FilamentMapBtnPanel::Select(bool selected)
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void GUI::FilamentMapBtnPanel::Hide()
|
||||
bool GUI::FilamentMapBtnPanel::Show(bool show)
|
||||
{
|
||||
m_btn->Hide();
|
||||
m_label->Hide();
|
||||
m_detail->Hide();
|
||||
wxPanel::Hide();
|
||||
}
|
||||
void GUI::FilamentMapBtnPanel::Show()
|
||||
{
|
||||
m_btn->Show();
|
||||
m_label->Show();
|
||||
m_detail->Show();
|
||||
wxPanel::Show();
|
||||
m_btn->Show(show);
|
||||
m_label->Show(show);
|
||||
m_detail->Show(show);
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
FilamentMapAutoPanel::FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode, bool machine_synced) : wxPanel(parent)
|
||||
@@ -694,18 +687,11 @@ FilamentMapAutoPanel::FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mod
|
||||
Layout();
|
||||
GUI::wxGetApp().UpdateDarkUIWin(this);
|
||||
}
|
||||
void FilamentMapAutoPanel::Hide()
|
||||
bool FilamentMapAutoPanel::Show(bool show)
|
||||
{
|
||||
m_flush_panel->Hide();
|
||||
m_match_panel->Hide();
|
||||
wxPanel::Hide();
|
||||
}
|
||||
|
||||
void FilamentMapAutoPanel::Show()
|
||||
{
|
||||
m_flush_panel->Show();
|
||||
m_match_panel->Show();
|
||||
wxPanel::Show();
|
||||
m_flush_panel->Show(show);
|
||||
m_match_panel->Show(show);
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
void FilamentMapAutoPanel::UpdateStatus()
|
||||
@@ -743,16 +729,10 @@ FilamentMapDefaultPanel::FilamentMapDefaultPanel(wxWindow *parent) : wxPanel(par
|
||||
GUI::wxGetApp().UpdateDarkUIWin(this);
|
||||
}
|
||||
|
||||
void FilamentMapDefaultPanel::Hide()
|
||||
bool FilamentMapDefaultPanel::Show(bool show)
|
||||
{
|
||||
m_label->Hide();
|
||||
wxPanel::Hide();
|
||||
}
|
||||
|
||||
void FilamentMapDefaultPanel::Show()
|
||||
{
|
||||
m_label->Show();
|
||||
wxPanel::Show();
|
||||
m_label->Show(show);
|
||||
return wxPanel::Show(show);
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
@@ -69,10 +69,9 @@ class FilamentMapBtnPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
FilamentMapBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon_path);
|
||||
void Hide();
|
||||
void Show();
|
||||
bool Show(bool show = true) override;
|
||||
void Select(bool selected);
|
||||
bool Enable(bool enable);
|
||||
bool Enable(bool enable) override;
|
||||
bool IsEnabled() const { return m_enabled; }
|
||||
protected:
|
||||
void OnPaint(wxPaintEvent &event);
|
||||
@@ -99,8 +98,7 @@ class FilamentMapAutoPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode, bool machine_synced);
|
||||
void Hide();
|
||||
void Show();
|
||||
bool Show(bool show = true) override;
|
||||
FilamentMapMode GetMode() const { return m_mode; }
|
||||
|
||||
private:
|
||||
@@ -116,8 +114,7 @@ class FilamentMapDefaultPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
FilamentMapDefaultPanel(wxWindow *parent);
|
||||
void Hide();
|
||||
void Show();
|
||||
bool Show(bool show = true) override;
|
||||
|
||||
private:
|
||||
Label *m_label;
|
||||
|
||||
@@ -785,6 +785,19 @@ void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& fil
|
||||
}
|
||||
}
|
||||
|
||||
// Byte offset just past the first count characters of str, or its length if it is shorter.
|
||||
static size_t utf8_offset(const std::string& str, size_t count)
|
||||
{
|
||||
const char* const begin = str.c_str();
|
||||
const char* const end = begin + str.size();
|
||||
const char* pos = begin;
|
||||
for (size_t i = 0; i < count && pos < end; ++i) {
|
||||
unsigned int codepoint = 0;
|
||||
pos += ImTextCharFromUtf8(&codepoint, pos, end);
|
||||
}
|
||||
return pos - begin;
|
||||
}
|
||||
|
||||
//BBS: GUI refactor: move to right
|
||||
void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, float right, uint64_t curr_line_id) const
|
||||
{
|
||||
@@ -796,23 +809,27 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, f
|
||||
// read line from file
|
||||
const size_t start = id == 1 ? 0 : m_lines_ends[id - 2];
|
||||
const size_t original_len = m_lines_ends[id - 1] - start;
|
||||
const size_t len = std::min(original_len, (size_t) 55);
|
||||
// A character is four bytes at most, so 55 of them always fit in 220.
|
||||
const size_t len = std::min(original_len, (size_t) 55 * 4);
|
||||
std::string gline(m_file.data() + start, len);
|
||||
|
||||
// If original line is longer than 55 characters, truncate and append "..."
|
||||
if (original_len > 55)
|
||||
gline = gline.substr(0, 52) + "...";
|
||||
// If original line is longer than 55 characters, truncate and append "...".
|
||||
// The cut must land on a character boundary or it leaves half a character behind.
|
||||
if (len < original_len || utf8_offset(gline, 55) < gline.size())
|
||||
gline = gline.substr(0, utf8_offset(gline, 52)) + "...";
|
||||
|
||||
std::string command, parameters, comment;
|
||||
// extract comment
|
||||
std::vector<std::string> tokens;
|
||||
boost::split(tokens, gline, boost::is_any_of(";"), boost::token_compress_on);
|
||||
command = tokens.front();
|
||||
if (tokens.size() > 1)
|
||||
comment = ";" + tokens.back();
|
||||
const size_t comment_start = gline.find(';');
|
||||
if (comment_start == std::string::npos)
|
||||
command = gline;
|
||||
else {
|
||||
command = gline.substr(0, comment_start);
|
||||
comment = gline.substr(comment_start);
|
||||
}
|
||||
|
||||
// extract gcode command and parameters
|
||||
if (!command.empty()) {
|
||||
std::vector<std::string> tokens;
|
||||
boost::split(tokens, command, boost::is_any_of(" "), boost::token_compress_on);
|
||||
command = tokens.front();
|
||||
if (tokens.size() > 1) {
|
||||
|
||||
@@ -4168,7 +4168,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
// https://github.com/OrcaSlicer/OrcaSlicer/pull/14999#issuecomment-5151344759
|
||||
// We solve this by correcting the state of the event from the actual mouse state querying with `wxGetMouseState()`
|
||||
// so it works like on other platforms.
|
||||
{
|
||||
// Only fill in state the event does not carry, to preserve wx's synthetic right button for Ctrl+left.
|
||||
if (!evt.ButtonIsDown(wxMOUSE_BTN_ANY)) {
|
||||
const auto state = wxGetMouseState();
|
||||
evt.SetLeftDown(state.LeftIsDown());
|
||||
evt.SetMiddleDown(state.MiddleIsDown());
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#include "slic3r/GUI/TaskManager.hpp"
|
||||
#include "format.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
#include "BuildCommit.hpp"
|
||||
#include "Downloader.hpp"
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/locale/encoding_utf.hpp>
|
||||
#include <boost/log/detail/native_typeof.hpp>
|
||||
#include <libslic3r/Config.hpp>
|
||||
#include <mutex>
|
||||
@@ -2580,7 +2582,7 @@ void GUI_App::init_app_config()
|
||||
set_log_path_and_level(log_filename, 3);
|
||||
#endif
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("gui mode, Current OrcaSlicer Version %1% build %2%") % SoftFever_VERSION % GIT_COMMIT_HASH;
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("gui mode, Current OrcaSlicer Version %1% build %2%") % SoftFever_VERSION % build_commit_label;
|
||||
|
||||
//BBS: remove GCodeViewer as seperate APP logic
|
||||
if (!app_config)
|
||||
|
||||
@@ -591,16 +591,11 @@ private:
|
||||
wxColour m_hover_colour;
|
||||
wxBoxSizer* m_top_sizer{nullptr};
|
||||
wxBoxSizer* m_page_sizer{nullptr};
|
||||
wxBoxSizer* m_page_top_sizer{nullptr};
|
||||
wxTextCtrl* m_search_line{ nullptr };
|
||||
ObjectGrid* m_object_grid{nullptr};
|
||||
ObjectGridTable* m_object_grid_table{nullptr};
|
||||
wxStaticText* m_page_text{nullptr};
|
||||
ScalableButton* m_global_reset{nullptr};
|
||||
wxScrolledWindow* m_side_window{nullptr};
|
||||
ObjectTableSettings* m_object_settings{ nullptr };
|
||||
Model* m_model{nullptr};
|
||||
ModelConfig* m_config {nullptr};
|
||||
Plater* m_plater{nullptr};
|
||||
|
||||
int m_cur_row { -1 };
|
||||
@@ -625,8 +620,6 @@ class ObjectTableDialog : public GUI::DPIDialog
|
||||
const int POPUP_HEIGHT = FromDIP(1024);
|
||||
|
||||
//wxPanel* m_panel{ nullptr };
|
||||
wxBoxSizer* m_top_sizer{ nullptr };
|
||||
wxStaticText* m_static_title{ nullptr };
|
||||
//wxTimer* m_refresh_timer;
|
||||
ObjectTablePanel* m_obj_panel{ nullptr };
|
||||
Model* m_model{ nullptr };
|
||||
|
||||
@@ -94,7 +94,6 @@ class GLGizmoCut3D : public GLGizmoBase
|
||||
GLModel m_reference_radius;
|
||||
GLModel m_angle_arc;
|
||||
|
||||
Vec3d m_old_center;
|
||||
Vec3d m_cut_normal;
|
||||
|
||||
struct InvalidConnectorsStatistics
|
||||
|
||||
@@ -25,7 +25,6 @@ class HMSNotifyItem : public wxPanel
|
||||
wxStaticBitmap *m_bitmap_notify;
|
||||
wxStaticBitmap *m_bitmap_arrow;
|
||||
wxStaticText * m_hms_content;
|
||||
wxHtmlWindow * m_html;
|
||||
wxPanel * m_staticline;
|
||||
|
||||
wxBitmap m_img_notify_lv1;
|
||||
|
||||
@@ -216,7 +216,6 @@ private:
|
||||
long m_extra_style;
|
||||
float m_label_koef{1.0};
|
||||
|
||||
float m_zero_layer_height = 0.0f;
|
||||
std::vector<double> m_values;
|
||||
TickCodeInfo m_ticks;
|
||||
std::vector<double> m_layers_times;
|
||||
|
||||
@@ -20,7 +20,6 @@ class BindJob : public Job
|
||||
std::string m_sec_link;
|
||||
std::string m_ssdp_version;
|
||||
bool m_job_finished{ false };
|
||||
int m_print_job_completed_id = 0;
|
||||
bool m_improved{false};
|
||||
|
||||
public:
|
||||
|
||||
@@ -27,7 +27,6 @@ class UpgradeNetworkJob : public Job
|
||||
wxWindow * m_event_handle{nullptr};
|
||||
std::function<void()> m_success_fun{nullptr};
|
||||
bool m_job_finished{ false };
|
||||
int m_print_job_completed_id = 0;
|
||||
|
||||
InstallProgressFn pro_fn { nullptr };
|
||||
|
||||
|
||||
@@ -4530,10 +4530,9 @@ std::string MainFrame::get_dir_name(const wxString &full_name) const
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SettingsDialog::SettingsDialog(MainFrame* mainframe)
|
||||
:DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "settings_dialog"),
|
||||
:DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "settings_dialog")
|
||||
//: DPIDialog(mainframe, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize,
|
||||
// wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX, "settings_dialog"),
|
||||
m_main_frame(mainframe)
|
||||
{
|
||||
if (wxGetApp().is_gcode_viewer())
|
||||
return;
|
||||
|
||||
@@ -94,7 +94,6 @@ class SettingsDialog : public DPIDialog//DPIDialog
|
||||
{
|
||||
//wxNotebook* m_tabpanel { nullptr };
|
||||
Notebook* m_tabpanel{ nullptr };
|
||||
MainFrame* m_main_frame { nullptr };
|
||||
wxMenuBar* m_menubar{ nullptr };
|
||||
public:
|
||||
SettingsDialog(MainFrame* mainframe);
|
||||
|
||||
@@ -494,13 +494,13 @@ void MediaPlayCtrl::ToggleStream()
|
||||
DownloadProgressDialog2(MediaPlayCtrl *ctrl) : DownloadProgressDialog(_L("Downloading Virtual Camera Tools")), ctrl(ctrl) {}
|
||||
struct UpgradeNetworkJob2 : UpgradeNetworkJob
|
||||
{
|
||||
UpgradeNetworkJob2(std::shared_ptr<ProgressIndicator> pri) : UpgradeNetworkJob() {
|
||||
UpgradeNetworkJob2() {
|
||||
name = "cameratools";
|
||||
package_name = "camera_tools.zip";
|
||||
}
|
||||
};
|
||||
std::shared_ptr<UpgradeNetworkJob> make_job(std::shared_ptr<ProgressIndicator> pri)
|
||||
{ return std::make_shared<UpgradeNetworkJob2>(pri); }
|
||||
std::unique_ptr<UpgradeNetworkJob> make_job() override
|
||||
{ return std::make_unique<UpgradeNetworkJob2>(); }
|
||||
void on_finish() override
|
||||
{
|
||||
ctrl->CallAfter([ctrl = this->ctrl] { ctrl->ToggleStream(); });
|
||||
|
||||
@@ -126,7 +126,6 @@ MixedFilamentDialog::MixedFilamentDialog(wxWindow* parent,
|
||||
const std::vector<std::string>& physical_types)
|
||||
: DPIDialog(parent, wxID_ANY, _L("Add Mixed Filament"), wxDefaultPosition,
|
||||
wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
|
||||
, m_edit_mode(false)
|
||||
, m_physical_colors(physical_colors)
|
||||
, m_physical_names(physical_names)
|
||||
, m_physical_types(physical_types)
|
||||
@@ -157,7 +156,6 @@ MixedFilamentDialog::MixedFilamentDialog(wxWindow* parent,
|
||||
: DPIDialog(parent, wxID_ANY, _L("Edit Mixed Filament"), wxDefaultPosition,
|
||||
wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
|
||||
, m_result(existing)
|
||||
, m_edit_mode(true)
|
||||
, m_physical_colors(physical_colors)
|
||||
, m_physical_names(physical_names)
|
||||
, m_physical_types(physical_types)
|
||||
|
||||
@@ -115,7 +115,6 @@ private:
|
||||
wxColour comp_colour(size_t i) const;
|
||||
|
||||
MixedFilamentResult m_result;
|
||||
bool m_edit_mode{false};
|
||||
std::vector<std::string> m_physical_colors;
|
||||
std::vector<std::string> m_physical_names;
|
||||
std::vector<std::string> m_physical_types;
|
||||
|
||||
@@ -78,7 +78,6 @@ private:
|
||||
Tabbook* m_tabpanel{ nullptr };
|
||||
wxSizer* m_main_sizer{ nullptr };
|
||||
|
||||
AddMachinePanel* m_status_add_machine_panel;
|
||||
StatusPanel* m_status_info_panel;
|
||||
MediaFilePanel* m_media_file_panel;
|
||||
UpgradePanel* m_upgrade_panel;
|
||||
@@ -86,8 +85,6 @@ private:
|
||||
|
||||
/* side tools */
|
||||
SideTools* m_side_tools{nullptr};
|
||||
wxStaticBitmap* m_bitmap_arrow;
|
||||
wxStaticBitmap* m_bitmap_wifi_signal;
|
||||
SelectMachinePopup m_select_machine;
|
||||
|
||||
/* images */
|
||||
|
||||
@@ -177,7 +177,6 @@ public:
|
||||
// Generic rich message dialog, used intead of wxRichMessageDialog
|
||||
class RichMessageDialog : public MsgDialog
|
||||
{
|
||||
wxCheckBox* m_checkBox{ nullptr };
|
||||
wxString m_checkBoxText;
|
||||
bool m_checkBoxValue{ false };
|
||||
|
||||
@@ -416,7 +415,6 @@ private:
|
||||
wxString m_new_keys;
|
||||
Button * m_update_btn = nullptr;
|
||||
Button * m_later_btn = nullptr;
|
||||
wxStaticText *m_msg_text = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,6 @@ private:
|
||||
wxBoxSizer* m_main_sizer{nullptr};
|
||||
wxBoxSizer* m_sizer_machine_list{nullptr};
|
||||
wxScrolledWindow* m_machine_list{ nullptr };
|
||||
wxStaticText* m_selected_num{ nullptr };
|
||||
|
||||
// table head
|
||||
wxPanel* m_table_head_panel{ nullptr };
|
||||
@@ -99,8 +98,6 @@ private:
|
||||
int m_total_count{ 0 };
|
||||
int m_count_page_item{ 10 };
|
||||
|
||||
bool prev{ false };
|
||||
bool next{ false };
|
||||
Button* btn_last_page{ nullptr };
|
||||
Button* btn_next_page{ nullptr };
|
||||
wxStaticText* st_page_number{ nullptr };
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user