Merge branch 'dk_SPE-2438'

This commit is contained in:
Lukas Matena 2024-08-29 10:36:50 +02:00
commit 78400b3399
19 changed files with 748 additions and 318 deletions

View File

@ -1,8 +1,8 @@
set(LibBGCode_SOURCE_DIR "" CACHE PATH "Optionally specify local LibBGCode source directory")
set(_source_dir_line
URL https://github.com/prusa3d/libbgcode/archive/8ae75bd0eea622f0e34cae311b3bd065b55eae9b.zip
URL_HASH SHA256=141a8cea3baea6066527389fda734057181414c4fa296d34501ef8f69ea412e9)
URL https://github.com/prusa3d/libbgcode/archive/d20e3a3a6d1ee3d8026bf20c5a9ce2ad88f4b433.zip
URL_HASH SHA256=bfcba51262bdda6f0bf06b9508f4386c50145d3e97bba6c76ee1f1520dae3b93)
if (LibBGCode_SOURCE_DIR)
set(_source_dir_line "SOURCE_DIR;${LibBGCode_SOURCE_DIR};BUILD_ALWAYS;ON")

View File

@ -957,8 +957,8 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
// printer data - this section contains duplicates from the slicer metadata
// that we just created. Find and copy the entries that we want to duplicate.
const auto& slicer_metadata = binary_data.slicer_metadata.raw_data;
const std::vector<std::string> keys_to_duplicate = { "printer_model", "filament_type", "nozzle_diameter", "bed_temperature",
"brim_width", "fill_density", "layer_height", "temperature", "ironing", "support_material", "extruder_colour" };
const std::vector<std::string> keys_to_duplicate = { "printer_model", "filament_type", "filament_abrasive", "nozzle_diameter", "nozzle_high_flow", "bed_temperature",
"brim_width", "fill_density", "layer_height", "temperature", "ironing", "support_material", "extruder_colour"};
assert(std::is_sorted(slicer_metadata.begin(), slicer_metadata.end(),
[](const auto& a, const auto& b) { return a.first < b.first; }));
for (const std::string& key : keys_to_duplicate) {

View File

@ -165,6 +165,13 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
res.repo_id = "";
}
const auto repo_prefix = vendor_section.find("repo_prefix");
if (repo_prefix != vendor_section.not_found()) {
res.repo_prefix = repo_prefix->second.data();
} else {
res.repo_prefix = "";
}
if (! load_all) {
return res;
}
@ -486,7 +493,7 @@ static std::vector<std::string> s_Preset_print_options {
};
static std::vector<std::string> s_Preset_filament_options {
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", "filament_infill_max_speed", "filament_infill_max_crossing_speed",
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_abrasive", "filament_notes", "filament_max_volumetric_speed", "filament_infill_max_speed", "filament_infill_max_crossing_speed",
"extrusion_multiplier", "filament_density", "filament_cost", "filament_spool_weight", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
"filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_stamping_loading_speed", "filament_stamping_distance",
"filament_cooling_initial_speed", "filament_purge_multiplier", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower",
@ -525,7 +532,8 @@ static std::vector<std::string> s_Preset_printer_options {
"cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "multimaterial_purging",
"max_print_height", "default_print_profile", "inherits",
"remaining_times", "silent_mode",
"machine_limits_usage", "thumbnails", "thumbnails_format"
"machine_limits_usage", "thumbnails", "thumbnails_format",
"nozzle_high_flow"
};
static std::vector<std::string> s_Preset_sla_print_options {

View File

@ -40,6 +40,7 @@ public:
std::string config_update_url;
std::string changelog_url;
std::string repo_id;
std::string repo_prefix;
bool templates_profile { false };
struct PrinterVariant {

View File

@ -114,6 +114,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"fan_always_on",
"fan_below_layer_time",
"full_fan_speed_layer",
"filament_abrasive",
"filament_colour",
"filament_diameter",
"filament_density",
@ -126,6 +127,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"first_layer_speed_over_raft",
"gcode_comments",
"gcode_label_objects",
"nozzle_high_flow",
"infill_acceleration",
"layer_gcode",
"min_fan_speed",

View File

@ -1370,6 +1370,12 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBools { false });
def = this->add("filament_abrasive", coBools);
def->label = L("Abrasive material");
def->tooltip = L("This flag means that the material is abrasive and requires a hardened nozzle. The value is used by the printer to check it.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBools { false });
def = this->add("filament_cost", coFloats);
def->label = L("Cost");
def->tooltip = L("Enter your filament cost per kg here. This is only for statistical information.");
@ -2550,6 +2556,12 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert;
def->set_default_value(new ConfigOptionBools{false});
def = this->add("nozzle_high_flow", coBools);
def->label = L("High flow nozzle");
def->tooltip = L("High flow nozzles allow higher print speeds.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBools{false});
def = this->add("retract_lift", coFloats);
def->label = L("Lift height");
def->tooltip = L("Lift height applied before travel.");
@ -3715,7 +3727,7 @@ void PrintConfigDef::init_extruder_option_keys()
"retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe",
"travel_slope", "travel_max_lift", "travel_ramping_lift", "travel_lift_before_obstacle",
"retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour",
"default_filament_profile"
"default_filament_profile", "nozzle_high_flow"
};
m_extruder_retract_keys = {

View File

@ -782,6 +782,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloats, filament_density))
((ConfigOptionStrings, filament_type))
((ConfigOptionBools, filament_soluble))
((ConfigOptionBools, filament_abrasive))
((ConfigOptionFloats, filament_cost))
((ConfigOptionFloats, filament_spool_weight))
((ConfigOptionFloats, filament_max_volumetric_speed))
@ -825,6 +826,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloats, travel_max_lift))
((ConfigOptionFloats, travel_slope))
((ConfigOptionBools, travel_lift_before_obstacle))
((ConfigOptionBools, nozzle_high_flow))
((ConfigOptionPercents, retract_before_wipe))
((ConfigOptionFloats, retract_length))
((ConfigOptionFloats, retract_length_toolchange))

View File

