mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 10:51:22 +00:00
Merge branch 'main' into pr/tommasobbianchi/15238
This commit is contained in:
+27
-2
@@ -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)
|
||||
@@ -75,7 +76,7 @@ if (SLIC3R_GUI)
|
||||
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX expat)
|
||||
list(APPEND wxWidgets_LIBRARIES ${EXPAT_LIBRARIES})
|
||||
endif ()
|
||||
|
||||
|
||||
# This is an issue in the new wxWidgets cmake build, doesn't deal with librt
|
||||
find_library(LIBRT rt)
|
||||
if(LIBRT)
|
||||
@@ -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}")
|
||||
@@ -294,6 +305,16 @@ if (WIN32)
|
||||
endif()
|
||||
|
||||
else ()
|
||||
if (NOT APPLE)
|
||||
set(output_sos_Release "")
|
||||
set(output_sos_Debug "")
|
||||
add_custom_target(OrcaSlicerSosCopy ALL DEPENDS OrcaSlicer)
|
||||
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
orcaslicer_copy_sos(OrcaSlicerSosCopy "Debug" "d" output_sos_Debug)
|
||||
else()
|
||||
orcaslicer_copy_sos(OrcaSlicerSosCopy "Release" "" output_sos_Release)
|
||||
endif()
|
||||
endif()
|
||||
if (APPLE AND NOT CMAKE_MACOSX_BUNDLE)
|
||||
# On OSX, the name of the binary matches the name of the Application.
|
||||
add_custom_command(TARGET OrcaSlicer POST_BUILD
|
||||
@@ -372,5 +393,9 @@ if (WIN32)
|
||||
install(FILES ${output_dlls_${build_type}} DESTINATION ".")
|
||||
install(DIRECTORY "${CMAKE_PREFIX_PATH}/libpython/" DESTINATION "python")
|
||||
else ()
|
||||
if (APPLE)
|
||||
else()
|
||||
install(FILES ${output_sos_${build_type}} DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
install(TARGETS OrcaSlicer RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif ()
|
||||
|
||||
+94
-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,7 @@ int CLI::run(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
auto load_config_file = [config_substitution_rule](const std::string& file, DynamicPrintConfig& config, std::string& config_type,
|
||||
auto load_config_file = [](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;
|
||||
@@ -2343,8 +2348,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 +3144,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 +3756,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 +3768,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 +3973,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 +4173,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 +4823,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 +5203,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 +5276,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 +6537,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 +6569,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 +7369,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()) {
|
||||
@@ -7384,7 +7446,7 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn
|
||||
<< std::endl
|
||||
<< "Print setting priorities:" << std::endl
|
||||
<< "\t1) setting values from the command line (highest priority)"<< std::endl
|
||||
<< "\t2) setting values loaded with --load_settings and --load_filaments" << std::endl
|
||||
<< "\t2) setting values loaded with --load-settings and --load-filaments" << std::endl
|
||||
<< "\t3) setting values loaded from 3mf(lowest priority)" << std::endl;
|
||||
|
||||
/*if (include_print_options) {
|
||||
@@ -7423,6 +7485,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 +7614,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
|
||||
|
||||
|
||||
@@ -83,6 +83,10 @@ copy_shared_object_to_dir() {
|
||||
src_real="$(readlink -f "$src")"
|
||||
dst_name="$(basename "$src_real")"
|
||||
mkdir -p "$dst_dir"
|
||||
if [ "$src_real" = "$dst_dir/$dst_name" ]; then
|
||||
# Already bundled; the dependency resolved from the bundle directory.
|
||||
return 0
|
||||
fi
|
||||
cp -fL "$src_real" "$dst_dir/$dst_name"
|
||||
|
||||
if [ -L "$src" ]; then
|
||||
@@ -96,12 +100,23 @@ copy_shared_object_to_dir() {
|
||||
}
|
||||
|
||||
bundle_dependency_closure() {
|
||||
local dst_dir="$1"
|
||||
local dst_dir
|
||||
dst_dir="$(cd -- "$1" && pwd)"
|
||||
shift
|
||||
|
||||
local -a queue=("$@")
|
||||
local target dep dep_real copied_path
|
||||
local target dep dep_real dep_key copied_path
|
||||
declare -A seen=()
|
||||
# Dependencies are resolved with ldd, which only searches the default
|
||||
# loader path. Deps-built shared libraries (e.g. the FFmpeg stack) are not
|
||||
# installed there and carry no RUNPATH of their own, so once copied into
|
||||
# the bundle ldd can no longer resolve one sibling from another
|
||||
# (libavcodec -> libavutil) and reports it as missing. Extend the loader
|
||||
# path with the bundle directory plus the source directories of files
|
||||
# already bundled, so every library that was resolved once keeps resolving
|
||||
# for its own dependencies. The audit script does the same
|
||||
# (scripts/check_appimage_libs.sh).
|
||||
local -a search_dirs=("$dst_dir")
|
||||
|
||||
while [ ${#queue[@]} -gt 0 ]; do
|
||||
target="${queue[0]}"
|
||||
@@ -122,17 +137,24 @@ bundle_dependency_closure() {
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -n "${seen[$dep_real]}" ]; then
|
||||
# Key dedup on the bundled file rather than the source path: once
|
||||
# ldd resolves a library from the bundle directory (via the
|
||||
# LD_LIBRARY_PATH above) its path is a dst_dir path, which differs
|
||||
# from the source path the first resolution returned. Keying on
|
||||
# the source path would re-copy the file onto itself.
|
||||
dep_key="$dst_dir/$(basename "$dep_real")"
|
||||
if [ -n "${seen[$dep_key]}" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
seen[$dep_real]=1
|
||||
seen[$dep_key]=1
|
||||
copy_shared_object_to_dir "$dep" "$dst_dir"
|
||||
search_dirs+=("$(dirname "$dep_real")")
|
||||
copied_path="$dst_dir/$(basename "$dep_real")"
|
||||
if [ -e "$copied_path" ]; then
|
||||
queue+=("$copied_path")
|
||||
fi
|
||||
done < <(appimage_list_direct_dependencies "$target")
|
||||
done < <(LD_LIBRARY_PATH="$(IFS=:; printf '%s' "${search_dirs[*]}")${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" appimage_list_direct_dependencies "$target")
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
@@ -1460,6 +1460,7 @@ void AppConfig::set_mouse_device(const std::string& name, double translation_spe
|
||||
it->second["invert_yaw"] = invert_yaw ? "1" : "0";
|
||||
it->second["invert_pitch"] = invert_pitch ? "1" : "0";
|
||||
it->second["invert_roll"] = invert_roll ? "1" : "0";
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
std::vector<std::string> AppConfig::get_mouse_device_names() const
|
||||
|
||||
@@ -797,7 +797,7 @@ public:
|
||||
}
|
||||
});
|
||||
|
||||
m_pck.unfitIndicator([this](std::string name) {
|
||||
m_pck.unfitIndicator([](std::string name) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "arrange progress: " + name;
|
||||
});
|
||||
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -152,6 +152,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
|
||||
@@ -719,6 +721,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);
|
||||
}
|
||||
|
||||
@@ -1715,6 +1716,36 @@ const ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key) co
|
||||
return (it == options.end()) ? nullptr : it->second.get();
|
||||
}
|
||||
|
||||
// ConfigOptionBool(s)::deserialize only understands "1" and "0", but scripts commonly spell CLI
|
||||
// flags as --opt=true or --opt=no. Map the usual spellings onto what deserialize() accepts, per
|
||||
// comma-separated item so vector options keep working, and pass anything else through unchanged
|
||||
// so a genuine typo is still reported as invalid.
|
||||
static std::string normalize_cli_bool_value(const std::string &value)
|
||||
{
|
||||
static const char* true_values[] = { "1", "true", "yes", "on", "enabled" };
|
||||
static const char* false_values[] = { "0", "false", "no", "off", "disabled" };
|
||||
|
||||
auto matches = [](const std::string &item, const char* const* candidates, size_t count) {
|
||||
return std::any_of(candidates, candidates + count, [&item](const char* candidate) { return boost::iequals(item, candidate); });
|
||||
};
|
||||
|
||||
std::string normalized;
|
||||
std::istringstream is(value);
|
||||
std::string item;
|
||||
while (std::getline(is, item, ',')) {
|
||||
boost::trim(item);
|
||||
if (! normalized.empty())
|
||||
normalized += ",";
|
||||
if (matches(item, true_values, std::size(true_values)))
|
||||
normalized += "1";
|
||||
else if (matches(item, false_values, std::size(false_values)))
|
||||
normalized += "0";
|
||||
else
|
||||
normalized += item;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys)
|
||||
{
|
||||
// cache the CLI option => opt_key mapping
|
||||
@@ -1812,17 +1843,32 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option
|
||||
// to the end of the value.
|
||||
if (opt_base->type() == coBools && value.empty())
|
||||
static_cast<ConfigOptionBools*>(opt_base)->values.push_back(!no);
|
||||
else
|
||||
else {
|
||||
// Deserialize any other vector value (ConfigOptionInts, Floats, Percents, Points) the same way
|
||||
// they get deserialized from an .ini file. For ConfigOptionStrings, that means that the C-style unescape
|
||||
// will be applied for values enclosed in quotes, while values non-enclosed in quotes are left to be
|
||||
// unescaped by the calling shell.
|
||||
opt_vector->deserialize(value, true);
|
||||
const std::string vector_value = opt_base->type() == coBools ? normalize_cli_bool_value(value) : value;
|
||||
bool deserialized = false;
|
||||
try {
|
||||
deserialized = opt_vector->deserialize(vector_value, true);
|
||||
} catch (const std::exception &ex) {
|
||||
// e.g. "nil" deserialized into a non-nullable vector option throws instead of
|
||||
// returning false - treat that the same as any other invalid value here.
|
||||
deserialized = false;
|
||||
}
|
||||
if (! deserialized) {
|
||||
boost::nowide::cerr << "Invalid value for option --" << token.c_str() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (opt_base->type() == coBool) {
|
||||
if (value.empty())
|
||||
static_cast<ConfigOptionBool*>(opt_base)->value = !no;
|
||||
else
|
||||
opt_base->deserialize(value);
|
||||
else if (! opt_base->deserialize(normalize_cli_bool_value(value))) {
|
||||
boost::nowide::cerr << "Invalid value for option --" << token.c_str() << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else if (opt_base->type() == coString) {
|
||||
// Do not unescape single string values, the unescaping is left to the calling shell.
|
||||
static_cast<ConfigOptionString*>(opt_base)->value = value;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2395,12 +2395,7 @@ static std::vector<MonotonicRegionLink> chain_monotonic_regions(
|
||||
}
|
||||
|
||||
// Probability (unnormalized) of traversing a link between two monotonic regions.
|
||||
auto path_probability = [
|
||||
#ifndef __APPLE__
|
||||
// clang complains when capturing constexpr constants.
|
||||
pheromone_alpha, pheromone_beta
|
||||
#endif // __APPLE__
|
||||
](AntPath &path) {
|
||||
auto path_probability = [](AntPath &path) {
|
||||
return pow(path.pheromone, pheromone_alpha) * pow(path.visibility, pheromone_beta);
|
||||
};
|
||||
|
||||
|
||||
@@ -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_
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <string>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DIR_SEPARATOR '\\'
|
||||
|
||||
@@ -8197,9 +8197,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
}
|
||||
variable_speed = std::any_of(new_points.begin(), new_points.end(),
|
||||
[speed](const ProcessedPoint &p) { return fabs(double(p.speed) - speed) > 1; }); // Ignore small speed variations (under 1mm/sec)
|
||||
if (!NOZZLE_CONFIG(enable_overhang_speed) && FILAMENT_CONFIG(enable_overhang_bridge_fan) && m_enable_cooling_markers) {
|
||||
for (ProcessedPoint &point : new_points)
|
||||
point.speed = speed;
|
||||
if (FILAMENT_CONFIG(enable_overhang_bridge_fan) && m_enable_cooling_markers) {
|
||||
if (!NOZZLE_CONFIG(enable_overhang_speed))
|
||||
for (ProcessedPoint &point : new_points)
|
||||
point.speed = speed;
|
||||
variable_speed = new_points.size() > 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1024,28 +1024,29 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
}
|
||||
|
||||
if (need_set_fan) {
|
||||
const auto set_fan = [&](int speed) {
|
||||
if (m_current_fan_speed != speed) {
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, speed, part_cooling_fan_min_pwm);
|
||||
m_current_fan_speed = speed;
|
||||
}
|
||||
};
|
||||
if (fan_speed_change_requests[CoolingLine::TYPE_OVERHANG_FAN_START]){
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, overhang_fan_speed, part_cooling_fan_min_pwm);
|
||||
m_current_fan_speed = overhang_fan_speed;
|
||||
set_fan(overhang_fan_speed);
|
||||
} else if (fan_speed_change_requests[CoolingLine::TYPE_INTERNAL_BRIDGE_FAN_START]){ // ORCA: Add support for separate internal bridge fan speed control
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, internal_bridge_fan_speed, part_cooling_fan_min_pwm);
|
||||
m_current_fan_speed = internal_bridge_fan_speed;
|
||||
set_fan(internal_bridge_fan_speed);
|
||||
}
|
||||
else if (fan_speed_change_requests[CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_START]){
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, supp_interface_fan_speed, part_cooling_fan_min_pwm);
|
||||
m_current_fan_speed = supp_interface_fan_speed;
|
||||
set_fan(supp_interface_fan_speed);
|
||||
}
|
||||
else if (fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]){
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, ironing_fan_speed, part_cooling_fan_min_pwm);
|
||||
m_current_fan_speed = ironing_fan_speed;
|
||||
set_fan(ironing_fan_speed);
|
||||
}
|
||||
else if(fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] && m_current_fan_speed != -1){
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_current_fan_speed, part_cooling_fan_min_pwm);
|
||||
fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] = false;
|
||||
}
|
||||
else {
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed, part_cooling_fan_min_pwm);
|
||||
m_current_fan_speed = m_fan_speed;
|
||||
set_fan(m_fan_speed);
|
||||
}
|
||||
need_set_fan = false;
|
||||
}
|
||||
|
||||
@@ -170,14 +170,13 @@ void FanMover::_put_in_middle_G1(std::list<BufferData>::iterator item_to_split,
|
||||
|
||||
void FanMover::_print_in_middle_G1(BufferData& line_to_split, float nb_sec, const std::string &line_to_write) {
|
||||
if (nb_sec < line_to_split.time * 0.1) {
|
||||
// doesn't really need to be split, print it after
|
||||
m_process_output += line_to_split.raw + "\n";
|
||||
// Doesn't need to be split: the insertion point is at the start.
|
||||
m_process_output += line_to_write + (line_to_write.back() == '\n'?"":"\n");
|
||||
} else if (nb_sec > line_to_split.time * 0.9) {
|
||||
// doesn't really need to be split, print it before
|
||||
//will also print before if line_to_split.time == 0
|
||||
m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n");
|
||||
m_process_output += line_to_split.raw + "\n";
|
||||
} else if (nb_sec > line_to_split.time * 0.9) {
|
||||
// Doesn't need to be split: the insertion point is at the end.
|
||||
m_process_output += line_to_split.raw + "\n";
|
||||
m_process_output += line_to_write + (line_to_write.back() == '\n' ? "" : "\n");
|
||||
}else if(line_to_split.raw.size() > 2
|
||||
&& line_to_split.raw[0] == 'G' && line_to_split.raw[1] == '1' && line_to_split.raw[2] == ' ') {
|
||||
float percent = nb_sec / line_to_split.time;
|
||||
|
||||
@@ -532,7 +532,7 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P
|
||||
const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height;
|
||||
// ORCA: Fix issue with flow rate changes being visualized incorrectly
|
||||
const float mm3_per_mm = curr_move.mm3_per_mm;
|
||||
const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed;
|
||||
const float fan_speed = curr_move.fan_speed;
|
||||
const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature;
|
||||
actual_speed_moves.push_back({
|
||||
block.move_id,
|
||||
@@ -563,7 +563,7 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P
|
||||
const float height = interpolate ? lerp(prev_move.height, curr_move.height, t) : curr_move.height;
|
||||
// ORCA: Fix issue with flow rate changes being visualized incorrectly
|
||||
const float mm3_per_mm = curr_move.mm3_per_mm;
|
||||
const float fan_speed = interpolate ? lerp(prev_move.fan_speed, curr_move.fan_speed, t) : curr_move.fan_speed;
|
||||
const float fan_speed = curr_move.fan_speed;
|
||||
const float temperature = interpolate ? lerp(prev_move.temperature, curr_move.temperature, t) : curr_move.temperature;
|
||||
actual_speed_moves.push_back({
|
||||
block.move_id,
|
||||
@@ -1273,7 +1273,7 @@ void GCodeProcessor::run_post_process()
|
||||
// add lines M73 to exported gcode
|
||||
auto process_line_move = [
|
||||
// Lambdas, mostly for string formatting, all with an empty capture block.
|
||||
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,format_line_exhaust_fan_control,
|
||||
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
|
||||
&self = std::as_const(m_time_processor),
|
||||
// Caches, to be modified
|
||||
&g1_times_cache_it, &last_exported_main, &last_exported_stop,
|
||||
@@ -5304,7 +5304,7 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line)
|
||||
float filament_radius = 0.5f * filament_diameter;
|
||||
float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius);
|
||||
|
||||
auto absolute_position = [this, area_filament_cross_section](Axis axis, const GCodeReader::GCodeLine& lineG1) {
|
||||
auto absolute_position = [this](Axis axis, const GCodeReader::GCodeLine& lineG1) {
|
||||
bool is_relative = (m_global_positioning_type == EPositioningType::Relative);
|
||||
if (axis == E)
|
||||
is_relative |= (m_e_local_positioning_type == EPositioningType::Relative);
|
||||
@@ -5755,7 +5755,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line, bool cloc
|
||||
if (travel_length < 0.001)
|
||||
return;
|
||||
|
||||
auto adjust_target = [this, area_filament_cross_section](const AxisCoords& target, const AxisCoords& prev_position) {
|
||||
auto adjust_target = [this](const AxisCoords& target, const AxisCoords& prev_position) {
|
||||
AxisCoords ret = target;
|
||||
if (m_global_positioning_type == EPositioningType::Relative) {
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
@@ -7006,7 +7006,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type,
|
||||
get_acceleration(normal_mode));
|
||||
const float junction_deviation = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, normal_mode_id);
|
||||
const bool use_jd_jerk = (m_flavor == gcfMarlinFirmware && junction_deviation > 0.0f);
|
||||
const auto axis_jerk_for_preview = [this, normal_mode, use_jd_jerk, move_acceleration](Axis axis) {
|
||||
const auto axis_jerk_for_preview = [this, use_jd_jerk, move_acceleration](Axis axis) {
|
||||
return use_jd_jerk ? get_axis_max_jerk_with_jd(normal_mode, axis, move_acceleration) : get_axis_max_jerk(normal_mode, axis);
|
||||
};
|
||||
const float jerk_x = axis_jerk_for_preview(X);
|
||||
|
||||
@@ -78,7 +78,7 @@ struct PlateBBoxData
|
||||
int first_extruder = 0;
|
||||
float nozzle_diameter = 0.4;
|
||||
std::string bed_type;
|
||||
float first_layer_time;
|
||||
float first_layer_time = 0.0f;
|
||||
// version 1: use view type ColorPrint (filament color)
|
||||
// version 2: use view type FilamentId (filament id)
|
||||
int version = 2;
|
||||
|
||||
@@ -4083,7 +4083,7 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat
|
||||
}
|
||||
return time * 60.f;
|
||||
};
|
||||
auto estimate_wipe_time = [&estimate_time_kernel, & cleaning_box, &target_speed, &x_to_wipe, &xr, &xl, &dy, &WipeSpeedMap, &solid_tool_toolchange](int begin_line) -> float {
|
||||
auto estimate_wipe_time = [&estimate_time_kernel, & cleaning_box, &x_to_wipe, &xr, &xl, &dy, &solid_tool_toolchange](int begin_line) -> float {
|
||||
int n = std::ceil(x_to_wipe / (xr - xl));
|
||||
if (solid_tool_toolchange) n = (cleaning_box.lu[1] - cleaning_box.ld[1]) / dy;
|
||||
float total_time = estimate_time_kernel(n);
|
||||
@@ -5111,7 +5111,7 @@ Polygon WipeTower::generate_rib_polygon(const box_coordinates &wt_box)
|
||||
|
||||
Polygon WipeTower::generate_support_wall_new(WipeTowerWriter &writer, const box_coordinates &wt_box, double feedrate, bool first_layer,bool rib_wall, bool extrude_perimeter, bool skip_points)
|
||||
{
|
||||
auto get_closet_idx = [this, &writer](Polylines &pls) -> std::pair<int,int> {
|
||||
auto get_closet_idx = [&writer](Polylines &pls) -> std::pair<int,int> {
|
||||
Vec2f anchor{writer.x(), writer.y()};
|
||||
int closestIndex = -1;
|
||||
int closestPl = -1;
|
||||
|
||||
@@ -165,7 +165,6 @@ public:
|
||||
|
||||
|
||||
//BBS
|
||||
unsigned int m_last_additional_fan_speed;
|
||||
int m_last_bed_temperature;
|
||||
bool m_last_bed_temperature_reached;
|
||||
double m_lifted;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -33,15 +33,6 @@ public:
|
||||
SurfaceFeature(const Vec3d& pt)
|
||||
: m_type{SurfaceFeatureType::Point}, m_pt1{pt} {}
|
||||
|
||||
SurfaceFeature(const SurfaceFeature& sf){
|
||||
this->clone(sf);
|
||||
volume = sf.volume;
|
||||
plane_indices = sf.plane_indices;
|
||||
world_tran = sf.world_tran;
|
||||
world_plane_features = sf.world_plane_features;
|
||||
origin_surface_feature = sf.origin_surface_feature;
|
||||
}
|
||||
|
||||
void clone(const SurfaceFeature &sf)
|
||||
{
|
||||
m_type = sf.get_type();
|
||||
|
||||
@@ -880,7 +880,7 @@ void Model::convert_multipart_object(unsigned int max_extruders)
|
||||
// Revert the centering operation.
|
||||
trafo_volume.set_offset(trafo_volume.get_offset() - o->origin_translation);
|
||||
int counter = 1;
|
||||
auto copy_volume = [o, v, max_extruders, &counter, &extruder_counter](ModelVolume *new_v) {
|
||||
auto copy_volume = [o, v, &counter](ModelVolume *new_v) {
|
||||
assert(new_v != nullptr);
|
||||
new_v->name = (counter > 1) ? o->name + "_" + std::to_string(counter++) : o->name;
|
||||
//BBS: Use extruder priority: volumn > object > default
|
||||
|
||||
@@ -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))); }
|
||||
|
||||
@@ -39,7 +39,6 @@ namespace orientation {
|
||||
float height_to_bottom_hull_ratio = 0; // affects stability, the lower the better
|
||||
float unprintability = 0;
|
||||
Eigen::VectorXf areas_cooling;
|
||||
CostItems(CostItems const & other) = default;
|
||||
CostItems() = default;
|
||||
static std::string field_names() {
|
||||
return " overhang, bottom, bothull, contour, A_laf, A_prj, unprintability";
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -195,7 +195,6 @@ public:
|
||||
Point(int64_t x, int32_t y) : Vec2crd(coord_t(x), coord_t(y)) {}
|
||||
Point(int32_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {}
|
||||
Point(double x, double y) : Vec2crd(coord_t(std::round(x)), coord_t(std::round(y))) {}
|
||||
Point(const Point &rhs) { *this = rhs; }
|
||||
explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(std::round(rhs.x())), coord_t(std::round(rhs.y()))) {}
|
||||
// This constructor allows you to construct Point from Eigen expressions
|
||||
// This constructor has to be implicit (non-explicit) to allow implicit conversion from Eigen expressions.
|
||||
@@ -278,7 +277,6 @@ public:
|
||||
Point3(int32_t x, int32_t y, int32_t z = 0) : Vec3crd(coord_t(x), coord_t(y), coord_t(z)) {}
|
||||
Point3(int64_t x, int64_t y, int64_t z = 0) : Vec3crd(coord_t(x), coord_t(y), coord_t(z)) {}
|
||||
Point3(double x, double y, double z = 0.0) : Vec3crd(coord_t(std::round(x)), coord_t(std::round(y)), coord_t(std::round(z))) {}
|
||||
Point3(const Point3 &rhs) { *this = rhs; }
|
||||
explicit Point3(const Vec2crd& vec2crd, coord_t z = 0) : Vec3crd(vec2crd.x(), vec2crd.y(), z) {}
|
||||
explicit Point3(const Vec3crd &vec3crd) : Vec3crd(vec3crd) {}
|
||||
// This constructor allows you to construct Point from Eigen expressions
|
||||
|
||||
@@ -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");
|
||||
@@ -983,15 +983,19 @@ BedType Preset::get_default_bed_type(PresetBundle* preset_bundle)
|
||||
if (config.has("default_bed_type") && !config.opt_string("default_bed_type").empty()) {
|
||||
try {
|
||||
std::string str_bed_type = config.opt_string("default_bed_type");
|
||||
|
||||
// Try parsing as integer first (legacy format)
|
||||
BedType bed_type;
|
||||
if (ConfigOptionEnum<BedType>::from_string(str_bed_type, bed_type) &&
|
||||
bed_type > btDefault && bed_type < btCount) {
|
||||
return bed_type;
|
||||
}
|
||||
|
||||
// Try parsing as integer (legacy format)
|
||||
int bed_type_value = atoi(str_bed_type.c_str());
|
||||
if (bed_type_value > 0) {
|
||||
if (bed_type_value > 0 && bed_type_value < BedType::btCount) {
|
||||
return BedType(bed_type_value);
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "default_bed_type: invalid bed type: " << str_bed_type;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(error) << "default_bed_type: invalid bed type: " << str_bed_type;
|
||||
return BedType::btPEI;
|
||||
|
||||
} catch(...) {
|
||||
|
||||
@@ -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,
|
||||
@@ -840,13 +840,12 @@ public:
|
||||
|
||||
protected:
|
||||
PresetCollection() = default;
|
||||
// Copy constructor and copy operators are not to be used from outside PresetBundle,
|
||||
// as the Profile::vendor points to an instance of VendorProfile stored at parent PresetBundle!
|
||||
PresetCollection(const PresetCollection &other) = default;
|
||||
//BBS: add operator= logic insteadof default
|
||||
// Deleted by the std::recursive_mutex member. PresetBundle copies by assignment.
|
||||
PresetCollection(const PresetCollection &other) = delete;
|
||||
//BBS: hand-written because m_mutex cannot be copy-assigned.
|
||||
PresetCollection& operator=(const PresetCollection &other);
|
||||
// After copying a collection with the default operators above, call this function
|
||||
// to adjust Profile::vendor pointers.
|
||||
// Copying leaves every Preset::vendor pointing into the source bundle's vendor map.
|
||||
// This re-points them at the matching entries in vendors.
|
||||
void update_vendor_ptrs_after_copy(const VendorMap &vendors);
|
||||
|
||||
// Select a preset, if it exists. If it does not exist, select an invalid (-1) index.
|
||||
@@ -984,7 +983,8 @@ public:
|
||||
bool only_default_printers() const;
|
||||
private:
|
||||
PrinterPresetCollection() = default;
|
||||
PrinterPresetCollection(const PrinterPresetCollection &other) = default;
|
||||
// Deleted along with the base copy constructor.
|
||||
PrinterPresetCollection(const PrinterPresetCollection &other) = delete;
|
||||
PrinterPresetCollection& operator=(const PrinterPresetCollection &other) = default;
|
||||
|
||||
friend class PresetBundle;
|
||||
|
||||
+100
-10
@@ -2157,7 +2157,7 @@ int PresetBundle::validate_presets(const std::string &file_name, DynamicPrintCon
|
||||
|
||||
void PresetBundle::remove_users_preset(AppConfig &config, std::map<std::string, std::map<std::string, std::string>> *my_presets)
|
||||
{
|
||||
auto check_removed = [my_presets, this](Preset &preset) -> bool {
|
||||
auto check_removed = [my_presets](Preset &preset) -> bool {
|
||||
if (my_presets == nullptr) return true;
|
||||
if (my_presets->find(preset.name) != my_presets->end()) return false;
|
||||
if (!preset.sync_info.empty()) return false; // syncing, not remove
|
||||
@@ -2920,6 +2920,16 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
|
||||
// If executed due to a Config Wizard update, preferred_printer contains the first newly installed printer, otherwise nullptr.
|
||||
const Preset *preferred_printer = printers.find_system_preset_by_model_and_variant(preferred_selection.printer_model_id, preferred_selection.printer_variant);
|
||||
printers.select_preset_by_name(preferred_printer ? preferred_printer->name : initial_printer_profile_name, true);
|
||||
Preset &selected_printer = printers.get_edited_preset();
|
||||
if (selected_printer.printer_technology() == ptFFF) {
|
||||
BedType bed_type = selected_printer.get_default_bed_type(this);
|
||||
const std::string saved_bed_type = config.get_printer_setting(selected_printer.name, "curr_bed_type");
|
||||
const int saved_bed_type_value = atoi(saved_bed_type.c_str());
|
||||
if (saved_bed_type_value > btDefault && saved_bed_type_value < btCount)
|
||||
bed_type = static_cast<BedType>(saved_bed_type_value);
|
||||
project_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(bed_type));
|
||||
config.set("curr_bed_type", std::to_string(static_cast<int>(bed_type)));
|
||||
}
|
||||
CNumericLocalesSetter locales_setter;
|
||||
|
||||
// Orca: load from orca_presets
|
||||
@@ -3373,6 +3383,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();
|
||||
@@ -3395,6 +3423,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);
|
||||
@@ -3412,7 +3441,7 @@ void PresetBundle::get_ams_cobox_infos(AMSComboInfo& combox_info)
|
||||
combox_info.ams_names.push_back(ams_name);
|
||||
continue;
|
||||
}
|
||||
iter = std::find_if(filaments.begin(), filaments.end(), [&filament_type](auto &f) { return f.is_compatible && f.is_system; });
|
||||
iter = std::find_if(filaments.begin(), filaments.end(), [](auto &f) { return f.is_compatible && f.is_system; });
|
||||
if (iter == filaments.end())
|
||||
continue;
|
||||
}
|
||||
@@ -3497,6 +3526,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()) {
|
||||
@@ -4009,6 +4039,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;
|
||||
@@ -4039,6 +4072,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)
|
||||
{
|
||||
@@ -4047,7 +4114,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");
|
||||
@@ -5222,8 +5293,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(
|
||||
@@ -6160,7 +6231,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)
|
||||
@@ -6168,20 +6243,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)
|
||||
@@ -6189,9 +6273,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
|
||||
|
||||
@@ -350,6 +350,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,
|
||||
|
||||
@@ -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"
|
||||
@@ -2288,7 +2293,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
||||
obj->clear_shared_object();
|
||||
|
||||
//add the print_object share check logic
|
||||
auto is_print_object_the_same = [this](const PrintObject* object1, const PrintObject* object2) -> bool{
|
||||
auto is_print_object_the_same = [](const PrintObject* object1, const PrintObject* object2) -> bool{
|
||||
if (object1->trafo().matrix() != object2->trafo().matrix())
|
||||
return false;
|
||||
const ModelObject* model_obj1 = object1->model_object();
|
||||
@@ -5699,7 +5704,7 @@ int Print::load_cached_data(const std::string& directory)
|
||||
return CLI_IMPORT_CACHE_NOT_FOUND;
|
||||
}
|
||||
|
||||
auto find_region = [this](PrintObject* object, size_t config_hash) -> const PrintRegion* {
|
||||
auto find_region = [](PrintObject* object, size_t config_hash) -> const PrintRegion* {
|
||||
int regions_count = object->num_printing_regions();
|
||||
for (int index = 0; index < regions_count; index++ )
|
||||
{
|
||||
|
||||
@@ -560,9 +560,11 @@ static inline bool model_volume_solid_or_modifier(const ModelVolume &mv)
|
||||
|
||||
static inline Transform3f trafo_for_bbox(const Transform3d &object_trafo, const Transform3d &volume_trafo)
|
||||
{
|
||||
Transform3d m = object_trafo * volume_trafo;
|
||||
m.translation().x() = 0.;
|
||||
m.translation().y() = 0.;
|
||||
// Orca: Keep the volume's local XY offset for multipart overlap checks, but remove the object's bed placement.
|
||||
Transform3d object_trafo_local = object_trafo;
|
||||
object_trafo_local.translation().x() = 0.;
|
||||
object_trafo_local.translation().y() = 0.;
|
||||
Transform3d m = object_trafo_local * volume_trafo;
|
||||
return m.cast<float>();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
@@ -1130,8 +1132,7 @@ void PrintConfigDef::init_fff_params()
|
||||
// BBS
|
||||
def = this->add("supertack_plate_temp", coInts);
|
||||
def->label = L("Other layers");
|
||||
def->tooltip = L("Bed temperature for layers except the initial one. "
|
||||
"A value of 0 means the filament does not support printing on the Cool Plate SuperTack.");
|
||||
def->tooltip = L("This is the bed temperature for layers except for the first one. A value of 0 means the filament does not support printing on the Cool Plate SuperTack.");
|
||||
def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation
|
||||
def->full_label = L("Bed temperature");
|
||||
def->min = 0;
|
||||
@@ -2293,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");
|
||||
@@ -2301,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"));
|
||||
@@ -2383,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"
|
||||
@@ -2402,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"
|
||||
@@ -2770,7 +2773,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("fan_cooling_layer_time", coFloats);
|
||||
def->label = L("Layer time");
|
||||
def->tooltip = L("The part cooling fan will be enabled for layers where the estimated time is shorter than this value. Fan speed is interpolated between the minimum and maximum fan speeds according to layer printing time.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = 1000;
|
||||
def->mode = comSimple;
|
||||
@@ -2923,7 +2926,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Filament load time");
|
||||
def->tooltip = L("Time to load new filament when switch filament. It's usually applicable for single-extruder multi-material machines. "
|
||||
"For tool changers or multi-tool machines, it's typically 0. For statistics only.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.0));
|
||||
@@ -2932,7 +2935,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Filament unload time");
|
||||
def->tooltip = L("Time to unload old filament when switch filament. It's usually applicable for single-extruder multi-material machines. "
|
||||
"For tool changers or multi-tool machines, it's typically 0. For statistics only.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.0));
|
||||
@@ -2941,7 +2944,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Tool change time");
|
||||
def->tooltip = L("Time taken to switch tools. It's usually applicable for tool changers or multi-tool machines. "
|
||||
"For single-extruder multi-material machines, it's typically 0. For statistics only.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat { 0. });
|
||||
@@ -3087,7 +3090,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("Time to wait after the filament is unloaded. "
|
||||
"May help to get reliable tool changes with flexible materials "
|
||||
"that may need more time to shrink to original dimensions.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloats { 0. });
|
||||
@@ -4206,7 +4209,7 @@ void PrintConfigDef::init_fff_params()
|
||||
"\nIt won't move fan commands from custom G-code (they act as a sort of 'barrier')."
|
||||
"\nIt won't move fan commands into the start G-code if the 'only custom start G-code' is activated."
|
||||
"\nUse 0 to deactivate.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
@@ -4222,7 +4225,7 @@ void PrintConfigDef::init_fff_params()
|
||||
"\nThis is useful for fans where a low PWM/power may be insufficient to get the fan started spinning from a stop, or to "
|
||||
"get the fan up to speed faster."
|
||||
"\nSet to 0 to deactivate.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
@@ -4866,7 +4869,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Ironing expansion");
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Expand or contract the ironing area.");
|
||||
def->sidetext = L("mm");
|
||||
def->sidetext = L("mm"); // millimeters, CIS languages need translation
|
||||
def->min = -100;
|
||||
def->max = 100;
|
||||
def->mode = comExpert;
|
||||
@@ -4903,7 +4906,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Quality");
|
||||
def->tooltip = L("Minimum Z-layer height.\n"
|
||||
"Also controls the slicing plane.");
|
||||
def->sidetext = L("mm");
|
||||
def->sidetext = L("mm"); // millimeters, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comExpert;
|
||||
@@ -5102,7 +5105,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Machine limits");
|
||||
def->readonly = false;
|
||||
def->tooltip = L("The allowed maximum output force of Y axis");
|
||||
def->sidetext = L("N");
|
||||
def->sidetext = L_CONTEXT("N", "Newton"); // Newtons, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comDevelop;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
@@ -5112,7 +5115,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Machine limits");
|
||||
def->readonly = false;
|
||||
def->tooltip = L("The machine bed mass load of Y axis");
|
||||
def->sidetext = L("g");
|
||||
def->sidetext = L_CONTEXT("g", "gram"); // grams, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comDevelop;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
@@ -5122,7 +5125,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Machine limits");
|
||||
def->readonly = false;
|
||||
def->tooltip = L("The allowed max printed mass on a plate");
|
||||
def->sidetext = L("g");
|
||||
def->sidetext = L_CONTEXT("g", "gram"); // grams, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->mode = comDevelop;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
@@ -5481,7 +5484,7 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
def = this->add("reduce_infill_retraction", coBool);
|
||||
def->label = L("Reduce infill retraction");
|
||||
def->tooltip = L("Don\'t retract when the travel is entirely within an infill area. That means the oozing can\'t been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that z-hop is also not performed in areas where retraction is skipped.");
|
||||
def->tooltip = L("Don\'t retract when the travel is entirely within an infill area. That means the oozing can\'t been seen. This can reduce times of retraction for complex model and save printing time, but make slicing and G-code generating slower. Note that Z-hop is also not performed in areas where retraction is skipped.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
@@ -5736,7 +5739,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("retract_after_wipe", coPercents);
|
||||
def->label = L("Retract amount after wipe");
|
||||
// xgettext:no-c-format, no-boost-format
|
||||
def->tooltip = L("The length of fast retraction after wipe, relative to retraction length.\n"
|
||||
def->tooltip = L("This is the length of fast retraction after wipe, relative to retraction length.\n"
|
||||
"The value will be clamped by 100% minus the retract amount before the wipe value.");
|
||||
def->sidetext = "%";
|
||||
def->mode = comExpert;
|
||||
@@ -5802,7 +5805,7 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
def = this->add("z_hop", coFloats);
|
||||
def->label = L("Z-hop height");
|
||||
def->tooltip = L("Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift z can prevent stringing.");
|
||||
def->tooltip = L("Whenever there is a retraction, the nozzle is lifted a little to create clearance between the nozzle and the print. This prevents the nozzle from hitting the print when traveling more. Using spiral lines to lift Z can prevent stringing.");
|
||||
def->sidetext = L("mm"); // millimeters, CIS languages need translation
|
||||
def->mode = comSimple;
|
||||
def->min = 0;
|
||||
@@ -6380,7 +6383,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Layer time");
|
||||
def->tooltip = L("The printing speed in exported G-code will be slowed down when the estimated layer time is "
|
||||
"shorter than this value in order to get better cooling for these layers.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = 1000;
|
||||
def->mode = comSimple;
|
||||
@@ -6533,7 +6536,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Preheat time");
|
||||
def->tooltip = L("To reduce the waiting time after tool change, Orca can preheat the next tool while the current tool is still in use. "
|
||||
"This setting specifies the time in seconds to preheat the next tool. Orca will insert a M104 command to preheat the tool in advance.");
|
||||
def->sidetext = L("s"); // seconds, CIS languages need translation
|
||||
def->sidetext = L_CONTEXT("s", "second"); // seconds, CIS languages need translation
|
||||
def->min = 0;
|
||||
def->max = 120;
|
||||
def->mode = comAdvanced;
|
||||
@@ -6964,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;
|
||||
@@ -8025,7 +8030,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("machine_hotend_change_time", coFloat);
|
||||
def->label = L("Hotend change time");
|
||||
def->tooltip = L("Time to change hotend.");
|
||||
def->sidetext = L("s");
|
||||
def->sidetext = L_CONTEXT("s", "second");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.0));
|
||||
@@ -9866,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) {
|
||||
@@ -10091,6 +10104,10 @@ int DynamicPrintConfig::update_values_from_single_to_multi(DynamicPrintConfig& m
|
||||
|
||||
for (int index = 0; index < variant_count; index++)
|
||||
{
|
||||
//variant_count is the variant column width, src_opt the value array;
|
||||
//they disagree when the source was authored at a different width
|
||||
if (index >= (int)src_opt->values.size())
|
||||
break;
|
||||
if (opt->values[index] > src_opt->values[index])
|
||||
opt->values[index] = src_opt->values[index];
|
||||
}
|
||||
@@ -10108,6 +10125,8 @@ int DynamicPrintConfig::update_values_from_single_to_multi(DynamicPrintConfig& m
|
||||
|
||||
for (int index = 0; index < variant_count; index++)
|
||||
{
|
||||
if (index >= (int)src_opt->values.size())
|
||||
break;
|
||||
if (opt->values[index].value > src_opt->values[index].value)
|
||||
opt->values[index] = src_opt->values[index];
|
||||
}
|
||||
@@ -10302,6 +10321,10 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
|
||||
|
||||
for(auto idx : variant_indices){
|
||||
assert(idx < old_count);
|
||||
//the counts come from the variant columns, the arrays from the options;
|
||||
//they disagree when a config was authored at a different variant width
|
||||
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
|
||||
continue;
|
||||
if (old_values[idx] < opt->values[new_variant_index])
|
||||
opt->values[new_variant_index] = old_values[idx];
|
||||
}
|
||||
@@ -10332,6 +10355,10 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
|
||||
|
||||
for(auto idx : variant_indices){
|
||||
assert(idx < old_count);
|
||||
//the counts come from the variant columns, the arrays from the options;
|
||||
//they disagree when a config was authored at a different variant width
|
||||
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
|
||||
continue;
|
||||
if (old_values[idx] < opt->values[new_variant_index])
|
||||
opt->values[new_variant_index] = old_values[idx];
|
||||
}
|
||||
@@ -10362,6 +10389,8 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
|
||||
|
||||
for(auto idx : variant_indices){
|
||||
assert(idx < old_count);
|
||||
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
|
||||
continue;
|
||||
if (old_values[idx]) //enabled
|
||||
opt->values[new_variant_index] = old_values[idx];
|
||||
}
|
||||
@@ -10402,6 +10431,15 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
same_variant_indices.emplace_back(indices);
|
||||
}
|
||||
|
||||
//dst_values below is the destination PRINT preset's per-variant row, sized to its own
|
||||
//print_extruder_variant; dst_extruder_variants is the PRINTER's list. They disagree until
|
||||
//the print preset is re-selected, so size the row to the variant count before indexing it.
|
||||
const size_t dst_variant_count = dst_extruder_variants.size();
|
||||
if (dst_variant_count == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", Line %1%: empty destination variant list")%__LINE__;
|
||||
return -1;
|
||||
}
|
||||
|
||||
t_config_option_keys keys = this->keys();
|
||||
for(auto& key : keys){
|
||||
if(key_sets.find(key) == key_sets.end())
|
||||
@@ -10417,7 +10455,13 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
{
|
||||
ConfigOptionFloatsNullable* opt = this->option<ConfigOptionFloatsNullable>(key);
|
||||
auto src_values = opt->values;
|
||||
auto dst_values = dst_config.option<ConfigOptionFloatsNullable>(key) ->values;
|
||||
const auto* dst_opt = dst_config.option<ConfigOptionFloatsNullable>(key);
|
||||
if(!dst_opt){
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
|
||||
break;
|
||||
}
|
||||
auto dst_values = dst_opt->values;
|
||||
dst_values.resize(dst_variant_count, ConfigOptionFloatsNullable::nil_value());
|
||||
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
|
||||
auto& indices = same_variant_indices[dst_idx];
|
||||
if(indices.empty())
|
||||
@@ -10425,7 +10469,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
bool has_value = false;
|
||||
double target_value = std::numeric_limits<double>::max();
|
||||
for(auto idx : indices){
|
||||
if(opt && idx < opt->values.size() && !opt->is_nil(idx)){
|
||||
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
|
||||
has_value = true;
|
||||
target_value = std::min(target_value, src_values[idx]);
|
||||
}
|
||||
@@ -10441,7 +10485,13 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
{
|
||||
ConfigOptionFloatsOrPercentsNullable* opt = this->option<ConfigOptionFloatsOrPercentsNullable>(key);
|
||||
auto src_values = opt->values;
|
||||
auto dst_values = dst_config.option<ConfigOptionFloatsOrPercentsNullable>(key) ->values;
|
||||
const auto* dst_opt = dst_config.option<ConfigOptionFloatsOrPercentsNullable>(key);
|
||||
if(!dst_opt){
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
|
||||
break;
|
||||
}
|
||||
auto dst_values = dst_opt->values;
|
||||
dst_values.resize(dst_variant_count, ConfigOptionFloatsOrPercentsNullable::nil_value());
|
||||
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
|
||||
auto& indices = same_variant_indices[dst_idx];
|
||||
if(indices.empty())
|
||||
@@ -10449,7 +10499,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
bool has_value = false;
|
||||
FloatOrPercent target_value{9999.f, true};
|
||||
for(auto idx : indices){
|
||||
if(opt && !opt->is_nil(idx)){
|
||||
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
|
||||
has_value = true;
|
||||
target_value = src_values[idx].value < target_value.value ? src_values[idx] : target_value;
|
||||
}
|
||||
@@ -10465,15 +10515,21 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
{
|
||||
ConfigOptionBoolsNullable* opt = this->option<ConfigOptionBoolsNullable>(key);
|
||||
auto src_values = opt->values;
|
||||
auto dst_values = dst_config.option<ConfigOptionBoolsNullable>(key) ->values;
|
||||
const auto* dst_opt = dst_config.option<ConfigOptionBoolsNullable>(key);
|
||||
if(!dst_opt){
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
|
||||
break;
|
||||
}
|
||||
auto dst_values = dst_opt->values;
|
||||
dst_values.resize(dst_variant_count, ConfigOptionBoolsNullable::nil_value());
|
||||
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
|
||||
auto indices = same_variant_indices[dst_idx];
|
||||
if(indices.empty())
|
||||
continue;
|
||||
bool has_value = false;
|
||||
bool target_value;
|
||||
bool target_value = false;
|
||||
for(auto idx : indices){
|
||||
if(opt && !opt->is_nil(idx)){
|
||||
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
|
||||
has_value = true;
|
||||
target_value = src_values[idx];
|
||||
break;
|
||||
@@ -11948,13 +12004,11 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def = this->add("load_defaultfila", coBool);
|
||||
def->label = L("Load default filaments");
|
||||
def->tooltip = L("Load first filament as default for those not loaded.");
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("min_save", coBool);
|
||||
def->label = L("Minimum save");
|
||||
def->tooltip = L("Export 3MF with minimum size.");
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("mtcpp", coInt);
|
||||
@@ -11980,7 +12034,6 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def = this->add("normative_check", coBool);
|
||||
def->label = L("Normative check");
|
||||
def->tooltip = L("Check the normative items.");
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
/*def = this->add("help_fff", coBool);
|
||||
@@ -12247,7 +12300,7 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
def->cli_params = "level";
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
|
||||
def = this->add("logfile", coInt);
|
||||
def = this->add("logfile", coString);
|
||||
def->label = L("Log file");
|
||||
def->tooltip = L("Redirects debug logging to file.\n");
|
||||
def->cli_params = "file";
|
||||
@@ -12295,7 +12348,6 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
def = this->add("skip_modified_gcodes", coBool);
|
||||
def->label = L("Skip modified G-code in 3MF");
|
||||
def->tooltip = L("Skip the modified G-code in 3MF from printer or filament presets.");
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("makerlab_name", coString);
|
||||
@@ -12325,14 +12377,12 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
||||
def = this->add("allow_newer_file", coBool);
|
||||
def->label = L("Allow 3MF with newer version to be sliced");
|
||||
def->tooltip = L("Allow 3MF with newer version to be sliced.");
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("allow_mix_temp", coBool);
|
||||
// internal use only, don't need translation
|
||||
def->label = "Allow filaments with high/low temperature to be printed together";
|
||||
def->tooltip = "Allow filaments with high/low temperature to be printed together.";
|
||||
def->cli_params = "option";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2666,7 +2666,7 @@ void PrintObject::bridge_over_infill()
|
||||
// SECTION to gather and filter surfaces for expanding, and then cluster them by layer
|
||||
{
|
||||
tbb::concurrent_vector<CandidateSurface> candidate_surfaces;
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, this->layers().size()), [po = static_cast<const PrintObject *>(this), &candidate_surfaces, has_lightning_infill](tbb::blocked_range<size_t> r) {
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, this->layers().size()), [po = static_cast<const PrintObject *>(this), &candidate_surfaces](tbb::blocked_range<size_t> r) {
|
||||
PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
|
||||
for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
|
||||
const Layer *layer = po->get_layer(lidx);
|
||||
|
||||
@@ -304,11 +304,16 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
|
||||
float z = zs[z_idx];
|
||||
int idx_first_printable_region = -1;
|
||||
bool complex = false;
|
||||
std::vector<int> printable_region_ids;
|
||||
for (int idx_region = 0; idx_region < int(layer_range.volume_regions.size()); ++ idx_region) {
|
||||
const PrintObjectRegions::VolumeRegion ®ion = layer_range.volume_regions[idx_region];
|
||||
if (region.bbox->min().z() <= z && region.bbox->max().z() >= z) {
|
||||
if (idx_first_printable_region == -1 && region.model_volume->is_model_part())
|
||||
if (region.model_volume->is_model_part())
|
||||
printable_region_ids.push_back(idx_region);
|
||||
|
||||
if (idx_first_printable_region == -1 && region.model_volume->is_model_part()) {
|
||||
idx_first_printable_region = idx_region;
|
||||
}
|
||||
else if (idx_first_printable_region != -1) {
|
||||
// Test for overlap with some other region.
|
||||
for (int idx_region2 = idx_first_printable_region; idx_region2 < idx_region; ++ idx_region2) {
|
||||
@@ -324,8 +329,10 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions(
|
||||
if (complex)
|
||||
zs_complex.push_back({ z_idx, z });
|
||||
else if (idx_first_printable_region >= 0) {
|
||||
const PrintObjectRegions::VolumeRegion ®ion = layer_range.volume_regions[idx_first_printable_region];
|
||||
slices_by_region[region.region->print_object_region_id()][z_idx] = std::move(volume_slices_find_by_id(volume_slices, region.model_volume->id()).slices[z_idx]);
|
||||
for (int printable_region_id : printable_region_ids) {
|
||||
const PrintObjectRegions::VolumeRegion ®ion = layer_range.volume_regions[printable_region_id];
|
||||
append(slices_by_region[region.region->print_object_region_id()][z_idx], std::move(volume_slices_find_by_id(volume_slices, region.model_volume->id()).slices[z_idx]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -527,7 +534,7 @@ bool groupingVolumes(std::vector<VolumeSlices> objSliceByVolume, std::vector<gro
|
||||
}
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, osvIndex.size()),
|
||||
[&osvIndex, &objSliceByVolume, &offsetValue, &resolution](const tbb::blocked_range<int>& range) {
|
||||
[&osvIndex, &objSliceByVolume, &resolution](const tbb::blocked_range<int>& range) {
|
||||
for (auto k = range.begin(); k != range.end(); ++k) {
|
||||
for (ExPolygon& poly_ex : objSliceByVolume[osvIndex[k][0]].slices[osvIndex[k][1]])
|
||||
poly_ex.douglas_peucker(resolution);
|
||||
@@ -535,7 +542,7 @@ bool groupingVolumes(std::vector<VolumeSlices> objSliceByVolume, std::vector<gro
|
||||
});
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, osvIndex.size()),
|
||||
[&osvIndex, &objSliceByVolume,&offsetValue, &resolution](const tbb::blocked_range<int>& range) {
|
||||
[&osvIndex, &objSliceByVolume,&offsetValue](const tbb::blocked_range<int>& range) {
|
||||
for (auto k = range.begin(); k != range.end(); ++k) {
|
||||
objSliceByVolume[osvIndex[k][0]].slices[osvIndex[k][1]] = offset_ex(objSliceByVolume[osvIndex[k][0]].slices[osvIndex[k][1]], offsetValue);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
|
||||
#include <libslic3r/OpenVDBUtils.hpp>
|
||||
|
||||
@@ -44,9 +44,6 @@ struct DrainHole
|
||||
: pos(p), normal(n), radius(r), height(h), failed(fl)
|
||||
{}
|
||||
|
||||
DrainHole(const DrainHole& rhs) :
|
||||
DrainHole(rhs.pos, rhs.normal, rhs.radius, rhs.height, rhs.failed) {}
|
||||
|
||||
bool operator==(const DrainHole &sp) const;
|
||||
|
||||
bool operator!=(const DrainHole &sp) const { return !(sp == (*this)); }
|
||||
|
||||
@@ -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;
|
||||
@@ -132,7 +134,7 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
|
||||
return nullptr;
|
||||
};
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, int(intermediate_layers.size())),
|
||||
[&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer, &support_params,
|
||||
[&bottom_contacts, &top_contacts, &top_interface_layers, &top_base_interface_layers, &intermediate_layers, &insert_layer,
|
||||
num_top_interface_layers, num_bottom_interface_layers, num_top_base_interface_layers, num_bottom_base_interface_layers,
|
||||
num_top_interface_layers_only, num_bottom_interface_layers_only,
|
||||
snug_supports, &interface_layers, &base_interface_layers](const tbb::blocked_range<int>& range) {
|
||||
@@ -1234,10 +1236,6 @@ static void modulate_extrusion_by_overlapping_layers(
|
||||
(fragment_end.is_start ? &polyline.points.front() : &polyline.points.back());
|
||||
}
|
||||
private:
|
||||
ExtrusionPathFragmentEndPointAccessor& operator=(const ExtrusionPathFragmentEndPointAccessor&) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::vector<ExtrusionPathFragment> &m_path_fragments;
|
||||
};
|
||||
const coord_t search_radius = 7;
|
||||
@@ -1656,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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1588,7 +1588,7 @@ static inline std::tuple<Polygons, Polygons, double> detect_contacts(
|
||||
|
||||
// Cache support trimming polygons derived from lower layer polygons, possible merged with "on build plate only" trimming polygons.
|
||||
auto slices_margin_update =
|
||||
[&slices_margin, &layer, &lower_layer, &lower_layer_polygons, buildplate_only, has_enforcer, &annotations, layer_id]
|
||||
[&slices_margin, &lower_layer, &lower_layer_polygons, buildplate_only, has_enforcer, &annotations, layer_id]
|
||||
(float slices_margin_offset, float no_interface_offset) {
|
||||
if (slices_margin.offset != slices_margin_offset) {
|
||||
slices_margin.offset = slices_margin_offset;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -2667,7 +2667,7 @@ void TreeSupport::drop_nodes()
|
||||
SupportNode::diameter_angle_scale_factor = diameter_angle_scale_factor;
|
||||
float DO_NOT_MOVER_UNDER_MM = is_slim ? 0 : 5; // do not move contact points under 5mm
|
||||
|
||||
auto get_max_move_dist = [this, &config, tan_angle, wall_count, support_extrusion_width](const SupportNode *node, int power = 1) {
|
||||
auto get_max_move_dist = [this, tan_angle, support_extrusion_width](const SupportNode *node, int power = 1) {
|
||||
if (node->max_move_dist == 0) {
|
||||
node->radius = get_radius(node);
|
||||
node->max_move_dist = std::min(tan_angle * node->height, support_extrusion_width);
|
||||
|
||||
@@ -204,8 +204,9 @@ public:
|
||||
clear_nodes();
|
||||
}
|
||||
|
||||
TreeSupportData(TreeSupportData&&) = default;
|
||||
TreeSupportData& operator=(TreeSupportData&&) = default;
|
||||
// Deleted by the tbb::spin_mutex member.
|
||||
TreeSupportData(TreeSupportData&&) = delete;
|
||||
TreeSupportData& operator=(TreeSupportData&&) = delete;
|
||||
|
||||
TreeSupportData(const TreeSupportData&) = delete;
|
||||
TreeSupportData& operator=(const TreeSupportData&) = delete;
|
||||
|
||||
@@ -28,9 +28,9 @@ std::string CalibPressureAdvance::move_to(Vec2d pt, GCodeWriter &writer, std::st
|
||||
|
||||
gcode << writer.retract(); // retract before z move or move
|
||||
if(z > EPSILON && layer_height >= 0){
|
||||
gcode << writer.travel_to_z(z, "z-hop"); // Perform z hop
|
||||
gcode << writer.travel_to_z(z, "Z-hop"); // Perform z hop
|
||||
gcode << writer.travel_to_xy(pt, comment); // Travel with z move
|
||||
gcode << writer.travel_to_z(layer_height, "undo z-hop"); // Undo z hop
|
||||
gcode << writer.travel_to_z(layer_height, "undo Z-hop"); // Undo z hop
|
||||
}else {
|
||||
gcode << writer.travel_to_xy(pt, comment);
|
||||
}
|
||||
|
||||
+3
-17
@@ -91,29 +91,15 @@ class CaliPresetInfo
|
||||
{
|
||||
public:
|
||||
int tray_id;
|
||||
int extruder_id;
|
||||
NozzleVolumeType nozzle_volume_type;
|
||||
BedType bed_type;
|
||||
int extruder_id = 0;
|
||||
NozzleVolumeType nozzle_volume_type{nvtStandard};
|
||||
BedType bed_type{btDefault};
|
||||
float nozzle_diameter;
|
||||
int nozzle_pos_id{-1};
|
||||
std::string nozzle_sn;
|
||||
std::string filament_id;
|
||||
std::string setting_id;
|
||||
std::string name;
|
||||
|
||||
CaliPresetInfo &operator=(const CaliPresetInfo &other)
|
||||
{
|
||||
this->tray_id = other.tray_id;
|
||||
this->extruder_id = other.extruder_id;
|
||||
this->nozzle_volume_type = other.nozzle_volume_type;
|
||||
this->nozzle_diameter = other.nozzle_diameter;
|
||||
this->nozzle_pos_id = other.nozzle_pos_id;
|
||||
this->nozzle_sn = other.nozzle_sn;
|
||||
this->filament_id = other.filament_id;
|
||||
this->setting_id = other.setting_id;
|
||||
this->name = other.name;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct PrinterCaliInfo
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+53
-22
@@ -38,6 +38,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/AuxiliaryDataViewModel.hpp
|
||||
GUI/AuxiliaryDialog.cpp
|
||||
GUI/AuxiliaryDialog.hpp
|
||||
GUI/AVVideoDecoder.cpp
|
||||
GUI/AVVideoDecoder.hpp
|
||||
GUI/Auxiliary.hpp
|
||||
GUI/BackgroundSlicingProcess.cpp
|
||||
GUI/BackgroundSlicingProcess.hpp
|
||||
@@ -61,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
|
||||
@@ -611,6 +615,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/WipeTowerDialog.cpp
|
||||
GUI/wxExtensions.cpp
|
||||
GUI/wxExtensions.hpp
|
||||
GUI/wxMediaCtrl3.cpp
|
||||
GUI/wxMediaCtrl3.h
|
||||
plugin/PythonInterpreter.cpp
|
||||
plugin/PythonInterpreter.hpp
|
||||
plugin/PythonPluginBridge.cpp
|
||||
@@ -823,21 +829,8 @@ if (APPLE)
|
||||
GUI/DeepLinkHandlerMac.mm
|
||||
GUI/DeepLinkHandlerMac.h
|
||||
GUI/GUI_UtilsMac.mm
|
||||
GUI/wxMediaCtrl2.mm
|
||||
GUI/wxMediaCtrl2.h
|
||||
)
|
||||
FIND_LIBRARY(DISKARBITRATION_LIBRARY DiskArbitration)
|
||||
else ()
|
||||
list(APPEND SLIC3R_GUI_SOURCES
|
||||
GUI/wxMediaCtrl2.cpp
|
||||
GUI/wxMediaCtrl2.h
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
list(APPEND SLIC3R_GUI_SOURCES
|
||||
GUI/Printer/gstbambusrc.c
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(ORCA_UPDATER_SIG_KEY_B64 "${ORCA_UPDATER_SIG_KEY}")
|
||||
@@ -878,6 +871,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 "")
|
||||
@@ -935,8 +940,43 @@ 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)
|
||||
# Static FFmpeg from the deps install: nothing to bundle into the .app,
|
||||
# no rpath/install_name handling. Order matters: avcodec -> swscale -> avutil.
|
||||
find_library(LIBAVCODEC_LIBRARY NAMES libavcodec.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
find_library(LIBSWSCALE_LIBRARY NAMES libswscale.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
find_library(LIBAVUTIL_LIBRARY NAMES libavutil.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
if (NOT LIBAVCODEC_LIBRARY OR NOT LIBSWSCALE_LIBRARY OR NOT LIBAVUTIL_LIBRARY)
|
||||
message(FATAL_ERROR "Static FFmpeg (libavcodec.a/libswscale.a/libavutil.a) not found under ${CMAKE_PREFIX_PATH}/lib. Rebuild the deps — FFMPEG builds static-only on macOS.")
|
||||
endif ()
|
||||
target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
|
||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
||||
elseif (WIN32)
|
||||
# Prebuilt shared FFmpeg from the deps install. Windows has no pkg-config,
|
||||
# so resolve the import libraries out of the deps prefix directly; the DLLs
|
||||
# are copied next to the executable by the top level CMakeLists.
|
||||
find_library(LIBAVCODEC_LIBRARY NAMES avcodec PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
find_library(LIBSWSCALE_LIBRARY NAMES swscale PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
find_library(LIBAVUTIL_LIBRARY NAMES avutil PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||
if (NOT LIBAVCODEC_LIBRARY OR NOT LIBSWSCALE_LIBRARY OR NOT LIBAVUTIL_LIBRARY)
|
||||
message(FATAL_ERROR "FFmpeg (avcodec/swscale/avutil) not found under ${CMAKE_PREFIX_PATH}/lib. Rebuild the deps.")
|
||||
endif ()
|
||||
target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
|
||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
||||
else ()
|
||||
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
||||
libavcodec
|
||||
libswscale
|
||||
libavutil
|
||||
)
|
||||
target_link_libraries(libslic3r_gui PkgConfig::LIBAV)
|
||||
endif()
|
||||
|
||||
# We need to implement some hacks for wxWidgets and touch the underlying GTK
|
||||
# layer and sub-libraries. This forces us to use the include locations and
|
||||
# link these libraries.
|
||||
@@ -963,20 +1003,11 @@ if (UNIX AND NOT APPLE)
|
||||
target_compile_definitions(libslic3r_gui PRIVATE wxHAVE_GDK_WAYLAND)
|
||||
endif ()
|
||||
|
||||
# We add GStreamer for bambu:/// support.
|
||||
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
|
||||
pkg_check_modules(GST_BASE REQUIRED gstreamer-base-1.0)
|
||||
target_link_libraries(libslic3r_gui ${GSTREAMER_LIBRARIES} ${GST_BASE_LIBRARIES})
|
||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${GSTREAMER_INCLUDE_DIRS} ${GST_BASE_INCLUDE_DIRS})
|
||||
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
|
||||
|
||||
@@ -437,7 +437,7 @@ wxBoxSizer* AMSDryCtrWin::create_normal_state_panel(wxPanel* parent)
|
||||
m_temperature_input = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(80), -1));
|
||||
m_temperature_input->SetMaxLength(3); // Limit to 3 digits
|
||||
|
||||
m_temperature_input->Bind(wxEVT_CHAR, [this](wxKeyEvent& event) {
|
||||
m_temperature_input->Bind(wxEVT_CHAR, [](wxKeyEvent& event) {
|
||||
int keycode = event.GetKeyCode();
|
||||
if (keycode >= '0' && keycode <= '9') {
|
||||
event.Skip();
|
||||
@@ -464,7 +464,7 @@ wxBoxSizer* AMSDryCtrWin::create_normal_state_panel(wxPanel* parent)
|
||||
m_time_input = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(100), -1));
|
||||
m_time_input->SetMaxLength(3); // Limit to 3 digits
|
||||
|
||||
m_time_input->Bind(wxEVT_CHAR, [this](wxKeyEvent& event) {
|
||||
m_time_input->Bind(wxEVT_CHAR, [](wxKeyEvent& event) {
|
||||
int keycode = event.GetKeyCode();
|
||||
if (keycode >= '0' && keycode <= '9') {
|
||||
event.Skip();
|
||||
@@ -698,7 +698,7 @@ wxBoxSizer* AMSDryCtrWin::create_guide_info_section(wxPanel* parent)
|
||||
m_rotate_spool_toggle = new wxCheckBox(parent, wxID_ANY, "");
|
||||
m_rotate_spool_toggle->SetValue(false);
|
||||
|
||||
m_rotate_spool_toggle->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) {
|
||||
m_rotate_spool_toggle->Bind(wxEVT_CHECKBOX, [](wxCommandEvent& event) {
|
||||
bool is_checked = event.IsChecked();
|
||||
// Add toggle behavior logic here
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
@@ -55,7 +55,6 @@ private:
|
||||
|
||||
Label* m_text_label;
|
||||
wxStaticBitmap* m_icon_bitmap;
|
||||
int m_target_size;
|
||||
std::string m_icon_name;
|
||||
ScalableBitmap m_icon;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
#include "AVVideoDecoder.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
}
|
||||
|
||||
AVVideoDecoder::AVVideoDecoder()
|
||||
{
|
||||
codec_ctx_ = avcodec_alloc_context3(nullptr);
|
||||
}
|
||||
|
||||
AVVideoDecoder::~AVVideoDecoder()
|
||||
{
|
||||
if (sws_ctx_)
|
||||
sws_freeContext(sws_ctx_);
|
||||
if (frame_)
|
||||
av_frame_free(&frame_);
|
||||
if (codec_ctx_)
|
||||
avcodec_free_context(&codec_ctx_);
|
||||
}
|
||||
|
||||
int AVVideoDecoder::open(Bambu_StreamInfo const &info)
|
||||
{
|
||||
auto codec_id = info.sub_type == AVC1 ? AV_CODEC_ID_H264 : AV_CODEC_ID_MJPEG;
|
||||
auto codec = avcodec_find_decoder(codec_id);
|
||||
if (codec == nullptr) {
|
||||
fprintf(stderr, "AVVideoDecoder: unsupported codec!\n");
|
||||
return -1; // Codec not found
|
||||
}
|
||||
/* open the coderc */
|
||||
if (avcodec_open2(codec_ctx_, codec, nullptr) < 0) {
|
||||
fprintf(stderr, "AVVideoDecoder: could not open codec\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allocate an AVFrame structure
|
||||
frame_ = av_frame_alloc();
|
||||
if (frame_ == nullptr)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVVideoDecoder::decode(const Bambu_Sample &sample)
|
||||
{
|
||||
int ret = -1;
|
||||
AVPacket *pkt = av_packet_alloc();
|
||||
if (!pkt) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = av_new_packet(pkt, sample.size);
|
||||
if (ret != 0) {
|
||||
av_packet_free(&pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(pkt->data, sample.buffer, size_t(sample.size));
|
||||
|
||||
ret = avcodec_send_packet(codec_ctx_, pkt);
|
||||
if (ret == 0) {
|
||||
got_frame_ = avcodec_receive_frame(codec_ctx_, frame_) == 0;
|
||||
}
|
||||
|
||||
av_packet_unref(pkt);
|
||||
av_packet_free(&pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AVVideoDecoder::flush()
|
||||
{
|
||||
int ret = avcodec_send_packet(codec_ctx_, nullptr);
|
||||
got_frame_ = avcodec_receive_frame(codec_ctx_, frame_) == 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AVVideoDecoder::close()
|
||||
{
|
||||
}
|
||||
|
||||
bool AVVideoDecoder::toWxImage(wxImage &image, wxSize const &size2)
|
||||
{
|
||||
if (!got_frame_)
|
||||
return false;
|
||||
|
||||
auto size1 = size2;
|
||||
if (!size1.IsFullySpecified())
|
||||
size1 = {frame_->width, frame_->height };
|
||||
auto size = size1;
|
||||
if (size.GetWidth() & 0x0f) {
|
||||
size.SetWidth((size.GetWidth() & ~0x0f) + 0x10);
|
||||
if (size.GetWidth() != width_) {
|
||||
std::fill(bits_.begin(), bits_.end(), 0);
|
||||
width_ = size.GetWidth();
|
||||
}
|
||||
}
|
||||
AVPixelFormat wxFmt = AV_PIX_FMT_RGB24;
|
||||
sws_ctx_ = sws_getCachedContext(sws_ctx_,
|
||||
frame_->width, frame_->height, AVPixelFormat(frame_->format),
|
||||
size1.GetWidth(), size1.GetHeight(), wxFmt,
|
||||
SWS_GAUSS,
|
||||
nullptr, nullptr, nullptr);
|
||||
if (sws_ctx_ == nullptr)
|
||||
return false;
|
||||
int length = size.GetWidth() * size.GetHeight() * 3;
|
||||
if (bits_.size() < length)
|
||||
bits_.resize(length);
|
||||
uint8_t * datas[] = { bits_.data() };
|
||||
int strides[] = { size.GetWidth() * 3 };
|
||||
int result_h = sws_scale(sws_ctx_, frame_->data, frame_->linesize, 0, frame_->height, datas, strides);
|
||||
if (result_h != size.GetHeight()) {
|
||||
return false;
|
||||
}
|
||||
// Copy: the frame outlives this decoder and is painted by the GUI thread while the
|
||||
// next sws_scale is already overwriting bits_, so it must own its pixels. The Windows
|
||||
// path below needs no equivalent, wxBitmap copies the bits into GDI.
|
||||
image = wxImage(size.GetWidth(), size.GetHeight(), bits_.data(), true).Copy();
|
||||
if (!image.IsOk()) {
|
||||
fprintf(stderr, "AVVideoDecoder: image not ok %dx%d\n", size.GetWidth(), size.GetHeight());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AVVideoDecoder::toWxBitmap(wxBitmap &bitmap, wxSize const &size2)
|
||||
{
|
||||
if (!got_frame_)
|
||||
return false;
|
||||
|
||||
auto size1 = size2;
|
||||
if (!size1.IsFullySpecified())
|
||||
size1 = {frame_->width, frame_->height };
|
||||
auto size = size1;
|
||||
if (size.GetWidth() & 0x0f) {
|
||||
size.SetWidth((size.GetWidth() & ~0x0f) + 0x10);
|
||||
if (size.GetWidth() != width_) {
|
||||
std::fill(bits_.begin(), bits_.end(), 0);
|
||||
width_ = size.GetWidth();
|
||||
}
|
||||
}
|
||||
AVPixelFormat wxFmt = AV_PIX_FMT_RGB32;
|
||||
sws_ctx_ = sws_getCachedContext(sws_ctx_,
|
||||
frame_->width, frame_->height, AVPixelFormat(frame_->format),
|
||||
size1.GetWidth(), size1.GetHeight(), wxFmt,
|
||||
SWS_GAUSS,
|
||||
nullptr, nullptr, nullptr);
|
||||
if (sws_ctx_ == nullptr)
|
||||
return false;
|
||||
int length = size.GetWidth() * size.GetHeight() * 4;
|
||||
if (bits_.size() < length)
|
||||
bits_.resize(length);
|
||||
uint8_t *datas[] = { bits_.data() };
|
||||
int strides[] = { size.GetWidth() * 4 };
|
||||
int result_h = sws_scale(sws_ctx_, frame_->data, frame_->linesize, 0, frame_->height, datas, strides);
|
||||
if (result_h != size.GetHeight()) {
|
||||
fprintf(stderr, "AVVideoDecoder: result_h %d %d\n", result_h, size.GetHeight());
|
||||
return false;
|
||||
}
|
||||
bitmap = wxBitmap((char const *) bits_.data(), size.GetWidth(), size.GetHeight(), 32);
|
||||
assert(bitmap.IsOk());
|
||||
if (!bitmap.IsOk()) {
|
||||
fprintf(stderr, "AVVideoDecoder: bitmap not ok %dx%d\n", size.GetWidth(), size.GetHeight());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef AVVIDEODECODER_HPP
|
||||
#define AVVIDEODECODER_HPP
|
||||
|
||||
#include "Printer/BambuTunnel.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
#include <vector>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/image.h>
|
||||
|
||||
class wxBitmap;
|
||||
|
||||
class AVVideoDecoder
|
||||
{
|
||||
public:
|
||||
AVVideoDecoder();
|
||||
|
||||
~AVVideoDecoder();
|
||||
|
||||
public:
|
||||
int open(Bambu_StreamInfo const &info);
|
||||
|
||||
int decode(Bambu_Sample const &sample);
|
||||
|
||||
int flush();
|
||||
|
||||
void close();
|
||||
|
||||
bool toWxImage(wxImage &image, wxSize const &size);
|
||||
|
||||
bool toWxBitmap(wxBitmap &bitmap, wxSize const & size);
|
||||
|
||||
private:
|
||||
AVCodecContext *codec_ctx_ = nullptr;
|
||||
AVFrame * frame_ = nullptr;
|
||||
SwsContext * sws_ctx_ = nullptr;
|
||||
bool got_frame_ = false;
|
||||
int width_ { 0 }; // scale result width
|
||||
std::vector<uint8_t> bits_;
|
||||
};
|
||||
|
||||
#endif // AVVIDEODECODER_HPP
|
||||
@@ -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
|
||||
|
||||
@@ -60,7 +60,6 @@ class AboutDialog : public DPIDialog
|
||||
wxHtmlWindow* m_html;
|
||||
wxStaticBitmap* m_logo;
|
||||
int m_copy_rights_btn_id { wxID_ANY };
|
||||
int m_copy_version_btn_id { wxID_ANY };
|
||||
public:
|
||||
AboutDialog();
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ private:
|
||||
CenteredTitle* m_title_ctrl { nullptr };
|
||||
wxString m_titleText;
|
||||
|
||||
wxAuiToolBarItem* m_account_item;
|
||||
wxAuiToolBarItem* m_model_store_item;
|
||||
|
||||
//wxAuiToolBarItem *m_publish_item;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// BambuPlayer.h
|
||||
// BambuPlayer
|
||||
//
|
||||
// Created by cmguo on 2021/12/6.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVSampleBufferDisplayLayer.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface BambuPlayer : NSObject
|
||||
|
||||
+ (void) initialize;
|
||||
|
||||
- (instancetype) initWithDisplayLayer: (AVSampleBufferDisplayLayer*) layer;
|
||||
- (instancetype) initWithImageView: (NSView*) view;
|
||||
- (int) open: (char const *) url;
|
||||
- (NSSize) videoSize;
|
||||
- (int) play;
|
||||
- (void) stop;
|
||||
- (void) close;
|
||||
|
||||
- (void) setLogger: (void (*)(void const * context, int level, char const * msg)) logger withContext: (void const *) context;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -468,7 +468,7 @@ PingCodeBindDialog::~PingCodeBindDialog() {
|
||||
m_link_privacy_title->SetFont(Label::Head_13);
|
||||
m_link_privacy_title->SetMaxSize(wxSize(FromDIP(450), -1));
|
||||
m_link_privacy_title->Wrap(FromDIP(450));
|
||||
m_link_privacy_title->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
|
||||
m_link_privacy_title->Bind(wxEVT_LEFT_DOWN, [](auto& e) {
|
||||
std::string url;
|
||||
std::string country_code = Slic3r::GUI::wxGetApp().app_config->get_country_code();
|
||||
|
||||
@@ -893,7 +893,7 @@ void BindMachineDialog::on_show(wxShowEvent &event)
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_error([this](std::string body, std::string error, unsigned status) {
|
||||
.on_error([](std::string body, std::string error, unsigned status) {
|
||||
//BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error;
|
||||
}).perform();
|
||||
}
|
||||
@@ -1099,7 +1099,7 @@ void UnBindMachineDialog::on_show(wxShowEvent &event)
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_error([this](std::string body, std::string error, unsigned status) {
|
||||
.on_error([](std::string body, std::string error, unsigned status) {
|
||||
//BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error;
|
||||
}).perform();
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -443,7 +443,7 @@ void HistoryWindow::sync_history_data() {
|
||||
|
||||
auto edit_button = new Button(m_history_data_panel, _L("Edit"));
|
||||
edit_button->SetStyle(ButtonStyle::Confirm, ButtonType::Window);
|
||||
edit_button->Bind(wxEVT_BUTTON, [this, result, k_value, name_value, edit_button](auto& e) {
|
||||
edit_button->Bind(wxEVT_BUTTON, [this, result, k_value, name_value](auto& e) {
|
||||
if (m_ui_op_lock) return;
|
||||
|
||||
PACalibResult result_buffer = result;
|
||||
@@ -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;
|
||||
|
||||
@@ -201,7 +201,7 @@ wxWindow* CalibrationDialog::create_check_option(wxString title, wxWindow* paren
|
||||
checkbox->SetToolTip(tooltip);
|
||||
text->SetToolTip(tooltip);
|
||||
|
||||
text->Bind(wxEVT_LEFT_DOWN, [this, check](wxMouseEvent&) { check->SetValue(check->GetValue() ? false : true); });
|
||||
text->Bind(wxEVT_LEFT_DOWN, [check](wxMouseEvent&) { check->SetValue(check->GetValue() ? false : true); });
|
||||
m_checkbox_list[param] = check;
|
||||
m_checkbox_list[param]->SetValue(true);
|
||||
return checkbox;
|
||||
|
||||
@@ -477,7 +477,7 @@ void CalibrationWizard::on_cali_go_home()
|
||||
if (go_home_dialog == nullptr)
|
||||
go_home_dialog = new SecondaryCheckDialog(this, wxID_ANY, _L("Confirm"));
|
||||
|
||||
go_home_dialog->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, method](wxCommandEvent &e) {
|
||||
go_home_dialog->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this](wxCommandEvent &e) {
|
||||
if (curr_obj) {
|
||||
curr_obj->command_task_abort();
|
||||
} else {
|
||||
|
||||
@@ -90,7 +90,7 @@ void CalibrationCaliPage::on_subtask_abort(wxCommandEvent& event)
|
||||
|
||||
if (abort_dlg == nullptr) {
|
||||
abort_dlg = new SecondaryCheckDialog(this->GetParent(), wxID_ANY, _L("Cancel print"));
|
||||
abort_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, obj](wxCommandEvent& e) {
|
||||
abort_dlg->Bind(EVT_SECONDARY_CHECK_CONFIRM, [obj](wxCommandEvent& e) {
|
||||
if (obj) obj->command_task_abort();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -762,7 +762,7 @@ void CaliPageActionPanel::bind_button(CaliPageActionType action_type, bool is_bl
|
||||
|
||||
if (is_block) {
|
||||
m_action_btns[i]->Bind(wxEVT_BUTTON,
|
||||
[this](wxCommandEvent& evt) {
|
||||
[](wxCommandEvent& evt) {
|
||||
MessageDialog msg(nullptr, _L("The current firmware version of the printer does not support calibration.\nPlease upgrade the printer firmware."), _L("Calibration not supported"), wxOK | wxICON_WARNING);
|
||||
msg.ShowModal();
|
||||
});
|
||||
|
||||
@@ -272,7 +272,7 @@ void CaliPASaveAutoPanel::sync_cali_result(const std::vector<PACalibResult>& cal
|
||||
preset_names = default_naming(preset_names);
|
||||
|
||||
std::vector<PACalibResult> sorted_cali_result = cali_result;
|
||||
std::sort(sorted_cali_result.begin(), sorted_cali_result.end(), [this](const PACalibResult &left, const PACalibResult& right) {
|
||||
std::sort(sorted_cali_result.begin(), sorted_cali_result.end(), [](const PACalibResult &left, const PACalibResult& right) {
|
||||
return left.tray_id < right.tray_id;
|
||||
});
|
||||
|
||||
@@ -366,7 +366,7 @@ void CaliPASaveAutoPanel::sync_cali_result(const std::vector<PACalibResult>& cal
|
||||
}
|
||||
}
|
||||
|
||||
comboBox_tray_name->Bind(wxEVT_COMBOBOX, [this, comboBox_tray_name, k_value, n_value](auto& e) {
|
||||
comboBox_tray_name->Bind(wxEVT_COMBOBOX, [comboBox_tray_name](auto& e) {
|
||||
int selection = comboBox_tray_name->GetSelection();
|
||||
auto history = filtered_results[selection];
|
||||
});
|
||||
@@ -744,7 +744,7 @@ void CaliPASaveAutoPanel::sync_cali_result_for_multi_extruder(const std::vector<
|
||||
}
|
||||
}
|
||||
|
||||
comboBox_tray_name->Bind(wxEVT_COMBOBOX, [this, comboBox_tray_name, k_value, n_value](auto &e) {
|
||||
comboBox_tray_name->Bind(wxEVT_COMBOBOX, [comboBox_tray_name](auto &e) {
|
||||
int selection = comboBox_tray_name->GetSelection();
|
||||
auto history = filtered_results[selection];
|
||||
});
|
||||
|
||||
@@ -140,7 +140,7 @@ CameraPopup::CameraPopup(wxWindow *parent)
|
||||
vcamera_guide_link->Wrap(-1);
|
||||
vcamera_guide_link->SetForegroundColour(wxColour(0x1F, 0x8E, 0xEA));
|
||||
auto text_size = vcamera_guide_link->GetTextExtent(text);
|
||||
vcamera_guide_link->Bind(wxEVT_LEFT_DOWN, [this, url](wxMouseEvent& e) {wxLaunchDefaultBrowser(url); });
|
||||
vcamera_guide_link->Bind(wxEVT_LEFT_DOWN, [url](wxMouseEvent& e) {wxLaunchDefaultBrowser(url); });
|
||||
|
||||
link_underline = new wxPanel(m_panel, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL);
|
||||
link_underline->SetBackgroundColour(wxColour(0x1F, 0x8E, 0xEA));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -453,7 +453,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
|
||||
if (config->opt_bool("alternate_extra_wall") &&
|
||||
(config->opt_enum<EnsureVerticalShellThickness>("ensure_vertical_shell_thickness") == evstAll)) {
|
||||
wxString msg_text = _(L("Alternate extra wall does't work well when ensure vertical shell thickness is set to All."));
|
||||
wxString msg_text = _(L("Alternate extra wall doesn't work well when ensure vertical shell thickness is set to All."));
|
||||
|
||||
if (is_global_config)
|
||||
msg_text += "\n\n" + _(L("Change these settings automatically?\n"
|
||||
@@ -642,7 +642,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
|
||||
if (config->opt_enum<SeamScarfType>("seam_slope_type") != SeamScarfType::None &&
|
||||
config->get_abs_value("seam_slope_start_height") >= layer_height) {
|
||||
const wxString msg_text = _(L("seam_slope_start_height need to be smaller than layer_height.\nReset to 0."));
|
||||
const wxString msg_text = _(L("seam_slope_start_height needs to be smaller than layer_height.\nReset to 0."));
|
||||
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
|
||||
DynamicPrintConfig new_conf = *config;
|
||||
is_msg_dlg_already_exist = true;
|
||||
@@ -656,7 +656,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
float skin_depth = config->opt_float("skin_infill_depth");
|
||||
if (config->opt_float("infill_lock_depth") > skin_depth) {
|
||||
// xgettext:no-c-format, no-boost-format
|
||||
const wxString msg_text = _(L("Lock depth should smaller than skin depth.\nReset to 50% of skin depth."));
|
||||
const wxString msg_text = _(L("Lock depth should be smaller than skin depth.\nReset to 50% of skin depth."));
|
||||
MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK);
|
||||
DynamicPrintConfig new_conf = *config;
|
||||
is_msg_dlg_already_exist = true;
|
||||
@@ -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")));
|
||||
|
||||
|
||||
@@ -2752,7 +2752,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
|
||||
});
|
||||
|
||||
if (wxLinux_gtk3)
|
||||
this->Bind(wxEVT_SHOW, [this, vsizer](const wxShowEvent& e) {
|
||||
this->Bind(wxEVT_SHOW, [](const wxShowEvent& e) {
|
||||
;
|
||||
});
|
||||
|
||||
|
||||
@@ -599,7 +599,9 @@ static char* read_json_file(const std::string &preset_path)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fread(json_contents, 1, file_size, json_file);
|
||||
const size_t read_bytes = fread(json_contents, 1, file_size, json_file);
|
||||
if (read_bytes != static_cast<size_t>(file_size))
|
||||
BOOST_LOG_TRIVIAL(error) << "Read " << read_bytes << " of " << file_size << " bytes from the JSON file";
|
||||
fclose(json_file);
|
||||
|
||||
return json_contents;
|
||||
@@ -1885,7 +1887,7 @@ wxBoxSizer *CreatePrinterPresetDialog::create_nozzle_diameter_item(wxWindow *par
|
||||
|
||||
m_custom_nozzle_diameter_ctrl = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE);
|
||||
m_custom_nozzle_diameter_ctrl->SetHint(_L("Input Custom Nozzle Diameter"));
|
||||
m_custom_nozzle_diameter_ctrl->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) {
|
||||
m_custom_nozzle_diameter_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent &event) {
|
||||
int key = event.GetKeyCode();
|
||||
if (key != 44 && key != 46 && cannot_input_key.find(key) != cannot_input_key.end()) { // "@" can not be inputed
|
||||
event.Skip(false);
|
||||
@@ -3867,14 +3869,14 @@ void ExportConfigsDialog::select_curr_radiobox(std::vector<std::pair<RadioBox *,
|
||||
m_preset_sizer->Add(create_checkbox(m_presets_window, preset.second, printer_name, m_preset), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT,
|
||||
FromDIP(5));
|
||||
}
|
||||
m_serial_text->SetLabel(_L("Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip."));
|
||||
m_serial_text->SetLabel(_L("Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a ZIP archive."));
|
||||
} else if (export_type == m_exprot_type.filament_preset) {
|
||||
for (std::pair<std::string, std::vector<std::pair<std::string, Preset *>>> filament_name_to_preset : m_filament_name_to_presets) {
|
||||
if (filament_name_to_preset.second.empty()) continue;
|
||||
wxString filament_name = wxString::FromUTF8(filament_name_to_preset.first);
|
||||
m_preset_sizer->Add(create_checkbox(m_presets_window, filament_name, m_printer_name), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(5));
|
||||
}
|
||||
m_serial_text->SetLabel(_L("Only the filament names with user filament presets will be displayed, \nand all user filament presets in each filament name you select will be exported as a zip."));
|
||||
m_serial_text->SetLabel(_L("Only the filament names with user filament presets will be displayed, \nand all user filament presets in each filament name you select will be exported as a ZIP archive."));
|
||||
} else if (export_type == m_exprot_type.process_preset) {
|
||||
for (std::pair<std::string, std::vector<Preset *>> presets : m_process_presets) {
|
||||
Preset * printer_preset = preset_bundle->printers.find_preset(presets.first, false);
|
||||
@@ -3890,7 +3892,7 @@ void ExportConfigsDialog::select_curr_radiobox(std::vector<std::pair<RadioBox *,
|
||||
}
|
||||
|
||||
}
|
||||
m_serial_text->SetLabel(_L("Only printer names with changed process presets will be displayed, \nand all user process presets in each printer name you select will be exported as a zip."));
|
||||
m_serial_text->SetLabel(_L("Only printer names with changed process presets will be displayed, \nand all user process presets in each printer name you select will be exported as a ZIP archive."));
|
||||
}
|
||||
//m_presets_window->SetSizerAndFit(m_preset_sizer);
|
||||
m_presets_window->Layout();
|
||||
|
||||
@@ -74,12 +74,10 @@ 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_create = nullptr;
|
||||
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;
|
||||
ComboBox * m_exist_vendor_combobox = nullptr;
|
||||
ComboBox * m_filament_preset_combobox = nullptr;
|
||||
TextInput * m_filament_custom_vendor_input = nullptr;
|
||||
wxGridSizer * m_filament_presets_sizer = nullptr;
|
||||
|
||||
@@ -16,24 +16,27 @@ namespace Slic3r
|
||||
// This block is never executed at runtime.
|
||||
static void _toolhead_translation_markers()
|
||||
{
|
||||
// Dynamic toolhead display names from JSON config — xgettext cannot scan these
|
||||
L("Main Extruder"); L("Main extruder"); L("main extruder");
|
||||
L("Auxiliary Extruder"); L("Auxiliary extruder"); L("auxiliary extruder");
|
||||
L("Left Extruder"); L("Left extruder"); L("left extruder");
|
||||
L("Right Extruder"); L("Right extruder"); L("right extruder");
|
||||
L("Main Nozzle"); L("Main nozzle"); L("main nozzle");
|
||||
L("Auxiliary Nozzle"); L("Auxiliary nozzle"); L("auxiliary nozzle");
|
||||
L("Left Nozzle"); L("Left nozzle"); L("left nozzle");
|
||||
L("Right Nozzle"); L("Right nozzle"); L("right nozzle");
|
||||
L("Main Hotend"); L("Main hotend"); L("main hotend");
|
||||
L("Auxiliary Hotend"); L("Auxiliary hotend"); L("auxiliary hotend");
|
||||
L("Left Hotend"); L("Left hotend"); L("left hotend");
|
||||
L("Right Hotend"); L("Right hotend"); L("right hotend");
|
||||
// standalone position words (short_name=true runtime results)
|
||||
L("main"); L("auxiliary");
|
||||
L("Main"); L("Auxiliary");
|
||||
L("left"); L("right");
|
||||
L("Left"); L("Right");
|
||||
// Possible runtime values of tool_head_display_names, marked for extraction.
|
||||
static const char *const markers[] = {
|
||||
L("Main Extruder"), L("Main extruder"), L("main extruder"),
|
||||
L("Auxiliary Extruder"), L("Auxiliary extruder"), L("auxiliary extruder"),
|
||||
L("Left Extruder"), L("Left extruder"), L("left extruder"),
|
||||
L("Right Extruder"), L("Right extruder"), L("right extruder"),
|
||||
L("Main Nozzle"), L("Main nozzle"), L("main nozzle"),
|
||||
L("Auxiliary Nozzle"), L("Auxiliary nozzle"), L("auxiliary nozzle"),
|
||||
L("Left Nozzle"), L("Left nozzle"), L("left nozzle"),
|
||||
L("Right Nozzle"), L("Right nozzle"), L("right nozzle"),
|
||||
L("Main Hotend"), L("Main hotend"), L("main hotend"),
|
||||
L("Auxiliary Hotend"), L("Auxiliary hotend"), L("auxiliary hotend"),
|
||||
L("Left Hotend"), L("Left hotend"), L("left hotend"),
|
||||
L("Right Hotend"), L("Right hotend"), L("right hotend"),
|
||||
// standalone position words (short_name=true runtime results)
|
||||
L("main"), L("auxiliary"),
|
||||
L("Main"), L("Auxiliary"),
|
||||
L("left"), L("right"),
|
||||
L("Left"), L("Right"),
|
||||
};
|
||||
(void) markers;
|
||||
}
|
||||
|
||||
std::string DevPrinterConfigUtil::m_resource_file_path = "";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -199,7 +199,6 @@ private:
|
||||
void OnRefreshButton(wxCommandEvent& event);
|
||||
|
||||
private:
|
||||
int saveTimes{0};
|
||||
wxBoxSizer* mainSizer{nullptr};
|
||||
wxPanel* textPanel{nullptr};
|
||||
wxBoxSizer* textSizer{nullptr};
|
||||
|
||||
@@ -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);};
|
||||
|
||||
@@ -122,7 +122,6 @@ private:
|
||||
private:
|
||||
int m_ext_nozzle_id = -1;
|
||||
int m_rack_nozzle_id = -1;
|
||||
bool m_isRefreshFinish = false;
|
||||
bool findNozzleImage = false;
|
||||
|
||||
NozzleStatus m_nozzle_status = NOZZLE_STATUS_DC;
|
||||
@@ -154,7 +153,6 @@ private:
|
||||
Label* m_diameter_label;
|
||||
Label* m_flowtype_label;
|
||||
Label* m_type_label;
|
||||
ScalableButton* m_error_button{ nullptr };
|
||||
|
||||
Label* m_sn_label;
|
||||
Label* m_version_label;
|
||||
|
||||
@@ -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"));
|
||||
@@ -266,7 +266,7 @@ void wgtDeviceNozzleRackSelect::OnNozzleItemSelected(wxCommandEvent &evt)
|
||||
}
|
||||
|
||||
auto *item = dynamic_cast<wgtDeviceNozzleRackNozzleItem *>(evt.GetEventObject());
|
||||
if (item; auto ptr = m_nozzle_rack.lock()) {
|
||||
if (auto ptr = m_nozzle_rack.lock(); item && ptr) {
|
||||
int to_select_pos_id = sGetNozzlePosId(item, m_toolhead_nozzle_l, m_toolhead_nozzle_r);
|
||||
if (to_select_pos_id > -1 && to_select_pos_id != GetSelectedNozzlePosID()) {
|
||||
SetSelectedNozzle(ptr->GetNozzleSystem()->GetNozzleByPosId(to_select_pos_id));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -941,7 +941,11 @@ void TextCtrl::BUILD() {
|
||||
temp->SetToolTip(get_tooltip_text(text_value));
|
||||
|
||||
if (!m_opt.multiline) {
|
||||
text_ctrl->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent &e)
|
||||
text_ctrl->Bind(wxEVT_TEXT_ENTER, ([
|
||||
#if !defined(__WXGTK__)
|
||||
temp,
|
||||
#endif // __WXGTK__
|
||||
this](wxEvent &e)
|
||||
{
|
||||
#if !defined(__WXGTK__)
|
||||
e.Skip();
|
||||
@@ -973,7 +977,11 @@ void TextCtrl::BUILD() {
|
||||
temp->GetToolTip()->Enable(flag);
|
||||
}), text_ctrl->GetId());
|
||||
|
||||
temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent &e)
|
||||
temp->Bind(wxEVT_KILL_FOCUS, ([
|
||||
#if !defined(__WXGTK__)
|
||||
temp,
|
||||
#endif // __WXGTK__
|
||||
this](wxEvent &e)
|
||||
{
|
||||
e.Skip();
|
||||
#if !defined(__WXGTK__)
|
||||
@@ -1324,7 +1332,7 @@ void SpinCtrl::BUILD() {
|
||||
bEnterPressed = true;
|
||||
}), temp->GetId());
|
||||
|
||||
temp->GetTextCtrl()->Bind(wxEVT_TEXT, ([this, temp](wxCommandEvent e)
|
||||
temp->GetTextCtrl()->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
|
||||
{
|
||||
// # On OSX / Cocoa, SpinInput::GetValue() doesn't return the new value
|
||||
// # when it was changed from the text control, so the on_change callback
|
||||
@@ -2597,7 +2605,11 @@ void ColourPicker::BUILD()
|
||||
// // recast as a wxWindow to fit the calling convention
|
||||
window = dynamic_cast<wxWindow*>(temp);
|
||||
|
||||
temp->Bind(wxEVT_COLOURPICKER_CHANGED, ([this,temp](wxCommandEvent e) {
|
||||
temp->Bind(wxEVT_COLOURPICKER_CHANGED, ([
|
||||
#ifdef __WXMSW__
|
||||
temp,
|
||||
#endif
|
||||
this](wxCommandEvent e) {
|
||||
#ifdef __WXMSW__
|
||||
draw_bmp_btn(temp, temp->GetColour());
|
||||
#endif
|
||||
|
||||
@@ -241,7 +241,7 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
||||
|
||||
wxBoxSizer *mode_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_auto_btn = new CapsuleButton(this, PageType::ptAuto, only_saving_mode ? _L("Fila Saving") : _L("Auto"), false);
|
||||
m_auto_btn = new CapsuleButton(this, PageType::ptAuto, only_saving_mode ? _L("File Saving") : _L("Auto"), false);
|
||||
m_manual_btn = new CapsuleButton(this, PageType::ptManual, _L("Custom"), false);
|
||||
if (show_default)
|
||||
m_default_btn = new CapsuleButton(this, PageType::ptDefault, _L("Same as Global"), true);
|
||||
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user