@ -23,6 +23,8 @@ set(SLIC3R_GUI_SOURCES
GUI/UserAccountCommunication.hpp
GUI/UserAccountSession.cpp
GUI/UserAccountSession.hpp
GUI/UserAccountUtils.cpp
GUI/UserAccountUtils.hpp
GUI/UserAccount.cpp
GUI/UserAccount.hpp
GUI/WebViewDialog.cpp

View File

@ -101,6 +101,7 @@
#include "PhysicalPrinterDialog.hpp"
#include "WifiConfigDialog.hpp"
#include "UserAccount.hpp"
#include "UserAccountUtils.hpp"
#include "WebViewDialog.hpp"
#include "LoginDialog.hpp" // IWYU pragma: keep
#include "PresetArchiveDatabase.hpp"
@ -3823,14 +3824,102 @@ bool GUI_App::select_printer_preset(const Preset* preset)
return is_installed;
}
namespace {
const Preset* find_preset_by_nozzle_and_options(
const PrinterPresetCollection& collection
, const std::string& model_id
, std::map<std::string, std::vector<std::string>>& options)
{
// find all matching presets when repo prefix is ommited
std::vector<const Preset*> results;
for (const Preset &preset : collection) {
// trim repo prefix
std::string printer_model = preset.config.opt_string("printer_model");
std::string vendor_repo_prefix;
if (preset.vendor) {
vendor_repo_prefix = preset.vendor->repo_prefix;
} else if (std::string inherits = preset.inherits(); !inherits.empty()) {
const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits);
if (parent && parent->vendor) {
vendor_repo_prefix = parent->vendor->repo_prefix;
}
}
if (printer_model.find(vendor_repo_prefix) == 0) {
printer_model = printer_model.substr(vendor_repo_prefix.size()
);
boost::trim_left(printer_model);
}
if (!preset.is_system || printer_model != model_id)
continue;
// options (including nozzle_diameter)
bool failed = false;
for (const auto& opt : options) {
assert(preset.config.has(opt.first));
// We compare only first value now, but options contains data for all (some might be empty tho)
std::string opt_val;
if (preset.config.option(opt.first)->is_scalar()) {
opt_val = preset.config.option(opt.first)->serialize();
} else {
switch (preset.config.option(opt.first)->type()) {
case coInts: opt_val = std::to_string(static_cast<const ConfigOptionInts*>(preset.config.option(opt.first))->values[0]); break;
case coFloats:
opt_val = into_u8(double_to_string(static_cast<const ConfigOptionFloats*>(preset.config.option(opt.first))->values[0]));
if (size_t pos = opt_val.find(",") != std::string::npos)
opt_val.replace(pos, 1, 1, '.');
break;
case coStrings: opt_val = static_cast<const ConfigOptionStrings*>(preset.config.option(opt.first))->values[0]; break;
case coBools: opt_val = static_cast<const ConfigOptionBools*>(preset.config.option(opt.first))->values[0] ? "1" : "0"; break;
default:
assert(true);
continue;
}
}
if (opt_val != opt.second[0])
{
failed = true;
break;
}
}
if (!failed) {
results.push_back(&preset);
}
}
// find visible without prefix
for (const Preset *preset : results) {
if (preset->is_visible && preset->config.opt_string("printer_model") == model_id) {
return preset;
}
}
// find one visible
for (const Preset *preset : results) {
if (preset->is_visible) {
return preset;
}
}
// find one without prefix
for (const Preset* preset : results) {
if (preset->config.opt_string("printer_model") == model_id) {
return preset;
}
}
if (results.size() != 0) {
return results.front();
}
return nullptr;
}
}
bool GUI_App::select_printer_from_connect(const std::string& msg)
{
// parse message
std::string model_name = plater()->get_user_account()->get_keyword_from_json(msg, "printer_model");
std::string uuid = plater()->get_user_account()->get_keyword_from_json(msg, "uuid");
// parse message "binary_gcode"
boost::property_tree::ptree ptree;
std::string model_name = UserAccountUtils::get_keyword_from_json(ptree, msg, "printer_model");
std::string uuid = UserAccountUtils::get_keyword_from_json(ptree, msg, "uuid");
if (model_name.empty()) {
std::vector<std::string> compatible_printers;
plater()->get_user_account()->fill_supported_printer_models_from_json(msg, compatible_printers);
UserAccountUtils::fill_supported_printer_models_from_json(ptree, compatible_printers);
if (!compatible_printers.empty()) {
model_name = compatible_printers.front();
}
@ -3839,10 +3928,23 @@ bool GUI_App::select_printer_from_connect(const std::string& msg)
BOOST_LOG_TRIVIAL(error) << "Failed to select printer from Connect. Printer_model is empty.";
return false;
}
std::string nozzle = plater()->get_user_account()->get_nozzle_from_json(msg);
BOOST_LOG_TRIVIAL(info) << "Select printer from Connect. Model: " << model_name << "nozzle: " << nozzle;
std::map<std::string, std::vector<std::string>> config_options_to_match;
UserAccountUtils::fill_config_options_from_json(ptree, config_options_to_match);
// prevent not having nozzle diameter
if (config_options_to_match.find("nozzle_diameter") == config_options_to_match.end()) {
std::string diameter = UserAccountUtils::get_keyword_from_json(ptree, msg, "nozzle_diameter");
if (!diameter.empty())
config_options_to_match["nozzle_diameter"] = {diameter};
}
// log
BOOST_LOG_TRIVIAL(info) << "Select printer from Connect. Model: " << model_name;
for(const auto& pair :config_options_to_match) {
std::string out;
for(const std::string& val :pair.second) { out += val + ",";}
BOOST_LOG_TRIVIAL(info) << pair.first << ": " << out;
}
// select printer
const Preset* printer_preset = preset_bundle->printers.find_system_preset_by_model_and_variant(model_name, nozzle);
const Preset* printer_preset = find_preset_by_nozzle_and_options(preset_bundle->printers, model_name, config_options_to_match);
bool is_installed = printer_preset && select_printer_preset(printer_preset);
// notification
std::string out = printer_preset ?
@ -3871,11 +3973,14 @@ bool GUI_App::select_filament_preset(const Preset* preset, size_t extruder_index
assert(preset->is_visible);
return preset_bundle->extruders_filaments[extruder_index].select_filament(preset->name);
}
void GUI_App::search_and_select_filaments(const std::string& material, size_t extruder_index, std::string& out_message)
void GUI_App::search_and_select_filaments(const std::string& material, bool avoid_abrasive, size_t extruder_index, std::string& out_message)
{
const Preset* preset = preset_bundle->extruders_filaments[extruder_index].get_selected_preset();
// selected is ok
if (!preset->is_default && preset->config.has("filament_type") && preset->config.option("filament_type")->serialize() == material) {
if (!preset->is_default && preset->config.has("filament_type")
&& (!avoid_abrasive || preset->config.option<ConfigOptionBools>("filament_abrasive")->values[0] == false)
&& preset->config.option("filament_type")->serialize() == material)
{
return;
}
// find installed compatible filament that is Prusa with suitable type and select it
@ -3885,6 +3990,7 @@ void GUI_App::search_and_select_filaments(const std::string& material, size_t ex
&& filament.preset->is_visible
&& (!filament.preset->vendor || !filament.preset->vendor->templates_profile)
&& filament.preset->config.has("filament_type")
&& (!avoid_abrasive || filament.preset->config.option<ConfigOptionBools>("filament_abrasive")->values[0] == false)
&& filament.preset->config.option("filament_type")->serialize() == material
&& filament.preset->name.compare(0, 9, "Prusament") == 0
&& select_filament_preset(filament.preset, extruder_index)
@ -3903,6 +4009,7 @@ void GUI_App::search_and_select_filaments(const std::string& material, size_t ex
&& filament.preset->is_visible
&& (!filament.preset->vendor || !filament.preset->vendor->templates_profile)
&& filament.preset->config.has("filament_type")
&& (!avoid_abrasive || filament.preset->config.option<ConfigOptionBools>("filament_abrasive")->values[0] == false)
&& filament.preset->config.option("filament_type")->serialize() == material
&& select_filament_preset(filament.preset, extruder_index)
)
@ -3920,6 +4027,7 @@ void GUI_App::search_and_select_filaments(const std::string& material, size_t ex
&& !filament.preset->is_default
&& (!filament.preset->vendor || !filament.preset->vendor->templates_profile)
&& filament.preset->config.has("filament_type")
&& (!avoid_abrasive || filament.preset->config.option<ConfigOptionBools>("filament_abrasive")->values[0] == false)
&& filament.preset->config.option("filament_type")->serialize() == material
&& filament.preset->name.compare(0, 9, "Prusament") == 0
&& select_filament_preset(filament.preset, extruder_index))
@ -3935,7 +4043,8 @@ void GUI_App::select_filament_from_connect(const std::string& msg)
{
// parse message
std::vector<std::string> materials;
plater()->get_user_account()->fill_material_from_json(msg, materials);
std::vector<bool> avoid_abrasive;
UserAccountUtils::fill_material_from_json(msg, materials, avoid_abrasive);
if (materials.empty()) {
BOOST_LOG_TRIVIAL(error) << "Failed to select filament from Connect. No material data.";
return;
@ -3944,11 +4053,14 @@ void GUI_App::select_filament_from_connect(const std::string& msg)
size_t extruder_count = preset_bundle->extruders_filaments.size();
if (extruder_count != materials.size()) {
BOOST_LOG_TRIVIAL(error) << format("Failed to select filament from Connect. Selected printer has %1% extruders while data from Connect contains %2% materials.", extruder_count, materials.size());
plater()->get_notification_manager()->close_notification_of_type(NotificationType::SelectFilamentFromConnect);
// TRN: Notification text.
plater()->get_notification_manager()->push_notification(NotificationType::SelectFilamentFromConnect, NotificationManager::NotificationLevel::ImportantNotificationLevel, _u8L("Failed to select filament from Connect."));
return;
}
std::string notification_text;
for (size_t i = 0; i < extruder_count; i++) {
search_and_select_filaments(materials[i], i, notification_text);
search_and_select_filaments(materials[i], avoid_abrasive.size() > i ? avoid_abrasive[i] : false, i, notification_text);
}
// When all filaments are selected/intalled,
@ -3969,7 +4081,8 @@ void GUI_App::handle_connect_request_printer_select(const std::string& msg)
// Here comes code from ConnectWebViewPanel
// It only contains uuid of a printer to be selected
// Lets queue it and wait on result. The result is send via event to plater, where it is send to handle_connect_request_printer_select_inner
std::string uuid = plater()->get_user_account()->get_keyword_from_json(msg, "uuid");
boost::property_tree::ptree ptree;
std::string uuid = UserAccountUtils::get_keyword_from_json(ptree, msg, "uuid");
plater()->get_user_account()->enqueue_printer_data_action(uuid);
}
void GUI_App::handle_connect_request_printer_select_inner(const std::string & msg)
@ -3977,7 +4090,6 @@ void GUI_App::handle_connect_request_printer_select_inner(const std::string & ms
BOOST_LOG_TRIVIAL(debug) << "Handling web request: " << msg;
// return to plater
this->mainframe->select_tab(size_t(0));
if (!select_printer_from_connect(msg)) {
// If printer was not selected, do not select filament.
return;

View File

@ -416,7 +416,7 @@ public:
// return true if preset vas invisible and we have to installed it to make it selectable
bool select_printer_preset(const Preset* printer_preset);
bool select_filament_preset(const Preset* filament_preset, size_t extruder_index);
void search_and_select_filaments(const std::string& material, size_t extruder_index, std::string& out_message);
void search_and_select_filaments(const std::string& material, bool avoid_abrasive, size_t extruder_index, std::string& out_message);
void handle_script_message(std::string msg) {}
void request_model_download(std::string import_json) {}
void download_project(std::string project_id) {}

View File

@ -728,9 +728,10 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change)
for (PresetForPrinter* prstft : m_presets) {
std::string preset_name = prstft->get_preset_name();
if (Preset* preset = wxGetApp().preset_bundle->printers.find_preset(preset_name)) {
std::string model_id = preset->config.opt_string("printer_model");
std::string model_id = preset->config.opt_string("printer_model");
if (preset->vendor) {
if (preset->vendor->name == "Prusa Research") {
// No need to remove prefix from printer_model, family is not prefixed
if (preset->vendor->name.find("Prusa Research") != std::string::npos) {
const std::vector<VendorProfile::PrinterModel>& models = preset->vendor->models;
auto it = std::find_if(models.begin(), models.end(),
[model_id](const VendorProfile::PrinterModel& model) { return model.id == model_id; });
@ -754,11 +755,16 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change)
break;
}
std::string model_id = preset->config.opt_string("printer_model");
if (preset->vendor && preset->vendor->name != "Prusa Research") {
connect.supported = false;
break;
// remove prefix from printer_model
if (preset->vendor) {
std::string vendor_repo_prefix;
vendor_repo_prefix = preset->vendor->repo_prefix;
if (model_id.find(vendor_repo_prefix) == 0) {
model_id = model_id.substr(vendor_repo_prefix.size());
boost::trim_left(model_id);
}
}
if (preset->vendor && preset->vendor->name != "Prusa Research") {
if (preset->vendor && preset->vendor->name.find("Prusa Research") == std::string::npos) {
connect.supported = false;
break;
}

View File

@ -123,6 +123,7 @@
#include "Gizmos/GLGizmoCut.hpp"
#include "FileArchiveDialog.hpp"
#include "UserAccount.hpp"
#include "UserAccountUtils.hpp"
#include "DesktopIntegrationDialog.hpp"
#include "WebViewDialog.hpp"
#include "PresetArchiveDatabase.hpp"
@ -2059,6 +2060,22 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
if (full_config.has("binary_gcode")) // needed for SLA
full_config.set("binary_gcode", bool(full_config.opt_bool("binary_gcode") & wxGetApp().app_config->get_bool("use_binary_gcode_when_supported")));
const Preset &selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset();
std::string printer_model_serialized = full_config.option("printer_model")->serialize();
std::string vendor_repo_prefix;
if (selected_printer.vendor) {
vendor_repo_prefix = selected_printer.vendor->repo_prefix;
} else if (std::string inherits = selected_printer.inherits(); !inherits.empty()) {
const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits);
if (parent && parent->vendor) {
vendor_repo_prefix = parent->vendor->repo_prefix;
}
}
if (printer_model_serialized.find(vendor_repo_prefix) == 0) {
printer_model_serialized = printer_model_serialized.substr(vendor_repo_prefix.size());
boost::trim_left(printer_model_serialized);
full_config.set("printer_model", printer_model_serialized);
}
// If the update_background_process() was not called by the timer, kill the timer,
// so the update_restart_background_process() will not be called again in vain.
background_process_timer.Stop();
@ -3648,7 +3665,9 @@ bool Plater::priv::can_show_upload_to_connect() const
vendor_id = parent->vendor->id;
}
}
return vendor_id.compare(0, 5, "Prusa") == 0;
// Upload to Connect should show only for prusa printers
// Some vendors might have prefixed name due to repository id.
return vendor_id.find("Prusa") != std::string::npos;
}
void Plater::priv::show_action_buttons(const bool ready_to_slice_) const
@ -6022,10 +6041,11 @@ void Plater::connect_gcode()
*/
const Preset* selected_printer_preset = &wxGetApp().preset_bundle->printers.get_selected_preset();
const std::string filename = p->user_account->get_keyword_from_json(dialog_msg, "filename");
const std::string team_id = p->user_account->get_keyword_from_json(dialog_msg, "team_id");
boost::property_tree::ptree ptree;
const std::string filename = UserAccountUtils::get_keyword_from_json(ptree, dialog_msg, "filename");
const std::string team_id = UserAccountUtils::get_keyword_from_json(ptree, dialog_msg, "team_id");
std::string data_subtree = p->user_account->get_print_data_from_json(dialog_msg, "data");
std::string data_subtree = UserAccountUtils::get_print_data_from_json(dialog_msg, "data");
if (filename.empty() || team_id.empty() || data_subtree.empty()) {
std::string msg = _u8L("Failed to read response from Prusa Connect server. Upload is cancelled.");
BOOST_LOG_TRIVIAL(error) << msg;

View File

@ -970,16 +970,47 @@ static std::string get_connect_state_suffix_for_printer(const Preset& printer_pr
!printer_state_map.empty()) {
for (const auto& [printer_model_nozzle_pair, states] : printer_state_map) {
if (printer_model_nozzle_pair.first == printer_preset.config.opt_string("printer_model")
&& printer_model_nozzle_pair.second == printer_preset.config.opt_string("printer_variant"))
{
PrinterStatesCount states_cnt = get_printe_states_count(states);
std::string printer_model = printer_preset.config.opt_string("printer_model");
std::string vendor_repo_prefix;
if (printer_preset.vendor) {
vendor_repo_prefix = printer_preset.vendor->repo_prefix;
} else if (std::string inherits = printer_preset.inherits(); !inherits.empty()) {
const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits);
if (parent && parent->vendor) {
vendor_repo_prefix = parent->vendor->repo_prefix;
}
}
if (printer_model.find(vendor_repo_prefix) == 0) {
printer_model = printer_model.substr(vendor_repo_prefix.size());
boost::trim_left(printer_model);
}
if (states_cnt.available_cnt > 0)
return "_available";
if (states_cnt.busy_cnt > 0)
return "_busy";
return "_offline";
if (printer_preset.config.has("nozzle_diameter")) {
double nozzle_diameter = static_cast<const ConfigOptionFloats*>(printer_preset.config.option("nozzle_diameter"))->values[0];
wxString nozzle_diameter_serialized = double_to_string(nozzle_diameter);
nozzle_diameter_serialized.Replace(L",", L".");
if (printer_model_nozzle_pair.first == printer_model
&& printer_model_nozzle_pair.second == GUI::into_u8(nozzle_diameter_serialized))
{
PrinterStatesCount states_cnt = get_printe_states_count(states);
if (states_cnt.available_cnt > 0)
return "_available";
if (states_cnt.busy_cnt > 0)
return "_busy";
return "_offline";
}
} else {
if (printer_model_nozzle_pair.first == printer_model) {
PrinterStatesCount states_cnt = get_printe_states_count(states);
if (states_cnt.available_cnt > 0)
return "_available";
if (states_cnt.busy_cnt > 0)
return "_busy";
return "_offline";
}
}
}
}
@ -1002,21 +1033,56 @@ static bool fill_data_to_connect_info_line( const Preset& printer_preset,
!printer_state_map.empty()) {
for (const auto& [printer_model_nozzle_pair, states] : printer_state_map) {
if (printer_model_nozzle_pair.first == printer_preset.config.opt_string("printer_model")
&& printer_model_nozzle_pair.second == printer_preset.config.opt_string("printer_variant"))
{
PrinterStatesCount states_cnt = get_printe_states_count(states);
// get printer_model without repo prefix
std::string printer_model = printer_preset.config.opt_string("printer_model");
std::string vendor_repo_prefix;
if (printer_preset.vendor) {
vendor_repo_prefix = printer_preset.vendor->repo_prefix;
} else if (std::string inherits = printer_preset.inherits(); !inherits.empty()) {
const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits);
if (parent && parent->vendor) {
vendor_repo_prefix = parent->vendor->repo_prefix;
}
}
if (printer_model.find(vendor_repo_prefix) == 0) {
printer_model = printer_model.substr(vendor_repo_prefix.size());
boost::trim_left(printer_model);
}
if (printer_preset.config.has("nozzle_diameter")) {
double nozzle_diameter = static_cast<const ConfigOptionFloats*>(printer_preset.config.option("nozzle_diameter"))->values[0];
wxString nozzle_diameter_serialized = double_to_string(nozzle_diameter);
nozzle_diameter_serialized.Replace(L",", L".");
if (printer_model_nozzle_pair.first == printer_model
&& printer_model_nozzle_pair.second == GUI::into_u8(nozzle_diameter_serialized))
{
PrinterStatesCount states_cnt = get_printe_states_count(states);
#ifdef _WIN32
connect_available_info->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.available_cnt), _L("available")));
connect_offline_info ->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.offline_cnt), _L("offline")));
connect_printing_info ->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.busy_cnt), _L("printing")));
connect_available_info->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.available_cnt), _L("available")));
connect_offline_info ->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.offline_cnt), _L("offline")));
connect_printing_info ->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.busy_cnt), _L("printing")));
#else
connect_available_info->SetLabel(format_wxstr("%1% ", states_cnt.available_cnt));
connect_offline_info ->SetLabel(format_wxstr("%1% ", states_cnt.offline_cnt));
connect_printing_info ->SetLabel(format_wxstr("%1% ", states_cnt.busy_cnt));
connect_available_info->SetLabel(format_wxstr("%1% ", states_cnt.available_cnt));
connect_offline_info ->SetLabel(format_wxstr("%1% ", states_cnt.offline_cnt));
connect_printing_info ->SetLabel(format_wxstr("%1% ", states_cnt.busy_cnt));
#endif
return true;
return true;
}
} else {
if (printer_model_nozzle_pair.first == printer_model) {
PrinterStatesCount states_cnt = get_printe_states_count(states);
#ifdef _WIN32
connect_available_info->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.available_cnt), _L("available")));
connect_offline_info ->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.offline_cnt), _L("offline")));
connect_printing_info ->SetLabelMarkup(format_wxstr("%1% %2%", format("<b>%1%</b>", states_cnt.busy_cnt), _L("printing")));
#else
connect_available_info->SetLabel(format_wxstr("%1% ", states_cnt.available_cnt));
connect_offline_info ->SetLabel(format_wxstr("%1% ", states_cnt.offline_cnt));
connect_printing_info ->SetLabel(format_wxstr("%1% ", states_cnt.busy_cnt));
#endif
return true;
}
}
}
}

View File

@ -2227,6 +2227,7 @@ void TabFilament::build()
option.opt.width = Field::def_width();
optgroup->append_single_option_line(option);
optgroup->append_single_option_line("filament_soluble");
optgroup->append_single_option_line("filament_abrasive");
optgroup = page->new_optgroup(L("Print speed override"));
optgroup->append_single_option_line("filament_max_volumetric_speed", "max-volumetric-speed_127176");
@ -2653,22 +2654,26 @@ void TabPrinter::build_fff()
if (boost::any_cast<bool>(value) && m_extruders_count > 1) {
SuppressBackgroundProcessingUpdate sbpu;
std::vector<double> nozzle_diameters = static_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values;
const double frst_diam = nozzle_diameters[0];
std::vector<unsigned char> high_flow_nozzles = static_cast<const ConfigOptionBools*>(m_config->option("nozzle_high_flow"))->values;
assert(nozzle_diameters.size() == high_flow_nozzles.size());
for (auto cur_diam : nozzle_diameters) {
for (size_t i = 1; i < nozzle_diameters.size(); ++i) {
// if value is differs from first nozzle diameter value
if (fabs(cur_diam - frst_diam) > EPSILON) {
if (fabs(nozzle_diameters[i] - nozzle_diameters[0]) > EPSILON || high_flow_nozzles[i] != high_flow_nozzles[0]) {
const wxString msg_text = _(L("Single Extruder Multi Material is selected, \n"
"and all extruders must have the same diameter.\n"
"Do you want to change the diameter for all extruders to first extruder nozzle diameter value?"));
MessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO);
"and all extruders must have the same diameter and 'High flow' state.\n"
"Do you want to change these values for all extruders to first extruder values?"));
MessageDialog dialog(parent(), msg_text, _(L("Nozzle settings mismatch")), wxICON_WARNING | wxYES_NO);
DynamicPrintConfig new_conf = *m_config;
if (dialog.ShowModal() == wxID_YES) {
for (size_t i = 1; i < nozzle_diameters.size(); i++)
nozzle_diameters[i] = frst_diam;
for (size_t i = 1; i < nozzle_diameters.size(); i++) {
nozzle_diameters[i] = nozzle_diameters[0];
high_flow_nozzles[i] = high_flow_nozzles[0];
}
new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters));
new_conf.set_key_value("nozzle_high_flow", new ConfigOptionBools(high_flow_nozzles));
}
else
new_conf.set_key_value("single_extruder_multi_material", new ConfigOptionBool(false));
@ -3132,7 +3137,7 @@ const std::vector<std::string> extruder_options = {
"retract_length", "retract_lift", "retract_lift_above", "retract_lift_below",
"retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel",
"retract_layer_change", "wipe", "retract_before_wipe", "travel_ramping_lift",
"travel_slope", "travel_max_lift", "travel_lift_before_obstacle",
"travel_slope", "travel_max_lift", "travel_lift_before_obstacle", "nozzle_high_flow",
"retract_length_toolchange", "retract_restart_extra_toolchange",
};
@ -3150,7 +3155,8 @@ void TabPrinter::build_extruder_pages(size_t n_before_extruders)
optgroup->on_change = [this, extruder_idx](const t_config_option_key&opt_key, boost::any value)
{
const bool is_single_extruder_MM = m_config->opt_bool("single_extruder_multi_material");
const bool is_nozzle_diameter_changed = opt_key.find_first_of("nozzle_diameter") != std::string::npos;
const bool is_nozzle_diameter_changed = opt_key.find("nozzle_diameter") != std::string::npos;
const bool is_high_flow_changed = opt_key.find("nozzle_high_flow") != std::string::npos;
if (is_single_extruder_MM && m_extruders_count > 1 && is_nozzle_diameter_changed)
{
@ -3163,7 +3169,6 @@ void TabPrinter::build_extruder_pages(size_t n_before_extruders)
{
const wxString msg_text = _L("This is a single extruder multimaterial printer, diameters of all extruders "
"will be set to the new value. Do you want to proceed?");
//wxMessageDialog dialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO);
MessageDialog dialog(parent(), msg_text, _L("Nozzle diameter"), wxICON_WARNING | wxYES_NO);
DynamicPrintConfig new_conf = *m_config;
@ -3182,7 +3187,36 @@ void TabPrinter::build_extruder_pages(size_t n_before_extruders)
}
}
if (is_nozzle_diameter_changed) {
if (is_single_extruder_MM && m_extruders_count > 1 && is_high_flow_changed)
{
SuppressBackgroundProcessingUpdate sbpu;
const unsigned char new_hf = boost::any_cast<unsigned char>(value);
std::vector<unsigned char> nozzle_high_flow = static_cast<const ConfigOptionBools*>(m_config->option("nozzle_high_flow"))->values;
// if value was changed
if (nozzle_high_flow[extruder_idx == 0 ? 1 : 0] != new_hf)
{
const wxString msg_text = _L("This is a single extruder multimaterial printer, 'high_flow' state of all extruders "
"will be set to the new value. Do you want to proceed?");
MessageDialog dialog(parent(), msg_text, _L("High flow"), wxICON_WARNING | wxYES_NO);
DynamicPrintConfig new_conf = *m_config;
if (dialog.ShowModal() == wxID_YES) {
for (size_t i = 0; i < nozzle_high_flow.size(); i++) {
if (i==extruder_idx)
continue;
nozzle_high_flow[i] = new_hf;
}
}
else
nozzle_high_flow[extruder_idx] = nozzle_high_flow[extruder_idx == 0 ? 1 : 0];
new_conf.set_key_value("nozzle_high_flow", new ConfigOptionBools(nozzle_high_flow));
load_config(new_conf);
}
}
if (is_nozzle_diameter_changed || is_high_flow_changed) {
if (extruder_idx == 0)
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
@ -3195,6 +3229,8 @@ void TabPrinter::build_extruder_pages(size_t n_before_extruders)
update();
};
optgroup->append_single_option_line("nozzle_high_flow", "", extruder_idx);
optgroup = page->new_optgroup(L("Preview"));
auto reset_to_filament_color = [this, extruder_idx](wxWindow*parent) {

View File

@ -1,5 +1,6 @@
#include "UserAccount.hpp"
#include "UserAccountUtils.hpp"
#include "format.hpp"
#include "GUI.hpp"
@ -160,64 +161,7 @@ void UserAccount::on_communication_fail()
}
}
namespace {
std::string parse_tree_for_param(const pt::ptree& tree, const std::string& param)
{
for (const auto& section : tree) {
if (section.first == param) {
return section.second.data();
}
if (std::string res = parse_tree_for_param(section.second, param); !res.empty()) {
return res;
}
}
return {};
}
void parse_tree_for_param_vector(const pt::ptree& tree, const std::string& param, std::vector<std::string>& results)
{
for (const auto& section : tree) {
if (section.first == param) {
results.emplace_back(section.second.data());
} else {
parse_tree_for_param_vector(section.second, param, results);
}
}
}
pt::ptree parse_tree_for_subtree(const pt::ptree& tree, const std::string& param)
{
for (const auto& section : tree) {
if (section.first == param) {
return section.second;
}
else {
if (pt::ptree res = parse_tree_for_subtree(section.second, param); !res.empty())
return res;
}
}
return pt::ptree();
}
void fill_supported_printer_models_from_json_inner(const pt::ptree& ptree, std::vector<std::string>& result) {
std::string printer_model = parse_tree_for_param(ptree, "printer_model");
if (!printer_model.empty()) {
result.emplace_back(printer_model);
}
pt::ptree out = parse_tree_for_subtree(ptree, "supported_printer_models");
if (out.empty()) {
BOOST_LOG_TRIVIAL(error) << "Failed to find supported_printer_models in printer detail.";
return;
}
for (const auto& sub : out) {
if (printer_model != sub.second.data()) {
result.emplace_back(sub.second.data());
}
}
}
}
bool UserAccount::on_connect_printers_success(const std::string& data, AppConfig* app_config, bool& out_printers_changed)
{
@ -327,8 +271,8 @@ bool UserAccount::on_connect_uiid_map_success(const std::string& data, AppConfig
return on_connect_printers_success(data, app_config, out_printers_changed);
}
std::string UserAccount::get_current_printer_uuid_from_connect(const std::string& selected_printer_id) const
{
std::string UserAccount::get_current_printer_uuid_from_connect(const std::string &selected_printer_id
) const {
if (m_current_printer_data_json_from_connect.empty() || m_current_printer_uuid_from_connect.empty()) {
return {};
}
@ -343,12 +287,12 @@ std::string UserAccount::get_current_printer_uuid_from_connect(const std::string
return {};
}
std::string data_uuid = parse_tree_for_param(ptree, "uuid");
std::string data_uuid = UserAccountUtils::get_keyword_from_json(ptree, "", "uuid");
assert(data_uuid == m_current_printer_uuid_from_connect);
//std::string model_name = parse_tree_for_param(ptree, "printer_model");
std::vector<std::string> compatible_printers;
fill_supported_printer_models_from_json_inner(ptree, compatible_printers);
UserAccountUtils::fill_supported_printer_models_from_json(ptree, compatible_printers);
if (compatible_printers.empty()) {
return {};
}
@ -356,173 +300,4 @@ std::string UserAccount::get_current_printer_uuid_from_connect(const std::string
return std::find(compatible_printers.begin(), compatible_printers.end(), selected_printer_id) == compatible_printers.end() ? "" : m_current_printer_uuid_from_connect;
}
std::string UserAccount::get_nozzle_from_json(const std::string& message) const
{
std::string out;
try {
std::stringstream ss(message);
pt::ptree ptree;
pt::read_json(ss, ptree);
out = parse_tree_for_param(ptree, "nozzle_diameter");
//assert(!out.empty());
}
catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
}
// Get rid of trailing zeros.
// This is because somtimes we get "nozzle_diameter":0.40000000000000002
// This will return wrong result for f.e. 0.05. But we dont have such profiles right now.
if (size_t fist_dot = out.find('.'); fist_dot != std::string::npos) {
if (size_t first_zero = out.find('0', fist_dot); first_zero != std::string::npos) {
return out.substr(0, first_zero);
}
}
return out;
}
std::string UserAccount::get_keyword_from_json(const std::string& json, const std::string& keyword) const
{
std::string out;
try {
std::stringstream ss(json);
pt::ptree ptree;
pt::read_json(ss, ptree);
out = parse_tree_for_param(ptree, keyword);
//assert(!out.empty());
}
catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
}
return out;
}
std::string UserAccount::get_print_data_from_json(const std::string &json, const std::string &keyword) const
{
// copy subtree string f.e.
// { "<keyword>": {"param1": "something", "filename":"abcd.gcode", "param3":true}, "something_else" : 0 }
// into: {"param1": "something", "filename":"%1%", "param3":true, "size":%2%}
// yes there will be 2 placeholders for later format
// this will fail if not flat subtree
size_t start_of_keyword = json.find("\""+keyword+"\"");
if (start_of_keyword == std::string::npos)
return {};
size_t start_of_sub = json.find('{', start_of_keyword);
if (start_of_sub == std::string::npos)
return {};
size_t end_of_sub = json.find('}', start_of_sub);
if (end_of_sub == std::string::npos)
return {};
size_t start_of_filename = json.find("\"filename\"", start_of_sub);
if (start_of_filename == std::string::npos)
return {};
size_t filename_doubledot = json.find(':', start_of_filename);
if (filename_doubledot == std::string::npos)
return {};
size_t start_of_filename_data = json.find('\"', filename_doubledot);
if (start_of_filename_data == std::string::npos)
return {};
size_t end_of_filename_data = json.find('\"', start_of_filename_data + 1);
if (end_of_filename_data == std::string::npos)
return {};
size_t size = json.size();
std::string result = json.substr(start_of_sub, start_of_filename_data - start_of_sub + 1);
result += "%1%";
result += json.substr(end_of_filename_data, end_of_sub - end_of_filename_data);
result += ",\"size\":%2%}";
return result;
}
void UserAccount::fill_supported_printer_models_from_json(const std::string& json, std::vector<std::string>& result) const
{
try {
std::stringstream ss(json);
pt::ptree ptree;
pt::read_json(ss, ptree);
fill_supported_printer_models_from_json_inner(ptree, result);
}
catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
}
}
void UserAccount::fill_material_from_json(const std::string& json, std::vector<std::string>& result) const
{
/* option 1:
"slot": {
"active": 2,
"slots": {
"1": {
"material": "PLA",
"temp": 170,
"fan_hotend": 7689,
"fan_print": 0
},
"2": {
"material": "PLA",
"temp": 225,
"fan_hotend": 7798,
"fan_print": 6503
},
"3": {
"material": "PLA",
"temp": 36,
"fan_hotend": 6636,
"fan_print": 0
},
"4": {
"material": "PLA",
"temp": 35,
"fan_hotend": 0,
"fan_print": 0
},
"5": {
"material": "PETG",
"temp": 136,
"fan_hotend": 8132,
"fan_print": 0
}
}
}
*/
/* option 2
"filament": {
"material": "PLA",
"bed_temperature": 60,
"nozzle_temperature": 210
}
*/
// try finding "slot" subtree a use it to
// if not found, find "filament" subtree
try {
std::stringstream ss(json);
pt::ptree ptree;
pt::read_json(ss, ptree);
// find "slot" subtree
pt::ptree slot_subtree = parse_tree_for_subtree(ptree, "slot");
if (slot_subtree.empty()) {
// if not found, find "filament" subtree
pt::ptree filament_subtree = parse_tree_for_subtree(ptree, "filament");
if (!filament_subtree.empty()) {
std::string material = parse_tree_for_param(filament_subtree, "material");
if (!material.empty()) {
result.emplace_back(std::move(material));
}
}
return;
}
// search "slot" subtree for all "material"s
parse_tree_for_param_vector(slot_subtree, "material", result);
}
catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Could not parse prusaconnect message. " << e.what();
}
}
}} // namespace slic3r::GUI

View File

@ -67,13 +67,6 @@ public:
const ConnectPrinterStateMap& get_printer_state_map() const { return m_printer_map; }
boost::filesystem::path get_avatar_path(bool logged) const;
// standalone utility methods
std::string get_nozzle_from_json(const std::string& message) const;
std::string get_keyword_from_json(const std::string& json, const std::string& keyword) const;
std::string get_print_data_from_json(const std::string &json, const std::string &keyword) const;
void fill_supported_printer_models_from_json(const std::string& json, std::vector<std::string>& result) const;
void fill_material_from_json(const std::string& json, std::vector<std::string>& result) const;
const std::map<std::string, ConnectPrinterState>& get_printer_state_table() const { return printer_state_table; }
void set_current_printer_uuid_from_connect(const std::string& uuid) { m_current_printer_uuid_from_connect = uuid; }

View File

@ -0,0 +1,334 @@
#include "UserAccountUtils.hpp"
#include "format.hpp"
#include <boost/regex.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/log/trivial.hpp>
namespace pt = boost::property_tree;
namespace Slic3r { namespace GUI { namespace UserAccountUtils {
namespace {
std::string parse_tree_for_param(const pt::ptree& tree, const std::string& param) {
for (const auto &section : tree) {
if (section.first == param) {
return section.second.data();
}
if (std::string res = parse_tree_for_param(section.second, param); !res.empty()) {
return res;
}
}
return {};
}
void parse_tree_for_param_vector(
const pt::ptree &tree, const std::string& param, std::vector<std::string>& results) {
for (const auto &section : tree) {
if (section.first == param) {
results.emplace_back(section.second.data());
} else {
parse_tree_for_param_vector(section.second, param, results);
}
}
}
pt::ptree parse_tree_for_subtree(const pt::ptree& tree, const std::string& param) {
for (const auto &section : tree) {
if (section.first == param) {
return section.second;
} else {
if (pt::ptree res = parse_tree_for_subtree(section.second, param); !res.empty())
return res;
}
}
return pt::ptree();
}
void json_to_ptree(boost::property_tree::ptree& ptree, const std::string& json) {
try {
std::stringstream ss(json);
pt::read_json(ss, ptree);
} catch (const std::exception &e) {
BOOST_LOG_TRIVIAL(error) << "Failed to parse json to ptree. " << e.what();
BOOST_LOG_TRIVIAL(error) << "json: " << json;
}
}
} // namespace
std::string get_nozzle_from_json(boost::property_tree::ptree& ptree) {
assert(!ptree.empty());
std::string out = parse_tree_for_param(ptree, "nozzle_diameter");
// Get rid of trailing zeros.
// This is because somtimes we get "nozzle_diameter":0.40000000000000002
// This will return wrong result for f.e. 0.05. But we dont have such profiles right now.
if (size_t fist_dot = out.find('.'); fist_dot != std::string::npos) {
if (size_t first_zero = out.find('0', fist_dot); first_zero != std::string::npos) {
return out.substr(0, first_zero);
}
}
return out;
}
std::string get_keyword_from_json(boost::property_tree::ptree& ptree, const std::string& json, const std::string& keyword )
{
if (ptree.empty()) {
json_to_ptree(ptree, json);
}
assert(!ptree.empty());
return parse_tree_for_param(ptree, keyword);
}
void fill_supported_printer_models_from_json(boost::property_tree::ptree& ptree, std::vector<std::string>& result)
{
assert(!ptree.empty());
std::string printer_model = parse_tree_for_param(ptree, "printer_model");
if (!printer_model.empty()) {
result.emplace_back(printer_model);
}
pt::ptree out = parse_tree_for_subtree(ptree, "supported_printer_models");
if (out.empty()) {
BOOST_LOG_TRIVIAL(error) << "Failed to find supported_printer_models in printer detail.";
return;
}
for (const auto &sub : out) {
if (printer_model != sub.second.data()) {
result.emplace_back(sub.second.data());
}
}
}
namespace {
std::string json_var_to_opt_string(const std::string& json_var)
{
if (json_var == "true")
return "1";
if (json_var == "false")
return "0";
return json_var;
}
void fill_config_options_from_json_inner(boost::property_tree::ptree& ptree, std::map<std::string, std::vector<std::string>>& result, const std::map<std::string, std::string>& parameters)
{
pt::ptree slots = parse_tree_for_subtree(parse_tree_for_subtree(ptree, "slot"), "slots");
for (const auto &subtree : slots) {
size_t slot_id;
try {
slot_id = boost::lexical_cast<size_t>(subtree.first);
} catch (const boost::bad_lexical_cast&) {
continue;
}
for (const auto &item : subtree.second) {
if (parameters.find(item.first) == parameters.end()) {
continue;
}
std::string config_name = parameters.at(item.first);
// resolve value
std::string val;
if (item.second.size() > 0) {
for (const auto &subitem : item.second) {
if (!val.empty()) {
val += ",";
}
val += json_var_to_opt_string(subitem.second.data());
}
} else {
val = json_var_to_opt_string(item.second.data());
}
// insert value
while (result[config_name].size() < slot_id)
result[config_name].emplace_back();
result[config_name][slot_id - 1] = val;
}
}
}
}
void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map<std::string, std::vector<std::string>>& result)
{
assert(!ptree.empty());
/*
"slot": {
"active": 3,
"slots": {
"1": {
"material": "PETG",
"temp": 32.0,
"fan_hotend": 0.0,
"fan_print": 0.0,
"nozzle_diameter": 3.2, // float
"high_flow": true, // boolean
"high_temperature": false, // boolean
"hardened": true, // boolean
},
"3": {
"material": "ASA",
"temp": 35.0,
"fan_hotend": 0.0,
"fan_print": 0.0,
"nozzle_diameter": 3.2, // float
"high_flow": true, // boolean
"high_temperature": false, // boolean
"hardened": true, // boolean
},
}
}
*/
const std::map<std::string, std::string> parameters = {
// first name from connect, second config option
{"nozzle_diameter","nozzle_diameter"},
{"high_flow","nozzle_high_flow"},
//{"",""}
};
fill_config_options_from_json_inner(ptree, result, parameters);
}
void fill_material_from_json(const std::string& json, std::vector<std::string>& material_result, std::vector<bool>& avoid_abrasive_result)
{
pt::ptree ptree;
json_to_ptree(ptree, json);
assert(!ptree.empty());
/* option 1:
"slot": {
"active": 2,
"slots": {
"1": {
"material": "PLA",
"temp": 170,
"fan_hotend": 7689,
"fan_print": 0
},
"2": {
"material": "PLA",
"temp": 225,
"fan_hotend": 7798,
"fan_print": 6503
},
"3": {
"material": "PLA",
"temp": 36,
"fan_hotend": 6636,
"fan_print": 0
},
"4": {
"material": "PLA",
"temp": 35,
"fan_hotend": 0,
"fan_print": 0
},
"5": {
"material": "PETG",
"temp": 136,
"fan_hotend": 8132,
"fan_print": 0
}
}
}
*/
/* option 2
"filament": {
"material": "PLA",
"bed_temperature": 60,
"nozzle_temperature": 210
}
*/
// try finding "slot" subtree a use it to
// if not found, find "filament" subtree
// find "slot" subtree
pt::ptree slot_subtree = parse_tree_for_subtree(ptree, "slot");
if (slot_subtree.empty()) {
// if not found, find "filament" subtree
pt::ptree filament_subtree = parse_tree_for_subtree(ptree, "filament");
if (!filament_subtree.empty()) {
std::string material = parse_tree_for_param(filament_subtree, "material");
if (!material.empty()) {
material_result.emplace_back(std::move(material));
avoid_abrasive_result.emplace_back(true);
}
}
return;
}
// search "slot" subtree for all "material"s
// this parses "slots" with respect to numbers of slots and adds empty string to missing numbers
// if only filled should be used. Use: parse_tree_for_param_vector(slot_subtree, "material", result);
/*
pt::ptree slots = parse_tree_for_subtree(slot_subtree, "slots");
assert(!slots.empty());
for (const auto &subtree : slots) {
size_t slot_id;
try {
slot_id = boost::lexical_cast<size_t>(subtree.first);
} catch (const boost::bad_lexical_cast&) {
continue;
}
std::string val = parse_tree_for_param(subtree.second, "material");
// add empty for missing id
while (result.size() < slot_id)
result.emplace_back();
result[slot_id - 1] = val;
}
*/
const std::map<std::string, std::string> parameters = {
// first name from connect, second config option
{"material","material"},
{"hardened","hardened"},
//{"",""}
};
std::map<std::string, std::vector<std::string>> result_map;
fill_config_options_from_json_inner(ptree, result_map, parameters);
if (result_map.find("material") != result_map.end()) {
for (const std::string& val : result_map["material"]) {
material_result.emplace_back(val);
}
}
if (result_map.find("hardened") != result_map.end()) {
for (const std::string& val : result_map["hardened"]) {
avoid_abrasive_result.emplace_back(val == "0" ? 1 : 0);
}
}
}
std::string get_print_data_from_json(const std::string& json, const std::string& keyword) {
// copy subtree string f.e.
// { "<keyword>": {"param1": "something", "filename":"abcd.gcode", "param3":true},
// "something_else" : 0 } into: {"param1": "something", "filename":"%1%", "param3":true,
// "size":%2%} yes there will be 2 placeholders for later format
// this will fail if not flat subtree
size_t start_of_keyword = json.find("\"" + keyword + "\"");
if (start_of_keyword == std::string::npos)
return {};
size_t start_of_sub = json.find('{', start_of_keyword);
if (start_of_sub == std::string::npos)
return {};
size_t start_of_filename = json.find("\"filename\"", start_of_sub);
if (start_of_filename == std::string::npos)
return {};
size_t filename_doubledot = json.find(':', start_of_filename);
if (filename_doubledot == std::string::npos)
return {};
size_t start_of_filename_data = json.find('\"', filename_doubledot);
if (start_of_filename_data == std::string::npos)
return {};
size_t end_of_filename_data = json.find('\"', start_of_filename_data + 1);
if (end_of_filename_data == std::string::npos)
return {};
size_t end_of_sub = json.find('}', end_of_filename_data);
if (end_of_sub == std::string::npos)
return {};
size_t size = json.size();
std::string result = json.substr(start_of_sub, start_of_filename_data - start_of_sub + 1);
result += "%1%";
result += json.substr(end_of_filename_data, end_of_sub - end_of_filename_data);
result += ",\"size\":%2%}";
return result;
}
}}} // Slic3r::GUI::UserAccountUtils

View File

@ -0,0 +1,27 @@
#ifndef slic3r_UserAccountUtils_hpp_
#define slic3r_UserAccountUtils_hpp_
#include <string>
#include <vector>
#include <boost/property_tree/ptree.hpp>
namespace Slic3r { namespace GUI {
namespace UserAccountUtils {
// If ptree parameter is empty, json parameter needs to contain data and ptree is filled.
// If ptree is non-epty, json parameter is not used.
std::string get_keyword_from_json(boost::property_tree::ptree& ptree, const std::string& json, const std::string& keyword);
// Only ptree is passed since these functions are called on places that already has the ptree from get_keyword_from_json call
std::string get_nozzle_from_json(boost::property_tree::ptree &ptree);
void fill_supported_printer_models_from_json(boost::property_tree::ptree& ptree, std::vector<std::string>& result);
void fill_config_options_from_json(boost::property_tree::ptree& ptree, std::map<std::string,std::vector<std::string>>& result);
// Since fill_material_from_json is called only from one place where ptree doesnt need to be shared, it is not always read from json.
void fill_material_from_json(const std::string& json, std::vector<std::string>& material_result, std::vector<bool>& avoid_abrasive_result);
std::string get_print_data_from_json(const std::string &json, const std::string &keyword);
}}} // Slic3r::GUI::UserAccountUtils
#endif // slic3r_UserAccountUtils_hpp_

View File

@ -1274,32 +1274,52 @@ void PrinterPickWebViewDialog::on_connect_action_webapp_ready(const std::string&
}
}
void PrinterPickWebViewDialog::request_compatible_printers_FFF()
{
//PrinterParams: {
//material: Material;
//nozzleDiameter: number;
//printerType: string;
//filename: string;
//}
const Preset& selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset();
const Preset& selected_filament = wxGetApp().preset_bundle->filaments.get_selected_preset();
double nozzle_diameter = static_cast<const ConfigOptionFloats*>(selected_printer.config.option("nozzle_diameter"))->values[0];
void PrinterPickWebViewDialog::request_compatible_printers_FFF() {
// PrinterParams: {
// material: Material;
// nozzleDiameter: number;
// printerType: string;
// filename: string;
// }
const Preset &selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset();
const DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config();
double nozzle_diameter = static_cast<const ConfigOptionFloats *>(full_config.option("nozzle_diameter"))->values[0];
wxString nozzle_diameter_serialized = double_to_string(nozzle_diameter);
nozzle_diameter_serialized.Replace(L",", L".");
// Sending only first filament type for now. This should change to array of values
const std::string filament_type_serialized = selected_filament.config.option("filament_type")->serialize();
const std::string printer_model_serialized = selected_printer.config.option("printer_model")->serialize();
const std::string filament_type_serialized = full_config.option("filament_type")->serialize();
const std::string nozzle_high_flow_serialized = static_cast<const ConfigOptionBools *>(full_config.option("nozzle_high_flow"))->values[0] ? "1" : "0";
const std::string filament_abrasive_serialized = static_cast<const ConfigOptionBools *>(full_config.option("filament_abrasive"))->values[0] ? "1" : "0";
std::string printer_model_serialized = full_config.option("printer_model")->serialize();
std::string vendor_repo_prefix;
if (selected_printer.vendor) {
vendor_repo_prefix = selected_printer.vendor->repo_prefix;
} else if (std::string inherits = selected_printer.inherits(); !inherits.empty()) {
const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits);
if (parent && parent->vendor) {
vendor_repo_prefix = parent->vendor->repo_prefix;
}
}
if (printer_model_serialized.find(vendor_repo_prefix) == 0) {
printer_model_serialized = printer_model_serialized.substr(vendor_repo_prefix.size());
boost::trim_left(printer_model_serialized);
}
const std::string uuid = wxGetApp().plater()->get_user_account()->get_current_printer_uuid_from_connect(printer_model_serialized);
const std::string filename = wxGetApp().plater()->get_upload_filename();
const std::string request = GUI::format(
//filament_abrasive
std::string request = GUI::format(
"{"
"\"printerUuid\": \"%4%\", "
"\"printerModel\": \"%3%\", "
"\"nozzleDiameter\": %2%, "
"\"nozzle_diameter\": %2%, "
"\"material\": \"%1%\", "
"\"filename\": \"%5%\" "
"}", filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized, uuid, filename);
"\"filename\": \"%5%\", "
"\"filament_abrasive\": \"%6%\","
"\"nozzle_high_flow\": \"%7%\""
"}"
, filament_type_serialized, nozzle_diameter_serialized, printer_model_serialized, uuid, filename, nozzle_high_flow_serialized, filament_abrasive_serialized);
wxString script = GUI::format_wxstr("window._prusaConnect_v1.requestCompatiblePrinter(%1%)", request);
run_script(script);
@ -1307,7 +1327,21 @@ void PrinterPickWebViewDialog::request_compatible_printers_FFF()
void PrinterPickWebViewDialog::request_compatible_printers_SLA()
{
const Preset& selected_printer = wxGetApp().preset_bundle->printers.get_selected_preset();
const std::string printer_model_serialized = selected_printer.config.option("printer_model")->serialize();
std::string printer_model_serialized = selected_printer.config.option("printer_model")->serialize();
std::string vendor_repo_prefix;
if (selected_printer.vendor) {
vendor_repo_prefix = selected_printer.vendor->repo_prefix;
} else if (std::string inherits = selected_printer.inherits(); !inherits.empty()) {
const Preset *parent = wxGetApp().preset_bundle->printers.find_preset(inherits);
if (parent && parent->vendor) {
vendor_repo_prefix = parent->vendor->repo_prefix;
}
}
if (printer_model_serialized.find(vendor_repo_prefix) == 0) {
printer_model_serialized = printer_model_serialized.substr(vendor_repo_prefix.size());
boost::trim_left(printer_model_serialized);
}
const Preset& selected_material = wxGetApp().preset_bundle->sla_materials.get_selected_preset();
const std::string material_type_serialized = selected_material.config.option("material_type")->serialize();
const std::string uuid = wxGetApp().plater()->get_user_account()->get_current_printer_uuid_from_connect(printer_model_serialized);