From 34b354810208fe39d8a8a0e244b5a77d81f35578 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 12 Apr 2019 16:18:46 +0200 Subject: [PATCH 01/23] Filaments and materials selection/installation --- resources/profiles/PrusaResearch.ini | 95 +++++++ src/libslic3r/PrintConfig.cpp | 8 + src/slic3r/GUI/AppConfig.hpp | 6 + src/slic3r/GUI/ConfigWizard.cpp | 362 ++++++++++++++++++++++-- src/slic3r/GUI/ConfigWizard_private.hpp | 139 +++++++-- src/slic3r/GUI/Preset.cpp | 43 ++- src/slic3r/GUI/Preset.hpp | 5 + src/slic3r/GUI/PresetBundle.cpp | 8 + 8 files changed, 608 insertions(+), 58 deletions(-) diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 406fd93c80..6904713346 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -82,6 +82,29 @@ variants = default technology = SLA family = SL1 +[default_filaments] +Generic PLA = 1 +Generic PLA MMU2 = 1 +Prusa PLA = 1 +Prusa PLA MMU2 = 1 +Prusament PLA = 1 +Prusament PLA MMU2 = 1 + +[default_sla_materials] +Prusa Azure Blue Tough 0.05 = 1 +Prusa Black Tough 0.05 = 1 +Prusa Green Casting 0.05 = 1 +Prusa Grey Tough 0.05 = 1 +Prusa Maroon Tough 0.05 = 1 +Prusa Orange Tough 0.025 = 1 +Prusa Orange Tough 0.035 = 1 +Prusa Orange Tough 0.05 = 1 +Prusa Orange Tough 0.1 = 1 +Prusa Pink Tough 0.05 = 1 +Prusa Skin Tough 0.05 = 1 +Prusa Transparent Red Tough 0.05 = 1 +Prusa White Tough 0.05 = 1 + # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. @@ -1128,6 +1151,7 @@ filament_density = 3.9 filament_colour = #804040 filament_max_volumetric_speed = 9 filament_notes = "List of materials tested with standard print settings:\n\nColorFabb bronzeFill\nColorFabb brassFill\nColorFabb steelFill\nColorFabb copperFill" +filament_vendor = ColorFabb [filament:ColorFabb HT] inherits = *PET* @@ -1145,11 +1169,13 @@ max_fan_speed = 20 min_fan_speed = 10 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" temperature = 270 +filament_vendor = ColorFabb [filament:ColorFabb PLA-PHA] inherits = *PLA* filament_cost = 55.5 filament_density = 1.24 +filament_vendor = ColorFabb [filament:ColorFabb woodFill] inherits = *PLA* @@ -1163,6 +1189,7 @@ filament_max_volumetric_speed = 10 first_layer_temperature = 200 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 200 +filament_vendor = ColorFabb [filament:ColorFabb corkFill] inherits = *PLA* @@ -1175,6 +1202,7 @@ filament_max_volumetric_speed = 6 first_layer_temperature = 220 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 220 +filament_vendor = ColorFabb [filament:ColorFabb XT] inherits = *PET* @@ -1184,6 +1212,7 @@ filament_density = 1.27 first_layer_bed_temperature = 90 first_layer_temperature = 260 temperature = 270 +filament_vendor = ColorFabb [filament:ColorFabb XT-CF20] inherits = *PET* @@ -1199,6 +1228,7 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{el temperature = 260 filament_retract_length = nil filament_retract_lift = 0.2 +filament_vendor = ColorFabb [filament:ColorFabb nGen] inherits = *PET* @@ -1211,6 +1241,7 @@ filament_type = NGEN first_layer_temperature = 240 max_fan_speed = 35 min_fan_speed = 20 +filament_vendor = ColorFabb [filament:ColorFabb nGen flex] inherits = *FLEX* @@ -1231,12 +1262,14 @@ temperature = 260 filament_retract_length = nil filament_retract_lift = 0 compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material) +filament_vendor = ColorFabb [filament:E3D Edge] inherits = *PET* filament_cost = 56.9 filament_density = 1.26 filament_type = EDGE +filament_vendor = E3D [filament:E3D PC-ABS] inherits = *ABS* @@ -1245,6 +1278,7 @@ filament_type = PC filament_density = 1.05 first_layer_temperature = 270 temperature = 270 +filament_vendor = E3D [filament:Fillamentum ABS] inherits = *ABS* @@ -1252,6 +1286,7 @@ filament_cost = 32.4 filament_density = 1.04 first_layer_temperature = 240 temperature = 240 +filament_vendor = Fillamentum [filament:Fillamentum ASA] inherits = *ABS* @@ -1266,6 +1301,7 @@ slowdown_below_layer_time = 15 first_layer_temperature = 265 temperature = 265 filament_type = ASA +filament_vendor = Fillamentum [filament:Prusament ASA] inherits = *ABS* @@ -1296,6 +1332,7 @@ first_layer_temperature = 275 max_fan_speed = 50 min_fan_speed = 50 temperature = 275 +filament_vendor = Fillamentum [filament:Fillamentum Timberfill] inherits = *PLA* @@ -1309,24 +1346,28 @@ filament_max_volumetric_speed = 10 first_layer_temperature = 190 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 190 +filament_vendor = Fillamentum [filament:Generic ABS] inherits = *ABS* filament_cost = 27.82 filament_density = 1.04 filament_notes = "List of materials tested with standard ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS" +filament_vendor = Generic [filament:Generic PET] inherits = *PET* filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG" +filament_vendor = Generic [filament:Generic PLA] inherits = *PLA* filament_cost = 25.4 filament_density = 1.24 filament_notes = "List of materials tested with standard PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +filament_vendor = Generic [filament:Generic FLEX] inherits = *FLEX* @@ -1347,6 +1388,7 @@ filament_colour = #3A80CA first_layer_bed_temperature = 100 first_layer_temperature = 270 temperature = 270 +filament_vendor = Polymaker [filament:PrimaSelect PVA+] inherits = *PLA* @@ -1363,12 +1405,14 @@ filament_type = PVA first_layer_temperature = 195 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 195 +filament_vendor = PrimaSelect [filament:Prusa ABS] inherits = *ABS* filament_cost = 27.82 filament_density = 1.08 filament_notes = "List of materials tested with standard ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS" +filament_vendor = Prusa [filament:*ABS MMU2*] inherits = Prusa ABS @@ -1385,6 +1429,7 @@ filament_unloading_speed = 20 [filament:Generic ABS MMU2] inherits = *ABS MMU2* +filament_vendor = Generic [filament:Prusament ASA MMU2] inherits = *ABS MMU2* @@ -1410,6 +1455,7 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{el [filament:Prusa ABS MMU2] inherits = *ABS MMU2* +filament_vendor = Prusa [filament:Prusa HIPS] inherits = *ABS* @@ -1428,6 +1474,7 @@ max_fan_speed = 20 min_fan_speed = 20 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 220 +filament_vendor = Prusa [filament:Prusa PET] inherits = *PET* @@ -1435,6 +1482,7 @@ filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nPlasty Mladec PETG" compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +filament_vendor = Prusa [filament:Prusament PETG] inherits = *PET* @@ -1444,12 +1492,14 @@ filament_cost = 24.99 filament_density = 1.27 filament_type = PETG compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +filament_vendor = Prusa [filament:Prusa PET 0.6 nozzle] inherits = *PET06* filament_cost = 27.82 filament_density = 1.27 filament_notes = "List of manufacturers tested with standard PET print settings:\n\nE3D Edge\nPlasty Mladec PETG" +filament_vendor = Prusa [filament:Prusament PETG 0.6 nozzle] inherits = *PET06* @@ -1458,6 +1508,7 @@ temperature = 250 filament_cost = 24.99 filament_density = 1.27 filament_type = PETG +filament_vendor = Prusa [filament:*PET MMU2*] inherits = Prusa PET @@ -1485,9 +1536,11 @@ filament_max_volumetric_speed = 13 [filament:Generic PET MMU2] inherits = *PET MMU2* +filament_vendor = Generic [filament:Prusa PET MMU2] inherits = *PET MMU2* +filament_vendor = Prusa [filament:Prusament PETG MMU2] inherits = *PET MMU2* @@ -1498,16 +1551,19 @@ inherits = *PET MMU2 06* [filament:Prusa PET MMU2 0.6 nozzle] inherits = *PET MMU2 06* +filament_vendor = Prusa [filament:Prusament PETG MMU2 0.6 nozzle] inherits = *PET MMU2 06* filament_type = PETG +filament_vendor = Prusa [filament:Prusa PLA] inherits = *PLA* filament_cost = 25.4 filament_density = 1.24 filament_notes = "List of materials tested with standard PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFiberlogy PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nAmazonBasics PLA" +filament_vendor = Prusa [filament:Prusament PLA] inherits = *PLA* @@ -1515,6 +1571,7 @@ temperature = 215 filament_cost = 24.99 filament_density = 1.24 filament_notes = "Affordable filament for everyday printing in premium quality manufactured in-house by Josef Prusa" +filament_vendor = Prusa [filament:*PLA MMU2*] inherits = Prusa PLA @@ -1534,18 +1591,22 @@ filament_unloading_speed_start = 100 [filament:Generic PLA MMU2] inherits = *PLA MMU2* +filament_vendor = Generic [filament:Prusa PLA MMU2] inherits = *PLA MMU2* +filament_vendor = Prusa [filament:Prusament PLA MMU2] inherits = *PLA MMU2* +filament_vendor = Prusa [filament:SemiFlex or Flexfill 98A] inherits = *FLEX* filament_cost = 82 filament_density = 1.22 filament_max_volumetric_speed = 1.35 +filament_vendor = Flexfill [filament:Taulman Bridge] inherits = *common* @@ -1567,6 +1628,7 @@ max_fan_speed = 5 min_fan_speed = 0 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 250 +filament_vendor = Taulman [filament:Taulman T-Glase] inherits = *PET* @@ -1580,6 +1642,7 @@ first_layer_temperature = 240 max_fan_speed = 5 min_fan_speed = 0 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +filament_vendor = Taulman [filament:Verbatim BVOH] inherits = *common* @@ -1603,6 +1666,7 @@ max_fan_speed = 100 min_fan_speed = 100 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 210 +filament_vendor = Verbatim [filament:Verbatim BVOH MMU2] inherits = Verbatim BVOH @@ -1622,6 +1686,7 @@ filament_unload_time = 12 filament_unloading_speed = 20 filament_unloading_speed_start = 100 filament_loading_speed_start = 19 +filament_vendor = Verbatim [filament:PrimaSelect PVA+ MMU2] inherits = *common* @@ -1660,6 +1725,7 @@ min_print_speed = 15 slowdown_below_layer_time = 20 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" temperature = 195 +filament_vendor = PrimaSelect [filament:Verbatim PP] inherits = *common* @@ -1682,6 +1748,7 @@ max_fan_speed = 100 min_fan_speed = 100 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 220 +filament_vendor = Verbatim ## Filaments MMU1 @@ -1902,6 +1969,7 @@ initial_exposure_time = 40 inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 45 +material_vendor = Bluecast [sla_material:BlueCast X10 0.025] inherits = *common 0.025* @@ -1912,6 +1980,7 @@ initial_exposure_time = 100 inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 35 +material_vendor = Prusa [sla_material:Prusa Grey Tough 0.025] inherits = *common 0.025* @@ -1964,31 +2033,37 @@ initial_exposure_time = 35 inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 35 +material_vendor = Bluecast [sla_material:BlueCast Keramaster 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 45 +material_vendor = Bluecast [sla_material:BlueCast Keramaster Dental 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 50 +material_vendor = Bluecast [sla_material:BlueCast LCD-DLP Original 0.05] inherits = *common 0.05* exposure_time = 10 initial_exposure_time = 60 +material_vendor = Bluecast [sla_material:BlueCast Phrozen Wax 0.05] inherits = *common 0.05* exposure_time = 16 initial_exposure_time = 50 +material_vendor = Bluecast [sla_material:BlueCast S+ 0.05] inherits = *common 0.05* exposure_time = 9 initial_exposure_time = 45 +material_vendor = Bluecast [sla_material:BlueCast X10 0.05] inherits = *common 0.05* @@ -1999,26 +2074,31 @@ initial_exposure_time = 100 inherits = *common 0.05* exposure_time = 6 initial_exposure_time = 40 +material_vendor = Monocure [sla_material:Monocure 3D Blue Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 40 +material_vendor = Monocure [sla_material:Monocure 3D Clear Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 40 +material_vendor = Monocure [sla_material:Monocure 3D Grey Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 10 initial_exposure_time = 30 +material_vendor = Monocure [sla_material:Monocure 3D White Rapid Resin 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 40 +material_vendor = Monocure [sla_material:3DM-HTR140 (high temperature) 0.05] inherits = *common 0.05* @@ -2034,36 +2114,43 @@ initial_exposure_time = 25 inherits = *common 0.05* exposure_time = 20 initial_exposure_time = 40 +material_vendor = 3DM [sla_material:3DM-DENT 0.05] inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 45 +material_vendor = 3DM [sla_material:3DM-HR Green 0.05] inherits = *common 0.05* exposure_time = 15 initial_exposure_time = 40 +material_vendor = 3DM [sla_material:3DM-HR Red Wine 0.05] inherits = *common 0.05* exposure_time = 9 initial_exposure_time = 35 +material_vendor = 3DM [sla_material:3DM-XPRO White 0.05] inherits = *common 0.05* exposure_time = 9 initial_exposure_time = 35 +material_vendor = 3DM [sla_material:FTD Ash Grey 0.05] inherits = *common 0.05* exposure_time = 9 initial_exposure_time = 40 +material_vendor = FTD [sla_material:Harz Labs Model Resin Cherry 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 45 +material_vendor = Harz Labs [sla_material:Photocentric Hard Grey 0.05] inherits = *common 0.05* @@ -2116,6 +2203,7 @@ initial_exposure_time = 35 inherits = *common 0.05* exposure_time = 13 initial_exposure_time = 40 +material_vendor = Prusa ## [sla_material:Prusa Yellow Solid 0.05] ## inherits = *common 0.05* @@ -2126,6 +2214,7 @@ initial_exposure_time = 40 inherits = *common 0.05* exposure_time = 7.5 initial_exposure_time = 35 +material_vendor = Prusa ## [sla_material:Prusa Transparent Green Tough 0.05] ## inherits = *common 0.05* @@ -2136,21 +2225,25 @@ initial_exposure_time = 35 inherits = *common 0.05* exposure_time = 6 initial_exposure_time = 35 +material_vendor = Prusa [sla_material:Prusa Maroon Tough 0.05] inherits = *common 0.05* exposure_time = 7.5 initial_exposure_time = 35 +material_vendor = Prusa [sla_material:Prusa Pink Tough 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 35 +material_vendor = Prusa [sla_material:Prusa Azure Blue Tough 0.05] inherits = *common 0.05* exposure_time = 8 initial_exposure_time = 35 +material_vendor = Prusa [sla_material:Prusa Transparent Tough 0.05] inherits = *common 0.05* @@ -2193,6 +2286,7 @@ initial_exposure_time = 15 inherits = *common 0.035* exposure_time = 6 initial_exposure_time = 35 +material_vendor = Prusa ########### Materials 0.1 @@ -2235,6 +2329,7 @@ initial_exposure_time = 55 inherits = *common 0.1* exposure_time = 8 initial_exposure_time = 35 +material_vendor = Prusa [sla_material:Prusa Green Casting 0.1] inherits = *common 0.1* diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1ce00f269d..ac30941cb1 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -749,6 +749,10 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionStrings { "" }); def->cli = ConfigOptionDef::nocli; + def = this->add("filament_vendor", coString); + def->set_default_value(new ConfigOptionString(L("(Unknown)"))); + def->cli = ConfigOptionDef::nocli; + def = this->add("fill_angle", coFloat); def->label = L("Fill angle"); def->category = L("Infill"); @@ -2474,6 +2478,10 @@ void PrintConfigDef::init_sla_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("")); + def = this->add("material_vendor", coString); + def->set_default_value(new ConfigOptionString(L("(Unknown)"))); + def->cli = ConfigOptionDef::nocli; + def = this->add("default_sla_material_profile", coString); def->label = L("Default SLA material profile"); def->tooltip = L("Default print profile associated with the current printer profile. " diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp index 8ad17b9db8..fe30c0af69 100644 --- a/src/slic3r/GUI/AppConfig.hpp +++ b/src/slic3r/GUI/AppConfig.hpp @@ -80,6 +80,12 @@ public: } } + bool has_section(const std::string §ion) const + { return m_storage.find(section) != m_storage.end(); } + const std::map& get_section(const std::string §ion) const + { return m_storage.find(section)->second; } + void set_section(const std::string §ion, const std::map& data) + { m_storage[section] = data; } void clear_section(const std::string §ion) { m_storage[section].clear(); } diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 0115ff5f9c..0d35ce1afc 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1,3 +1,5 @@ +// FIXME: extract absolute units -> em + #include "ConfigWizard_private.hpp" #include @@ -19,6 +21,7 @@ #include #include #include +#include #include #include "libslic3r/Utils.hpp" @@ -62,7 +65,7 @@ struct PrinterPickerEvent : public wxEvent wxDEFINE_EVENT(EVT_PRINTER_PICK, PrinterPickerEvent); -PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig_vendors, const ModelFilter &filter) +PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig, const ModelFilter &filter) : wxPanel(parent) , vendor_id(vendor.id) , width(0) @@ -132,7 +135,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt auto *cbox = new Checkbox(variants_panel, label, model_id, variant.name); i == 0 ? cboxes.push_back(cbox) : cboxes_alt.push_back(cbox); - bool enabled = appconfig_vendors.get_variant("PrusaResearch", model_id, variant.name); + bool enabled = appconfig.get_variant("PrusaResearch", model_id, variant.name); cbox->SetValue(enabled); variants_sizer->Add(cbox, 0, wxBOTTOM, 3); @@ -210,8 +213,8 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt SetSizer(sizer); } -PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig_vendors) - : PrinterPicker(parent, vendor, std::move(title), max_cols, appconfig_vendors, [](const VendorProfile::PrinterModel&) { return true; }) +PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig) + : PrinterPicker(parent, vendor, std::move(title), max_cols, appconfig, [](const VendorProfile::PrinterModel&) { return true; }) {} void PrinterPicker::select_all(bool select, bool alternates) @@ -241,6 +244,19 @@ void PrinterPicker::select_one(size_t i, bool select) } } +bool PrinterPicker::any_selected() const +{ + for (const auto &cb : cboxes) { + if (cb->GetValue()) { return true; } + } + + for (const auto &cb : cboxes_alt) { + if (cb->GetValue()) { return true; } + } + + return false; +} + void PrinterPicker::on_checkbox(const Checkbox *cbox, bool checked) { PrinterPickerEvent evt(EVT_PRINTER_PICK, GetId(), vendor_id, cbox->model, cbox->variant, checked); @@ -289,6 +305,7 @@ void ConfigWizardPage::append_text(wxString text) void ConfigWizardPage::append_spacer(int space) { + // FIXME: scaling content->AddSpacer(space); } @@ -330,7 +347,7 @@ PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortn bool check_first_variant = technology == T_FFF && wizard_p()->check_first_variant(); - AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors; + AppConfig &appconfig = this->wizard_p()->appconfig_new; const auto families = vendor.families(); for (const auto &family : families) { @@ -345,7 +362,7 @@ PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortn } const auto picker_title = family.empty() ? wxString() : wxString::Format(_(L("%s Family")), family); - auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, appconfig_vendors, filter); + auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, appconfig, filter); if (check_first_variant) { // Select the default (first) model/variant on the Prusa vendor @@ -353,8 +370,9 @@ PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortn check_first_variant = false; } - picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) { - appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); + picker->Bind(EVT_PRINTER_PICK, [this, &appconfig](const PrinterPickerEvent &evt) { + appconfig.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); + wizard_p()->on_printer_pick(this); }); append(new wxStaticLine(this)); @@ -377,6 +395,159 @@ int PagePrinters::get_width() const [](int acc, const PrinterPicker *picker) { return std::max(acc, picker->get_width()); }); } +bool PagePrinters::any_selected() const +{ + for (const auto *picker : printer_pickers) { + if (picker->any_selected()) { return true; } + } + + return false; +} + + +const std::string PageMaterials::EMPTY; + +PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name) + : ConfigWizardPage(parent, std::move(title), std::move(shortname)) + , materials(materials) + , list_l1(new StringList(this)) + , list_l2(new StringList(this)) + , list_l3(new PresetList(this)) + , sel1_prev(wxNOT_FOUND) + , sel2_prev(wxNOT_FOUND) +{ + append_spacer(VERTICAL_SPACING); + + const int em = parent->em_unit(); + const int list_h = 30*em; + + list_l1->SetMinSize(wxSize(8*em, list_h)); + list_l2->SetMinSize(wxSize(13*em, list_h)); + list_l3->SetMinSize(wxSize(25*em, list_h)); + + auto *grid = new wxFlexGridSizer(3, 0, em); + + grid->Add(new wxStaticText(this, wxID_ANY, list1name)); + grid->Add(new wxStaticText(this, wxID_ANY, _(L("Vendor:")))); + grid->Add(new wxStaticText(this, wxID_ANY, _(L("Profile:")))); + + grid->Add(list_l1); + grid->Add(list_l2); + grid->Add(list_l3); + + auto *btn_sizer = new wxBoxSizer(wxHORIZONTAL); + auto *sel_all = new wxButton(this, wxID_ANY, _(L("All"))); + auto *sel_none = new wxButton(this, wxID_ANY, _(L("None"))); + btn_sizer->Add(sel_all, 0, wxRIGHT, em / 2); + btn_sizer->Add(sel_none); + + grid->Add(new wxBoxSizer(wxHORIZONTAL)); + grid->Add(new wxBoxSizer(wxHORIZONTAL)); + grid->Add(btn_sizer, 0, wxALIGN_RIGHT); + + append(grid); + + list_l1->append(_(L("(All)")), &EMPTY); + + for (const std::string &type : materials->types) { + list_l1->append(type, &type); + } + + list_l1->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) { + update_lists(list_l1->GetSelection(), list_l2->GetSelection()); + }); + list_l2->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) { + update_lists(list_l1->GetSelection(), list_l2->GetSelection()); + }); + + list_l3->Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent &evt) { select_material(evt.GetInt()); }); + + sel_all->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { select_all(true); }); + sel_none->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { select_all(false); }); + + if (list_l1->GetCount() > 0) { + list_l1->SetSelection(0); + update_lists(0, 0); + } +} + +void PageMaterials::update_lists(int sel1, int sel2) +{ + wxWindowUpdateLocker freeze_guard(this); + (void)freeze_guard; + + if (sel1 != sel1_prev) { + // Refresh the second list + + // XXX: The vendor list is created with quadratic complexity here, + // but the number of vendors is realistically so small this shouldn't be a problem. + + list_l2->Clear(); + list_l2->append(_(L("(All)")), &EMPTY); + if (sel1 != wxNOT_FOUND) { + const std::string &type = list_l1->get_data(sel1); + + materials->filter_presets(type, EMPTY, [this](Preset &p) { + const std::string &vendor = this->materials->get_vendor(p); + + if (list_l2->find(vendor) == wxNOT_FOUND) { + list_l2->append(vendor, &vendor); + } + }); + } + + sel1_prev = sel1; + sel2 = 0; + sel2_prev = wxNOT_FOUND; + list_l2->SetSelection(sel2); + list_l3->Clear(); + } + + if (sel2 != sel2_prev) { + // Refresh the third list + + list_l3->Clear(); + if (sel1 != wxNOT_FOUND && sel2 != wxNOT_FOUND) { + const std::string &type = list_l1->get_data(sel1); + const std::string &vendor = list_l2->get_data(sel2); + + materials->filter_presets(type, vendor, [this](Preset &p) { + const int i = list_l3->append(p.name, &p); + const bool checked = wizard_p()->appconfig_new.has(materials->appconfig_section(), p.name); + list_l3->Check(i, checked); + }); + } + + sel2_prev = sel2; + } +} + +void PageMaterials::select_material(int i) +{ + const bool checked = list_l3->IsChecked(i); + const Preset &preset = list_l3->get_data(i); + + if (checked) { + wizard_p()->appconfig_new.set(materials->appconfig_section(), preset.name, "1"); + } else { + wizard_p()->appconfig_new.erase(materials->appconfig_section(), preset.name); + } +} + +void PageMaterials::select_all(bool select) +{ + wxWindowUpdateLocker freeze_guard(this); + (void)freeze_guard; + + for (int i = 0; i < list_l3->GetCount(); i++) { + const bool current = list_l3->IsChecked(i); + if (current != select) { + list_l3->Check(i, select); + select_material(i); + } + } +} + const char *PageCustom::default_profile_name = "My Settings"; @@ -400,7 +571,7 @@ PageCustom::PageCustom(ConfigWizard *parent) cb_custom->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { tc_profile_name->Enable(custom_wanted()); - wizard_p()->on_custom_setup(custom_wanted()); + wizard_p()->on_custom_setup(); }); append(cb_custom); @@ -453,20 +624,20 @@ PageVendors::PageVendors(ConfigWizard *parent) auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); boldfont.SetWeight(wxFONTWEIGHT_BOLD); - AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors; + AppConfig &appconfig = this->wizard_p()->appconfig_new; wxArrayString choices_vendors; for (const auto vendor_pair : wizard_p()->vendors) { const auto &vendor = vendor_pair.second; if (vendor.id == "PrusaResearch") { continue; } - auto *picker = new PrinterPicker(this, vendor, "", MAX_COLS, appconfig_vendors); + auto *picker = new PrinterPicker(this, vendor, "", MAX_COLS, appconfig); picker->Hide(); pickers.push_back(picker); choices_vendors.Add(vendor.name); - picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) { - appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); + picker->Bind(EVT_PRINTER_PICK, [this, &appconfig](const PrinterPickerEvent &evt) { + appconfig.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); }); } @@ -875,6 +1046,68 @@ void ConfigWizardIndex::msw_rescale() } +// Materials + +const std::string Materials::UNKNOWN = "(Unknown)"; +const std::string Materials::SECTION_FILAMENTS = "filaments"; +const std::string Materials::SECTION_MATERIALS = "sla_materials"; + +const std::string& Materials::appconfig_section() const +{ + return (technology & T_FFF) ? SECTION_FILAMENTS : SECTION_MATERIALS; +} + +const std::string& Materials::get_type(Preset &preset) const +{ + return (technology & T_FFF) ? get_filament_type(preset) : get_material_type(preset); +} + +const std::string& Materials::get_vendor(Preset &preset) const +{ + return (technology & T_FFF) ? get_filament_vendor(preset) : get_material_vendor(preset); +} + +const std::string& Materials::get_filament_type(const Preset &preset) +{ + const auto *opt = preset.config.opt("filament_type"); + if (opt != nullptr && opt->values.size() > 0) { + return opt->values[0]; + } else { + return UNKNOWN; + } +} + +const std::string& Materials::get_filament_vendor(const Preset &preset) +{ + const auto *opt = preset.config.opt("filament_vendor"); + return opt != nullptr ? opt->value : UNKNOWN; +} + +const std::string& Materials::get_material_type(Preset &preset) +{ + // XXX: The initial_layer_height is of a float type and contains no string to reference, + // and so here he serialize it into an ad-hoc option initial_layer_height_str, which is then referenced + + const auto *opt_str = preset.config.opt("initial_layer_height_str"); + if (opt_str == nullptr) { + const auto *opt = preset.config.opt("initial_layer_height"); + if (opt == nullptr) { return UNKNOWN; } + + auto *new_opt_str = new ConfigOptionString(opt->serialize()); + preset.config.set_key_value("initial_layer_height_str", new_opt_str); + return new_opt_str->value; + } else { + return opt_str->value; + } +} + +const std::string& Materials::get_material_vendor(const Preset &preset) +{ + const auto *opt = preset.config.opt("material_vendor"); + return opt != nullptr ? opt->value : UNKNOWN; +} + + // priv static const std::unordered_map> legacy_preset_map {{ @@ -888,7 +1121,7 @@ static const std::unordered_map { "Original Prusa i3 MK3.ini", std::make_pair("MK3", "0.4") }, }}; -void ConfigWizard::priv::load_pages(bool custom_setup) +void ConfigWizard::priv::load_pages() { const auto former_active = index->active_item(); @@ -897,9 +1130,15 @@ void ConfigWizard::priv::load_pages(bool custom_setup) index->add_page(page_welcome); index->add_page(page_fff); index->add_page(page_msla); + + index->add_page(page_filaments); + if (any_sla_selected) { + index->add_page(page_sla_materials); + } + index->add_page(page_custom); - if (custom_setup) { + if (page_custom->custom_wanted()) { index->add_page(page_firmware); index->add_page(page_bed); index->add_page(page_diams); @@ -946,10 +1185,15 @@ void ConfigWizard::priv::load_vendors() const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor"; const auto rsrc_vendor_dir = fs::path(resources_dir()) / "profiles"; + PresetBundle bundle; + // Load vendors from the "vendors" directory in datadir - for (auto &dir_entry : boost::filesystem::directory_iterator(vendor_dir)) + // XXX: The VendorProfile is loaded twice here, ditto below + for (auto &dir_entry : boost::filesystem::directory_iterator(vendor_dir)) { if (Slic3r::is_ini_file(dir_entry)) { try { + bundle.load_configbundle(dir_entry.path().string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); + auto vp = VendorProfile::from_ini(dir_entry.path()); vendors[vp.id] = std::move(vp); } @@ -957,13 +1201,17 @@ void ConfigWizard::priv::load_vendors() BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what(); } } + } // Additionally load up vendors from the application resources directory, but only those not seen in the datadir - for (auto &dir_entry : boost::filesystem::directory_iterator(rsrc_vendor_dir)) + for (auto &dir_entry : boost::filesystem::directory_iterator(rsrc_vendor_dir)) { if (Slic3r::is_ini_file(dir_entry)) { const auto id = dir_entry.path().stem().string(); + if (vendors.find(id) == vendors.end()) { try { + bundle.load_configbundle(dir_entry.path().string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); + auto vp = VendorProfile::from_ini(dir_entry.path()); vendors_rsrc[vp.id] = dir_entry.path().filename().string(); vendors[vp.id] = std::move(vp); @@ -973,11 +1221,24 @@ void ConfigWizard::priv::load_vendors() } } } + } + + // Move materials to our Materials container: + for (auto &&f : bundle.filaments) { + f.vendor = nullptr; + filaments.presets.push_back(std::move(f)); + filaments.types.insert(Materials::get_filament_type(f)); + } + for (auto &&m : bundle.sla_materials) { + m.vendor = nullptr; + sla_materials.presets.push_back(std::move(m)); + sla_materials.types.insert(Materials::get_material_type(m)); + } // Load up the set of vendors / models / variants the user has had enabled up till now const AppConfig *app_config = GUI::get_app_config(); if (! app_config->legacy_datadir()) { - appconfig_vendors.set_vendors(*app_config); + appconfig_new.set_vendors(*app_config); } else { // In case of legacy datadir, try to guess the preference based on the printer preset files that are present const auto printer_dir = fs::path(Slic3r::data_dir()) / "printer"; @@ -988,9 +1249,31 @@ void ConfigWizard::priv::load_vendors() const auto &model = needle->second.first; const auto &variant = needle->second.second; - appconfig_vendors.set_variant("PrusaResearch", model, variant, true); + appconfig_new.set_variant("PrusaResearch", model, variant, true); } } + + // Load up the materials enabled till now + if (app_config->has_section(Materials::SECTION_FILAMENTS)) { + appconfig_new.set_section(Materials::SECTION_FILAMENTS, app_config->get_section(Materials::SECTION_FILAMENTS)); + } else { + // No AppConfig settings, load up defaults from vendor section(s) + for (const auto &vendor : bundle.vendors) { + for (const auto &profile : vendor.default_filaments) { + appconfig_new.set(Materials::SECTION_FILAMENTS, profile, "1"); + } + } + } + if (app_config->has_section(Materials::SECTION_MATERIALS)) { + appconfig_new.set_section(Materials::SECTION_MATERIALS, app_config->get_section(Materials::SECTION_MATERIALS)); + } else { + // No AppConfig settings, load up defaults from vendor section(s) + for (const auto &vendor : bundle.vendors) { + for (const auto &profile : vendor.default_sla_materials) { + appconfig_new.set(Materials::SECTION_MATERIALS, profile, "1"); + } + } + } } void ConfigWizard::priv::add_page(ConfigWizardPage *page) @@ -1004,14 +1287,25 @@ void ConfigWizard::priv::enable_next(bool enable) btn_finish->Enable(enable); } -void ConfigWizard::priv::on_custom_setup(bool custom_wanted) +void ConfigWizard::priv::on_custom_setup() { - load_pages(custom_wanted); + load_pages(); +} + +void ConfigWizard::priv::on_printer_pick(PagePrinters *page) +{ + if (page == page_msla) { + const bool any_sla_selected_new = page->any_selected(); + if (any_sla_selected != any_sla_selected_new) { + any_sla_selected = any_sla_selected_new; + load_pages(); + } + } } void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater) { - const auto enabled_vendors = appconfig_vendors.vendors(); + const auto enabled_vendors = appconfig_new.vendors(); // Install bundles from resources if needed: std::vector install_bundles; @@ -1066,7 +1360,13 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese preset_bundle->reset(true); } - app_config->set_vendors(appconfig_vendors); + app_config->set_vendors(appconfig_new); + if (appconfig_new.has_section(Materials::SECTION_FILAMENTS)) { + app_config->set_section(Materials::SECTION_FILAMENTS, appconfig_new.get_section(Materials::SECTION_FILAMENTS)); + } + if (appconfig_new.has_section(Materials::SECTION_MATERIALS)) { + app_config->set_section(Materials::SECTION_MATERIALS, appconfig_new.get_section(Materials::SECTION_MATERIALS)); + } app_config->set("version_check", page_update->version_check ? "1" : "0"); app_config->set("preset_update", page_update->preset_update ? "1" : "0"); @@ -1155,12 +1455,17 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) p->add_page(p->page_welcome = new PageWelcome(this)); - p->page_fff = new PagePrinters(this, _(L("Prusa FFF Technology Printers")), "Prusa FFF", vendor_prusa, 0, PagePrinters::T_FFF); + p->page_fff = new PagePrinters(this, _(L("Prusa FFF Technology Printers")), "Prusa FFF", vendor_prusa, 0, T_FFF); p->add_page(p->page_fff); - p->page_msla = new PagePrinters(this, _(L("Prusa MSLA Technology Printers")), "Prusa MSLA", vendor_prusa, 0, PagePrinters::T_SLA); + p->page_msla = new PagePrinters(this, _(L("Prusa MSLA Technology Printers")), "Prusa MSLA", vendor_prusa, 0, T_SLA); p->add_page(p->page_msla); + p->add_page(p->page_filaments = new PageMaterials(this, &p->filaments, + _(L("Filament Profiles Selection")), _(L("Filaments")), _(L("Type:")) )); + p->add_page(p->page_sla_materials = new PageMaterials(this, &p->sla_materials, + _(L("SLA Material Profiles Selection")), _(L("SLA Materials")), _(L("Layer height:")) )); + p->add_page(p->page_custom = new PageCustom(this)); p->add_page(p->page_update = new PageUpdate(this)); p->add_page(p->page_vendors = new PageVendors(this)); @@ -1169,7 +1474,8 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) p->add_page(p->page_diams = new PageDiameters(this)); p->add_page(p->page_temps = new PageTemperatures(this)); - p->load_pages(false); + p->any_sla_selected = p->page_msla->any_selected(); + p->load_pages(); vsizer->Add(topsizer, 1, wxEXPAND | wxALL, DIALOG_MARGIN); vsizer->Add(hline, 0, wxEXPAND); @@ -1191,6 +1497,8 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) p->btn_finish->Hide(); p->btn_sel_all->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { + p->any_sla_selected = true; + p->load_pages(); p->page_fff->select_all(true, false); p->page_msla->select_all(true, false); p->index->go_to(p->page_update); @@ -1240,7 +1548,7 @@ void ConfigWizard::on_dpi_changed(const wxRect &suggested_rect) { p->index->msw_rescale(); - const int& em = em_unit(); + const int em = em_unit(); msw_buttons_rescale(this, em, { wxID_APPLY, wxID_CANCEL, diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index f4848933fc..b57161c00e 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "libslic3r/PrintConfig.hpp" #include "slic3r/Utils/PresetUpdater.hpp" @@ -41,6 +43,13 @@ enum { ROW_SPACING = 75, }; +enum Technology { + // Bitflag equivalent of PrinterTechnology + T_FFF = 0x1, + T_SLA = 0x2, + T_Any = ~0, +}; + typedef std::function ModelFilter; struct PrinterPicker: wxPanel @@ -61,19 +70,20 @@ struct PrinterPicker: wxPanel std::vector cboxes; std::vector cboxes_alt; - PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig_vendors, const ModelFilter &filter); - PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig_vendors); + PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig, const ModelFilter &filter); + PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig); void select_all(bool select, bool alternates = false); void select_one(size_t i, bool select); - void on_checkbox(const Checkbox *cbox, bool checked); + bool any_selected() const; int get_width() const { return width; } const std::vector& get_button_indexes() { return m_button_indexes; } private: int width; - std::vector m_button_indexes; + + void on_checkbox(const Checkbox *cbox, bool checked); }; struct ConfigWizardPage: wxPanel @@ -111,19 +121,93 @@ struct PageWelcome: ConfigWizardPage struct PagePrinters: ConfigWizardPage { - enum Technology { - // Bitflag equivalent of PrinterTechnology - T_FFF = 0x1, - T_SLA = 0x2, - T_Any = ~0, - }; - std::vector printer_pickers; PagePrinters(ConfigWizard *parent, wxString title, wxString shortname, const VendorProfile &vendor, unsigned indent, Technology technology); void select_all(bool select, bool alternates = false); int get_width() const; + bool any_selected() const; +}; + + +struct Materials +{ + Technology technology; + std::vector presets; + std::set types; + + Materials(Technology technology) : technology(technology) {} + + const std::string& appconfig_section() const; + const std::string& get_type(Preset &preset) const; + const std::string& get_vendor(Preset &preset) const; + + template void filter_presets(const std::string &type, const std::string &vendor, F cb) { + for (Preset &preset : presets) { + if ((type.empty() || get_type(preset) == type) && (vendor.empty() || get_vendor(preset) == vendor)) { + cb(preset); + } + } + } + + static const std::string UNKNOWN; + static const std::string SECTION_FILAMENTS; + static const std::string SECTION_MATERIALS; + static const std::string& get_filament_type(const Preset &preset); + static const std::string& get_filament_vendor(const Preset &preset); + static const std::string& get_material_type(Preset &preset); + static const std::string& get_material_vendor(const Preset &preset); +}; + +// Here we extend wxListBox and wxCheckListBox +// to make the client data API much easier to use. +template struct DataList : public T +{ + DataList(wxWindow *parent) : T(parent, wxID_ANY) {} + + int append(const std::string &label, const D *data) { + void *ptr = reinterpret_cast(const_cast(data)); + return this->Append(from_u8(label), ptr); + } + + int append(const wxString &label, const D *data) { + void *ptr = reinterpret_cast(const_cast(data)); + return this->Append(label, ptr); + } + + const D& get_data(int n) { + return *reinterpret_cast(this->GetClientData(n)); + } + + int find(const D &data) { + for (int i = 0; i < this->GetCount(); i++) { + if (get_data(i) == data) { return i; } + } + + return wxNOT_FOUND; + } +}; + +typedef DataList StringList; +typedef DataList PresetList; + +struct PageMaterials: ConfigWizardPage +{ + // Technology technology; + Materials *materials; + StringList *list_l1, *list_l2; + PresetList *list_l3; + // wxCheckListBox *list_l3; + int sel1_prev, sel2_prev; + + PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name); + + void update_lists(int sel1, int sel2); + void select_material(int i); + void select_all(bool select); + + static const std::string EMPTY; }; struct PageCustom: ConfigWizardPage @@ -228,12 +312,6 @@ private: int em_w; int em_h; - /* #ys_FIXME_delete_after_testing by VK - const wxBitmap bg; - const wxBitmap bullet_black; - const wxBitmap bullet_blue; - const wxBitmap bullet_white; - */ ScalableBitmap bg; ScalableBitmap bullet_black; ScalableBitmap bullet_blue; @@ -245,9 +323,6 @@ private: ssize_t item_hover; size_t last_page; - /* #ys_FIXME_delete_after_testing by VK - int item_height() const { return std::max(bullet_black.GetSize().GetHeight(), em_w) + em_w; } - */ int item_height() const { return std::max(bullet_black.bmp().GetSize().GetHeight(), em_w) + em_w; } void on_paint(wxPaintEvent &evt); @@ -256,14 +331,18 @@ private: wxDEFINE_EVENT(EVT_INDEX_PAGE, wxCommandEvent); + struct ConfigWizard::priv { ConfigWizard *q; ConfigWizard::RunReason run_reason; - AppConfig appconfig_vendors; + AppConfig appconfig_new; // Backing for vendor/model/variant and material selections in the GUI std::unordered_map vendors; - std::unordered_map vendors_rsrc; - std::unique_ptr custom_config; + Materials filaments; // Holds available filament presets and their types & vendors + Materials sla_materials; // Ditto for SLA materials + std::unordered_map vendors_rsrc; // List of bundles to install from resources + std::unique_ptr custom_config; // Backing for custom printer definition + bool any_sla_selected; // Used to decide whether to display SLA Materials page wxScrolledWindow *hscroll = nullptr; wxBoxSizer *hscroll_sizer = nullptr; @@ -279,6 +358,8 @@ struct ConfigWizard::priv PageWelcome *page_welcome = nullptr; PagePrinters *page_fff = nullptr; PagePrinters *page_msla = nullptr; + PageMaterials *page_filaments = nullptr; + PageMaterials *page_sla_materials = nullptr; PageCustom *page_custom = nullptr; PageUpdate *page_update = nullptr; PageVendors *page_vendors = nullptr; // XXX: ? @@ -289,9 +370,14 @@ struct ConfigWizard::priv PageDiameters *page_diams = nullptr; PageTemperatures *page_temps = nullptr; - priv(ConfigWizard *q) : q(q) {} + priv(ConfigWizard *q) + : q(q) + , filaments(T_FFF) + , sla_materials(T_SLA) + , any_sla_selected(false) + {} - void load_pages(bool custom_setup); + void load_pages(); void init_dialog_size(); bool check_first_variant() const; @@ -299,7 +385,8 @@ struct ConfigWizard::priv void add_page(ConfigWizardPage *page); void enable_next(bool enable); - void on_custom_setup(bool custom_wanted); + void on_custom_setup(); + void on_printer_pick(PagePrinters *page); void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index d2503d349d..01cd4fa4d1 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -99,6 +99,9 @@ static const std::unordered_map pre_family_model_map { VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem::path &path, bool load_all) { static const std::string printer_model_key = "printer_model:"; + static const std::string filaments_section = "default_filaments"; + static const std::string materials_section = "default_sla_materials"; + const std::string id = path.stem().string(); if (! boost::filesystem::exists(path)) { @@ -107,6 +110,7 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem VendorProfile res(id); + // Helper to get compulsory fields auto get_or_throw = [&](const ptree &tree, const std::string &key) -> ptree::const_assoc_iterator { auto res = tree.find(key); @@ -116,6 +120,7 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem return res; }; + // Load the header const auto &vendor_section = get_or_throw(tree, "vendor")->second; res.name = get_or_throw(vendor_section, "name")->second.data(); @@ -127,6 +132,7 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem res.config_version = std::move(*config_version); } + // Load URLs const auto config_update_url = vendor_section.find("config_update_url"); if (config_update_url != vendor_section.not_found()) { res.config_update_url = config_update_url->second.data(); @@ -141,6 +147,7 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem return res; } + // Load printer models for (auto §ion : tree) { if (boost::starts_with(section.first, printer_model_key)) { VendorProfile::PrinterModel model; @@ -182,6 +189,24 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem } } + // Load filaments and sla materials to be installed by default + const auto filaments = tree.find(filaments_section); + if (filaments != tree.not_found()) { + for (auto &pair : filaments->second) { + if (pair.second.data() == "1") { + res.default_filaments.insert(pair.first); + } + } + } + const auto materials = tree.find(materials_section); + if (materials != tree.not_found()) { + for (auto &pair : materials->second) { + if (pair.second.data() == "1") { + res.default_sla_materials.insert(pair.first); + } + } + } + return res; } @@ -351,10 +376,17 @@ bool Preset::update_compatible(const Preset &active_printer, const DynamicPrintC void Preset::set_visible_from_appconfig(const AppConfig &app_config) { if (vendor == nullptr) { return; } - const std::string &model = config.opt_string("printer_model"); - const std::string &variant = config.opt_string("printer_variant"); - if (model.empty() || variant.empty()) { return; } - is_visible = app_config.get_variant(vendor->id, model, variant); + + if (type == TYPE_PRINTER) { + const std::string &model = config.opt_string("printer_model"); + const std::string &variant = config.opt_string("printer_variant"); + if (model.empty() || variant.empty()) { return; } + is_visible = app_config.get_variant(vendor->id, model, variant); + } else if (type == TYPE_FILAMENT) { + is_visible = app_config.has("filaments", name); + } else if (type == TYPE_SLA_MATERIAL) { + is_visible = app_config.has("sla_materials", name); + } } const std::vector& Preset::print_options() @@ -404,7 +436,7 @@ const std::vector& Preset::filament_options() "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel", "filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe", // Profile compatibility - "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" + "filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" }; return s_opts; } @@ -504,6 +536,7 @@ const std::vector& Preset::sla_material_options() "initial_exposure_time", "material_correction", "material_notes", + "material_vendor", "default_sla_material_profile", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index e1efdc1ef0..dfb72d495e 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -71,9 +71,14 @@ public: }; std::vector models; + std::set default_filaments; + std::set default_sla_materials; + VendorProfile() {} VendorProfile(std::string id) : id(std::move(id)) {} + // Load VendorProfile from an ini file. + // If `load_all` is false, only the header with basic info (name, version, URLs) is loaded. static VendorProfile from_ini(const boost::filesystem::path &path, bool load_all=true); static VendorProfile from_ini(const boost::property_tree::ptree &tree, const boost::filesystem::path &path, bool load_all=true); diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index d9e90333c6..f254ad15c1 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -323,6 +323,14 @@ void PresetBundle::load_installed_printers(const AppConfig &config) for (auto &preset : printers) { preset.set_visible_from_appconfig(config); } + + for (auto &preset : filaments) { + preset.set_visible_from_appconfig(config); + } + + for (auto &preset : sla_materials) { + preset.set_visible_from_appconfig(config); + } } // Load selections (current print, current filaments, current printer) from config.ini From 87b7b1cc1dc79ea77d2100481fd0f58a85b59037 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 3 Jun 2019 10:15:26 +0200 Subject: [PATCH 02/23] Load default filament/material selections from vendor profiles --- src/slic3r/GUI/AppConfig.cpp | 3 ++ src/slic3r/GUI/AppConfig.hpp | 2 ++ src/slic3r/GUI/ConfigWizard.cpp | 42 ++++++++----------------- src/slic3r/GUI/ConfigWizard_private.hpp | 2 -- src/slic3r/GUI/PresetBundle.cpp | 23 +++++++++++++- src/slic3r/GUI/PresetBundle.hpp | 6 +++- 6 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index 5a165e8aed..6b3f54f3a7 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -28,6 +28,9 @@ static const std::string VENDOR_PREFIX = "vendor:"; static const std::string MODEL_PREFIX = "model:"; static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version"; +const std::string AppConfig::SECTION_FILAMENTS = "filaments"; +const std::string AppConfig::SECTION_MATERIALS = "sla_materials"; + void AppConfig::reset() { m_storage.clear(); diff --git a/src/slic3r/GUI/AppConfig.hpp b/src/slic3r/GUI/AppConfig.hpp index fe30c0af69..97c369ab64 100644 --- a/src/slic3r/GUI/AppConfig.hpp +++ b/src/slic3r/GUI/AppConfig.hpp @@ -131,6 +131,8 @@ public: std::vector get_recent_projects() const; void set_recent_projects(const std::vector& recent_projects); + static const std::string SECTION_FILAMENTS; + static const std::string SECTION_MATERIALS; private: // Map of section, name -> value std::map> m_storage; diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 0d35ce1afc..9dbf3d0377 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1049,12 +1049,10 @@ void ConfigWizardIndex::msw_rescale() // Materials const std::string Materials::UNKNOWN = "(Unknown)"; -const std::string Materials::SECTION_FILAMENTS = "filaments"; -const std::string Materials::SECTION_MATERIALS = "sla_materials"; const std::string& Materials::appconfig_section() const { - return (technology & T_FFF) ? SECTION_FILAMENTS : SECTION_MATERIALS; + return (technology & T_FFF) ? AppConfig::SECTION_FILAMENTS : AppConfig::SECTION_MATERIALS; } const std::string& Materials::get_type(Preset &preset) const @@ -1236,7 +1234,7 @@ void ConfigWizard::priv::load_vendors() } // Load up the set of vendors / models / variants the user has had enabled up till now - const AppConfig *app_config = GUI::get_app_config(); + AppConfig *app_config = GUI::get_app_config(); if (! app_config->legacy_datadir()) { appconfig_new.set_vendors(*app_config); } else { @@ -1253,27 +1251,13 @@ void ConfigWizard::priv::load_vendors() } } - // Load up the materials enabled till now - if (app_config->has_section(Materials::SECTION_FILAMENTS)) { - appconfig_new.set_section(Materials::SECTION_FILAMENTS, app_config->get_section(Materials::SECTION_FILAMENTS)); - } else { - // No AppConfig settings, load up defaults from vendor section(s) - for (const auto &vendor : bundle.vendors) { - for (const auto &profile : vendor.default_filaments) { - appconfig_new.set(Materials::SECTION_FILAMENTS, profile, "1"); - } - } - } - if (app_config->has_section(Materials::SECTION_MATERIALS)) { - appconfig_new.set_section(Materials::SECTION_MATERIALS, app_config->get_section(Materials::SECTION_MATERIALS)); - } else { - // No AppConfig settings, load up defaults from vendor section(s) - for (const auto &vendor : bundle.vendors) { - for (const auto &profile : vendor.default_sla_materials) { - appconfig_new.set(Materials::SECTION_MATERIALS, profile, "1"); - } - } - } + // Load up the materials enabled till now, + // apply defaults from vendor profiles if there are no selections yet. + bundle.init_materials_selection(*app_config); + wxCHECK_RET(app_config->has_section(AppConfig::SECTION_FILAMENTS) && app_config->has_section(AppConfig::SECTION_MATERIALS), + "Failed to initialize default material selections"); + appconfig_new.set_section(AppConfig::SECTION_FILAMENTS, app_config->get_section(AppConfig::SECTION_FILAMENTS)); + appconfig_new.set_section(AppConfig::SECTION_MATERIALS, app_config->get_section(AppConfig::SECTION_MATERIALS)); } void ConfigWizard::priv::add_page(ConfigWizardPage *page) @@ -1361,11 +1345,11 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese } app_config->set_vendors(appconfig_new); - if (appconfig_new.has_section(Materials::SECTION_FILAMENTS)) { - app_config->set_section(Materials::SECTION_FILAMENTS, appconfig_new.get_section(Materials::SECTION_FILAMENTS)); + if (appconfig_new.has_section(AppConfig::SECTION_FILAMENTS)) { + app_config->set_section(AppConfig::SECTION_FILAMENTS, appconfig_new.get_section(AppConfig::SECTION_FILAMENTS)); } - if (appconfig_new.has_section(Materials::SECTION_MATERIALS)) { - app_config->set_section(Materials::SECTION_MATERIALS, appconfig_new.get_section(Materials::SECTION_MATERIALS)); + if (appconfig_new.has_section(AppConfig::SECTION_MATERIALS)) { + app_config->set_section(AppConfig::SECTION_MATERIALS, appconfig_new.get_section(AppConfig::SECTION_MATERIALS)); } app_config->set("version_check", page_update->version_check ? "1" : "0"); app_config->set("preset_update", page_update->preset_update ? "1" : "0"); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index b57161c00e..1c7cc94de2 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -152,8 +152,6 @@ struct Materials } static const std::string UNKNOWN; - static const std::string SECTION_FILAMENTS; - static const std::string SECTION_MATERIALS; static const std::string& get_filament_type(const Preset &preset); static const std::string& get_filament_vendor(const Preset &preset); static const std::string& get_material_type(Preset &preset); diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index f254ad15c1..2ea03d755a 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -194,7 +194,7 @@ void PresetBundle::setup_directories() } } -void PresetBundle::load_presets(const AppConfig &config, const std::string &preferred_model_id) +void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_model_id) { // First load the vendor specific system presets. std::string errors_cummulative = this->load_system_presets(); @@ -237,6 +237,10 @@ void PresetBundle::load_presets(const AppConfig &config, const std::string &pref if (! errors_cummulative.empty()) throw std::runtime_error(errors_cummulative); + // Make sure there are filament / material selections in the AppConfig, + // if there are none, load up defaults from vendor profiles. + this->init_materials_selection(config); + this->load_selections(config, preferred_model_id); } @@ -407,6 +411,23 @@ void PresetBundle::export_selections(AppConfig &config) config.set("presets", "printer", printers.get_selected_preset_name()); } +void PresetBundle::init_materials_selection(AppConfig &config) const { + if (! config.has_section(AppConfig::SECTION_FILAMENTS)) { + for (const auto &vendor : this->vendors) { + for (const auto &profile : vendor.default_filaments) { + config.set(AppConfig::SECTION_FILAMENTS, profile, "1"); + } + } + } + if (! config.has_section(AppConfig::SECTION_MATERIALS)) { + for (const auto &vendor : this->vendors) { + for (const auto &profile : vendor.default_sla_materials) { + config.set(AppConfig::SECTION_MATERIALS, profile, "1"); + } + } + } +} + void PresetBundle::load_compatible_bitmaps(wxWindow *window) { // We don't actually pass the window pointer here and instead generate diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index f351f66ac3..847b370187 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -31,11 +31,15 @@ public: // Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets. // Load selections (current print, current filaments, current printer) from config.ini // This is done just once on application start up. - void load_presets(const AppConfig &config, const std::string &preferred_model_id = ""); + void load_presets(AppConfig &config, const std::string &preferred_model_id = ""); // Export selections (current print, current filaments, current printer) into config.ini void export_selections(AppConfig &config); + // Make sure filament and sla_materials section in AppConfig are initialized + // to defaults from vendor profiles if they don't exist already + void init_materials_selection(AppConfig &config) const; + PresetCollection prints; PresetCollection sla_prints; PresetCollection filaments; From dba9925c4ed37d5b44f6672824987fa9ca0ad7b8 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 4 Jun 2019 18:01:41 +0200 Subject: [PATCH 03/23] Move ConfigWizard instance in GUI_App, lazy-initialized, add filament/material installation item in Sidebar combo boxes --- src/slic3r/GUI/ConfigWizard.cpp | 37 +++++++++++++------ src/slic3r/GUI/ConfigWizard.hpp | 12 +++++- src/slic3r/GUI/ConfigWizard_private.hpp | 5 +-- src/slic3r/GUI/GUI.cpp | 43 ---------------------- src/slic3r/GUI/GUI.hpp | 8 ---- src/slic3r/GUI/GUI_App.cpp | 49 +++++++++++++++++++++++-- src/slic3r/GUI/GUI_App.hpp | 7 ++++ src/slic3r/GUI/Plater.cpp | 13 +++++-- src/slic3r/GUI/Plater.hpp | 8 +++- src/slic3r/GUI/Preset.cpp | 4 +- src/slic3r/GUI/PresetBundle.cpp | 3 ++ src/slic3r/GUI/Tab.cpp | 6 +-- src/slic3r/Utils/PresetUpdater.cpp | 5 +-- 13 files changed, 115 insertions(+), 85 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 9dbf3d0377..d368d4fbdf 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -584,7 +584,7 @@ PageUpdate::PageUpdate(ConfigWizard *parent) , version_check(true) , preset_update(true) { - const AppConfig *app_config = GUI::get_app_config(); + const AppConfig *app_config = wxGetApp().app_config; auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); boldfont.SetWeight(wxFONTWEIGHT_BOLD); @@ -1084,7 +1084,7 @@ const std::string& Materials::get_filament_vendor(const Preset &preset) const std::string& Materials::get_material_type(Preset &preset) { // XXX: The initial_layer_height is of a float type and contains no string to reference, - // and so here he serialize it into an ad-hoc option initial_layer_height_str, which is then referenced + // and so here we serialize it into an ad-hoc option initial_layer_height_str, which is then referenced const auto *opt_str = preset.config.opt("initial_layer_height_str"); if (opt_str == nullptr) { @@ -1234,7 +1234,7 @@ void ConfigWizard::priv::load_vendors() } // Load up the set of vendors / models / variants the user has had enabled up till now - AppConfig *app_config = GUI::get_app_config(); + AppConfig *app_config = wxGetApp().app_config; if (! app_config->legacy_datadir()) { appconfig_new.set_vendors(*app_config); } else { @@ -1271,6 +1271,16 @@ void ConfigWizard::priv::enable_next(bool enable) btn_finish->Enable(enable); } +void ConfigWizard::priv::set_start_page(ConfigWizard::StartPage start_page) +{ + switch (start_page) { + case ConfigWizard::SP_PRINTERS: index->go_to(page_fff); break; + case ConfigWizard::SP_FILAMENTS: index->go_to(page_filaments); break; + case ConfigWizard::SP_MATERIALS: index->go_to(page_sla_materials); break; + default: index->go_to(page_welcome); break; + } +} + void ConfigWizard::priv::on_custom_setup() { load_pages(); @@ -1390,12 +1400,11 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese // Public -ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) - : DPIDialog(parent, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + name(), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +ConfigWizard::ConfigWizard() + : DPIDialog(nullptr, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + name(), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) , p(new priv(this)) { this->SetFont(wxGetApp().normal_font()); - p->run_reason = reason; p->load_vendors(); p->custom_config.reset(DynamicPrintConfig::new_from_defaults_keys({ @@ -1499,13 +1508,18 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) ConfigWizard::~ConfigWizard() {} -bool ConfigWizard::run(PresetBundle *preset_bundle, const PresetUpdater *updater) +bool ConfigWizard::run(RunReason reason, StartPage start_page) { - BOOST_LOG_TRIVIAL(info) << "Running ConfigWizard, reason: " << p->run_reason; + BOOST_LOG_TRIVIAL(info) << boost::format("Running ConfigWizard, reason: %1%, start_page: %2%") % reason % start_page; + + GUI_App &app = wxGetApp(); + + p->run_reason = reason; + p->set_start_page(start_page); + if (ShowModal() == wxID_OK) { - auto *app_config = GUI::get_app_config(); - p->apply_config(app_config, preset_bundle, updater); - app_config->set_legacy_datadir(false); + p->apply_config(app.app_config, app.preset_bundle, app.preset_updater); + app.app_config->set_legacy_datadir(false); BOOST_LOG_TRIVIAL(info) << "ConfigWizard applied"; return true; } else { @@ -1514,7 +1528,6 @@ bool ConfigWizard::run(PresetBundle *preset_bundle, const PresetUpdater *updater } } - const wxString& ConfigWizard::name(const bool from_menu/* = false*/) { // A different naming convention is used for the Wizard on Windows vs. OSX & GTK. diff --git a/src/slic3r/GUI/ConfigWizard.hpp b/src/slic3r/GUI/ConfigWizard.hpp index b707e525ba..3c85b73432 100644 --- a/src/slic3r/GUI/ConfigWizard.hpp +++ b/src/slic3r/GUI/ConfigWizard.hpp @@ -26,7 +26,15 @@ public: RR_USER, // User requested the Wizard from the menus }; - ConfigWizard(wxWindow *parent, RunReason run_reason); + // What page should wizard start on + enum StartPage { + SP_WELCOME, + SP_PRINTERS, + SP_FILAMENTS, + SP_MATERIALS, + }; + + ConfigWizard(); ConfigWizard(ConfigWizard &&) = delete; ConfigWizard(const ConfigWizard &) = delete; ConfigWizard &operator=(ConfigWizard &&) = delete; @@ -34,7 +42,7 @@ public: ~ConfigWizard(); // Run the Wizard. Return whether it was completed. - bool run(PresetBundle *preset_bundle, const PresetUpdater *updater); + bool run(RunReason reason, StartPage start_page = SP_WELCOME); static const wxString& name(const bool from_menu = false); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 1c7cc94de2..82708cc59b 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -192,11 +192,9 @@ typedef DataList PresetList; struct PageMaterials: ConfigWizardPage { - // Technology technology; Materials *materials; StringList *list_l1, *list_l2; PresetList *list_l3; - // wxCheckListBox *list_l3; int sel1_prev, sel2_prev; PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name); @@ -333,7 +331,7 @@ wxDEFINE_EVENT(EVT_INDEX_PAGE, wxCommandEvent); struct ConfigWizard::priv { ConfigWizard *q; - ConfigWizard::RunReason run_reason; + ConfigWizard::RunReason run_reason = RR_USER; AppConfig appconfig_new; // Backing for vendor/model/variant and material selections in the GUI std::unordered_map vendors; Materials filaments; // Holds available filament presets and their types & vendors @@ -382,6 +380,7 @@ struct ConfigWizard::priv void load_vendors(); void add_page(ConfigWizardPage *page); void enable_next(bool enable); + void set_start_page(ConfigWizard::StartPage start_page); void on_custom_setup(); void on_printer_pick(PagePrinters *page); diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index f94372667c..c22fd6f792 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -101,49 +101,6 @@ const std::string& shortkey_alt_prefix() return str; } -bool config_wizard_startup(bool app_config_exists) -{ - if (!app_config_exists || wxGetApp().preset_bundle->printers.size() <= 1) { - config_wizard(ConfigWizard::RR_DATA_EMPTY); - return true; - } else if (get_app_config()->legacy_datadir()) { - // Looks like user has legacy pre-vendorbundle data directory, - // explain what this is and run the wizard - - MsgDataLegacy dlg; - dlg.ShowModal(); - - config_wizard(ConfigWizard::RR_DATA_LEGACY); - return true; - } - return false; -} - -void config_wizard(int reason) -{ - // Exit wizard if there are unsaved changes and the user cancels the action. - if (! wxGetApp().check_unsaved_changes()) - return; - - try { - ConfigWizard wizard(nullptr, static_cast(reason)); - wizard.run(wxGetApp().preset_bundle, wxGetApp().preset_updater); - } - catch (const std::exception &e) { - show_error(nullptr, e.what()); - } - - wxGetApp().load_current_presets(); - - if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && model_has_multi_part_objects(wxGetApp().model())) - { - show_info(nullptr, - _(L("It's impossible to print multi-part object(s) with SLA technology.")) + "\n\n" + - _(L("Please check and fix your object list.")), - _(L("Attention!"))); - } -} - // opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element) void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) { diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index 4074c2afc8..0b904bad86 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -35,14 +35,6 @@ extern AppConfig* get_app_config(); extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change); -// Checks if configuration wizard needs to run, calls config_wizard if so. -// Returns whether the Wizard ran. -extern bool config_wizard_startup(bool app_config_exists); - -// Opens the configuration wizard, returns true if wizard is finished & accepted. -// The run_reason argument is actually ConfigWizard::RunReason, but int is used here because of Perl. -extern void config_wizard(int run_reason); - // Change option value in config void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 80c02ea78e..028886915d 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -38,7 +38,6 @@ #include "../Utils/PresetUpdater.hpp" #include "../Utils/PrintHost.hpp" #include "../Utils/MacDarkMode.hpp" -#include "ConfigWizard.hpp" #include "slic3r/Config/Snapshot.hpp" #include "ConfigSnapshotDialog.hpp" #include "FirmwareDialog.hpp" @@ -46,6 +45,7 @@ #include "Tab.hpp" #include "SysInfoDialog.hpp" #include "KBShortcutsDialog.hpp" +#include "UpdateDialogs.hpp" #ifdef __WXMSW__ #include @@ -148,6 +148,7 @@ GUI_App::GUI_App() : wxApp() , m_em_unit(10) , m_imgui(new ImGuiWrapper()) + , m_wizard(nullptr) {} GUI_App::~GUI_App() @@ -204,7 +205,6 @@ bool GUI_App::on_init_inner() // supplied as argument to --datadir; in that case we should still run the wizard preset_bundle->setup_directories(); - app_conf_exists = app_config->exists(); // load settings app_conf_exists = app_config->exists(); if (app_conf_exists) { @@ -287,7 +287,7 @@ bool GUI_App::on_init_inner() } CallAfter([this] { - config_wizard_startup(app_conf_exists); + config_wizard_startup(); preset_updater->slic3r_update_notify(); preset_updater->sync(preset_bundle); }); @@ -826,7 +826,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu) local_menu->Bind(wxEVT_MENU, [this, config_id_base](wxEvent &event) { switch (event.GetId() - config_id_base) { case ConfigMenuWizard: - config_wizard(ConfigWizard::RR_USER); + run_wizard(ConfigWizard::RR_USER); break; case ConfigMenuTakeSnapshot: // Take a configuration snapshot. @@ -1057,6 +1057,29 @@ void GUI_App::open_web_page_localized(const std::string &http_address) wxLaunchDefaultBrowser(http_address + "&lng=" + this->current_language_code_safe()); } +bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage start_page) +{ + if (! m_wizard) { + m_wizard.reset(new ConfigWizard()); + } + + const bool res = m_wizard->run(reason, start_page); + + if (res) { + load_current_presets(); + + if (preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA + && Slic3r::model_has_multi_part_objects(wxGetApp().model())) { + GUI::show_info(nullptr, + _(L("It's impossible to print multi-part object(s) with SLA technology.")) + "\n\n" + + _(L("Please check and fix your object list.")), + _(L("Attention!"))); + } + } + + return res; +} + void GUI_App::window_pos_save(wxTopLevelWindow* window, const std::string &name) { if (name.empty()) { return; } @@ -1105,6 +1128,24 @@ void GUI_App::window_pos_sanitize(wxTopLevelWindow* window) } } +bool GUI_App::config_wizard_startup() +{ + if (!app_conf_exists || preset_bundle->printers.size() <= 1) { + run_wizard(ConfigWizard::RR_DATA_EMPTY); + return true; + } else if (get_app_config()->legacy_datadir()) { + // Looks like user has legacy pre-vendorbundle data directory, + // explain what this is and run the wizard + + MsgDataLegacy dlg; + dlg.ShowModal(); + + run_wizard(ConfigWizard::RR_DATA_LEGACY); + return true; + } + return false; +} + // static method accepting a wxWindow object as first parameter // void warning_catcher{ // my($self, $message_dialog) = @_; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index a8043e9915..8c5f0c30c8 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -6,6 +6,7 @@ #include "libslic3r/PrintConfig.hpp" #include "MainFrame.hpp" #include "ImGuiWrapper.hpp" +#include "ConfigWizard.hpp" #include #include @@ -69,6 +70,7 @@ enum ConfigMenuIDs { }; class Tab; +class ConfigWizard; static wxString dots("…", wxConvUTF8); @@ -96,6 +98,7 @@ class GUI_App : public wxApp std::unique_ptr m_imgui; std::unique_ptr m_printhost_job_queue; + std::unique_ptr m_wizard; public: bool OnInit() override; @@ -184,6 +187,7 @@ public: PrintHostJobQueue& printhost_job_queue() { return *m_printhost_job_queue.get(); } void open_web_page_localized(const std::string &http_address); + bool run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage start_page = ConfigWizard::SP_WELCOME); private: bool on_init_inner(); @@ -191,6 +195,9 @@ private: void window_pos_restore(wxTopLevelWindow* window, const std::string &name, bool default_maximized = false); void window_pos_sanitize(wxTopLevelWindow* window); bool select_language(); + + bool config_wizard_startup(); + #ifdef __WXMSW__ void associate_3mf_files(); #endif // __WXMSW__ diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c5aad48a9e..4427921fff 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -251,11 +251,18 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * auto selected_item = this->GetSelection(); auto marker = reinterpret_cast(this->GetClientData(selected_item)); - if (marker == LABEL_ITEM_MARKER || marker == LABEL_ITEM_CONFIG_WIZARD) { + if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) { this->SetSelection(this->last_selected); evt.StopPropagation(); - if (marker == LABEL_ITEM_CONFIG_WIZARD) - wxTheApp->CallAfter([]() { Slic3r::GUI::config_wizard(Slic3r::GUI::ConfigWizard::RR_USER); }); + if (marker >= LABEL_ITEM_WIZARD_PRINTERS) { + ConfigWizard::StartPage sp = ConfigWizard::SP_WELCOME; + switch (marker) { + case LABEL_ITEM_WIZARD_PRINTERS: sp = ConfigWizard::SP_PRINTERS; break; + case LABEL_ITEM_WIZARD_FILAMENTS: sp = ConfigWizard::SP_FILAMENTS; break; + case LABEL_ITEM_WIZARD_MATERIALS: sp = ConfigWizard::SP_MATERIALS; break; + } + wxTheApp->CallAfter([sp]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, sp); }); + } } else if ( this->last_selected != selected_item || wxGetApp().get_tab(this->preset_type)->get_presets()->current_is_dirty() ) { this->last_selected = selected_item; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 6b488fef14..eb714dcd58 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -56,8 +56,12 @@ public: ScalableButton* edit_btn { nullptr }; enum LabelItemType { - LABEL_ITEM_MARKER = 0x4d, - LABEL_ITEM_CONFIG_WIZARD = 0x4e + LABEL_ITEM_MARKER = 0xffffff01, + LABEL_ITEM_WIZARD_PRINTERS, + LABEL_ITEM_WIZARD_FILAMENTS, + LABEL_ITEM_WIZARD_MATERIALS, + + LABEL_ITEM_MAX, }; void set_label_marker(int item, LabelItemType label_item_type = LABEL_ITEM_MARKER); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 01cd4fa4d1..bda096d66d 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -1070,7 +1070,9 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui) bmps.emplace_back(m_bitmap_add ? *m_bitmap_add : wxNullBitmap); bmp = m_bitmap_cache->insert(bitmap_key, bmps); } - ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add a new printer")), *bmp), GUI::PresetComboBox::LABEL_ITEM_CONFIG_WIZARD); + ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add a new printer")), *bmp), GUI::PresetComboBox::LABEL_ITEM_WIZARD_PRINTERS); + } else if (m_type == Preset::TYPE_SLA_MATERIAL) { + ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add/Remove materials")), wxNullBitmap), GUI::PresetComboBox::LABEL_ITEM_WIZARD_MATERIALS); } ui->SetSelection(selected_preset_item); diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 2ea03d755a..5f91111115 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -1601,6 +1601,9 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr selected_preset_item = ui->GetCount() - 1; } } + + ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add/Remove filaments")), wxNullBitmap), GUI::PresetComboBox::LABEL_ITEM_WIZARD_FILAMENTS); + ui->SetSelection(selected_preset_item); ui->SetToolTip(ui->GetString(selected_preset_item)); ui->check_selection(); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index c87626a483..921a18147b 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -227,9 +227,9 @@ void Tab::create_preset_tab() m_treectrl->Bind(wxEVT_KEY_DOWN, &Tab::OnKeyDown, this); m_presets_choice->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent e) { - //! Because of The MSW and GTK version of wxBitmapComboBox derived from wxComboBox, + //! Because of The MSW and GTK version of wxBitmapComboBox derived from wxComboBox, //! but the OSX version derived from wxOwnerDrawnCombo, instead of: - //! select_preset(m_presets_choice->GetStringSelection().ToUTF8().data()); + //! select_preset(m_presets_choice->GetStringSelection().ToUTF8().data()); //! we doing next: int selected_item = m_presets_choice->GetSelection(); if (m_selected_preset_item == size_t(selected_item) && !m_presets->current_is_dirty()) @@ -241,7 +241,7 @@ void Tab::create_preset_tab() selected_string == "------- User presets -------"*/) { m_presets_choice->SetSelection(m_selected_preset_item); if (wxString::FromUTF8(selected_string.c_str()) == PresetCollection::separator(L("Add a new printer"))) - wxTheApp->CallAfter([]() { Slic3r::GUI::config_wizard(Slic3r::GUI::ConfigWizard::RR_USER); }); + wxTheApp->CallAfter([]() { wxGetApp().run_wizard(ConfigWizard::RR_USER); }); return; } m_selected_preset_item = selected_item; diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 5723afca2f..cafdbb14ef 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -643,13 +643,10 @@ PresetUpdater::UpdateResult PresetUpdater::config_update() const // (snapshot is taken beforehand) p->perform_updates(std::move(updates)); - GUI::ConfigWizard wizard(nullptr, GUI::ConfigWizard::RR_DATA_INCOMPAT); - - if (! wizard.run(GUI::wxGetApp().preset_bundle, this)) { + if (! GUI::wxGetApp().run_wizard(GUI::ConfigWizard::RR_DATA_INCOMPAT)) { return R_INCOMPAT_EXIT; } - GUI::wxGetApp().load_current_presets(); return R_INCOMPAT_CONFIGURED; } else { BOOST_LOG_TRIVIAL(info) << "User wants to exit Slic3r, bye..."; From 235b659cf97211f0b80c47008d8458b9173a3a40 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 17 Jun 2019 16:39:22 +0200 Subject: [PATCH 04/23] WIP: ConfigWizard: 3rd party bundle installation roughly done --- src/slic3r/Config/Snapshot.cpp | 6 +- src/slic3r/GUI/ConfigWizard.cpp | 469 ++++++++++++++++-------- src/slic3r/GUI/ConfigWizard.hpp | 2 +- src/slic3r/GUI/ConfigWizard_private.hpp | 135 +++++-- src/slic3r/GUI/GUI_App.cpp | 4 +- src/slic3r/GUI/GUI_App.hpp | 2 +- src/slic3r/GUI/Preset.cpp | 6 +- src/slic3r/GUI/Preset.hpp | 10 +- src/slic3r/GUI/PresetBundle.cpp | 52 ++- src/slic3r/GUI/PresetBundle.hpp | 8 +- src/slic3r/Utils/PresetUpdater.cpp | 14 +- 11 files changed, 493 insertions(+), 215 deletions(-) diff --git a/src/slic3r/Config/Snapshot.cpp b/src/slic3r/Config/Snapshot.cpp index 622b31a178..521a7c5315 100644 --- a/src/slic3r/Config/Snapshot.cpp +++ b/src/slic3r/Config/Snapshot.cpp @@ -393,9 +393,9 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot: // Read the active config bundle, parse the config version. PresetBundle bundle; bundle.load_configbundle((data_dir / "vendor" / (cfg.name + ".ini")).string(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY); - for (const VendorProfile &vp : bundle.vendors) - if (vp.id == cfg.name) - cfg.version.config_version = vp.config_version; + for (const auto &vp : bundle.vendors) + if (vp.second.id == cfg.name) + cfg.version.config_version = vp.second.config_version; // Fill-in the min/max slic3r version from the config index, if possible. try { // Load the config index for the vendor. diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index d368d4fbdf..8a850b7a0b 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,7 @@ #include #include "libslic3r/Utils.hpp" -#include "PresetBundle.hpp" +// #include "PresetBundle.hpp" #include "GUI.hpp" #include "GUI_Utils.hpp" #include "slic3r/Config/Snapshot.hpp" @@ -40,6 +41,92 @@ using Config::Snapshot; using Config::SnapshotDB; +// Configuration data structures extensions needed for the wizard + +Bundle::Bundle(fs::path source_path, bool is_in_resources, bool is_prusa_bundle) + : source_path(std::move(source_path)) + , preset_bundle(new PresetBundle) + , vendor_profile(nullptr) + , is_in_resources(is_in_resources) + , is_prusa_bundle(is_prusa_bundle) +{ + // XXX: consider removing path <-> string juggling + preset_bundle->load_configbundle(this->source_path.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); + auto first_vendor = preset_bundle->vendors.begin(); + wxCHECK_RET(first_vendor != preset_bundle->vendors.end(), "Failed to load preset bundle"); + vendor_profile = &first_vendor->second; +} + +Bundle::Bundle(Bundle &&other) + : source_path(std::move(source_path)) + , preset_bundle(std::move(other.preset_bundle)) + , vendor_profile(other.vendor_profile) + , is_in_resources(other.is_in_resources) + , is_prusa_bundle(other.is_prusa_bundle) +{ + other.vendor_profile = nullptr; +} + +BundleMap BundleMap::load() +{ + BundleMap res; + + // XXX: Keep Prusa bundle separate? (Probably no - keep same codepaths) + + const auto vendor_dir = (boost::filesystem::path(Slic3r::data_dir()) / "vendor").make_preferred(); + const auto rsrc_vendor_dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred(); + + // XXX + // const auto prusa_bundle_vendor = (vendor_dir / PRUSA_BUNDLE).replace_extension(".ini"); + // const auto prusa_bundle = boost::filesystem::exists(prusa_bundle_vendor) ? prusa_bundle_vendor + // : (rsrc_vendor_dir / PRUSA_BUNDLE).replace_extension(".ini"); + auto prusa_bundle_path = (vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini"); + auto prusa_bundle_rsrc = false; + if (! boost::filesystem::exists(prusa_bundle_path)) { + prusa_bundle_path = (rsrc_vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini"); + prusa_bundle_rsrc = true; + } + Bundle prusa_bundle(std::move(prusa_bundle_path), prusa_bundle_rsrc, true); + res.emplace(PresetBundle::PRUSA_BUNDLE, std::move(prusa_bundle)); + + // Load the other bundles in the datadir/vendor directory + // and then additionally from resources/profiles. + bool is_in_resources = false; + for (auto dir : { &vendor_dir, &rsrc_vendor_dir }) { + for (const auto &dir_entry : boost::filesystem::directory_iterator(*dir)) { + if (Slic3r::is_ini_file(dir_entry)) { + std::string id = dir_entry.path().stem().string(); // stem() = filename() without the trailing ".ini" part + + // Don't load this bundle if we've already loaded it. + if (res.find(id) != res.end()) { continue; } + + Bundle bundle(dir_entry.path(), is_in_resources); + res.emplace(std::move(id), std::move(bundle)); + } + } + + is_in_resources = true; + } + + return res; +} + +Bundle& BundleMap::prusa_bundle() +{ + auto it = find(PresetBundle::PRUSA_BUNDLE); + if (it == end()) { + throw std::runtime_error("ConfigWizard: Internal error in BundleMap: PRUSA_BUNDLE not loaded"); + } + + return it->second; +} + +const Bundle& BundleMap::prusa_bundle() const +{ + return const_cast(this)->prusa_bundle(); +} + + // Printer model picker GUI control struct PrinterPickerEvent : public wxEvent @@ -65,6 +152,8 @@ struct PrinterPickerEvent : public wxEvent wxDEFINE_EVENT(EVT_PRINTER_PICK, PrinterPickerEvent); +const std::string PrinterPicker::PRINTER_PLACEHOLDER = "printer_placeholder.png"; + PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig, const ModelFilter &filter) : wxPanel(parent) , vendor_id(vendor.id) @@ -96,6 +185,17 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt if (wxFileExists(bitmap_file)) { bitmap.LoadFile(bitmap_file, wxBITMAP_TYPE_PNG); bitmap_width = bitmap.GetWidth(); + } else { + BOOST_LOG_TRIVIAL(warning) << boost::format("Can't find bitmap file `%1%` for vendor `%2%`, printer `%3%`, using placeholder icon instead") + % bitmap_file + % vendor.id + % model.id; + + const wxString placeholder_file = GUI::from_u8(Slic3r::var(PRINTER_PLACEHOLDER)); + if (wxFileExists(placeholder_file)) { + bitmap.LoadFile(placeholder_file, wxBITMAP_TYPE_PNG); + bitmap_width = bitmap.GetWidth(); + } } auto *title = new wxStaticText(this, wxID_ANY, model.name, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); @@ -135,7 +235,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt auto *cbox = new Checkbox(variants_panel, label, model_id, variant.name); i == 0 ? cboxes.push_back(cbox) : cboxes_alt.push_back(cbox); - bool enabled = appconfig.get_variant("PrusaResearch", model_id, variant.name); + bool enabled = appconfig.get_variant(vendor.id, model_id, variant.name); cbox->SetValue(enabled); variants_sizer->Add(cbox, 0, wxBOTTOM, 3); @@ -295,12 +395,13 @@ ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxStrin ConfigWizardPage::~ConfigWizardPage() {} -void ConfigWizardPage::append_text(wxString text) +wxStaticText* ConfigWizardPage::append_text(wxString text) { auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); widget->Wrap(WRAP_WIDTH); widget->SetMinSize(wxSize(WRAP_WIDTH, -1)); append(widget); + return widget; } void ConfigWizardPage::append_spacer(int space) @@ -320,34 +421,42 @@ PageWelcome::PageWelcome(ConfigWizard *parent) _(L("Welcome to the %s Configuration Wizard")) #endif , SLIC3R_APP_NAME), _(L("Welcome"))) - , cbox_reset(nullptr) + , welcome_text(append_text(wxString::Format( + _(L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")), + SLIC3R_APP_NAME, + ConfigWizard::name()) + )) + , cbox_reset(append( + new wxCheckBox(this, wxID_ANY, _(L("Remove user profiles - install from scratch (a snapshot will be taken beforehand)"))) + )) { - if (wizard_p()->run_reason == ConfigWizard::RR_DATA_EMPTY) { - wxString::Format(_(L("Run %s")), ConfigWizard::name()); - append_text(wxString::Format( - _(L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")), - SLIC3R_APP_NAME, - ConfigWizard::name()) - ); - } else { - cbox_reset = new wxCheckBox(this, wxID_ANY, _(L("Remove user profiles - install from scratch (a snapshot will be taken beforehand)"))); - append(cbox_reset); - } + welcome_text->Hide(); + cbox_reset->Hide(); +} - Show(); +void PageWelcome::set_run_reason(ConfigWizard::RunReason run_reason) +{ + const bool data_empty = run_reason == ConfigWizard::RR_DATA_EMPTY; + welcome_text->Show(data_empty); + cbox_reset->Show(!data_empty); } -PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortname, const VendorProfile &vendor, unsigned indent, Technology technology) +PagePrinters::PagePrinters(ConfigWizard *parent, + wxString title, + wxString shortname, + const VendorProfile &vendor, + unsigned indent, + Technology technology) : ConfigWizardPage(parent, std::move(title), std::move(shortname), indent) + , technology(technology) + , install(false) // only used for 3rd party vendors { enum { COL_SIZE = 200, }; - bool check_first_variant = technology == T_FFF && wizard_p()->check_first_variant(); - - AppConfig &appconfig = this->wizard_p()->appconfig_new; + AppConfig *appconfig = &this->wizard_p()->appconfig_new; const auto families = vendor.families(); for (const auto &family : families) { @@ -362,16 +471,10 @@ PagePrinters::PagePrinters(ConfigWizard *parent, wxString title, wxString shortn } const auto picker_title = family.empty() ? wxString() : wxString::Format(_(L("%s Family")), family); - auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, appconfig, filter); + auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, *appconfig, filter); - if (check_first_variant) { - // Select the default (first) model/variant on the Prusa vendor - picker->select_one(0, true); - check_first_variant = false; - } - - picker->Bind(EVT_PRINTER_PICK, [this, &appconfig](const PrinterPickerEvent &evt) { - appconfig.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); + picker->Bind(EVT_PRINTER_PICK, [this, appconfig](const PrinterPickerEvent &evt) { + appconfig->set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); wizard_p()->on_printer_pick(this); }); @@ -404,6 +507,15 @@ bool PagePrinters::any_selected() const return false; } +void PagePrinters::set_run_reason(ConfigWizard::RunReason run_reason) +{ + if (technology == T_FFF + && (run_reason == ConfigWizard::RR_DATA_EMPTY || run_reason == ConfigWizard::RR_DATA_LEGACY) + && printer_pickers.size() > 0) { + printer_pickers[0]->select_one(0, true); + } +} + const std::string PageMaterials::EMPTY; @@ -619,48 +731,26 @@ PageUpdate::PageUpdate(ConfigWizard *parent) PageVendors::PageVendors(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) { - append_text(wxString::Format(_(L("Pick another vendor supported by %s:")), SLIC3R_APP_NAME)); + + + // FIXME: persistence: this doesn't reload choices + + + append_text(wxString::Format(_(L("Pick another vendor supported by %s: (FIXME: this text)")), SLIC3R_APP_NAME)); auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); boldfont.SetWeight(wxFONTWEIGHT_BOLD); - AppConfig &appconfig = this->wizard_p()->appconfig_new; - wxArrayString choices_vendors; + for (const auto &pair : wizard_p()->bundles) { + const VendorProfile *vendor = pair.second.vendor_profile; + if (vendor->id == PresetBundle::PRUSA_BUNDLE) { continue; } - for (const auto vendor_pair : wizard_p()->vendors) { - const auto &vendor = vendor_pair.second; - if (vendor.id == "PrusaResearch") { continue; } - - auto *picker = new PrinterPicker(this, vendor, "", MAX_COLS, appconfig); - picker->Hide(); - pickers.push_back(picker); - choices_vendors.Add(vendor.name); - - picker->Bind(EVT_PRINTER_PICK, [this, &appconfig](const PrinterPickerEvent &evt) { - appconfig.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); + auto *cbox = new wxCheckBox(this, wxID_ANY, vendor->name); + cbox->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent &event) { + wizard_p()->on_3rdparty_install(vendor, cbox->IsChecked()); }); - } - auto *vendor_picker = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices_vendors); - if (choices_vendors.GetCount() > 0) { - vendor_picker->SetSelection(0); - on_vendor_pick(0); - } - - vendor_picker->Bind(wxEVT_CHOICE, [this](wxCommandEvent &evt) { - this->on_vendor_pick(evt.GetInt()); - }); - - append(vendor_picker); - for (PrinterPicker *picker : pickers) { this->append(picker); } -} - -void PageVendors::on_vendor_pick(size_t i) -{ - for (PrinterPicker *picker : pickers) { picker->Hide(); } - if (i < pickers.size()) { - pickers[i]->Show(); - parent->Layout(); + append(cbox); } } @@ -954,12 +1044,15 @@ void ConfigWizardIndex::go_to(size_t i) } } -void ConfigWizardIndex::go_to(ConfigWizardPage *page) +void ConfigWizardIndex::go_to(const ConfigWizardPage *page) { if (page == nullptr) { return; } for (size_t i = 0; i < items.size(); i++) { - if (items[i].page == page) { go_to(i); } + if (items[i].page == page) { + go_to(i); + return; + } } } @@ -1121,21 +1214,25 @@ static const std::unordered_map void ConfigWizard::priv::load_pages() { - const auto former_active = index->active_item(); + wxWindowUpdateLocker freeze_guard(q); + (void)freeze_guard; + + const ConfigWizardPage *former_active = index->active_page(); index->clear(); index->add_page(page_welcome); + + // Printers index->add_page(page_fff); index->add_page(page_msla); - - index->add_page(page_filaments); - if (any_sla_selected) { - index->add_page(page_sla_materials); + index->add_page(page_vendors); + for (const auto &pair : pages_3rdparty) { + PagePrinters *page = pair.second; + if (page->install) { index->add_page(page); } } index->add_page(page_custom); - if (page_custom->custom_wanted()) { index->add_page(page_firmware); index->add_page(page_bed); @@ -1143,6 +1240,10 @@ void ConfigWizard::priv::load_pages() index->add_page(page_temps); } + // Filaments & Materials + if (any_fff_selected) { index->add_page(page_filaments); } + if (any_sla_selected) { index->add_page(page_sla_materials); } + index->add_page(page_update); index->go_to(former_active); // Will restore the active item/page if possible @@ -1173,66 +1274,75 @@ void ConfigWizard::priv::init_dialog_size() q->SetSize(window_rect); } -bool ConfigWizard::priv::check_first_variant() const -{ - return run_reason == RR_DATA_EMPTY || run_reason == RR_DATA_LEGACY; -} - void ConfigWizard::priv::load_vendors() { - const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor"; - const auto rsrc_vendor_dir = fs::path(resources_dir()) / "profiles"; + // const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor"; + // const auto rsrc_vendor_dir = fs::path(resources_dir()) / "profiles"; - PresetBundle bundle; + // PresetBundle bundle; + // bundle.load_available_system_presets(); + bundles = BundleMap::load(); - // Load vendors from the "vendors" directory in datadir - // XXX: The VendorProfile is loaded twice here, ditto below - for (auto &dir_entry : boost::filesystem::directory_iterator(vendor_dir)) { - if (Slic3r::is_ini_file(dir_entry)) { - try { - bundle.load_configbundle(dir_entry.path().string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); + // // Load vendors from the "vendors" directory in datadir + // // XXX: The VendorProfile is loaded twice here, ditto below + // for (auto &dir_entry : boost::filesystem::directory_iterator(vendor_dir)) { + // if (Slic3r::is_ini_file(dir_entry)) { + // try { + // bundle.load_configbundle(dir_entry.path().string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); - auto vp = VendorProfile::from_ini(dir_entry.path()); - vendors[vp.id] = std::move(vp); - } - catch (const std::exception& e) { - BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what(); - } + // auto vp = VendorProfile::from_ini(dir_entry.path()); + // vendors[vp.id] = std::move(vp); + // } + // catch (const std::exception& e) { + // BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what(); + // } + // } + // } + + // // Additionally load up vendors from the application resources directory, but only those not seen in the datadir + // for (auto &dir_entry : boost::filesystem::directory_iterator(rsrc_vendor_dir)) { + // if (Slic3r::is_ini_file(dir_entry)) { + // const auto id = dir_entry.path().stem().string(); + + // if (vendors.find(id) == vendors.end()) { + // try { + // bundle.load_configbundle(dir_entry.path().string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); + + // auto vp = VendorProfile::from_ini(dir_entry.path()); + // vendors_rsrc[vp.id] = dir_entry.path().filename().string(); + // vendors[vp.id] = std::move(vp); + // } + // catch (const std::exception& e) { + // BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what(); + // } + // } + // } + // } + + // // Move materials to our Materials container: + // for (auto &&f : bundle.filaments) { + // f.vendor = nullptr; + // filaments.presets.push_back(std::move(f)); + // filaments.types.insert(Materials::get_filament_type(f)); + // } + // for (auto &&m : bundle.sla_materials) { + // m.vendor = nullptr; + // sla_materials.presets.push_back(std::move(m)); + // sla_materials.types.insert(Materials::get_material_type(m)); + // } + for (auto &pair : bundles) { + for (auto &&f : pair.second.preset_bundle->filaments) { + f.vendor = nullptr; + filaments.presets.push_back(std::move(f)); + filaments.types.insert(Materials::get_filament_type(f)); } - } - - // Additionally load up vendors from the application resources directory, but only those not seen in the datadir - for (auto &dir_entry : boost::filesystem::directory_iterator(rsrc_vendor_dir)) { - if (Slic3r::is_ini_file(dir_entry)) { - const auto id = dir_entry.path().stem().string(); - - if (vendors.find(id) == vendors.end()) { - try { - bundle.load_configbundle(dir_entry.path().string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); - - auto vp = VendorProfile::from_ini(dir_entry.path()); - vendors_rsrc[vp.id] = dir_entry.path().filename().string(); - vendors[vp.id] = std::move(vp); - } - catch (const std::exception& e) { - BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what(); - } - } + for (auto &&m : pair.second.preset_bundle->sla_materials) { + m.vendor = nullptr; + sla_materials.presets.push_back(std::move(m)); + sla_materials.types.insert(Materials::get_material_type(m)); } } - // Move materials to our Materials container: - for (auto &&f : bundle.filaments) { - f.vendor = nullptr; - filaments.presets.push_back(std::move(f)); - filaments.types.insert(Materials::get_filament_type(f)); - } - for (auto &&m : bundle.sla_materials) { - m.vendor = nullptr; - sla_materials.presets.push_back(std::move(m)); - sla_materials.types.insert(Materials::get_material_type(m)); - } - // Load up the set of vendors / models / variants the user has had enabled up till now AppConfig *app_config = wxGetApp().app_config; if (! app_config->legacy_datadir()) { @@ -1251,11 +1361,14 @@ void ConfigWizard::priv::load_vendors() } } +// TODO: This'll be done differently, cf. the design document // Load up the materials enabled till now, // apply defaults from vendor profiles if there are no selections yet. - bundle.init_materials_selection(*app_config); - wxCHECK_RET(app_config->has_section(AppConfig::SECTION_FILAMENTS) && app_config->has_section(AppConfig::SECTION_MATERIALS), - "Failed to initialize default material selections"); + // bundle.init_materials_selection(*app_config); + + // XXX: ? + // wxCHECK_RET(app_config->has_section(AppConfig::SECTION_FILAMENTS) && app_config->has_section(AppConfig::SECTION_MATERIALS), + // "Failed to initialize default material selections"); appconfig_new.set_section(AppConfig::SECTION_FILAMENTS, app_config->get_section(AppConfig::SECTION_FILAMENTS)); appconfig_new.set_section(AppConfig::SECTION_MATERIALS, app_config->get_section(AppConfig::SECTION_MATERIALS)); } @@ -1263,6 +1376,7 @@ void ConfigWizard::priv::load_vendors() void ConfigWizard::priv::add_page(ConfigWizardPage *page) { hscroll_sizer->Add(page, 0, wxEXPAND); + all_pages.push_back(page); } void ConfigWizard::priv::enable_next(bool enable) @@ -1281,6 +1395,27 @@ void ConfigWizard::priv::set_start_page(ConfigWizard::StartPage start_page) } } +void ConfigWizard::priv::create_3rdparty_pages() +{ + for (const auto &pair : bundles) { + const VendorProfile *vendor = pair.second.vendor_profile; + if (vendor->id == PresetBundle::PRUSA_BUNDLE) { continue; } + + auto *page = new PagePrinters(q, vendor->name, vendor->name, *vendor, 1, T_ANY); + add_page(page); + + pages_3rdparty.insert({vendor->id, page}); + } +} + +void ConfigWizard::priv::set_run_reason(RunReason run_reason) +{ + this->run_reason = run_reason; + for (auto &page : all_pages) { + page->set_run_reason(run_reason); + } +} + void ConfigWizard::priv::on_custom_setup() { load_pages(); @@ -1288,23 +1423,43 @@ void ConfigWizard::priv::on_custom_setup() void ConfigWizard::priv::on_printer_pick(PagePrinters *page) { - if (page == page_msla) { - const bool any_sla_selected_new = page->any_selected(); - if (any_sla_selected != any_sla_selected_new) { - any_sla_selected = any_sla_selected_new; - load_pages(); - } + if (page_msla->any_selected() != any_sla_selected || + page_fff->any_selected() != any_fff_selected) { + any_fff_selected = page_fff->any_selected(); + any_sla_selected = page_msla->any_selected(); + + load_pages(); } } +void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool install) +{ + auto it = pages_3rdparty.find(vendor->id); + wxCHECK_RET(it != pages_3rdparty.end(), "Internal error: GUI page not found for 3rd party vendor profile"); + PagePrinters *page = it->second; + page->install = install; + page->Layout(); + + load_pages(); +} + void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater) { const auto enabled_vendors = appconfig_new.vendors(); // Install bundles from resources if needed: std::vector install_bundles; - for (const auto &vendor_rsrc : vendors_rsrc) { - const auto vendor = enabled_vendors.find(vendor_rsrc.first); + for (const auto &pair : bundles) { + if (! pair.second.is_in_resources) { continue; } + + if (pair.second.is_prusa_bundle) { + // Always install Prusa bundle, because it has a lot of filaments/materials + // likely to be referenced by other profiles. + install_bundles.emplace_back(pair.first); + continue; + } + + const auto vendor = enabled_vendors.find(pair.first); if (vendor == enabled_vendors.end()) { continue; } size_t size_sum = 0; @@ -1312,7 +1467,7 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese if (size_sum > 0) { // This vendor needs to be installed - install_bundles.emplace_back(vendor_rsrc.second); + install_bundles.emplace_back(pair.first); } } @@ -1370,17 +1525,18 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese // The default is the first selected printer model (one with at least 1 variant selected). // The default is only applied by load_presets() if the user doesn't have a (visible) printer // selected already. - const auto vendor_prusa = vendors.find("PrusaResearch"); - const auto config_prusa = enabled_vendors.find("PrusaResearch"); - if (vendor_prusa != vendors.end() && config_prusa != enabled_vendors.end()) { - for (const auto &model : vendor_prusa->second.models) { - const auto model_it = config_prusa->second.find(model.id); - if (model_it != config_prusa->second.end() && model_it->second.size() > 0) { - preferred_model = model.id; - break; - } - } - } +// TODO + // const auto vendor_prusa = bundle.vendors.find("PrusaResearch"); + // const auto config_prusa = enabled_vendors.find("PrusaResearch"); + // if (vendor_prusa != bundle.vendors.end() && config_prusa != enabled_vendors.end()) { + // for (const auto &model : vendor_prusa->second.models) { + // const auto model_it = config_prusa->second.find(model.id); + // if (model_it != config_prusa->second.end() && model_it->second.size() > 0) { + // preferred_model = model.id; + // break; + // } + // } + // } preset_bundle->load_presets(*app_config, preferred_model); @@ -1398,10 +1554,11 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese preset_bundle->export_selections(*app_config); } + // Public -ConfigWizard::ConfigWizard() - : DPIDialog(nullptr, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + name(), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +ConfigWizard::ConfigWizard(wxWindow *parent) + : DPIDialog(parent, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + name(), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) , p(new priv(this)) { this->SetFont(wxGetApp().normal_font()); @@ -1441,17 +1598,16 @@ ConfigWizard::ConfigWizard() p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING); p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING); - const auto &vendors = p->vendors; - const auto vendor_prusa_it = vendors.find("PrusaResearch"); - wxCHECK_RET(vendor_prusa_it != vendors.cend(), "Vendor PrusaResearch not found"); - const VendorProfile &vendor_prusa = vendor_prusa_it->second; + const auto prusa_it = p->bundles.find("PrusaResearch"); + wxCHECK_RET(prusa_it != p->bundles.cend(), "Vendor PrusaResearch not found"); + const VendorProfile *vendor_prusa = prusa_it->second.vendor_profile; p->add_page(p->page_welcome = new PageWelcome(this)); - p->page_fff = new PagePrinters(this, _(L("Prusa FFF Technology Printers")), "Prusa FFF", vendor_prusa, 0, T_FFF); + p->page_fff = new PagePrinters(this, _(L("Prusa FFF Technology Printers")), "Prusa FFF", *vendor_prusa, 0, T_FFF); p->add_page(p->page_fff); - p->page_msla = new PagePrinters(this, _(L("Prusa MSLA Technology Printers")), "Prusa MSLA", vendor_prusa, 0, T_SLA); + p->page_msla = new PagePrinters(this, _(L("Prusa MSLA Technology Printers")), "Prusa MSLA", *vendor_prusa, 0, T_SLA); p->add_page(p->page_msla); p->add_page(p->page_filaments = new PageMaterials(this, &p->filaments, @@ -1467,7 +1623,10 @@ ConfigWizard::ConfigWizard() p->add_page(p->page_diams = new PageDiameters(this)); p->add_page(p->page_temps = new PageTemperatures(this)); + p->create_3rdparty_pages(); + p->any_sla_selected = p->page_msla->any_selected(); + p->any_fff_selected = p->page_fff->any_selected(); p->load_pages(); vsizer->Add(topsizer, 1, wxEXPAND | wxALL, DIALOG_MARGIN); @@ -1514,7 +1673,7 @@ bool ConfigWizard::run(RunReason reason, StartPage start_page) GUI_App &app = wxGetApp(); - p->run_reason = reason; + p->set_run_reason(reason); p->set_start_page(start_page); if (ShowModal() == wxID_OK) { diff --git a/src/slic3r/GUI/ConfigWizard.hpp b/src/slic3r/GUI/ConfigWizard.hpp index 3c85b73432..942f4b4ce8 100644 --- a/src/slic3r/GUI/ConfigWizard.hpp +++ b/src/slic3r/GUI/ConfigWizard.hpp @@ -34,7 +34,7 @@ public: SP_MATERIALS, }; - ConfigWizard(); + ConfigWizard(wxWindow *parent); ConfigWizard(ConfigWizard &&) = delete; ConfigWizard(const ConfigWizard &) = delete; ConfigWizard &operator=(ConfigWizard &&) = delete; diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 82708cc59b..e6f389785b 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -21,7 +21,8 @@ #include "libslic3r/PrintConfig.hpp" #include "slic3r/Utils/PresetUpdater.hpp" #include "AppConfig.hpp" -#include "Preset.hpp" +// #include "Preset.hpp" +#include "PresetBundle.hpp" #include "BedShapeDialog.hpp" namespace fs = boost::filesystem; @@ -43,13 +44,70 @@ enum { ROW_SPACING = 75, }; + + +// Configuration data structures extensions needed for the wizard + enum Technology { // Bitflag equivalent of PrinterTechnology T_FFF = 0x1, T_SLA = 0x2, - T_Any = ~0, + T_ANY = ~0, }; +struct Materials +{ + Technology technology; + std::vector presets; + std::set types; + + Materials(Technology technology) : technology(technology) {} + + const std::string& appconfig_section() const; + const std::string& get_type(Preset &preset) const; + const std::string& get_vendor(Preset &preset) const; + + template void filter_presets(const std::string &type, const std::string &vendor, F cb) { + for (Preset &preset : presets) { + if ((type.empty() || get_type(preset) == type) && (vendor.empty() || get_vendor(preset) == vendor)) { + cb(preset); + } + } + } + + static const std::string UNKNOWN; + static const std::string& get_filament_type(const Preset &preset); + static const std::string& get_filament_vendor(const Preset &preset); + static const std::string& get_material_type(Preset &preset); + static const std::string& get_material_vendor(const Preset &preset); +}; + +struct Bundle +{ + fs::path source_path; // XXX: not needed? + std::unique_ptr preset_bundle; + VendorProfile *vendor_profile; + const bool is_in_resources; + const bool is_prusa_bundle; + + Bundle(fs::path source_path, bool is_in_resources, bool is_prusa_bundle = false); + Bundle(Bundle &&other); + + const std::string& vendor_id() const { return vendor_profile->id; } +}; + +struct BundleMap: std::unordered_map +{ + static BundleMap load(); + + Bundle& prusa_bundle(); + const Bundle& prusa_bundle() const; +}; + + + +// GUI elements + typedef std::function ModelFilter; struct PrinterPicker: wxPanel @@ -79,6 +137,8 @@ struct PrinterPicker: wxPanel int get_width() const { return width; } const std::vector& get_button_indexes() { return m_button_indexes; } + + static const std::string PRINTER_PLACEHOLDER; private: int width; std::vector m_button_indexes; @@ -97,65 +157,50 @@ struct ConfigWizardPage: wxPanel virtual ~ConfigWizardPage(); template - void append(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) + T* append(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) { content->Add(thing, proportion, flag, border); + return thing; } - void append_text(wxString text); + wxStaticText* append_text(wxString text); void append_spacer(int space); ConfigWizard::priv *wizard_p() const { return parent->p.get(); } virtual void apply_custom_config(DynamicPrintConfig &config) {} + virtual void set_run_reason(ConfigWizard::RunReason run_reason) {} }; struct PageWelcome: ConfigWizardPage { + wxStaticText *welcome_text; wxCheckBox *cbox_reset; PageWelcome(ConfigWizard *parent); bool reset_user_profile() const { return cbox_reset != nullptr ? cbox_reset->GetValue() : false; } + + virtual void set_run_reason(ConfigWizard::RunReason run_reason) override; }; struct PagePrinters: ConfigWizardPage { std::vector printer_pickers; + Technology technology; + bool install; - PagePrinters(ConfigWizard *parent, wxString title, wxString shortname, const VendorProfile &vendor, unsigned indent, Technology technology); + PagePrinters(ConfigWizard *parent, + wxString title, + wxString shortname, + const VendorProfile &vendor, + unsigned indent, Technology technology); void select_all(bool select, bool alternates = false); int get_width() const; bool any_selected() const; -}; - -struct Materials -{ - Technology technology; - std::vector presets; - std::set types; - - Materials(Technology technology) : technology(technology) {} - - const std::string& appconfig_section() const; - const std::string& get_type(Preset &preset) const; - const std::string& get_vendor(Preset &preset) const; - - template void filter_presets(const std::string &type, const std::string &vendor, F cb) { - for (Preset &preset : presets) { - if ((type.empty() || get_type(preset) == type) && (vendor.empty() || get_vendor(preset) == vendor)) { - cb(preset); - } - } - } - - static const std::string UNKNOWN; - static const std::string& get_filament_type(const Preset &preset); - static const std::string& get_filament_vendor(const Preset &preset); - static const std::string& get_material_type(Preset &preset); - static const std::string& get_material_vendor(const Preset &preset); + virtual void set_run_reason(ConfigWizard::RunReason run_reason) override; }; // Here we extend wxListBox and wxCheckListBox @@ -232,11 +277,11 @@ struct PageUpdate: ConfigWizardPage struct PageVendors: ConfigWizardPage { - std::vector pickers; + // std::vector pickers; PageVendors(ConfigWizard *parent); - void on_vendor_pick(size_t i); + // void on_vendor_pick(size_t i); }; struct PageFirmware: ConfigWizardPage @@ -290,7 +335,7 @@ public: void go_prev(); void go_next(); void go_to(size_t i); - void go_to(ConfigWizardPage *page); + void go_to(const ConfigWizardPage *page); void clear(); void msw_rescale(); @@ -328,16 +373,24 @@ private: wxDEFINE_EVENT(EVT_INDEX_PAGE, wxCommandEvent); + +// ConfigWizard private data + struct ConfigWizard::priv { ConfigWizard *q; ConfigWizard::RunReason run_reason = RR_USER; AppConfig appconfig_new; // Backing for vendor/model/variant and material selections in the GUI - std::unordered_map vendors; + // std::unordered_map vendors; + // PresetBundle bundle; // XXX: comment + BundleMap bundles; // XXX: comment Materials filaments; // Holds available filament presets and their types & vendors Materials sla_materials; // Ditto for SLA materials - std::unordered_map vendors_rsrc; // List of bundles to install from resources + // std::set install_3rdparty; + // XXX: rm: (?) + // std::unordered_map vendors_rsrc; // List of bundles to install from resources std::unique_ptr custom_config; // Backing for custom printer definition + bool any_fff_selected; // Used to decide whether to display Filaments page bool any_sla_selected; // Used to decide whether to display SLA Materials page wxScrolledWindow *hscroll = nullptr; @@ -359,6 +412,7 @@ struct ConfigWizard::priv PageCustom *page_custom = nullptr; PageUpdate *page_update = nullptr; PageVendors *page_vendors = nullptr; // XXX: ? + std::map pages_3rdparty; // Custom setup pages PageFirmware *page_firmware = nullptr; @@ -366,6 +420,9 @@ struct ConfigWizard::priv PageDiameters *page_diams = nullptr; PageTemperatures *page_temps = nullptr; + // Pointers to all pages (regardless or whether currently part of the ConfigWizardIndex) + std::vector all_pages; + priv(ConfigWizard *q) : q(q) , filaments(T_FFF) @@ -376,14 +433,16 @@ struct ConfigWizard::priv void load_pages(); void init_dialog_size(); - bool check_first_variant() const; void load_vendors(); void add_page(ConfigWizardPage *page); void enable_next(bool enable); void set_start_page(ConfigWizard::StartPage start_page); + void create_3rdparty_pages(); + void set_run_reason(RunReason run_reason); void on_custom_setup(); void on_printer_pick(PagePrinters *page); + void on_3rdparty_install(const VendorProfile *vendor, bool install); // XXX: ? void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 028886915d..b5d9c3d61c 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1059,8 +1059,10 @@ void GUI_App::open_web_page_localized(const std::string &http_address) bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage start_page) { + wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null"); + if (! m_wizard) { - m_wizard.reset(new ConfigWizard()); + m_wizard = new ConfigWizard(mainframe); } const bool res = m_wizard->run(reason, start_page); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 8c5f0c30c8..c5ddc01528 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -98,7 +98,7 @@ class GUI_App : public wxApp std::unique_ptr m_imgui; std::unique_ptr m_printhost_job_queue; - std::unique_ptr m_wizard; + ConfigWizard* m_wizard; // Managed by wxWindow tree public: bool OnInit() override; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index bda096d66d..be53267f9c 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -1318,7 +1318,7 @@ bool PresetCollection::select_preset_by_name_strict(const std::string &name) } // Merge one vendor's presets with the other vendor's presets, report duplicates. -std::vector PresetCollection::merge_presets(PresetCollection &&other, const std::set &new_vendors) +std::vector PresetCollection::merge_presets(PresetCollection &&other, const VendorMap &new_vendors) { std::vector duplicates; for (Preset &preset : other.m_presets) { @@ -1329,9 +1329,9 @@ std::vector PresetCollection::merge_presets(PresetCollection &&othe if (it == m_presets.end() || it->name != preset.name) { if (preset.vendor != nullptr) { // Re-assign a pointer to the vendor structure in the new PresetBundle. - auto it = new_vendors.find(*preset.vendor); + auto it = new_vendors.find(preset.vendor->id); assert(it != new_vendors.end()); - preset.vendor = &(*it); + preset.vendor = &it->second; } this->m_presets.emplace(it, std::move(preset)); } else diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index dfb72d495e..8be1388f09 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -2,6 +2,8 @@ #define slic3r_Preset_hpp_ #include +#include +#include #include #include @@ -89,6 +91,12 @@ public: bool operator==(const VendorProfile &rhs) const { return this->id == rhs.id; } }; +// Note: it is imporant that map is used here rather than unordered_map, +// because we need iterators to not be invalidated, +// because Preset and the ConfigWizard hold pointers to VendorProfiles. +// XXX: maybe set is enough (cf. changes in Wizard) +typedef std::map VendorMap; + class Preset { public: @@ -435,7 +443,7 @@ protected: bool select_preset_by_name_strict(const std::string &name); // Merge one vendor's presets with the other vendor's presets, report duplicates. - std::vector merge_presets(PresetCollection &&other, const std::set &new_vendors); + std::vector merge_presets(PresetCollection &&other, const VendorMap &new_vendors); private: PresetCollection(); diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 5f91111115..579c74dcac 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -41,6 +41,8 @@ static std::vector s_project_options { "wiping_volumes_matrix" }; +const char *PresetBundle::PRUSA_BUNDLE = "PrusaResearch"; + PresetBundle::PresetBundle() : prints(Preset::TYPE_PRINT, Preset::print_options(), static_cast(FullPrintConfig::defaults())), filaments(Preset::TYPE_FILAMENT, Preset::filament_options(), static_cast(FullPrintConfig::defaults())), @@ -244,6 +246,48 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_ this->load_selections(config, preferred_model_id); } +// FIXME: Comment +// XXX: rm +void PresetBundle::load_available_system_presets() +{ + const auto vendor_dir = (boost::filesystem::path(Slic3r::data_dir()) / "vendor").make_preferred(); + const auto rsrc_vendor_dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred(); + + const auto prusa_bundle_vendor = (vendor_dir / PRUSA_BUNDLE).replace_extension(".ini"); + const auto prusa_bundle = boost::filesystem::exists(prusa_bundle_vendor) ? prusa_bundle_vendor + : (rsrc_vendor_dir / PRUSA_BUNDLE).replace_extension(".ini"); + + // Reset this PresetBundle and load the Prusa bundle first. + this->load_configbundle(prusa_bundle.string(), LOAD_CFGBNDLE_SYSTEM); + + // Load the other bundles in the datadir/vendor directory + // and then additionally from resources/profiles. + for (auto dir : { &vendor_dir, &rsrc_vendor_dir }) { + for (const auto &dir_entry : boost::filesystem::directory_iterator(*dir)) { + if (Slic3r::is_ini_file(dir_entry)) { + std::string id = dir_entry.path().stem().string(); // stem() = filename() without the trailing ".ini" part + + // Don't load this bundle if we've already loaded it. + // Note that this takes care of not loading the PRUSA_BUNDLE which was loaded upfront + // as well as bundles with the same name (id) in rsrc_vendor_dir as in vendor_dir. + if (vendors.find(id) != vendors.end()) { continue; } + + PresetBundle other; + other.load_configbundle(dir_entry.path().string(), LOAD_CFGBNDLE_SYSTEM); + + std::vector duplicates = this->merge_presets(std::move(other)); + if (! duplicates.empty()) { + std::string msg = "Vendor configuration file " + id + " contains the following presets with names used by other vendors: "; + for (size_t i = 0; i < duplicates.size(); ++ i) { + if (i > 0) { msg += ", "; } + msg += duplicates[i]; + } + } + } + } + } +} + // Load system presets into this PresetBundle. // For each vendor, there will be a single PresetBundle loaded. std::string PresetBundle::load_system_presets() @@ -414,14 +458,14 @@ void PresetBundle::export_selections(AppConfig &config) void PresetBundle::init_materials_selection(AppConfig &config) const { if (! config.has_section(AppConfig::SECTION_FILAMENTS)) { for (const auto &vendor : this->vendors) { - for (const auto &profile : vendor.default_filaments) { + for (const auto &profile : vendor.second.default_filaments) { config.set(AppConfig::SECTION_FILAMENTS, profile, "1"); } } } if (! config.has_section(AppConfig::SECTION_MATERIALS)) { for (const auto &vendor : this->vendors) { - for (const auto &profile : vendor.default_sla_materials) { + for (const auto &profile : vendor.second.default_sla_materials) { config.set(AppConfig::SECTION_MATERIALS, profile, "1"); } } @@ -1061,9 +1105,9 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla auto vp = VendorProfile::from_ini(tree, path); if (vp.num_variants() == 0) return 0; - vendor_profile = &(*this->vendors.insert(vp).first); + vendor_profile = &this->vendors.insert({vp.id, vp}).first->second; } - + if (flags & LOAD_CFGBUNDLE_VENDOR_ONLY) { return 0; } diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index 847b370187..d7ec5e3f09 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -4,7 +4,9 @@ #include "AppConfig.hpp" #include "Preset.hpp" +#include #include +#include #include class wxWindow; @@ -56,7 +58,8 @@ public: // There will be an entry for each system profile loaded, // and the system profiles will point to the VendorProfile instances owned by PresetBundle::vendors. - std::set vendors; + // std::set vendors; + VendorMap vendors; struct ObsoletePresets { std::vector prints; @@ -135,6 +138,9 @@ public: void load_default_preset_bitmaps(wxWindow *window); + void load_available_system_presets(); // XXX: name XXX: retval (VendorMap stored internally) + + static const char *PRUSA_BUNDLE; private: std::string load_system_presets(); // Merge one vendor's presets with the other vendor's presets, report duplicates. diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index cafdbb14ef..3cebf2f89e 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -153,7 +153,7 @@ struct PresetUpdater::priv bool get_file(const std::string &url, const fs::path &target_path) const; void prune_tmps() const; void sync_version() const; - void sync_config(const std::set vendors); + void sync_config(const VendorMap vendors); void check_install_indices() const; Updates get_config_updates() const; @@ -266,7 +266,7 @@ void PresetUpdater::priv::sync_version() const // Download vendor indices. Also download new bundles if an index indicates there's a new one available. // Both are saved in cache. -void PresetUpdater::priv::sync_config(const std::set vendors) +void PresetUpdater::priv::sync_config(const VendorMap vendors) { BOOST_LOG_TRIVIAL(info) << "Syncing configuration cache"; @@ -276,13 +276,13 @@ void PresetUpdater::priv::sync_config(const std::set vendors) for (auto &index : index_db) { if (cancel) { return; } - const auto vendor_it = vendors.find(VendorProfile(index.vendor())); + const auto vendor_it = vendors.find(index.vendor()); if (vendor_it == vendors.end()) { BOOST_LOG_TRIVIAL(warning) << "No such vendor: " << index.vendor(); continue; } - const VendorProfile &vendor = *vendor_it; + const VendorProfile &vendor = vendor_it->second; if (vendor.config_update_url.empty()) { BOOST_LOG_TRIVIAL(info) << "Vendor has no config_update_url: " << vendor.name; continue; @@ -574,7 +574,7 @@ void PresetUpdater::sync(PresetBundle *preset_bundle) // Copy the whole vendors data for use in the background thread // Unfortunatelly as of C++11, it needs to be copied again // into the closure (but perhaps the compiler can elide this). - std::set vendors = preset_bundle->vendors; + VendorMap vendors = preset_bundle->vendors; p->thread = std::move(std::thread([this, vendors]() { this->p->prune_tmps(); @@ -691,8 +691,8 @@ void PresetUpdater::install_bundles_rsrc(std::vector bundles, bool BOOST_LOG_TRIVIAL(info) << boost::format("Installing %1% bundles from resources ...") % bundles.size(); for (const auto &bundle : bundles) { - auto path_in_rsrc = p->rsrc_path / bundle; - auto path_in_vendors = p->vendor_path / bundle; + auto path_in_rsrc = (p->rsrc_path / bundle).replace_extension(".ini"); + auto path_in_vendors = (p->vendor_path / bundle).replace_extension(".ini"); updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", ""); } From 270008a3fd7bade37d5cd26e1c219fa26cc42738 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 2 Aug 2019 16:15:27 +0200 Subject: [PATCH 05/23] Add material_type config option for SLA materials, use in Wizard --- resources/profiles/PrusaResearch.ini | 2 + src/libslic3r/PrintConfig.cpp | 12 ++++ src/libslic3r/PrintConfig.hpp | 8 +++ src/slic3r/GUI/ConfigWizard.cpp | 79 ++++++++++++++----------- src/slic3r/GUI/ConfigWizard_private.hpp | 10 ++-- src/slic3r/GUI/Preset.cpp | 1 + 6 files changed, 71 insertions(+), 41 deletions(-) diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 6904713346..9add73b4dc 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -1966,6 +1966,7 @@ exposure_time = 6 initial_exposure_time = 40 [sla_material:BlueCast Keramaster Dental 0.025] +material_type = Dental inherits = *common 0.025* exposure_time = 6 initial_exposure_time = 45 @@ -2042,6 +2043,7 @@ initial_exposure_time = 45 material_vendor = Bluecast [sla_material:BlueCast Keramaster Dental 0.05] +material_type = Dental inherits = *common 0.05* exposure_time = 7 initial_exposure_time = 50 diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ac30941cb1..6a57125d01 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2401,6 +2401,18 @@ void PrintConfigDef::init_sla_params() // SLA Material settings. + def = this->add("material_type", coString); + def->label = L("SLA material type"); + def->tooltip = L("SLA material type"); + def->gui_type = "f_enum_open"; // TODO: ??? + def->gui_flags = "show_value"; + def->enum_values.push_back("Tough"); + def->enum_values.push_back("Flexible"); + def->enum_values.push_back("Casting"); + def->enum_values.push_back("Dental"); + def->enum_values.push_back("Heat-resistant"); + def->set_default_value(new ConfigOptionString("Tough")); + def = this->add("initial_layer_height", coFloat); def->label = L("Initial layer height"); def->tooltip = L("Initial layer height"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6a19edf845..fc1916f1bf 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -52,6 +52,14 @@ enum FilamentType { }; */ +enum SLAMaterial { + slamTough, + slamFlex, + slamCasting, + slamDental, + slamHeatResistant, +}; + enum SLADisplayOrientation { sladoLandscape, sladoPortrait diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 8a850b7a0b..1c70ad7261 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -235,7 +235,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt auto *cbox = new Checkbox(variants_panel, label, model_id, variant.name); i == 0 ? cboxes.push_back(cbox) : cboxes_alt.push_back(cbox); - bool enabled = appconfig.get_variant(vendor.id, model_id, variant.name); + const bool enabled = appconfig.get_variant(vendor.id, model_id, variant.name); cbox->SetValue(enabled); variants_sizer->Add(cbox, 0, wxBOTTOM, 3); @@ -731,10 +731,7 @@ PageUpdate::PageUpdate(ConfigWizard *parent) PageVendors::PageVendors(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) { - - - // FIXME: persistence: this doesn't reload choices - + const AppConfig &appconfig = this->wizard_p()->appconfig_new; append_text(wxString::Format(_(L("Pick another vendor supported by %s: (FIXME: this text)")), SLIC3R_APP_NAME)); @@ -750,6 +747,16 @@ PageVendors::PageVendors(ConfigWizard *parent) wizard_p()->on_3rdparty_install(vendor, cbox->IsChecked()); }); + const auto &vendors = appconfig.vendors(); + const bool enabled = vendors.find(pair.first) != vendors.end(); + if (enabled) { + cbox->SetValue(true); + + auto pair = wizard_p()->pages_3rdparty.find(vendor->id); + wxCHECK_RET(pair != wizard_p()->pages_3rdparty.end(), "Internal error: 3rd party vendor printers page not created"); + pair->second->install = true; + } + append(cbox); } } @@ -866,18 +873,18 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config) auto set_extrusion_width = [&config, opt_nozzle](const char *key, double dmr) { char buf[64]; sprintf(buf, "%.2lf", dmr * opt_nozzle->values.front() / 0.4); - config.set_key_value(key, new ConfigOptionFloatOrPercent(atof(buf), false)); - }; + config.set_key_value(key, new ConfigOptionFloatOrPercent(atof(buf), false)); + }; set_extrusion_width("support_material_extrusion_width", 0.35); - set_extrusion_width("top_infill_extrusion_width", 0.40); - set_extrusion_width("first_layer_extrusion_width", 0.42); + set_extrusion_width("top_infill_extrusion_width", 0.40); + set_extrusion_width("first_layer_extrusion_width", 0.42); - set_extrusion_width("extrusion_width", 0.45); - set_extrusion_width("perimeter_extrusion_width", 0.45); - set_extrusion_width("external_perimeter_extrusion_width", 0.45); - set_extrusion_width("infill_extrusion_width", 0.45); - set_extrusion_width("solid_infill_extrusion_width", 0.45); + set_extrusion_width("extrusion_width", 0.45); + set_extrusion_width("perimeter_extrusion_width", 0.45); + set_extrusion_width("external_perimeter_extrusion_width", 0.45); + set_extrusion_width("infill_extrusion_width", 0.45); + set_extrusion_width("solid_infill_extrusion_width", 0.45); } PageTemperatures::PageTemperatures(ConfigWizard *parent) @@ -1114,7 +1121,7 @@ void ConfigWizardIndex::on_mouse_move(wxMouseEvent &evt) const ssize_t item_hover_new = pos.y / item_height(); - if (item_hover_new < ssize_t(items.size()) && item_hover_new != item_hover) { + if (item_hover_new < ssize_t(items.size()) && item_hover_new != item_hover) { item_hover = item_hover_new; Refresh(); } @@ -1176,19 +1183,11 @@ const std::string& Materials::get_filament_vendor(const Preset &preset) const std::string& Materials::get_material_type(Preset &preset) { - // XXX: The initial_layer_height is of a float type and contains no string to reference, - // and so here we serialize it into an ad-hoc option initial_layer_height_str, which is then referenced - - const auto *opt_str = preset.config.opt("initial_layer_height_str"); - if (opt_str == nullptr) { - const auto *opt = preset.config.opt("initial_layer_height"); - if (opt == nullptr) { return UNKNOWN; } - - auto *new_opt_str = new ConfigOptionString(opt->serialize()); - preset.config.set_key_value("initial_layer_height_str", new_opt_str); - return new_opt_str->value; + const auto *opt = preset.config.opt("material_type"); + if (opt != nullptr) { + return opt->value; } else { - return opt_str->value; + return UNKNOWN; } } @@ -1366,11 +1365,16 @@ void ConfigWizard::priv::load_vendors() // apply defaults from vendor profiles if there are no selections yet. // bundle.init_materials_selection(*app_config); - // XXX: ? - // wxCHECK_RET(app_config->has_section(AppConfig::SECTION_FILAMENTS) && app_config->has_section(AppConfig::SECTION_MATERIALS), - // "Failed to initialize default material selections"); - appconfig_new.set_section(AppConfig::SECTION_FILAMENTS, app_config->get_section(AppConfig::SECTION_FILAMENTS)); - appconfig_new.set_section(AppConfig::SECTION_MATERIALS, app_config->get_section(AppConfig::SECTION_MATERIALS)); + // TODO: load up sane defaults if no previous data in AppConfig + // as per the design doc: + // - all f/m for installed printers if prev Slicer version + // - default f/m set from bundle + default for each printer from bundle if fresh install + if (app_config->has_section(AppConfig::SECTION_FILAMENTS)) { + appconfig_new.set_section(AppConfig::SECTION_FILAMENTS, app_config->get_section(AppConfig::SECTION_FILAMENTS)); + } + if (app_config->has_section(AppConfig::SECTION_MATERIALS)) { + appconfig_new.set_section(AppConfig::SECTION_MATERIALS, app_config->get_section(AppConfig::SECTION_MATERIALS)); + } } void ConfigWizard::priv::add_page(ConfigWizardPage *page) @@ -1437,6 +1441,10 @@ void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool i auto it = pages_3rdparty.find(vendor->id); wxCHECK_RET(it != pages_3rdparty.end(), "Internal error: GUI page not found for 3rd party vendor profile"); PagePrinters *page = it->second; + + if (page->install && !install) { + page->select_all(false); + } page->install = install; page->Layout(); @@ -1525,7 +1533,7 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese // The default is the first selected printer model (one with at least 1 variant selected). // The default is only applied by load_presets() if the user doesn't have a (visible) printer // selected already. -// TODO +// TODO: // const auto vendor_prusa = bundle.vendors.find("PrusaResearch"); // const auto config_prusa = enabled_vendors.find("PrusaResearch"); // if (vendor_prusa != bundle.vendors.end() && config_prusa != enabled_vendors.end()) { @@ -1617,13 +1625,14 @@ ConfigWizard::ConfigWizard(wxWindow *parent) p->add_page(p->page_custom = new PageCustom(this)); p->add_page(p->page_update = new PageUpdate(this)); - p->add_page(p->page_vendors = new PageVendors(this)); p->add_page(p->page_firmware = new PageFirmware(this)); p->add_page(p->page_bed = new PageBedShape(this)); p->add_page(p->page_diams = new PageDiameters(this)); p->add_page(p->page_temps = new PageTemperatures(this)); - p->create_3rdparty_pages(); + // Pages for 3rd party vendors + p->create_3rdparty_pages(); // Needs to ne done _before_ creating PageVendors + p->add_page(p->page_vendors = new PageVendors(this)); p->any_sla_selected = p->page_msla->any_selected(); p->any_fff_selected = p->page_fff->any_selected(); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index e6f389785b..708eb94fc6 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -96,7 +96,7 @@ struct Bundle const std::string& vendor_id() const { return vendor_profile->id; } }; -struct BundleMap: std::unordered_map +struct BundleMap: std::unordered_map { static BundleMap load(); @@ -277,11 +277,7 @@ struct PageUpdate: ConfigWizardPage struct PageVendors: ConfigWizardPage { - // std::vector pickers; - PageVendors(ConfigWizard *parent); - - // void on_vendor_pick(size_t i); }; struct PageFirmware: ConfigWizardPage @@ -319,6 +315,8 @@ struct PageTemperatures: ConfigWizardPage virtual void apply_custom_config(DynamicPrintConfig &config); }; +typedef std::map Pages3rdparty; + class ConfigWizardIndex: public wxPanel { @@ -412,7 +410,7 @@ struct ConfigWizard::priv PageCustom *page_custom = nullptr; PageUpdate *page_update = nullptr; PageVendors *page_vendors = nullptr; // XXX: ? - std::map pages_3rdparty; + Pages3rdparty pages_3rdparty; // Custom setup pages PageFirmware *page_firmware = nullptr; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index be53267f9c..9b16d94801 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -531,6 +531,7 @@ const std::vector& Preset::sla_material_options() static std::vector s_opts; if (s_opts.empty()) { s_opts = { + "material_type", "initial_layer_height", "exposure_time", "initial_exposure_time", From 9a465514ff1169d9fece05449d37285f4997b346 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 27 Aug 2019 16:59:07 +0200 Subject: [PATCH 06/23] Filament and material default installation based on enabled printers --- src/slic3r/GUI/PresetBundle.cpp | 74 +++++++++++++++++++++++---------- src/slic3r/GUI/PresetBundle.hpp | 11 ++--- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 579c74dcac..e3ee84e872 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -239,10 +240,6 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_ if (! errors_cummulative.empty()) throw std::runtime_error(errors_cummulative); - // Make sure there are filament / material selections in the AppConfig, - // if there are none, load up defaults from vendor profiles. - this->init_materials_selection(config); - this->load_selections(config, preferred_model_id); } @@ -371,10 +368,56 @@ void PresetBundle::load_installed_printers(const AppConfig &config) for (auto &preset : printers) { preset.set_visible_from_appconfig(config); } +} + +void PresetBundle::load_installed_filaments(AppConfig &config) +{ + if (! config.has_section(AppConfig::SECTION_FILAMENTS)) { + std::unordered_set comp_filaments; + + for (const Preset &printer : printers) { + if (! printer.is_visible || printer.printer_technology() != ptFFF) { + continue; + } + + for (const Preset &filament : filaments) { + if (filament.is_compatible_with_printer(printer)) { + comp_filaments.insert(&filament); + } + } + } + + for (const auto &filament: comp_filaments) { + config.set(AppConfig::SECTION_FILAMENTS, filament->name, "1"); + } + } for (auto &preset : filaments) { preset.set_visible_from_appconfig(config); } +} + +void PresetBundle::load_installed_sla_materials(AppConfig &config) +{ + if (! config.has_section(AppConfig::SECTION_MATERIALS)) { + std::unordered_set comp_sla_materials; + + for (const Preset &printer : printers) { + if (! printer.is_visible || printer.printer_technology() != ptSLA) { + continue; + } + + for (const Preset &material : sla_materials) { + if (material.is_compatible_with_printer(printer)) { + comp_sla_materials.insert(&material); + } + } + } + + for (const auto &material: comp_sla_materials) { + config.set(AppConfig::SECTION_MATERIALS, material->name, "1"); + } + } for (auto &preset : sla_materials) { preset.set_visible_from_appconfig(config); @@ -383,11 +426,15 @@ void PresetBundle::load_installed_printers(const AppConfig &config) // Load selections (current print, current filaments, current printer) from config.ini // This is done on application start up or after updates are applied. -void PresetBundle::load_selections(const AppConfig &config, const std::string &preferred_model_id) +void PresetBundle::load_selections(AppConfig &config, const std::string &preferred_model_id) { // Update visibility of presets based on application vendor / model / variant configuration. this->load_installed_printers(config); + // Update visibility of filament and sla material presets + this->load_installed_filaments(config); + this->load_installed_sla_materials(config); + // Parse the initial print / filament / printer profile names. std::string initial_print_profile_name = remove_ini_suffix(config.get("presets", "print")); std::string initial_sla_print_profile_name = remove_ini_suffix(config.get("presets", "sla_print")); @@ -455,23 +502,6 @@ void PresetBundle::export_selections(AppConfig &config) config.set("presets", "printer", printers.get_selected_preset_name()); } -void PresetBundle::init_materials_selection(AppConfig &config) const { - if (! config.has_section(AppConfig::SECTION_FILAMENTS)) { - for (const auto &vendor : this->vendors) { - for (const auto &profile : vendor.second.default_filaments) { - config.set(AppConfig::SECTION_FILAMENTS, profile, "1"); - } - } - } - if (! config.has_section(AppConfig::SECTION_MATERIALS)) { - for (const auto &vendor : this->vendors) { - for (const auto &profile : vendor.second.default_sla_materials) { - config.set(AppConfig::SECTION_MATERIALS, profile, "1"); - } - } - } -} - void PresetBundle::load_compatible_bitmaps(wxWindow *window) { // We don't actually pass the window pointer here and instead generate diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index d7ec5e3f09..0fea2a0f8a 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -38,10 +38,6 @@ public: // Export selections (current print, current filaments, current printer) into config.ini void export_selections(AppConfig &config); - // Make sure filament and sla_materials section in AppConfig are initialized - // to defaults from vendor profiles if they don't exist already - void init_materials_selection(AppConfig &config) const; - PresetCollection prints; PresetCollection sla_prints; PresetCollection filaments; @@ -151,9 +147,14 @@ private: // If the "vendor" section is missing, enable all models and variants of the particular vendor. void load_installed_printers(const AppConfig &config); + // Set the enabled flag for filaments and sla materials, + // apply defaults based on enabled printers when no filaments/materials are installed. + void load_installed_filaments(AppConfig &config); + void load_installed_sla_materials(AppConfig &config); + // Load selections (current print, current filaments, current printer) from config.ini // This is done just once on application start up. - void load_selections(const AppConfig &config, const std::string &preferred_model_id = ""); + void load_selections(AppConfig &config, const std::string &preferred_model_id = ""); // Load print, filament & printer presets from a config. If it is an external config, then the name is extracted from the external path. // and the external config is just referenced, not stored into user profile directory. From c5a67ff931f78adb78ed853756ba46c8d9da0fd4 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 30 Aug 2019 17:40:25 +0200 Subject: [PATCH 07/23] WIP: filament/material filtering per selected printers --- src/slic3r/GUI/ConfigWizard.cpp | 267 +++++++++++++++--------- src/slic3r/GUI/ConfigWizard_private.hpp | 52 +++-- src/slic3r/GUI/PresetBundle.hpp | 13 +- 3 files changed, 206 insertions(+), 126 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 1c70ad7261..691a2f2cdc 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -475,7 +475,7 @@ PagePrinters::PagePrinters(ConfigWizard *parent, picker->Bind(EVT_PRINTER_PICK, [this, appconfig](const PrinterPickerEvent &evt) { appconfig->set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); - wizard_p()->on_printer_pick(this); + wizard_p()->on_printer_pick(this, evt); }); append(new wxStaticLine(this)); @@ -527,6 +527,7 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin , list_l3(new PresetList(this)) , sel1_prev(wxNOT_FOUND) , sel2_prev(wxNOT_FOUND) + , presets_loaded(false) { append_spacer(VERTICAL_SPACING); @@ -559,12 +560,6 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin append(grid); - list_l1->append(_(L("(All)")), &EMPTY); - - for (const std::string &type : materials->types) { - list_l1->append(type, &type); - } - list_l1->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) { update_lists(list_l1->GetSelection(), list_l2->GetSelection()); }); @@ -577,10 +572,27 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin sel_all->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { select_all(true); }); sel_none->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { select_all(false); }); + reload_presets(); +} + +void PageMaterials::reload_presets() +{ + list_l1->Clear(); + + list_l1->append(_(L("(All)")), &EMPTY); + + for (const std::string &type : materials->types) { + list_l1->append(type, &type); + } + if (list_l1->GetCount() > 0) { list_l1->SetSelection(0); + sel1_prev = wxNOT_FOUND; + sel2_prev = wxNOT_FOUND; update_lists(0, 0); } + + presets_loaded = true; } void PageMaterials::update_lists(int sel1, int sel2) @@ -592,14 +604,14 @@ void PageMaterials::update_lists(int sel1, int sel2) // Refresh the second list // XXX: The vendor list is created with quadratic complexity here, - // but the number of vendors is realistically so small this shouldn't be a problem. + // but the number of vendors is going to be very small this shouldn't be a problem. list_l2->Clear(); list_l2->append(_(L("(All)")), &EMPTY); if (sel1 != wxNOT_FOUND) { const std::string &type = list_l1->get_data(sel1); - materials->filter_presets(type, EMPTY, [this](Preset &p) { + materials->filter_presets(type, EMPTY, [this](const Preset *p) { const std::string &vendor = this->materials->get_vendor(p); if (list_l2->find(vendor) == wxNOT_FOUND) { @@ -623,9 +635,9 @@ void PageMaterials::update_lists(int sel1, int sel2) const std::string &type = list_l1->get_data(sel1); const std::string &vendor = list_l2->get_data(sel2); - materials->filter_presets(type, vendor, [this](Preset &p) { - const int i = list_l3->append(p.name, &p); - const bool checked = wizard_p()->appconfig_new.has(materials->appconfig_section(), p.name); + materials->filter_presets(type, vendor, [this](const Preset *p) { + const int i = list_l3->append(p->name, p); + const bool checked = wizard_p()->appconfig_new.has(materials->appconfig_section(), p->name); list_l3->Check(i, checked); }); } @@ -660,6 +672,24 @@ void PageMaterials::select_all(bool select) } } +void PageMaterials::clear() +{ + list_l1->Clear(); + list_l2->Clear(); + list_l3->Clear(); + sel1_prev = wxNOT_FOUND; + sel2_prev = wxNOT_FOUND; + presets_loaded = false; +} + +void PageMaterials::on_activate() +{ + if (! presets_loaded) { + wizard_p()->update_materials(); + reload_presets(); + } +} + const char *PageCustom::default_profile_name = "My Settings"; @@ -952,8 +982,8 @@ ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) , bullet_black(ScalableBitmap(parent, "bullet_black.png")) , bullet_blue(ScalableBitmap(parent, "bullet_blue.png")) , bullet_white(ScalableBitmap(parent, "bullet_white.png")) - , item_active(0) - , item_hover(-1) + , item_active(NO_ITEM) + , item_hover(NO_ITEM) , last_page((size_t)-1) { SetMinSize(bg.bmp().GetSize()); @@ -1015,6 +1045,8 @@ void ConfigWizardIndex::go_prev() { // Search for a preceiding item that is a page (not a label, ie. page != nullptr) + if (item_active == NO_ITEM) { return; } + for (size_t i = item_active; i > 0; i--) { if (items[i - 1].page != nullptr) { go_to(i - 1); @@ -1027,6 +1059,8 @@ void ConfigWizardIndex::go_next() { // Search for a next item that is a page (not a label, ie. page != nullptr) + if (item_active == NO_ITEM) { return; } + for (size_t i = item_active + 1; i < items.size(); i++) { if (items[i].page != nullptr) { go_to(i); @@ -1035,19 +1069,27 @@ void ConfigWizardIndex::go_next() } } +// This one actually performs the go-to op void ConfigWizardIndex::go_to(size_t i) { - if (i < items.size() && items[i].page != nullptr) { + if (i != item_active + && i < items.size() + && items[i].page != nullptr) { + auto *new_active = items[i].page; auto *former_active = active_page(); - if (former_active != nullptr) { former_active->Hide(); } + if (former_active != nullptr) { + former_active->Hide(); + } item_active = i; - items[i].page->Show(); + new_active->Show(); wxCommandEvent evt(EVT_INDEX_PAGE, GetId()); AddPendingEvent(evt); Refresh(); + + new_active->on_activate(); } } @@ -1069,7 +1111,7 @@ void ConfigWizardIndex::clear() if (former_active != nullptr) { former_active->Hide(); } items.clear(); - item_active = 0; + item_active = NO_ITEM; } void ConfigWizardIndex::on_paint(wxPaintEvent & evt) @@ -1150,24 +1192,38 @@ void ConfigWizardIndex::msw_rescale() const std::string Materials::UNKNOWN = "(Unknown)"; +void Materials::push(const Preset *preset) +{ + presets.insert(preset); + types.insert(technology & T_FFF + ? Materials::get_filament_type(preset) + : Materials::get_material_type(preset)); +} + +void Materials::clear() +{ + presets.clear(); + types.clear(); +} + const std::string& Materials::appconfig_section() const { return (technology & T_FFF) ? AppConfig::SECTION_FILAMENTS : AppConfig::SECTION_MATERIALS; } -const std::string& Materials::get_type(Preset &preset) const +const std::string& Materials::get_type(const Preset *preset) const { return (technology & T_FFF) ? get_filament_type(preset) : get_material_type(preset); } -const std::string& Materials::get_vendor(Preset &preset) const +const std::string& Materials::get_vendor(const Preset *preset) const { return (technology & T_FFF) ? get_filament_vendor(preset) : get_material_vendor(preset); } -const std::string& Materials::get_filament_type(const Preset &preset) +const std::string& Materials::get_filament_type(const Preset *preset) { - const auto *opt = preset.config.opt("filament_type"); + const auto *opt = preset->config.opt("filament_type"); if (opt != nullptr && opt->values.size() > 0) { return opt->values[0]; } else { @@ -1175,15 +1231,15 @@ const std::string& Materials::get_filament_type(const Preset &preset) } } -const std::string& Materials::get_filament_vendor(const Preset &preset) +const std::string& Materials::get_filament_vendor(const Preset *preset) { - const auto *opt = preset.config.opt("filament_vendor"); + const auto *opt = preset->config.opt("filament_vendor"); return opt != nullptr ? opt->value : UNKNOWN; } -const std::string& Materials::get_material_type(Preset &preset) +const std::string& Materials::get_material_type(const Preset *preset) { - const auto *opt = preset.config.opt("material_type"); + const auto *opt = preset->config.opt("material_type"); if (opt != nullptr) { return opt->value; } else { @@ -1191,9 +1247,9 @@ const std::string& Materials::get_material_type(Preset &preset) } } -const std::string& Materials::get_material_vendor(const Preset &preset) +const std::string& Materials::get_material_vendor(const Preset *preset) { - const auto *opt = preset.config.opt("material_vendor"); + const auto *opt = preset->config.opt("material_vendor"); return opt != nullptr ? opt->value : UNKNOWN; } @@ -1275,73 +1331,8 @@ void ConfigWizard::priv::init_dialog_size() void ConfigWizard::priv::load_vendors() { - // const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor"; - // const auto rsrc_vendor_dir = fs::path(resources_dir()) / "profiles"; - - // PresetBundle bundle; - // bundle.load_available_system_presets(); bundles = BundleMap::load(); - // // Load vendors from the "vendors" directory in datadir - // // XXX: The VendorProfile is loaded twice here, ditto below - // for (auto &dir_entry : boost::filesystem::directory_iterator(vendor_dir)) { - // if (Slic3r::is_ini_file(dir_entry)) { - // try { - // bundle.load_configbundle(dir_entry.path().string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); - - // auto vp = VendorProfile::from_ini(dir_entry.path()); - // vendors[vp.id] = std::move(vp); - // } - // catch (const std::exception& e) { - // BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what(); - // } - // } - // } - - // // Additionally load up vendors from the application resources directory, but only those not seen in the datadir - // for (auto &dir_entry : boost::filesystem::directory_iterator(rsrc_vendor_dir)) { - // if (Slic3r::is_ini_file(dir_entry)) { - // const auto id = dir_entry.path().stem().string(); - - // if (vendors.find(id) == vendors.end()) { - // try { - // bundle.load_configbundle(dir_entry.path().string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); - - // auto vp = VendorProfile::from_ini(dir_entry.path()); - // vendors_rsrc[vp.id] = dir_entry.path().filename().string(); - // vendors[vp.id] = std::move(vp); - // } - // catch (const std::exception& e) { - // BOOST_LOG_TRIVIAL(error) << boost::format("Error loading vendor bundle %1%: %2%") % dir_entry.path() % e.what(); - // } - // } - // } - // } - - // // Move materials to our Materials container: - // for (auto &&f : bundle.filaments) { - // f.vendor = nullptr; - // filaments.presets.push_back(std::move(f)); - // filaments.types.insert(Materials::get_filament_type(f)); - // } - // for (auto &&m : bundle.sla_materials) { - // m.vendor = nullptr; - // sla_materials.presets.push_back(std::move(m)); - // sla_materials.types.insert(Materials::get_material_type(m)); - // } - for (auto &pair : bundles) { - for (auto &&f : pair.second.preset_bundle->filaments) { - f.vendor = nullptr; - filaments.presets.push_back(std::move(f)); - filaments.types.insert(Materials::get_filament_type(f)); - } - for (auto &&m : pair.second.preset_bundle->sla_materials) { - m.vendor = nullptr; - sla_materials.presets.push_back(std::move(m)); - sla_materials.types.insert(Materials::get_material_type(m)); - } - } - // Load up the set of vendors / models / variants the user has had enabled up till now AppConfig *app_config = wxGetApp().app_config; if (! app_config->legacy_datadir()) { @@ -1360,15 +1351,13 @@ void ConfigWizard::priv::load_vendors() } } -// TODO: This'll be done differently, cf. the design document - // Load up the materials enabled till now, - // apply defaults from vendor profiles if there are no selections yet. - // bundle.init_materials_selection(*app_config); + // Initialize the is_visible flag in printer Presets + for (auto &pair : bundles) { + pair.second.preset_bundle->load_installed_printers(appconfig_new); + } + + update_materials(); - // TODO: load up sane defaults if no previous data in AppConfig - // as per the design doc: - // - all f/m for installed printers if prev Slicer version - // - default f/m set from bundle + default for each printer from bundle if fresh install if (app_config->has_section(AppConfig::SECTION_FILAMENTS)) { appconfig_new.set_section(AppConfig::SECTION_FILAMENTS, app_config->get_section(AppConfig::SECTION_FILAMENTS)); } @@ -1420,12 +1409,66 @@ void ConfigWizard::priv::set_run_reason(RunReason run_reason) } } +void ConfigWizard::priv::update_materials() +{ + filaments.clear(); + sla_materials.clear(); + + if (any_fff_selected) { + // Iterate filaments in all bundles + for (const auto &pair : bundles) { + for (const auto &filament : pair.second.preset_bundle->filaments) { + // Check if filament is already added + if (filaments.containts(&filament)) { continue; } + + // Iterate printers in all bundles + for (const auto &pair : bundles) { + for (const auto &printer : pair.second.preset_bundle->printers) { + // Filter out inapplicable printers + if (!printer.is_visible || printer.printer_technology() != ptFFF) { + continue; + } + + if (filament.is_compatible_with_printer(printer)) { + filaments.push(&filament); + } + } + } + } + } + } + + if (any_sla_selected) { + // Iterate SLA materials in all bundles + for (const auto &pair : bundles) { + for (const auto &material : pair.second.preset_bundle->sla_materials) { + // Check if material is already added + if (sla_materials.containts(&material)) { continue; } + + // Iterate printers in all bundles + for (const auto &pair : bundles) { + for (const auto &printer : pair.second.preset_bundle->printers) { + // Filter out inapplicable printers + if (!printer.is_visible || printer.printer_technology() != ptSLA) { + continue; + } + + if (material.is_compatible_with_printer(printer)) { + sla_materials.push(&material); + } + } + } + } + } + } +} + void ConfigWizard::priv::on_custom_setup() { load_pages(); } -void ConfigWizard::priv::on_printer_pick(PagePrinters *page) +void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt) { if (page_msla->any_selected() != any_sla_selected || page_fff->any_selected() != any_fff_selected) { @@ -1434,6 +1477,24 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page) load_pages(); } + + // Update the is_visible flag on relevant printer profiles + for (auto &pair : bundles) { + if (pair.first != evt.vendor_id) { continue; } + + for (auto &preset : pair.second.preset_bundle->printers) { + if (preset.config.opt_string("printer_model") == evt.model_id + && preset.config.opt_string("printer_variant") == evt.variant_name) { + preset.is_visible = evt.enable; + } + } + } + + if (page == page_fff) { + page_filaments->clear(); + } else if (page == page_msla) { + page_sla_materials->clear(); + } } void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool install) @@ -1636,7 +1697,9 @@ ConfigWizard::ConfigWizard(wxWindow *parent) p->any_sla_selected = p->page_msla->any_selected(); p->any_fff_selected = p->page_fff->any_selected(); + p->load_pages(); + p->index->go_to(size_t{0}); vsizer->Add(topsizer, 1, wxEXPAND | wxALL, DIALOG_MARGIN); vsizer->Add(hline, 0, wxEXPAND); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 708eb94fc6..0d2123695b 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -21,7 +21,6 @@ #include "libslic3r/PrintConfig.hpp" #include "slic3r/Utils/PresetUpdater.hpp" #include "AppConfig.hpp" -// #include "Preset.hpp" #include "PresetBundle.hpp" #include "BedShapeDialog.hpp" @@ -58,17 +57,23 @@ enum Technology { struct Materials { Technology technology; - std::vector presets; + std::set presets; std::set types; Materials(Technology technology) : technology(technology) {} + void push(const Preset *preset); + void clear(); + bool containts(const Preset *preset) { + return presets.find(preset) != presets.end(); + } + const std::string& appconfig_section() const; - const std::string& get_type(Preset &preset) const; - const std::string& get_vendor(Preset &preset) const; + const std::string& get_type(const Preset *preset) const; + const std::string& get_vendor(const Preset *preset) const; template void filter_presets(const std::string &type, const std::string &vendor, F cb) { - for (Preset &preset : presets) { + for (const Preset *preset : presets) { if ((type.empty() || get_type(preset) == type) && (vendor.empty() || get_vendor(preset) == vendor)) { cb(preset); } @@ -76,10 +81,10 @@ struct Materials } static const std::string UNKNOWN; - static const std::string& get_filament_type(const Preset &preset); - static const std::string& get_filament_vendor(const Preset &preset); - static const std::string& get_material_type(Preset &preset); - static const std::string& get_material_vendor(const Preset &preset); + static const std::string& get_filament_type(const Preset *preset); + static const std::string& get_filament_vendor(const Preset *preset); + static const std::string& get_material_type(const Preset *preset); + static const std::string& get_material_vendor(const Preset *preset); }; struct Bundle @@ -104,6 +109,7 @@ struct BundleMap: std::unordered_map const Bundle& prusa_bundle() const; }; +struct PrinterPickerEvent; // GUI elements @@ -170,6 +176,7 @@ struct ConfigWizardPage: wxPanel virtual void apply_custom_config(DynamicPrintConfig &config) {} virtual void set_run_reason(ConfigWizard::RunReason run_reason) {} + virtual void on_activate() {} }; struct PageWelcome: ConfigWizardPage @@ -209,6 +216,9 @@ template struct DataList : public T { DataList(wxWindow *parent) : T(parent, wxID_ANY) {} + // Note: We're _not_ using wxLB_SORT here because it doesn't do the right thing, + // eg. "ABS" is sorted before "(All)" + int append(const std::string &label, const D *data) { void *ptr = reinterpret_cast(const_cast(data)); return this->Append(from_u8(label), ptr); @@ -241,14 +251,19 @@ struct PageMaterials: ConfigWizardPage StringList *list_l1, *list_l2; PresetList *list_l3; int sel1_prev, sel2_prev; + bool presets_loaded; + + static const std::string EMPTY; PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name); + void reload_presets(); void update_lists(int sel1, int sel2); void select_material(int i); void select_all(bool select); + void clear(); - static const std::string EMPTY; + virtual void on_activate() override; }; struct PageCustom: ConfigWizardPage @@ -339,6 +354,8 @@ public: void msw_rescale(); int em() const { return em_w; } + + static const size_t NO_ITEM = size_t(-1); private: struct Item { @@ -379,14 +396,12 @@ struct ConfigWizard::priv ConfigWizard *q; ConfigWizard::RunReason run_reason = RR_USER; AppConfig appconfig_new; // Backing for vendor/model/variant and material selections in the GUI - // std::unordered_map vendors; - // PresetBundle bundle; // XXX: comment - BundleMap bundles; // XXX: comment + BundleMap bundles; // Holds all loaded config bundles, the key is the vendor names. + // Materials refers to Presets in those bundles by pointers. + // Also we update the is_visible flag in printer Presets according to the + // PrinterPickers state. Materials filaments; // Holds available filament presets and their types & vendors Materials sla_materials; // Ditto for SLA materials - // std::set install_3rdparty; - // XXX: rm: (?) - // std::unordered_map vendors_rsrc; // List of bundles to install from resources std::unique_ptr custom_config; // Backing for custom printer definition bool any_fff_selected; // Used to decide whether to display Filaments page bool any_sla_selected; // Used to decide whether to display SLA Materials page @@ -437,10 +452,11 @@ struct ConfigWizard::priv void set_start_page(ConfigWizard::StartPage start_page); void create_3rdparty_pages(); void set_run_reason(RunReason run_reason); + void update_materials(); void on_custom_setup(); - void on_printer_pick(PagePrinters *page); - void on_3rdparty_install(const VendorProfile *vendor, bool install); // XXX: ? + void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt); + void on_3rdparty_install(const VendorProfile *vendor, bool install); void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index 0fea2a0f8a..79519071b5 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -134,20 +134,21 @@ public: void load_default_preset_bitmaps(wxWindow *window); + // FIXME: rm void load_available_system_presets(); // XXX: name XXX: retval (VendorMap stored internally) + // Set the is_visible flag for printer vendors, printer models and printer variants + // based on the user configuration. + // If the "vendor" section is missing, enable all models and variants of the particular vendor. + void load_installed_printers(const AppConfig &config); + static const char *PRUSA_BUNDLE; private: std::string load_system_presets(); // Merge one vendor's presets with the other vendor's presets, report duplicates. std::vector merge_presets(PresetBundle &&other); - // Set the "enabled" flag for printer vendors, printer models and printer variants - // based on the user configuration. - // If the "vendor" section is missing, enable all models and variants of the particular vendor. - void load_installed_printers(const AppConfig &config); - - // Set the enabled flag for filaments and sla materials, + // Set the is_visible flag for filaments and sla materials, // apply defaults based on enabled printers when no filaments/materials are installed. void load_installed_filaments(AppConfig &config); void load_installed_sla_materials(AppConfig &config); From cb1ee5ce5542bc96a8babdb45ed3264bbb2a0855 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 17 Sep 2019 15:52:26 +0200 Subject: [PATCH 08/23] ConfigWizard: Add view mode setting page --- src/slic3r/GUI/ConfigWizard.cpp | 41 +++++++++++++++++++++++++ src/slic3r/GUI/ConfigWizard_private.hpp | 17 +++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 691a2f2cdc..d77812e3a6 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -758,6 +758,43 @@ PageUpdate::PageUpdate(ConfigWizard *parent) box_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->preset_update = event.IsChecked(); }); } +PageMode::PageMode(ConfigWizard *parent) + : ConfigWizardPage(parent, _(L("View mode")), _(L("View mode"))) +{ + append_text(_(L("PrusaSlicer's user interfaces comes in three variants:\nSimple, Advanced, and Expert.\n" + "The Simple mode shows only the most frequently used settings relevant for regular 3D printing. " + "The other two offer progressivly more specialized fine-tuning, " + "they are suitable for advanced and expert usiser, respectively. (FIXME: review this text)"))); + + radio_simple = new wxRadioButton(this, wxID_ANY, _(L("Simple mode"))); + radio_advanced = new wxRadioButton(this, wxID_ANY, _(L("Advanced mode"))); + radio_expert = new wxRadioButton(this, wxID_ANY, _(L("Expert mode"))); + + append(radio_simple); + append(radio_advanced); + append(radio_expert); +} + +void PageMode::on_activate() +{ + std::string mode { "simple" }; + wxGetApp().app_config->get("", "view_mode", mode); + + if (mode == "advanced") { radio_advanced->SetValue(true); } + else if (mode == "expert") { radio_expert->SetValue(true); } + else { radio_simple->SetValue(true); } +} + +void PageMode::serialize_mode(AppConfig *app_config) const +{ + const char *mode = "simple"; + + if (radio_advanced->GetValue()) { mode = "advanced"; } + if (radio_expert->GetValue()) { mode = "expert"; } + + app_config->set("view_mode", mode); +} + PageVendors::PageVendors(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) { @@ -1300,6 +1337,7 @@ void ConfigWizard::priv::load_pages() if (any_sla_selected) { index->add_page(page_sla_materials); } index->add_page(page_update); + index->add_page(page_mode); index->go_to(former_active); // Will restore the active item/page if possible @@ -1587,6 +1625,7 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese } app_config->set("version_check", page_update->version_check ? "1" : "0"); app_config->set("preset_update", page_update->preset_update ? "1" : "0"); + page_mode->serialize_mode(app_config); std::string preferred_model; @@ -1686,6 +1725,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent) p->add_page(p->page_custom = new PageCustom(this)); p->add_page(p->page_update = new PageUpdate(this)); + p->add_page(p->page_mode = new PageMode(this)); p->add_page(p->page_firmware = new PageFirmware(this)); p->add_page(p->page_bed = new PageBedShape(this)); p->add_page(p->page_diams = new PageDiameters(this)); @@ -1751,6 +1791,7 @@ bool ConfigWizard::run(RunReason reason, StartPage start_page) if (ShowModal() == wxID_OK) { p->apply_config(app.app_config, app.preset_bundle, app.preset_updater); app.app_config->set_legacy_datadir(false); + app.update_mode(); BOOST_LOG_TRIVIAL(info) << "ConfigWizard applied"; return true; } else { diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 0d2123695b..6c94d37003 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "libslic3r/PrintConfig.hpp" #include "slic3r/Utils/PresetUpdater.hpp" @@ -290,6 +291,19 @@ struct PageUpdate: ConfigWizardPage PageUpdate(ConfigWizard *parent); }; +struct PageMode: ConfigWizardPage +{ + wxRadioButton *radio_simple; + wxRadioButton *radio_advanced; + wxRadioButton *radio_expert; + + PageMode(ConfigWizard *parent); + + void serialize_mode(AppConfig *app_config) const; + + virtual void on_activate(); +}; + struct PageVendors: ConfigWizardPage { PageVendors(ConfigWizard *parent); @@ -424,7 +438,8 @@ struct ConfigWizard::priv PageMaterials *page_sla_materials = nullptr; PageCustom *page_custom = nullptr; PageUpdate *page_update = nullptr; - PageVendors *page_vendors = nullptr; // XXX: ? + PageMode *page_mode = nullptr; + PageVendors *page_vendors = nullptr; Pages3rdparty pages_3rdparty; // Custom setup pages From 107ff6fd3618e8a468aacb90903f4cc09ca65f49 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 17 Sep 2019 16:59:52 +0200 Subject: [PATCH 09/23] Materials: Cleanup --- src/slic3r/GUI/ConfigWizard.cpp | 20 +++--------- src/slic3r/GUI/ConfigWizard_private.hpp | 3 +- src/slic3r/GUI/PresetBundle.cpp | 42 ------------------------- src/slic3r/GUI/PresetBundle.hpp | 3 -- 4 files changed, 6 insertions(+), 62 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index d77812e3a6..cbbaa32b64 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -26,7 +26,6 @@ #include #include "libslic3r/Utils.hpp" -// #include "PresetBundle.hpp" #include "GUI.hpp" #include "GUI_Utils.hpp" #include "slic3r/Config/Snapshot.hpp" @@ -44,22 +43,19 @@ using Config::SnapshotDB; // Configuration data structures extensions needed for the wizard Bundle::Bundle(fs::path source_path, bool is_in_resources, bool is_prusa_bundle) - : source_path(std::move(source_path)) - , preset_bundle(new PresetBundle) + : preset_bundle(new PresetBundle) , vendor_profile(nullptr) , is_in_resources(is_in_resources) , is_prusa_bundle(is_prusa_bundle) { - // XXX: consider removing path <-> string juggling - preset_bundle->load_configbundle(this->source_path.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); + preset_bundle->load_configbundle(source_path.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); auto first_vendor = preset_bundle->vendors.begin(); wxCHECK_RET(first_vendor != preset_bundle->vendors.end(), "Failed to load preset bundle"); vendor_profile = &first_vendor->second; } Bundle::Bundle(Bundle &&other) - : source_path(std::move(source_path)) - , preset_bundle(std::move(other.preset_bundle)) + : preset_bundle(std::move(other.preset_bundle)) , vendor_profile(other.vendor_profile) , is_in_resources(other.is_in_resources) , is_prusa_bundle(other.is_prusa_bundle) @@ -71,15 +67,9 @@ BundleMap BundleMap::load() { BundleMap res; - // XXX: Keep Prusa bundle separate? (Probably no - keep same codepaths) - const auto vendor_dir = (boost::filesystem::path(Slic3r::data_dir()) / "vendor").make_preferred(); const auto rsrc_vendor_dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred(); - // XXX - // const auto prusa_bundle_vendor = (vendor_dir / PRUSA_BUNDLE).replace_extension(".ini"); - // const auto prusa_bundle = boost::filesystem::exists(prusa_bundle_vendor) ? prusa_bundle_vendor - // : (rsrc_vendor_dir / PRUSA_BUNDLE).replace_extension(".ini"); auto prusa_bundle_path = (vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini"); auto prusa_bundle_rsrc = false; if (! boost::filesystem::exists(prusa_bundle_path)) { @@ -663,7 +653,7 @@ void PageMaterials::select_all(bool select) wxWindowUpdateLocker freeze_guard(this); (void)freeze_guard; - for (int i = 0; i < list_l3->GetCount(); i++) { + for (unsigned i = 0; i < list_l3->GetCount(); i++) { const bool current = list_l3->IsChecked(i); if (current != select) { list_l3->Check(i, select); @@ -1646,7 +1636,7 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese // } // } - preset_bundle->load_presets(*app_config, preferred_model); + // preset_bundle->load_presets(*app_config, preferred_model); if (page_custom->custom_wanted()) { page_firmware->apply_custom_config(*custom_config); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 6c94d37003..3f688adff1 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -90,7 +90,6 @@ struct Materials struct Bundle { - fs::path source_path; // XXX: not needed? std::unique_ptr preset_bundle; VendorProfile *vendor_profile; const bool is_in_resources; @@ -235,7 +234,7 @@ template struct DataList : public T } int find(const D &data) { - for (int i = 0; i < this->GetCount(); i++) { + for (unsigned i = 0; i < this->GetCount(); i++) { if (get_data(i) == data) { return i; } } diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index e3ee84e872..54dd92a71b 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -243,48 +243,6 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_ this->load_selections(config, preferred_model_id); } -// FIXME: Comment -// XXX: rm -void PresetBundle::load_available_system_presets() -{ - const auto vendor_dir = (boost::filesystem::path(Slic3r::data_dir()) / "vendor").make_preferred(); - const auto rsrc_vendor_dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred(); - - const auto prusa_bundle_vendor = (vendor_dir / PRUSA_BUNDLE).replace_extension(".ini"); - const auto prusa_bundle = boost::filesystem::exists(prusa_bundle_vendor) ? prusa_bundle_vendor - : (rsrc_vendor_dir / PRUSA_BUNDLE).replace_extension(".ini"); - - // Reset this PresetBundle and load the Prusa bundle first. - this->load_configbundle(prusa_bundle.string(), LOAD_CFGBNDLE_SYSTEM); - - // Load the other bundles in the datadir/vendor directory - // and then additionally from resources/profiles. - for (auto dir : { &vendor_dir, &rsrc_vendor_dir }) { - for (const auto &dir_entry : boost::filesystem::directory_iterator(*dir)) { - if (Slic3r::is_ini_file(dir_entry)) { - std::string id = dir_entry.path().stem().string(); // stem() = filename() without the trailing ".ini" part - - // Don't load this bundle if we've already loaded it. - // Note that this takes care of not loading the PRUSA_BUNDLE which was loaded upfront - // as well as bundles with the same name (id) in rsrc_vendor_dir as in vendor_dir. - if (vendors.find(id) != vendors.end()) { continue; } - - PresetBundle other; - other.load_configbundle(dir_entry.path().string(), LOAD_CFGBNDLE_SYSTEM); - - std::vector duplicates = this->merge_presets(std::move(other)); - if (! duplicates.empty()) { - std::string msg = "Vendor configuration file " + id + " contains the following presets with names used by other vendors: "; - for (size_t i = 0; i < duplicates.size(); ++ i) { - if (i > 0) { msg += ", "; } - msg += duplicates[i]; - } - } - } - } - } -} - // Load system presets into this PresetBundle. // For each vendor, there will be a single PresetBundle loaded. std::string PresetBundle::load_system_presets() diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index 79519071b5..b1010e07b0 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -134,9 +134,6 @@ public: void load_default_preset_bitmaps(wxWindow *window); - // FIXME: rm - void load_available_system_presets(); // XXX: name XXX: retval (VendorMap stored internally) - // Set the is_visible flag for printer vendors, printer models and printer variants // based on the user configuration. // If the "vendor" section is missing, enable all models and variants of the particular vendor. From 3a40565d03608c2440e772d58121ef16fc84744e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 19 Sep 2019 09:09:11 +0200 Subject: [PATCH 10/23] Added tech ENABLE_ENHANCED_RELOAD_FROM_DISK 1) Reworked void Plater::priv::reload_from_disk() to be more general 2) Added source data to class ModelVolume 3) Modified .3mf import/export to save/load volume matrices and source data 4) Incremented .3mf version to 2 --- src/libslic3r/Format/3mf.cpp | 130 ++++++++++++++++++++- src/libslic3r/Model.cpp | 15 +++ src/libslic3r/Model.hpp | 37 +++++- src/libslic3r/Technologies.hpp | 7 ++ src/slic3r/GUI/GLCanvas3D.cpp | 148 +++++++++++++++--------- src/slic3r/GUI/GUI_ObjectList.cpp | 21 ++++ src/slic3r/GUI/GUI_ObjectList.hpp | 5 +- src/slic3r/GUI/Plater.cpp | 183 ++++++++++++++++++++++++++++++ src/slic3r/GUI/Plater.hpp | 6 + src/slic3r/GUI/Selection.cpp | 4 + 10 files changed, 496 insertions(+), 60 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 0f89e61930..fbec5b00b9 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -31,7 +31,12 @@ namespace pt = boost::property_tree; // VERSION NUMBERS // 0 : .3mf, files saved by older slic3r or other applications. No version definition in them. // 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files. +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +// 2 : Meshes saved in their local system and volumes matrices added to Metadata/Slic3r_PE_model.config file. +const unsigned int VERSION_3MF = 2; +#else const unsigned int VERSION_3MF = 1; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const char* SLIC3RPE_3MF_VERSION = "slic3rpe:Version3mf"; // definition of the metadata name saved into .model file const std::string MODEL_FOLDER = "3D/"; @@ -87,6 +92,15 @@ const char* VOLUME_TYPE = "volume"; const char* NAME_KEY = "name"; const char* MODIFIER_KEY = "modifier"; const char* VOLUME_TYPE_KEY = "volume_type"; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +const char* MATRIX_KEY = "matrix"; +const char* SOURCE_FILE_KEY = "source_file"; +const char* SOURCE_OBJECT_ID_KEY = "source_object_id"; +const char* SOURCE_VOLUME_ID_KEY = "source_volume_id"; +const char* SOURCE_OFFSET_X_KEY = "source_offset_x"; +const char* SOURCE_OFFSET_Y_KEY = "source_offset_y"; +const char* SOURCE_OFFSET_Z_KEY = "source_offset_z"; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const unsigned int VALID_OBJECT_TYPES_COUNT = 1; const char* VALID_OBJECT_TYPES[] = @@ -148,11 +162,25 @@ bool get_attribute_value_bool(const char** attributes, unsigned int attributes_s return (text != nullptr) ? (bool)::atoi(text) : true; } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +Slic3r::Transform3d get_transform_from_3mf_specs_string(const std::string& mat_str) +#else Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK { +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + // check: https://3mf.io/3d-manufacturing-format/ or https://github.com/3MFConsortium/spec_core/blob/master/3MF%20Core%20Specification.md + // to see how matrices are stored inside 3mf according to specifications + Slic3r::Transform3d ret = Slic3r::Transform3d::Identity(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + if (mat_str.empty()) // empty string means default identity matrix +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + return ret; +#else return Slic3r::Transform3d::Identity(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK std::vector mat_elements_str; boost::split(mat_elements_str, mat_str, boost::is_any_of(" "), boost::token_compress_on); @@ -160,9 +188,13 @@ Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) unsigned int size = (unsigned int)mat_elements_str.size(); if (size != 12) // invalid data, return identity matrix +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + return ret; +#else return Slic3r::Transform3d::Identity(); Slic3r::Transform3d ret = Slic3r::Transform3d::Identity(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK unsigned int i = 0; // matrices are stored into 3mf files as 4x3 // we need to transpose them @@ -176,6 +208,35 @@ Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) return ret; } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) +{ + Slic3r::Transform3d ret = Slic3r::Transform3d::Identity(); + + if (mat_str.empty()) + // empty string means default identity matrix + return ret; + + std::vector mat_elements_str; + boost::split(mat_elements_str, mat_str, boost::is_any_of(" "), boost::token_compress_on); + + unsigned int size = (unsigned int)mat_elements_str.size(); + if (size != 16) + // invalid data, return identity matrix + return ret; + + unsigned int i = 0; + for (unsigned int r = 0; r < 4; ++r) + { + for (unsigned int c = 0; c < 4; ++c) + { + ret(r, c) = ::atof(mat_elements_str[i++].c_str()); + } + } + return ret; +} +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + float get_unit_factor(const std::string& unit) { const char* text = unit.c_str(); @@ -1375,7 +1436,11 @@ namespace Slic3r { bool _3MF_Importer::_handle_start_component(const char** attributes, unsigned int num_attributes) { int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + Transform3d transform = get_transform_from_3mf_specs_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); +#else Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK IdToModelObjectMap::iterator object_item = m_objects.find(object_id); if (object_item == m_objects.end()) @@ -1421,7 +1486,11 @@ namespace Slic3r { // see specifications int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + Transform3d transform = get_transform_from_3mf_specs_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); +#else Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK int printable = get_attribute_value_bool(attributes, num_attributes, PRINTABLE_ATTR); return _create_object_instance(object_id, transform, printable, 1); @@ -1659,7 +1728,9 @@ namespace Slic3r { triangle_mesh.repair(); ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); +#if !ENABLE_ENHANCED_RELOAD_FROM_DISK volume->center_geometry_after_creation(); +#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK volume->calculate_convex_hull(); // apply volume's name and config data @@ -1671,6 +1742,22 @@ namespace Slic3r { volume->set_type(ModelVolumeType::PARAMETER_MODIFIER); else if (metadata.key == VOLUME_TYPE_KEY) volume->set_type(ModelVolume::type_from_string(metadata.value)); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + else if (metadata.key == MATRIX_KEY) + volume->set_transformation(Slic3r::Geometry::Transformation(get_transform_from_string(metadata.value))); + else if (metadata.key == SOURCE_FILE_KEY) + volume->source.input_file = metadata.value; + else if (metadata.key == SOURCE_OBJECT_ID_KEY) + volume->source.object_idx = ::atoi(metadata.value.c_str()); + else if (metadata.key == SOURCE_VOLUME_ID_KEY) + volume->source.volume_idx = ::atoi(metadata.value.c_str()); + else if (metadata.key == SOURCE_OFFSET_X_KEY) + volume->source.mesh_offset(0) = ::atof(metadata.value.c_str()); + else if (metadata.key == SOURCE_OFFSET_Y_KEY) + volume->source.mesh_offset(1) = ::atof(metadata.value.c_str()); + else if (metadata.key == SOURCE_OFFSET_Z_KEY) + volume->source.mesh_offset(2) = ::atof(metadata.value.c_str()); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK else volume->config.set_deserialize(metadata.key, metadata.value); } @@ -2056,8 +2143,19 @@ namespace Slic3r { vertices_count += (int)its.vertices.size(); +#if !ENABLE_ENHANCED_RELOAD_FROM_DISK const Transform3d& matrix = volume->get_matrix(); +#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + for (const Vec3f& v : its.vertices) + { + stream << " <" << VERTEX_TAG << " "; + stream << "x=\"" << v(0) << "\" "; + stream << "y=\"" << v(1) << "\" "; + stream << "z=\"" << v(2) << "\" />\n"; + } +#else for (size_t i = 0; i < its.vertices.size(); ++i) { stream << " <" << VERTEX_TAG << " "; @@ -2066,6 +2164,7 @@ namespace Slic3r { stream << "y=\"" << v(1) << "\" "; stream << "z=\"" << v(2) << "\" />\n"; } +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } stream << " \n"; @@ -2116,7 +2215,7 @@ namespace Slic3r { for (const BuildItem& item : build_items) { - stream << " <" << ITEM_TAG << " objectid=\"" << item.id << "\" transform =\""; + stream << " <" << ITEM_TAG << " " << OBJECTID_ATTR << "=\"" << item.id << "\" " << TRANSFORM_ATTR << "=\""; for (unsigned c = 0; c < 4; ++c) { for (unsigned r = 0; r < 3; ++r) @@ -2126,7 +2225,7 @@ namespace Slic3r { stream << " "; } } - stream << "\" printable =\"" << item.printable << "\" />\n"; + stream << "\" " << PRINTABLE_ATTR << "=\"" << item.printable << "\" />\n"; } stream << " \n"; @@ -2344,6 +2443,33 @@ namespace Slic3r { stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " << VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n"; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + // stores volume's local matrix + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\""; + const Transform3d& matrix = volume->get_matrix(); + for (int r = 0; r < 4; ++r) + { + for (int c = 0; c < 4; ++c) + { + stream << matrix(r, c); + if ((r != 3) || (c != 3)) + stream << " "; + } + } + stream << "\"/>\n"; + + // stores volume's source data + if (!volume->source.input_file.empty()) + { + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_FILE_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->source.input_file) << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OBJECT_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.object_idx << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_VOLUME_ID_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.volume_idx << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_X_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(0) << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_Y_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(1) << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_Z_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(2) << "\"/>\n"; + } +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + // stores volume's config data for (const std::string& key : volume->config.keys()) { diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 7526dd16aa..d36f5b7acc 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -141,12 +141,14 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig for (ModelObject *o : model.objects) { +#if !ENABLE_ENHANCED_RELOAD_FROM_DISK if (boost::algorithm::iends_with(input_file, ".zip.amf")) { // we remove the .zip part of the extension to avoid it be added to filenames when exporting o->input_file = boost::ireplace_last_copy(input_file, ".zip.", "."); } else +#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK o->input_file = input_file; } @@ -170,6 +172,11 @@ ModelObject* Model::add_object(const char *name, const char *path, const Triangl new_object->input_file = path; ModelVolume *new_volume = new_object->add_volume(mesh); new_volume->name = name; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + new_volume->source.input_file = path; + new_volume->source.object_idx = (int)this->objects.size() - 1; + new_volume->source.volume_idx = (int)new_object->volumes.size() - 1; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK new_object->invalidate_bounding_box(); return new_object; } @@ -182,6 +189,11 @@ ModelObject* Model::add_object(const char *name, const char *path, TriangleMesh new_object->input_file = path; ModelVolume *new_volume = new_object->add_volume(std::move(mesh)); new_volume->name = name; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + new_volume->source.input_file = path; + new_volume->source.object_idx = (int)this->objects.size() - 1; + new_volume->source.volume_idx = (int)new_object->volumes.size() - 1; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK new_object->invalidate_bounding_box(); return new_object; } @@ -1554,6 +1566,9 @@ void ModelVolume::center_geometry_after_creation() const_cast(m_convex_hull.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); translate(shift); } +//================================================================================================================================================================================================ + source.mesh_offset = shift; +//================================================================================================================================================================================================ } void ModelVolume::calculate_convex_hull() diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 19f032b1c6..c91f72a956 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -392,6 +392,19 @@ class ModelVolume final : public ObjectBase { public: std::string name; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + // struct used by reload from disk command to recover data from disk + struct Source + { + std::string input_file; + int object_idx{ -1 }; + int volume_idx{ -1 }; + Vec3d mesh_offset{ Vec3d::Zero() }; + + template void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset); } + }; + Source source; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK // The triangular model. const TriangleMesh& mesh() const { return *m_mesh.get(); } void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared(mesh); } @@ -529,7 +542,11 @@ private: // Copying an existing volume, therefore this volume will get a copy of the ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other) : ObjectBase(other), +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) +#else name(other.name), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK { assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id()); assert(this->id() == other.id() && this->config.id() == other.config.id()); @@ -537,7 +554,11 @@ private: } // Providing a new mesh, therefore this volume will get a new unique ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + name(other.name), source(other.source), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) +#else name(other.name), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK { assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id()); assert(this->id() != other.id() && this->config.id() == other.config.id()); @@ -558,8 +579,12 @@ private: } template void load(Archive &ar) { bool has_convex_hull; - ar(name, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); - cereal::load_by_value(ar, config); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); +#else + ar(name, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + cereal::load_by_value(ar, config); assert(m_mesh); if (has_convex_hull) { cereal::load_optional(ar, m_convex_hull); @@ -571,8 +596,12 @@ private: } template void save(Archive &ar) const { bool has_convex_hull = m_convex_hull.get() != nullptr; - ar(name, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); - cereal::save_by_value(ar, config); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); +#else + ar(name, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + cereal::save_by_value(ar, config); if (has_convex_hull) cereal::save_optional(ar, m_convex_hull); } diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 51d0920946..60ae17a82d 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -32,4 +32,11 @@ #define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1) +//==================== +// 2.2.0.alpha1 techs +//==================== +#define ENABLE_2_2_0_ALPHA1 1 + +#define ENABLE_ENHANCED_RELOAD_FROM_DISK (1 && ENABLE_2_2_0_ALPHA1) + #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index edb9c78307..60f76db3d9 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1747,101 +1747,118 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re _set_current(); struct ModelVolumeState { - ModelVolumeState(const GLVolume *volume) : - model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {} - ModelVolumeState(const ModelVolume *model_volume, const ObjectID &instance_id, const GLVolume::CompositeID &composite_id) : - model_volume(model_volume), geometry_id(std::make_pair(model_volume->id().id, instance_id.id)), composite_id(composite_id), volume_idx(-1) {} - ModelVolumeState(const ObjectID &volume_id, const ObjectID &instance_id) : - model_volume(nullptr), geometry_id(std::make_pair(volume_id.id, instance_id.id)), volume_idx(-1) {} - bool new_geometry() const { return this->volume_idx == size_t(-1); } - const ModelVolume *model_volume; + ModelVolumeState(const GLVolume* volume) : + model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {} + ModelVolumeState(const ModelVolume* model_volume, const ObjectID& instance_id, const GLVolume::CompositeID& composite_id) : + model_volume(model_volume), geometry_id(std::make_pair(model_volume->id().id, instance_id.id)), composite_id(composite_id), volume_idx(-1) {} + ModelVolumeState(const ObjectID& volume_id, const ObjectID& instance_id) : + model_volume(nullptr), geometry_id(std::make_pair(volume_id.id, instance_id.id)), volume_idx(-1) {} + bool new_geometry() const { return this->volume_idx == size_t(-1); } + const ModelVolume* model_volume; // ObjectID of ModelVolume + ObjectID of ModelInstance // or timestamp of an SLAPrintObjectStep + ObjectID of ModelInstance std::pair geometry_id; GLVolume::CompositeID composite_id; // Volume index in the new GLVolume vector. - size_t volume_idx; + size_t volume_idx; }; std::vector model_volume_state; - std::vector aux_volume_state; + std::vector aux_volume_state; + +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + struct GLVolumeState { + GLVolumeState() : + volume_idx(-1) {} + GLVolumeState(const GLVolume* volume, unsigned int volume_idx) : + composite_id(volume->composite_id), volume_idx(volume_idx) {} + + GLVolume::CompositeID composite_id; + // Volume index in the old GLVolume vector. + size_t volume_idx; + }; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK // SLA steps to pull the preview meshes for. - typedef std::array SLASteps; - SLASteps sla_steps = { slaposSupportTree, slaposBasePool }; + typedef std::array SLASteps; + SLASteps sla_steps = { slaposSupportTree, slaposBasePool }; struct SLASupportState { - std::array::value> step; + std::array::value> step; }; // State of the sla_steps for all SLAPrintObjects. std::vector sla_support_state; std::vector instance_ids_selected; std::vector map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1)); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + std::vector deleted_volumes; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK std::vector glvolumes_new; glvolumes_new.reserve(m_volumes.volumes.size()); - auto model_volume_state_lower = [](const ModelVolumeState &m1, const ModelVolumeState &m2) { return m1.geometry_id < m2.geometry_id; }; + auto model_volume_state_lower = [](const ModelVolumeState& m1, const ModelVolumeState& m2) { return m1.geometry_id < m2.geometry_id; }; - m_reload_delayed = ! m_canvas->IsShown() && ! refresh_immediately && ! force_full_scene_refresh; + m_reload_delayed = !m_canvas->IsShown() && !refresh_immediately && !force_full_scene_refresh; - PrinterTechnology printer_technology = m_process->current_printer_technology(); + PrinterTechnology printer_technology = m_process->current_printer_technology(); int volume_idx_wipe_tower_old = -1; // Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed). // First initialize model_volumes_new_sorted & model_instances_new_sorted. - for (int object_idx = 0; object_idx < (int)m_model->objects.size(); ++ object_idx) { - const ModelObject *model_object = m_model->objects[object_idx]; - for (int instance_idx = 0; instance_idx < (int)model_object->instances.size(); ++ instance_idx) { - const ModelInstance *model_instance = model_object->instances[instance_idx]; - for (int volume_idx = 0; volume_idx < (int)model_object->volumes.size(); ++ volume_idx) { - const ModelVolume *model_volume = model_object->volumes[volume_idx]; - model_volume_state.emplace_back(model_volume, model_instance->id(), GLVolume::CompositeID(object_idx, volume_idx, instance_idx)); + for (int object_idx = 0; object_idx < (int)m_model->objects.size(); ++object_idx) { + const ModelObject* model_object = m_model->objects[object_idx]; + for (int instance_idx = 0; instance_idx < (int)model_object->instances.size(); ++instance_idx) { + const ModelInstance* model_instance = model_object->instances[instance_idx]; + for (int volume_idx = 0; volume_idx < (int)model_object->volumes.size(); ++volume_idx) { + const ModelVolume* model_volume = model_object->volumes[volume_idx]; + model_volume_state.emplace_back(model_volume, model_instance->id(), GLVolume::CompositeID(object_idx, volume_idx, instance_idx)); } } } if (printer_technology == ptSLA) { - const SLAPrint *sla_print = this->sla_print(); - #ifndef NDEBUG + const SLAPrint* sla_print = this->sla_print(); +#ifndef NDEBUG // Verify that the SLAPrint object is synchronized with m_model. check_model_ids_equal(*m_model, sla_print->model()); - #endif /* NDEBUG */ +#endif /* NDEBUG */ sla_support_state.reserve(sla_print->objects().size()); - for (const SLAPrintObject *print_object : sla_print->objects()) { + for (const SLAPrintObject* print_object : sla_print->objects()) { SLASupportState state; - for (size_t istep = 0; istep < sla_steps.size(); ++ istep) { - state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]); - if (state.step[istep].state == PrintStateBase::DONE) { - if (! print_object->has_mesh(sla_steps[istep])) + for (size_t istep = 0; istep < sla_steps.size(); ++istep) { + state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]); + if (state.step[istep].state == PrintStateBase::DONE) { + if (!print_object->has_mesh(sla_steps[istep])) // Consider the DONE step without a valid mesh as invalid for the purpose // of mesh visualization. state.step[istep].state = PrintStateBase::INVALID; else - for (const ModelInstance *model_instance : print_object->model_object()->instances) - // Only the instances, which are currently printable, will have the SLA support structures kept. - // The instances outside the print bed will have the GLVolumes of their support structures released. - if (model_instance->is_printable()) + for (const ModelInstance* model_instance : print_object->model_object()->instances) + // Only the instances, which are currently printable, will have the SLA support structures kept. + // The instances outside the print bed will have the GLVolumes of their support structures released. + if (model_instance->is_printable()) aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id()); } - } - sla_support_state.emplace_back(state); + } + sla_support_state.emplace_back(state); } } std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower); - std::sort(aux_volume_state .begin(), aux_volume_state .end(), model_volume_state_lower); + std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower); // Release all ModelVolume based GLVolumes not found in the current Model. - for (size_t volume_id = 0; volume_id < m_volumes.volumes.size(); ++ volume_id) { - GLVolume *volume = m_volumes.volumes[volume_id]; + for (size_t volume_id = 0; volume_id < m_volumes.volumes.size(); ++volume_id) { + GLVolume* volume = m_volumes.volumes[volume_id]; ModelVolumeState key(volume); - ModelVolumeState *mvs = nullptr; + ModelVolumeState* mvs = nullptr; if (volume->volume_idx() < 0) { - auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); + auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); if (it != aux_volume_state.end() && it->geometry_id == key.geometry_id) // This can be an SLA support structure that should not be rendered (in case someone used undo // to revert to before it was generated). We only reuse the volume if that's not the case. if (m_model->objects[volume->composite_id.object_id]->sla_points_status != sla::PointsStatus::NoPoints) mvs = &(*it); - } else { - auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); + } + else { + auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); if (it != model_volume_state.end() && it->geometry_id == key.geometry_id) - mvs = &(*it); + mvs = &(*it); } // Emplace instance ID of the volume. Both the aux volumes and model volumes share the same instance ID. // The wipe tower has its own wipe_tower_instance_id(). @@ -1854,19 +1871,27 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(volume_idx_wipe_tower_old == -1); volume_idx_wipe_tower_old = (int)volume_id; } - if (! m_reload_delayed) + if (!m_reload_delayed) +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + { + deleted_volumes.emplace_back(volume, volume_id); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK delete volume; - } else { +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + } +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + } + else { // This GLVolume will be reused. volume->set_sla_shift_z(0.0); map_glvolume_old_to_new[volume_id] = glvolumes_new.size(); mvs->volume_idx = glvolumes_new.size(); glvolumes_new.emplace_back(volume); // Update color of the volume based on the current extruder. - if (mvs->model_volume != nullptr) { - int extruder_id = mvs->model_volume->extruder_id(); - if (extruder_id != -1) - volume->extruder_id = extruder_id; + if (mvs->model_volume != nullptr) { + int extruder_id = mvs->model_volume->extruder_id(); + if (extruder_id != -1) + volume->extruder_id = extruder_id; volume->is_modifier = !mvs->model_volume->is_model_part(); volume->set_color_from_model_volume(mvs->model_volume); @@ -1882,7 +1907,19 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (m_reload_delayed) return; - bool update_object_list = false; + bool update_object_list = false; + +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + auto find_old_volume_id = [&deleted_volumes](const GLVolume::CompositeID& id) -> unsigned int { + for (unsigned int i = 0; i < (unsigned int)deleted_volumes.size(); ++i) + { + const GLVolumeState& v = deleted_volumes[i]; + if (v.composite_id == id) + return v.volume_idx; + } + return (unsigned int)-1; + }; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK if (m_volumes.volumes != glvolumes_new) update_object_list = true; @@ -1898,9 +1935,14 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); if (it->new_geometry()) { // New volume. +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + unsigned int old_id = find_old_volume_id(it->composite_id); + if (old_id != -1) + map_glvolume_old_to_new[old_id] = m_volumes.volumes.size(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; - update_object_list = true; + update_object_list = true; } else { // Recycling an old GLVolume. GLVolume &existing_volume = *m_volumes.volumes[it->volume_idx]; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 49f0f6fa23..2ccdfbc42b 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1466,6 +1466,14 @@ void ObjectList::append_menu_item_export_stl(wxMenu* menu) const menu->AppendSeparator(); } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +void ObjectList::append_menu_item_reload_from_disk(wxMenu* menu) const +{ + append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")), + [this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu, []() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater()); +} +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const { const wxString name = _(L("Change extruder")); @@ -1515,6 +1523,9 @@ void ObjectList::create_object_popupmenu(wxMenu *menu) append_menu_items_osx(menu); #endif // __WXOSX__ +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + append_menu_item_reload_from_disk(menu); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_export_stl(menu); append_menu_item_fix_through_netfabb(menu); append_menu_item_scale_selection_to_fit_print_volume(menu); @@ -1538,6 +1549,9 @@ void ObjectList::create_sla_object_popupmenu(wxMenu *menu) append_menu_items_osx(menu); #endif // __WXOSX__ +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + append_menu_item_reload_from_disk(menu); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_export_stl(menu); append_menu_item_fix_through_netfabb(menu); // rest of a object_sla_menu will be added later in: @@ -1550,8 +1564,15 @@ void ObjectList::create_part_popupmenu(wxMenu *menu) append_menu_items_osx(menu); #endif // __WXOSX__ +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + append_menu_item_reload_from_disk(menu); +#else append_menu_item_fix_through_netfabb(menu); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_export_stl(menu); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + append_menu_item_fix_through_netfabb(menu); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_split(menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 13d1106fc6..87e2e5aa09 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -232,7 +232,10 @@ public: wxMenuItem* append_menu_item_printable(wxMenu* menu, wxWindow* parent); void append_menu_items_osx(wxMenu* menu); wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu); - void append_menu_item_export_stl(wxMenu* menu) const ; + void append_menu_item_export_stl(wxMenu* menu) const; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + void append_menu_item_reload_from_disk(wxMenu* menu) const; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void append_menu_item_change_extruder(wxMenu* menu) const; void append_menu_item_delete(wxMenu* menu); void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 0dc7519e84..32ee6d57ae 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -10,6 +10,9 @@ #include #include #include +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +#include +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK #include #include @@ -1905,6 +1908,9 @@ struct Plater::priv bool can_fix_through_netfabb() const; bool can_set_instance_to_object() const; bool can_mirror() const; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + bool can_reload_from_disk() const; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void msw_rescale_object_menu(); @@ -1941,7 +1947,9 @@ private: * */ std::string m_last_fff_printer_profile_name; std::string m_last_sla_printer_profile_name; +#if !ENABLE_ENHANCED_RELOAD_FROM_DISK bool m_update_objects_list_on_loading{ true }; +#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK }; const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase); @@ -2467,12 +2475,16 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode _(L("Object too large?"))); } +#if !ENABLE_ENHANCED_RELOAD_FROM_DISK if (m_update_objects_list_on_loading) { +#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK for (const size_t idx : obj_idxs) { wxGetApp().obj_list()->add_object_to_list(idx); } +#if !ENABLE_ENHANCED_RELOAD_FROM_DISK } +#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK update(); object_list_changed(); @@ -3092,6 +3104,111 @@ void Plater::priv::update_sla_scene() void Plater::priv::reload_from_disk() { +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + Plater::TakeSnapshot snapshot(q, _(L("Reload from disk"))); + + const Selection& selection = get_selection(); + + if (selection.is_wipe_tower()) + return; + + // struct to hold selected ModelVolumes by their indices + struct SelectedVolume + { + int object_idx; + int volume_idx; + + // operators needed by std::algorithms + bool operator < (const SelectedVolume& other) const { return (object_idx < other.object_idx) || ((object_idx == other.object_idx) && (volume_idx < other.volume_idx)); } + bool operator == (const SelectedVolume& other) const { return (object_idx == other.object_idx) && (volume_idx == other.volume_idx); } + }; + std::vector selected_volumes; + + // collects selected ModelVolumes + const std::set& selected_volumes_idxs = selection.get_volume_idxs(); + for (unsigned int idx : selected_volumes_idxs) + { + const GLVolume* v = selection.get_volume(idx); + int o_idx = v->object_idx(); + int v_idx = v->volume_idx(); + selected_volumes.push_back({ o_idx, v_idx }); + } + std::sort(selected_volumes.begin(), selected_volumes.end()); + selected_volumes.erase(std::unique(selected_volumes.begin(), selected_volumes.end()), selected_volumes.end()); + + // collects paths of files to load + std::vector input_paths; + for (const SelectedVolume& v : selected_volumes) + { + const ModelVolume* volume = model.objects[v.object_idx]->volumes[v.volume_idx]; + if (!volume->source.input_file.empty() && boost::filesystem::exists(volume->source.input_file)) + input_paths.push_back(volume->source.input_file); + } + std::sort(input_paths.begin(), input_paths.end()); + input_paths.erase(std::unique(input_paths.begin(), input_paths.end()), input_paths.end()); + + // load one file at a time + for (size_t i = 0; i < input_paths.size(); ++i) + { + const auto& path = input_paths[i].string(); + Model new_model; + try + { + new_model = Model::read_from_file(path, nullptr, true, false); + for (ModelObject* model_object : new_model.objects) + { + model_object->center_around_origin(); + model_object->ensure_on_bed(); + } + } + catch (std::exception&) + { + // error while loading + view3D->get_canvas3d()->enable_render(true); + return; + } + + // update the selected volumes whose source is the current file + for (const SelectedVolume& old_v : selected_volumes) + { + ModelObject* old_model_object = model.objects[old_v.object_idx]; + ModelVolume* old_volume = old_model_object->volumes[old_v.volume_idx]; + int new_volume_idx = old_volume->source.volume_idx; + int new_object_idx = old_volume->source.object_idx; + + if (old_volume->source.input_file == path) + { + if (new_object_idx < (int)new_model.objects.size()) + { + ModelObject* new_model_object = new_model.objects[new_object_idx]; + if (new_volume_idx < (int)new_model_object->volumes.size()) + { + old_model_object->add_volume(*new_model_object->volumes[new_volume_idx]); + ModelVolume* new_volume = old_model_object->volumes.back(); + new_volume->set_new_unique_id(); + new_volume->config.apply(old_volume->config); + new_volume->set_type(old_volume->type()); + new_volume->set_transformation(old_volume->get_transformation()); + new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); + std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back()); + old_model_object->delete_volume(old_model_object->volumes.size() - 1); + } + } + } + } + } + + model.adjust_min_z(); + + // update 3D scene + update(); + + // new GLVolumes have been created at this point, so update their printable state + for (size_t i = 0; i < model.objects.size(); ++i) + { + view3D->get_canvas3d()->update_instance_printable_state_for_object(i); + } +#else Plater::TakeSnapshot snapshot(q, _(L("Reload from Disk"))); auto& selection = get_selection(); @@ -3113,6 +3230,7 @@ void Plater::priv::reload_from_disk() { // error while loading view3D->get_canvas3d()->enable_render(true); + m_update_objects_list_on_loading = true; return; } @@ -3174,6 +3292,7 @@ void Plater::priv::reload_from_disk() { selection.add_instance((unsigned int)idx - 1, instance_idx, false); } +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) @@ -3587,6 +3706,11 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), [this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")), + [this](wxCommandEvent&) { q->reload_from_disk(); }, "", menu, [this]() { return can_reload_from_disk(); }, q); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + sidebar->obj_list()->append_menu_item_export_stl(menu); } else { @@ -3613,8 +3737,13 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q); menu->AppendSeparator(); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected object from disk")), + [this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr, [this]() { return can_reload_from_disk(); }, q); +#else append_menu_item(menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")), [this](wxCommandEvent&) { reload_from_disk(); }); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")), [this](wxCommandEvent&) { q->export_stl(false, true); }); @@ -3769,6 +3898,50 @@ bool Plater::priv::can_mirror() const return get_selection().is_from_single_instance(); } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +bool Plater::priv::can_reload_from_disk() const +{ + // struct to hold selected ModelVolumes by their indices + struct SelectedVolume + { + int object_idx; + int volume_idx; + + // operators needed by std::algorithms + bool operator < (const SelectedVolume& other) const { return (object_idx < other.object_idx) || ((object_idx == other.object_idx) && (volume_idx < other.volume_idx)); } + bool operator == (const SelectedVolume& other) const { return (object_idx == other.object_idx) && (volume_idx == other.volume_idx); } + }; + std::vector selected_volumes; + + const Selection& selection = get_selection(); + + // collects selected ModelVolumes + const std::set& selected_volumes_idxs = selection.get_volume_idxs(); + for (unsigned int idx : selected_volumes_idxs) + { + const GLVolume* v = selection.get_volume(idx); + int o_idx = v->object_idx(); + int v_idx = v->volume_idx(); + selected_volumes.push_back({ o_idx, v_idx }); + } + std::sort(selected_volumes.begin(), selected_volumes.end()); + selected_volumes.erase(std::unique(selected_volumes.begin(), selected_volumes.end()), selected_volumes.end()); + + // collects paths of files to load + std::vector paths; + for (const SelectedVolume& v : selected_volumes) + { + const ModelVolume* volume = model.objects[v.object_idx]->volumes[v.volume_idx]; + if (!volume->source.input_file.empty() && boost::filesystem::exists(volume->source.input_file)) + paths.push_back(volume->source.input_file); + } + std::sort(paths.begin(), paths.end()); + paths.erase(std::unique(paths.begin(), paths.end()), paths.end()); + + return !paths.empty(); +} +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + void Plater::priv::set_bed_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model) { bool new_shape = bed.set_shape(shape, custom_texture, custom_model); @@ -4552,6 +4725,13 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) } } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +void Plater::reload_from_disk() +{ + p->reload_from_disk(); +} +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + bool Plater::has_toolpaths_to_export() const { return p->preview->get_canvas3d()->has_toolpaths_to_export(); @@ -5044,6 +5224,9 @@ bool Plater::can_copy_to_clipboard() const bool Plater::can_undo() const { return p->undo_redo_stack().has_undo_snapshot(); } bool Plater::can_redo() const { return p->undo_redo_stack().has_redo_snapshot(); } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); } +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); } void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); } void Plater::leave_gizmos_stack() { p->leave_gizmos_stack(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 0dc2985665..f23259e473 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -183,6 +183,9 @@ public: void export_stl(bool extended = false, bool selection_only = false); void export_amf(); void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + void reload_from_disk(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK bool has_toolpaths_to_export() const; void export_toolpaths_to_obj() const; void reslice(); @@ -246,6 +249,9 @@ public: bool can_copy_to_clipboard() const; bool can_undo() const; bool can_redo() const; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + bool can_reload_from_disk() const; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void msw_rescale(); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 40fbbbac63..346f46e00c 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -472,7 +472,11 @@ void Selection::volumes_changed(const std::vector &map_volume_old_to_new for (unsigned int idx : m_list) if (map_volume_old_to_new[idx] != size_t(-1)) { unsigned int new_idx = (unsigned int)map_volume_old_to_new[idx]; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + (*m_volumes)[new_idx]->selected = true; +#else assert((*m_volumes)[new_idx]->selected); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK list_new.insert(new_idx); } m_list = std::move(list_new); From 74747226f70a77736866ce7c256a7b655d626efe Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 19 Sep 2019 12:39:59 +0200 Subject: [PATCH 11/23] ENABLE_ENHANCED_RELOAD_FROM_DISK 1) Modified .zip.amf import/export to save/load volume matrices and source data 2) Incremented .zip.amf version to 3 --- src/libslic3r/Format/3mf.cpp | 37 +++--------------- src/libslic3r/Format/AMF.cpp | 76 +++++++++++++++++++++++++++++++++++- src/libslic3r/Geometry.cpp | 33 ++++++++++++++++ src/libslic3r/Geometry.hpp | 3 ++ src/libslic3r/Model.cpp | 11 ++++-- src/libslic3r/Model.hpp | 4 ++ src/slic3r/GUI/Plater.cpp | 1 + 7 files changed, 130 insertions(+), 35 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index fbec5b00b9..494da5fe64 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -32,7 +32,7 @@ namespace pt = boost::property_tree; // 0 : .3mf, files saved by older slic3r or other applications. No version definition in them. // 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files. #if ENABLE_ENHANCED_RELOAD_FROM_DISK -// 2 : Meshes saved in their local system and volumes matrices added to Metadata/Slic3r_PE_model.config file. +// 2 : Meshes saved in their local system; Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file. const unsigned int VERSION_3MF = 2; #else const unsigned int VERSION_3MF = 1; @@ -208,35 +208,6 @@ Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) return ret; } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK -Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) -{ - Slic3r::Transform3d ret = Slic3r::Transform3d::Identity(); - - if (mat_str.empty()) - // empty string means default identity matrix - return ret; - - std::vector mat_elements_str; - boost::split(mat_elements_str, mat_str, boost::is_any_of(" "), boost::token_compress_on); - - unsigned int size = (unsigned int)mat_elements_str.size(); - if (size != 16) - // invalid data, return identity matrix - return ret; - - unsigned int i = 0; - for (unsigned int r = 0; r < 4; ++r) - { - for (unsigned int c = 0; c < 4; ++c) - { - ret(r, c) = ::atof(mat_elements_str[i++].c_str()); - } - } - return ret; -} -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK - float get_unit_factor(const std::string& unit) { const char* text = unit.c_str(); @@ -1744,7 +1715,11 @@ namespace Slic3r { volume->set_type(ModelVolume::type_from_string(metadata.value)); #if ENABLE_ENHANCED_RELOAD_FROM_DISK else if (metadata.key == MATRIX_KEY) - volume->set_transformation(Slic3r::Geometry::Transformation(get_transform_from_string(metadata.value))); + { + Slic3r::Geometry::Transformation transform; + transform.set_from_string(metadata.value); + volume->set_transformation(transform); + } else if (metadata.key == SOURCE_FILE_KEY) volume->source.input_file = metadata.value; else if (metadata.key == SOURCE_OBJECT_ID_KEY) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 92c958d8ab..3f85b4b603 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -12,6 +12,9 @@ #include "../PrintConfig.hpp" #include "../Utils.hpp" #include "../I18N.hpp" +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +#include "../Geometry.hpp" +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK #include "AMF.hpp" @@ -36,7 +39,12 @@ // Added x and y components of rotation // Added x, y and z components of scale // Added x, y and z components of mirror +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +// 3 : Meshes saved in their local system; Added volumes' matrices and source data +const unsigned int VERSION_AMF = 3; +#else const unsigned int VERSION_AMF = 2; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version"; const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config"; @@ -568,7 +576,12 @@ void AMFParserContext::endElement(const char * /* name */) stl_get_size(&stl); mesh.repair(); m_volume->set_mesh(std::move(mesh)); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + // pass false if the mesh offset has been already taken from the data + m_volume->center_geometry_after_creation(m_volume->source.input_file.empty()); +#else m_volume->center_geometry_after_creation(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK m_volume->calculate_convex_hull(); m_volume_facets.clear(); m_volume = nullptr; @@ -664,6 +677,31 @@ void AMFParserContext::endElement(const char * /* name */) } else if (strcmp(opt_key, "volume_type") == 0) { m_volume->set_type(ModelVolume::type_from_string(m_value[1])); } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + else if (strcmp(opt_key, "matrix") == 0) { + Geometry::Transformation transform; + transform.set_from_string(m_value[1]); + m_volume->set_transformation(transform); + } + else if (strcmp(opt_key, "source_file") == 0) { + m_volume->source.input_file = m_value[1]; + } + else if (strcmp(opt_key, "source_object_id") == 0) { + m_volume->source.object_idx = ::atoi(m_value[1].c_str()); + } + else if (strcmp(opt_key, "source_volume_id") == 0) { + m_volume->source.volume_idx = ::atoi(m_value[1].c_str()); + } + else if (strcmp(opt_key, "source_offset_x") == 0) { + m_volume->source.mesh_offset(0) = ::atof(m_value[1].c_str()); + } + else if (strcmp(opt_key, "source_offset_y") == 0) { + m_volume->source.mesh_offset(1) = ::atof(m_value[1].c_str()); + } + else if (strcmp(opt_key, "source_offset_z") == 0) { + m_volume->source.mesh_offset(2) = ::atof(m_value[1].c_str()); + } +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } } else if (m_path.size() == 3) { if (m_path[1] == NODE_TYPE_MATERIAL) { @@ -1029,6 +1067,18 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (! volume->mesh().has_shared_vertices()) throw std::runtime_error("store_amf() requires shared vertices"); const indexed_triangle_set &its = volume->mesh().its; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + for (const Vec3f& v : its.vertices) + { + stream << " \n"; + stream << " \n"; + stream << " " << v(0) << "\n"; + stream << " " << v(1) << "\n"; + stream << " " << v(2) << "\n"; + stream << " \n"; + stream << " \n"; + } +#else const Transform3d& matrix = volume->get_matrix(); for (size_t i = 0; i < its.vertices.size(); ++i) { stream << " \n"; @@ -1040,6 +1090,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " \n"; stream << " \n"; } +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK num_vertices += (int)its.vertices.size(); } stream << " \n"; @@ -1057,7 +1108,30 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (volume->is_modifier()) stream << " 1\n"; stream << " " << ModelVolume::type_to_string(volume->type()) << "\n"; - const indexed_triangle_set &its = volume->mesh().its; +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + stream << " "; + const Transform3d& matrix = volume->get_matrix(); + for (int r = 0; r < 4; ++r) + { + for (int c = 0; c < 4; ++c) + { + stream << matrix(r, c); + if ((r != 3) || (c != 3)) + stream << " "; + } + } + stream << "\n"; + if (!volume->source.input_file.empty()) + { + stream << " " << xml_escape(volume->source.input_file) << "\n"; + stream << " " << volume->source.object_idx << "\n"; + stream << " " << volume->source.volume_idx << "\n"; + stream << " " << volume->source.mesh_offset(0) << "\n"; + stream << " " << volume->source.mesh_offset(1) << "\n"; + stream << " " << volume->source.mesh_offset(2) << "\n"; + } +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + const indexed_triangle_set &its = volume->mesh().its; for (size_t i = 0; i < its.indices.size(); ++i) { stream << " \n"; for (int j = 0; j < 3; ++j) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index cc8a86a96c..280233b2a6 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -15,6 +15,11 @@ #include #include +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +#include +#include +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + #ifdef SLIC3R_DEBUG #include "SVG.hpp" #endif @@ -1376,6 +1381,34 @@ void Transformation::set_from_transform(const Transform3d& transform) // std::cout << "something went wrong in extracting data from matrix" << std::endl; } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +void Transformation::set_from_string(const std::string& transform_str) +{ + Transform3d transform = Transform3d::Identity(); + + if (!transform_str.empty()) + { + std::vector mat_elements_str; + boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on); + + unsigned int size = (unsigned int)mat_elements_str.size(); + if (size == 16) + { + unsigned int i = 0; + for (unsigned int r = 0; r < 4; ++r) + { + for (unsigned int c = 0; c < 4; ++c) + { + transform(r, c) = ::atof(mat_elements_str[i++].c_str()); + } + } + } + } + + set_from_transform(transform); +} +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + void Transformation::reset() { m_offset = Vec3d::Zero(); diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index eec2673227..43f7917235 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -278,6 +278,9 @@ public: void set_mirror(Axis axis, double mirror); void set_from_transform(const Transform3d& transform); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + void set_from_string(const std::string& transform_str); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void reset(); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index d36f5b7acc..ffc4c24540 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1555,7 +1555,11 @@ bool ModelVolume::is_splittable() const return m_is_splittable == 1; } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK +void ModelVolume::center_geometry_after_creation(bool update_source_offset) +#else void ModelVolume::center_geometry_after_creation() +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK { Vec3d shift = this->mesh().bounding_box().center(); if (!shift.isApprox(Vec3d::Zero())) @@ -1566,9 +1570,10 @@ void ModelVolume::center_geometry_after_creation() const_cast(m_convex_hull.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); translate(shift); } -//================================================================================================================================================================================================ - source.mesh_offset = shift; -//================================================================================================================================================================================================ +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + if (update_source_offset) + source.mesh_offset = shift; +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } void ModelVolume::calculate_convex_hull() diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index c91f72a956..6a9bc82fa2 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -453,7 +453,11 @@ public: // Translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box. // Attention! This method may only be called just after ModelVolume creation! It must not be called once the TriangleMesh of this ModelVolume is shared! +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + void center_geometry_after_creation(bool update_source_offset = true); +#else void center_geometry_after_creation(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void calculate_convex_hull(); const TriangleMesh& get_convex_hull() const; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 32ee6d57ae..4db8d6858c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3188,6 +3188,7 @@ void Plater::priv::reload_from_disk() new_volume->set_new_unique_id(); new_volume->config.apply(old_volume->config); new_volume->set_type(old_volume->type()); + new_volume->set_material_id(old_volume->material_id()); new_volume->set_transformation(old_volume->get_transformation()); new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset)); std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back()); From 5eb4692442ffae935a74f92dccbfe7aafe6e4364 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 23 Sep 2019 12:33:21 +0200 Subject: [PATCH 12/23] ENABLE_ENHANCED_RELOAD_FROM_DISK -> Fixed export/import to/from .3mf to keep compatibility with 3rd part software. --- src/libslic3r/Format/3mf.cpp | 56 +++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 494da5fe64..6ce4ac4a53 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1674,6 +1674,23 @@ namespace Slic3r { return false; } +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + Slic3r::Geometry::Transformation transform; + if (m_version > 1) + { + // extract the volume transformation from the volume's metadata, if present + for (const Metadata& metadata : volume_data.metadata) + { + if (metadata.key == MATRIX_KEY) + { + transform.set_from_string(metadata.value); + break; + } + } + } + Transform3d inv_matrix = transform.get_matrix().inverse(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + // splits volume out of imported geometry TriangleMesh triangle_mesh; stl_file &stl = triangle_mesh.stl; @@ -1691,7 +1708,16 @@ namespace Slic3r { stl_facet& facet = stl.facet_start[i]; for (unsigned int v = 0; v < 3; ++v) { +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3; + Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]); + if (m_version > 1) + // revert the vertices to the original mesh reference system + vertex = (inv_matrix * vertex.cast()).cast(); + ::memcpy(facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float)); +#else ::memcpy(facet.vertex[v].data(), (const void*)&geometry.vertices[geometry.triangles[src_start_id + ii + v] * 3], 3 * sizeof(float)); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } } @@ -1699,12 +1725,20 @@ namespace Slic3r { triangle_mesh.repair(); ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); -#if !ENABLE_ENHANCED_RELOAD_FROM_DISK +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + // apply the volume matrix taken from the metadata, if present + if (m_version > 1) + volume->set_transformation(transform); +#else volume->center_geometry_after_creation(); -#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK volume->calculate_convex_hull(); +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + // apply the remaining volume's metadata +#else // apply volume's name and config data +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK for (const Metadata& metadata : volume_data.metadata) { if (metadata.key == NAME_KEY) @@ -1714,12 +1748,6 @@ namespace Slic3r { else if (metadata.key == VOLUME_TYPE_KEY) volume->set_type(ModelVolume::type_from_string(metadata.value)); #if ENABLE_ENHANCED_RELOAD_FROM_DISK - else if (metadata.key == MATRIX_KEY) - { - Slic3r::Geometry::Transformation transform; - transform.set_from_string(metadata.value); - volume->set_transformation(transform); - } else if (metadata.key == SOURCE_FILE_KEY) volume->source.input_file = metadata.value; else if (metadata.key == SOURCE_OBJECT_ID_KEY) @@ -2118,19 +2146,8 @@ namespace Slic3r { vertices_count += (int)its.vertices.size(); -#if !ENABLE_ENHANCED_RELOAD_FROM_DISK const Transform3d& matrix = volume->get_matrix(); -#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK -#if ENABLE_ENHANCED_RELOAD_FROM_DISK - for (const Vec3f& v : its.vertices) - { - stream << " <" << VERTEX_TAG << " "; - stream << "x=\"" << v(0) << "\" "; - stream << "y=\"" << v(1) << "\" "; - stream << "z=\"" << v(2) << "\" />\n"; - } -#else for (size_t i = 0; i < its.vertices.size(); ++i) { stream << " <" << VERTEX_TAG << " "; @@ -2139,7 +2156,6 @@ namespace Slic3r { stream << "y=\"" << v(1) << "\" "; stream << "z=\"" << v(2) << "\" />\n"; } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } stream << " \n"; From 1115e77b38ae974f67252524fc401282bec1209f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 23 Sep 2019 13:54:49 +0200 Subject: [PATCH 13/23] ENABLE_ENHANCED_RELOAD_FROM_DISK -> Fixed export/import to/from .amf to keep compatibility with 3rd part software. --- src/libslic3r/Format/AMF.cpp | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 3f85b4b603..490a479d69 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -568,10 +568,30 @@ void AMFParserContext::endElement(const char * /* name */) stl.stats.number_of_facets = int(m_volume_facets.size() / 3); stl.stats.original_num_facets = stl.stats.number_of_facets; stl_allocate(&stl); + +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + Slic3r::Geometry::Transformation transform; + if (m_version > 2) + transform = m_volume->get_transformation(); + + Transform3d inv_matrix = transform.get_matrix().inverse(); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + for (size_t i = 0; i < m_volume_facets.size();) { stl_facet &facet = stl.facet_start[i/3]; - for (unsigned int v = 0; v < 3; ++ v) + for (unsigned int v = 0; v < 3; ++v) +#if ENABLE_ENHANCED_RELOAD_FROM_DISK + { + unsigned int tri_id = m_volume_facets[i++] * 3; + Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]); + if (m_version > 2) + // revert the vertices to the original mesh reference system + vertex = (inv_matrix * vertex.cast()).cast(); + ::memcpy((void*)facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float)); + } +#else memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float)); +#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } stl_get_size(&stl); mesh.repair(); @@ -1067,18 +1087,6 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (! volume->mesh().has_shared_vertices()) throw std::runtime_error("store_amf() requires shared vertices"); const indexed_triangle_set &its = volume->mesh().its; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK - for (const Vec3f& v : its.vertices) - { - stream << " \n"; - stream << " \n"; - stream << " " << v(0) << "\n"; - stream << " " << v(1) << "\n"; - stream << " " << v(2) << "\n"; - stream << " \n"; - stream << " \n"; - } -#else const Transform3d& matrix = volume->get_matrix(); for (size_t i = 0; i < its.vertices.size(); ++i) { stream << " \n"; @@ -1090,7 +1098,6 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " \n"; stream << " \n"; } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK num_vertices += (int)its.vertices.size(); } stream << " \n"; From 2dc9949a4c129a448d0a5881ac2d2d165e2fea4c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 23 Sep 2019 15:35:49 +0200 Subject: [PATCH 14/23] ENABLE_ENHANCED_RELOAD_FROM_DISK set as default --- src/libslic3r/Format/3mf.cpp | 47 ------------ src/libslic3r/Format/AMF.cpp | 20 ----- src/libslic3r/Geometry.cpp | 4 - src/libslic3r/Geometry.hpp | 2 - src/libslic3r/Model.cpp | 25 ++----- src/libslic3r/Model.hpp | 23 +----- src/libslic3r/Technologies.hpp | 7 -- src/slic3r/GUI/GLCanvas3D.cpp | 12 --- src/slic3r/GUI/GUI_ObjectList.cpp | 12 --- src/slic3r/GUI/GUI_ObjectList.hpp | 2 - src/slic3r/GUI/Plater.cpp | 117 +----------------------------- src/slic3r/GUI/Plater.hpp | 4 - src/slic3r/GUI/Selection.cpp | 4 - 13 files changed, 10 insertions(+), 269 deletions(-) diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 6ce4ac4a53..47a8e52808 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -31,12 +31,8 @@ namespace pt = boost::property_tree; // VERSION NUMBERS // 0 : .3mf, files saved by older slic3r or other applications. No version definition in them. // 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files. -#if ENABLE_ENHANCED_RELOAD_FROM_DISK // 2 : Meshes saved in their local system; Volumes' matrices and source data added to Metadata/Slic3r_PE_model.config file. const unsigned int VERSION_3MF = 2; -#else -const unsigned int VERSION_3MF = 1; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const char* SLIC3RPE_3MF_VERSION = "slic3rpe:Version3mf"; // definition of the metadata name saved into .model file const std::string MODEL_FOLDER = "3D/"; @@ -92,7 +88,6 @@ const char* VOLUME_TYPE = "volume"; const char* NAME_KEY = "name"; const char* MODIFIER_KEY = "modifier"; const char* VOLUME_TYPE_KEY = "volume_type"; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK const char* MATRIX_KEY = "matrix"; const char* SOURCE_FILE_KEY = "source_file"; const char* SOURCE_OBJECT_ID_KEY = "source_object_id"; @@ -100,7 +95,6 @@ const char* SOURCE_VOLUME_ID_KEY = "source_volume_id"; const char* SOURCE_OFFSET_X_KEY = "source_offset_x"; const char* SOURCE_OFFSET_Y_KEY = "source_offset_y"; const char* SOURCE_OFFSET_Z_KEY = "source_offset_z"; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const unsigned int VALID_OBJECT_TYPES_COUNT = 1; const char* VALID_OBJECT_TYPES[] = @@ -162,25 +156,15 @@ bool get_attribute_value_bool(const char** attributes, unsigned int attributes_s return (text != nullptr) ? (bool)::atoi(text) : true; } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK Slic3r::Transform3d get_transform_from_3mf_specs_string(const std::string& mat_str) -#else -Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK { -#if ENABLE_ENHANCED_RELOAD_FROM_DISK // check: https://3mf.io/3d-manufacturing-format/ or https://github.com/3MFConsortium/spec_core/blob/master/3MF%20Core%20Specification.md // to see how matrices are stored inside 3mf according to specifications Slic3r::Transform3d ret = Slic3r::Transform3d::Identity(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK if (mat_str.empty()) // empty string means default identity matrix -#if ENABLE_ENHANCED_RELOAD_FROM_DISK return ret; -#else - return Slic3r::Transform3d::Identity(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK std::vector mat_elements_str; boost::split(mat_elements_str, mat_str, boost::is_any_of(" "), boost::token_compress_on); @@ -188,13 +172,8 @@ Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) unsigned int size = (unsigned int)mat_elements_str.size(); if (size != 12) // invalid data, return identity matrix -#if ENABLE_ENHANCED_RELOAD_FROM_DISK return ret; -#else - return Slic3r::Transform3d::Identity(); - Slic3r::Transform3d ret = Slic3r::Transform3d::Identity(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK unsigned int i = 0; // matrices are stored into 3mf files as 4x3 // we need to transpose them @@ -1407,11 +1386,7 @@ namespace Slic3r { bool _3MF_Importer::_handle_start_component(const char** attributes, unsigned int num_attributes) { int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK Transform3d transform = get_transform_from_3mf_specs_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); -#else - Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK IdToModelObjectMap::iterator object_item = m_objects.find(object_id); if (object_item == m_objects.end()) @@ -1457,11 +1432,7 @@ namespace Slic3r { // see specifications int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK Transform3d transform = get_transform_from_3mf_specs_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); -#else - Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK int printable = get_attribute_value_bool(attributes, num_attributes, PRINTABLE_ATTR); return _create_object_instance(object_id, transform, printable, 1); @@ -1674,7 +1645,6 @@ namespace Slic3r { return false; } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK Slic3r::Geometry::Transformation transform; if (m_version > 1) { @@ -1689,7 +1659,6 @@ namespace Slic3r { } } Transform3d inv_matrix = transform.get_matrix().inverse(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK // splits volume out of imported geometry TriangleMesh triangle_mesh; @@ -1708,16 +1677,12 @@ namespace Slic3r { stl_facet& facet = stl.facet_start[i]; for (unsigned int v = 0; v < 3; ++v) { -#if ENABLE_ENHANCED_RELOAD_FROM_DISK unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3; Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]); if (m_version > 1) // revert the vertices to the original mesh reference system vertex = (inv_matrix * vertex.cast()).cast(); ::memcpy(facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float)); -#else - ::memcpy(facet.vertex[v].data(), (const void*)&geometry.vertices[geometry.triangles[src_start_id + ii + v] * 3], 3 * sizeof(float)); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } } @@ -1725,20 +1690,12 @@ namespace Slic3r { triangle_mesh.repair(); ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK // apply the volume matrix taken from the metadata, if present if (m_version > 1) volume->set_transformation(transform); -#else - volume->center_geometry_after_creation(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK volume->calculate_convex_hull(); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK // apply the remaining volume's metadata -#else - // apply volume's name and config data -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK for (const Metadata& metadata : volume_data.metadata) { if (metadata.key == NAME_KEY) @@ -1747,7 +1704,6 @@ namespace Slic3r { volume->set_type(ModelVolumeType::PARAMETER_MODIFIER); else if (metadata.key == VOLUME_TYPE_KEY) volume->set_type(ModelVolume::type_from_string(metadata.value)); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK else if (metadata.key == SOURCE_FILE_KEY) volume->source.input_file = metadata.value; else if (metadata.key == SOURCE_OBJECT_ID_KEY) @@ -1760,7 +1716,6 @@ namespace Slic3r { volume->source.mesh_offset(1) = ::atof(metadata.value.c_str()); else if (metadata.key == SOURCE_OFFSET_Z_KEY) volume->source.mesh_offset(2) = ::atof(metadata.value.c_str()); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK else volume->config.set_deserialize(metadata.key, metadata.value); } @@ -2434,7 +2389,6 @@ namespace Slic3r { stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " << VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n"; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK // stores volume's local matrix stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\""; const Transform3d& matrix = volume->get_matrix(); @@ -2459,7 +2413,6 @@ namespace Slic3r { stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_Y_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(1) << "\"/>\n"; stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << SOURCE_OFFSET_Z_KEY << "\" " << VALUE_ATTR << "=\"" << volume->source.mesh_offset(2) << "\"/>\n"; } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK // stores volume's config data for (const std::string& key : volume->config.keys()) diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 490a479d69..2b5638f573 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -12,9 +12,7 @@ #include "../PrintConfig.hpp" #include "../Utils.hpp" #include "../I18N.hpp" -#if ENABLE_ENHANCED_RELOAD_FROM_DISK #include "../Geometry.hpp" -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK #include "AMF.hpp" @@ -39,12 +37,8 @@ // Added x and y components of rotation // Added x, y and z components of scale // Added x, y and z components of mirror -#if ENABLE_ENHANCED_RELOAD_FROM_DISK // 3 : Meshes saved in their local system; Added volumes' matrices and source data const unsigned int VERSION_AMF = 3; -#else -const unsigned int VERSION_AMF = 2; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version"; const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config"; @@ -569,18 +563,15 @@ void AMFParserContext::endElement(const char * /* name */) stl.stats.original_num_facets = stl.stats.number_of_facets; stl_allocate(&stl); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK Slic3r::Geometry::Transformation transform; if (m_version > 2) transform = m_volume->get_transformation(); Transform3d inv_matrix = transform.get_matrix().inverse(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK for (size_t i = 0; i < m_volume_facets.size();) { stl_facet &facet = stl.facet_start[i/3]; for (unsigned int v = 0; v < 3; ++v) -#if ENABLE_ENHANCED_RELOAD_FROM_DISK { unsigned int tri_id = m_volume_facets[i++] * 3; Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]); @@ -589,19 +580,12 @@ void AMFParserContext::endElement(const char * /* name */) vertex = (inv_matrix * vertex.cast()).cast(); ::memcpy((void*)facet.vertex[v].data(), (const void*)vertex.data(), 3 * sizeof(float)); } -#else - memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float)); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } stl_get_size(&stl); mesh.repair(); m_volume->set_mesh(std::move(mesh)); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK // pass false if the mesh offset has been already taken from the data m_volume->center_geometry_after_creation(m_volume->source.input_file.empty()); -#else - m_volume->center_geometry_after_creation(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK m_volume->calculate_convex_hull(); m_volume_facets.clear(); m_volume = nullptr; @@ -697,7 +681,6 @@ void AMFParserContext::endElement(const char * /* name */) } else if (strcmp(opt_key, "volume_type") == 0) { m_volume->set_type(ModelVolume::type_from_string(m_value[1])); } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK else if (strcmp(opt_key, "matrix") == 0) { Geometry::Transformation transform; transform.set_from_string(m_value[1]); @@ -721,7 +704,6 @@ void AMFParserContext::endElement(const char * /* name */) else if (strcmp(opt_key, "source_offset_z") == 0) { m_volume->source.mesh_offset(2) = ::atof(m_value[1].c_str()); } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } } else if (m_path.size() == 3) { if (m_path[1] == NODE_TYPE_MATERIAL) { @@ -1115,7 +1097,6 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) if (volume->is_modifier()) stream << " 1\n"; stream << " " << ModelVolume::type_to_string(volume->type()) << "\n"; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK stream << " "; const Transform3d& matrix = volume->get_matrix(); for (int r = 0; r < 4; ++r) @@ -1137,7 +1118,6 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config) stream << " " << volume->source.mesh_offset(1) << "\n"; stream << " " << volume->source.mesh_offset(2) << "\n"; } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const indexed_triangle_set &its = volume->mesh().its; for (size_t i = 0; i < its.indices.size(); ++i) { stream << " \n"; diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 280233b2a6..643e42f17d 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -15,10 +15,8 @@ #include #include -#if ENABLE_ENHANCED_RELOAD_FROM_DISK #include #include -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK #ifdef SLIC3R_DEBUG #include "SVG.hpp" @@ -1381,7 +1379,6 @@ void Transformation::set_from_transform(const Transform3d& transform) // std::cout << "something went wrong in extracting data from matrix" << std::endl; } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK void Transformation::set_from_string(const std::string& transform_str) { Transform3d transform = Transform3d::Identity(); @@ -1407,7 +1404,6 @@ void Transformation::set_from_string(const std::string& transform_str) set_from_transform(transform); } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void Transformation::reset() { diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 43f7917235..c15ecbdfda 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -278,9 +278,7 @@ public: void set_mirror(Axis axis, double mirror); void set_from_transform(const Transform3d& transform); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK void set_from_string(const std::string& transform_str); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void reset(); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ffc4c24540..26973a5f58 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -141,14 +141,12 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig for (ModelObject *o : model.objects) { -#if !ENABLE_ENHANCED_RELOAD_FROM_DISK - if (boost::algorithm::iends_with(input_file, ".zip.amf")) - { - // we remove the .zip part of the extension to avoid it be added to filenames when exporting - o->input_file = boost::ireplace_last_copy(input_file, ".zip.", "."); - } - else -#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK +// if (boost::algorithm::iends_with(input_file, ".zip.amf")) +// { +// // we remove the .zip part of the extension to avoid it be added to filenames when exporting +// o->input_file = boost::ireplace_last_copy(input_file, ".zip.", "."); +// } +// else o->input_file = input_file; } @@ -172,11 +170,9 @@ ModelObject* Model::add_object(const char *name, const char *path, const Triangl new_object->input_file = path; ModelVolume *new_volume = new_object->add_volume(mesh); new_volume->name = name; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK new_volume->source.input_file = path; new_volume->source.object_idx = (int)this->objects.size() - 1; new_volume->source.volume_idx = (int)new_object->volumes.size() - 1; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK new_object->invalidate_bounding_box(); return new_object; } @@ -189,11 +185,9 @@ ModelObject* Model::add_object(const char *name, const char *path, TriangleMesh new_object->input_file = path; ModelVolume *new_volume = new_object->add_volume(std::move(mesh)); new_volume->name = name; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK new_volume->source.input_file = path; new_volume->source.object_idx = (int)this->objects.size() - 1; new_volume->source.volume_idx = (int)new_object->volumes.size() - 1; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK new_object->invalidate_bounding_box(); return new_object; } @@ -1555,11 +1549,7 @@ bool ModelVolume::is_splittable() const return m_is_splittable == 1; } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK void ModelVolume::center_geometry_after_creation(bool update_source_offset) -#else -void ModelVolume::center_geometry_after_creation() -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK { Vec3d shift = this->mesh().bounding_box().center(); if (!shift.isApprox(Vec3d::Zero())) @@ -1570,10 +1560,9 @@ void ModelVolume::center_geometry_after_creation() const_cast(m_convex_hull.get())->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2)); translate(shift); } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK + if (update_source_offset) source.mesh_offset = shift; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } void ModelVolume::calculate_convex_hull() diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 6a9bc82fa2..410c2d3ef4 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -392,7 +392,6 @@ class ModelVolume final : public ObjectBase { public: std::string name; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK // struct used by reload from disk command to recover data from disk struct Source { @@ -404,7 +403,7 @@ public: template void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset); } }; Source source; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK + // The triangular model. const TriangleMesh& mesh() const { return *m_mesh.get(); } void set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared(mesh); } @@ -453,11 +452,7 @@ public: // Translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box. // Attention! This method may only be called just after ModelVolume creation! It must not be called once the TriangleMesh of this ModelVolume is shared! -#if ENABLE_ENHANCED_RELOAD_FROM_DISK void center_geometry_after_creation(bool update_source_offset = true); -#else - void center_geometry_after_creation(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void calculate_convex_hull(); const TriangleMesh& get_convex_hull() const; @@ -546,11 +541,7 @@ private: // Copying an existing volume, therefore this volume will get a copy of the ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other) : ObjectBase(other), -#if ENABLE_ENHANCED_RELOAD_FROM_DISK name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) -#else - name(other.name), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK { assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id()); assert(this->id() == other.id() && this->config.id() == other.config.id()); @@ -558,11 +549,7 @@ private: } // Providing a new mesh, therefore this volume will get a new unique ID assigned. ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : -#if ENABLE_ENHANCED_RELOAD_FROM_DISK name(other.name), source(other.source), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) -#else - name(other.name), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation) -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK { assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id()); assert(this->id() != other.id() && this->config.id() == other.config.id()); @@ -583,11 +570,7 @@ private: } template void load(Archive &ar) { bool has_convex_hull; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); -#else - ar(name, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK cereal::load_by_value(ar, config); assert(m_mesh); if (has_convex_hull) { @@ -600,11 +583,7 @@ private: } template void save(Archive &ar) const { bool has_convex_hull = m_convex_hull.get() != nullptr; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); -#else - ar(name, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK cereal::save_by_value(ar, config); if (has_convex_hull) cereal::save_optional(ar, m_convex_hull); diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 60ae17a82d..51d0920946 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -32,11 +32,4 @@ #define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1) -//==================== -// 2.2.0.alpha1 techs -//==================== -#define ENABLE_2_2_0_ALPHA1 1 - -#define ENABLE_ENHANCED_RELOAD_FROM_DISK (1 && ENABLE_2_2_0_ALPHA1) - #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7a94b82387..ec79d0ec1d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1765,7 +1765,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re std::vector model_volume_state; std::vector aux_volume_state; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK struct GLVolumeState { GLVolumeState() : volume_idx(-1) {} @@ -1776,7 +1775,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Volume index in the old GLVolume vector. size_t volume_idx; }; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK // SLA steps to pull the preview meshes for. typedef std::array SLASteps; @@ -1789,9 +1787,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re std::vector instance_ids_selected; std::vector map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1)); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK std::vector deleted_volumes; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK std::vector glvolumes_new; glvolumes_new.reserve(m_volumes.volumes.size()); auto model_volume_state_lower = [](const ModelVolumeState& m1, const ModelVolumeState& m2) { return m1.geometry_id < m2.geometry_id; }; @@ -1872,14 +1868,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re volume_idx_wipe_tower_old = (int)volume_id; } if (!m_reload_delayed) -#if ENABLE_ENHANCED_RELOAD_FROM_DISK { deleted_volumes.emplace_back(volume, volume_id); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK delete volume; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } else { // This GLVolume will be reused. @@ -1909,7 +1901,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re bool update_object_list = false; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK auto find_old_volume_id = [&deleted_volumes](const GLVolume::CompositeID& id) -> unsigned int { for (unsigned int i = 0; i < (unsigned int)deleted_volumes.size(); ++i) { @@ -1919,7 +1910,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } return (unsigned int)-1; }; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK if (m_volumes.volumes != glvolumes_new) update_object_list = true; @@ -1935,11 +1925,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); if (it->new_geometry()) { // New volume. -#if ENABLE_ENHANCED_RELOAD_FROM_DISK unsigned int old_id = find_old_volume_id(it->composite_id); if (old_id != -1) map_glvolume_old_to_new[old_id] = m_volumes.volumes.size(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 7c9941bef2..a59a1288e6 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1510,13 +1510,11 @@ void ObjectList::append_menu_item_export_stl(wxMenu* menu) const menu->AppendSeparator(); } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK void ObjectList::append_menu_item_reload_from_disk(wxMenu* menu) const { append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")), [this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu, []() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater()); } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const { @@ -1567,9 +1565,7 @@ void ObjectList::create_object_popupmenu(wxMenu *menu) append_menu_items_osx(menu); #endif // __WXOSX__ -#if ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_reload_from_disk(menu); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_export_stl(menu); append_menu_item_fix_through_netfabb(menu); append_menu_item_scale_selection_to_fit_print_volume(menu); @@ -1593,9 +1589,7 @@ void ObjectList::create_sla_object_popupmenu(wxMenu *menu) append_menu_items_osx(menu); #endif // __WXOSX__ -#if ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_reload_from_disk(menu); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_export_stl(menu); append_menu_item_fix_through_netfabb(menu); // rest of a object_sla_menu will be added later in: @@ -1608,15 +1602,9 @@ void ObjectList::create_part_popupmenu(wxMenu *menu) append_menu_items_osx(menu); #endif // __WXOSX__ -#if ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_reload_from_disk(menu); -#else - append_menu_item_fix_through_netfabb(menu); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_export_stl(menu); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_fix_through_netfabb(menu); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item_split(menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index c8d89cbe33..e1b0b7993a 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -234,9 +234,7 @@ public: void append_menu_items_osx(wxMenu* menu); wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu); void append_menu_item_export_stl(wxMenu* menu) const; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK void append_menu_item_reload_from_disk(wxMenu* menu) const; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void append_menu_item_change_extruder(wxMenu* menu) const; void append_menu_item_delete(wxMenu* menu); void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2819bcdf25..e9ea411e8d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -10,9 +10,7 @@ #include #include #include -#if ENABLE_ENHANCED_RELOAD_FROM_DISK #include -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK #include #include @@ -1910,9 +1908,7 @@ struct Plater::priv bool can_fix_through_netfabb() const; bool can_set_instance_to_object() const; bool can_mirror() const; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK bool can_reload_from_disk() const; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void msw_rescale_object_menu(); @@ -1949,9 +1945,6 @@ private: * */ std::string m_last_fff_printer_profile_name; std::string m_last_sla_printer_profile_name; -#if !ENABLE_ENHANCED_RELOAD_FROM_DISK - bool m_update_objects_list_on_loading{ true }; -#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK }; const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase); @@ -2477,16 +2470,9 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode _(L("Object too large?"))); } -#if !ENABLE_ENHANCED_RELOAD_FROM_DISK - if (m_update_objects_list_on_loading) - { -#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK - for (const size_t idx : obj_idxs) { - wxGetApp().obj_list()->add_object_to_list(idx); - } -#if !ENABLE_ENHANCED_RELOAD_FROM_DISK + for (const size_t idx : obj_idxs) { + wxGetApp().obj_list()->add_object_to_list(idx); } -#endif // !ENABLE_ENHANCED_RELOAD_FROM_DISK update(); object_list_changed(); @@ -3110,7 +3096,6 @@ void Plater::priv::update_sla_scene() void Plater::priv::reload_from_disk() { -#if ENABLE_ENHANCED_RELOAD_FROM_DISK Plater::TakeSnapshot snapshot(q, _(L("Reload from disk"))); const Selection& selection = get_selection(); @@ -3215,91 +3200,6 @@ void Plater::priv::reload_from_disk() { view3D->get_canvas3d()->update_instance_printable_state_for_object(i); } -#else - Plater::TakeSnapshot snapshot(q, _(L("Reload from Disk"))); - - auto& selection = get_selection(); - const auto obj_orig_idx = selection.get_object_idx(); - if (selection.is_wipe_tower() || obj_orig_idx == -1) { return; } - int instance_idx = selection.get_instance_idx(); - - auto *object_orig = model.objects[obj_orig_idx]; - std::vector input_paths(1, object_orig->input_file); - - // disable render to avoid to show intermediate states - view3D->get_canvas3d()->enable_render(false); - - // disable update of objects list while loading to avoid to show intermediate states - m_update_objects_list_on_loading = false; - - const auto new_idxs = load_files(input_paths, true, false); - if (new_idxs.empty()) - { - // error while loading - view3D->get_canvas3d()->enable_render(true); - m_update_objects_list_on_loading = true; - return; - } - - for (const auto idx : new_idxs) - { - ModelObject *object = model.objects[idx]; - object->config.apply(object_orig->config); - - object->clear_instances(); - for (const ModelInstance *instance : object_orig->instances) - { - object->add_instance(*instance); - } - - for (const ModelVolume* v : object_orig->volumes) - { - if (v->is_modifier()) - object->add_volume(*v); - } - - Vec3d offset = object_orig->origin_translation - object->origin_translation; - - if (object->volumes.size() == object_orig->volumes.size()) - { - for (size_t i = 0; i < object->volumes.size(); i++) - { - object->volumes[i]->config.apply(object_orig->volumes[i]->config); - object->volumes[i]->translate(offset); - } - } - - // XXX: Restore more: layer_height_ranges, layer_height_profile (?) - } - - // re-enable update of objects list - m_update_objects_list_on_loading = true; - - // puts the new objects into the list - for (const auto idx : new_idxs) - { - wxGetApp().obj_list()->add_object_to_list(idx); - } - - remove(obj_orig_idx); - - // new GLVolumes have been created at this point, so update their printable state - for (size_t i = 0; i < model.objects.size(); ++i) - { - view3D->get_canvas3d()->update_instance_printable_state_for_object(i); - } - - // re-enable render - view3D->get_canvas3d()->enable_render(true); - - // the previous call to remove() clears the selection - // select newly added objects - selection.clear(); - for (const auto idx : new_idxs) - { - selection.add_instance((unsigned int)idx - 1, instance_idx, false); - } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK } void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) @@ -3724,10 +3624,8 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), [this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")), [this](wxCommandEvent&) { q->reload_from_disk(); }, "", menu, [this]() { return can_reload_from_disk(); }, q); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK sidebar->obj_list()->append_menu_item_export_stl(menu); } @@ -3755,13 +3653,8 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q); menu->AppendSeparator(); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected object from disk")), [this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr, [this]() { return can_reload_from_disk(); }, q); -#else - append_menu_item(menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")), - [this](wxCommandEvent&) { reload_from_disk(); }); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")), [this](wxCommandEvent&) { q->export_stl(false, true); }); @@ -3916,7 +3809,6 @@ bool Plater::priv::can_mirror() const return get_selection().is_from_single_instance(); } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK bool Plater::priv::can_reload_from_disk() const { // struct to hold selected ModelVolumes by their indices @@ -3958,7 +3850,6 @@ bool Plater::priv::can_reload_from_disk() const return !paths.empty(); } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void Plater::priv::set_bed_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model) { @@ -4743,12 +4634,10 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) } } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK void Plater::reload_from_disk() { p->reload_from_disk(); } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK bool Plater::has_toolpaths_to_export() const { @@ -5247,9 +5136,7 @@ bool Plater::can_copy_to_clipboard() const bool Plater::can_undo() const { return p->undo_redo_stack().has_undo_snapshot(); } bool Plater::can_redo() const { return p->undo_redo_stack().has_redo_snapshot(); } -#if ENABLE_ENHANCED_RELOAD_FROM_DISK bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); } -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); } void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); } void Plater::leave_gizmos_stack() { p->leave_gizmos_stack(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 6ebecac44d..d842e37f79 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -183,9 +183,7 @@ public: void export_stl(bool extended = false, bool selection_only = false); void export_amf(); void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); -#if ENABLE_ENHANCED_RELOAD_FROM_DISK void reload_from_disk(); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK bool has_toolpaths_to_export() const; void export_toolpaths_to_obj() const; void reslice(); @@ -250,9 +248,7 @@ public: bool can_copy_to_clipboard() const; bool can_undo() const; bool can_redo() const; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK bool can_reload_from_disk() const; -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK void msw_rescale(); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 346f46e00c..79df60464d 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -472,11 +472,7 @@ void Selection::volumes_changed(const std::vector &map_volume_old_to_new for (unsigned int idx : m_list) if (map_volume_old_to_new[idx] != size_t(-1)) { unsigned int new_idx = (unsigned int)map_volume_old_to_new[idx]; -#if ENABLE_ENHANCED_RELOAD_FROM_DISK (*m_volumes)[new_idx]->selected = true; -#else - assert((*m_volumes)[new_idx]->selected); -#endif // ENABLE_ENHANCED_RELOAD_FROM_DISK list_new.insert(new_idx); } m_list = std::move(list_new); From eda01341d0579576ab10450017b6e160c00a3d6e Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 7 Oct 2019 11:10:18 +0200 Subject: [PATCH 15/23] ConfigWizard: Fix a memory access issue between PageMaterial instances --- src/slic3r/GUI/ConfigWizard.cpp | 26 ++++++++++++------------- src/slic3r/GUI/ConfigWizard_private.hpp | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 4038426bab..5af298cc1f 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -515,9 +515,6 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin , list_l1(new StringList(this)) , list_l2(new StringList(this)) , list_l3(new PresetList(this)) - , sel1_prev(wxNOT_FOUND) - , sel2_prev(wxNOT_FOUND) - , presets_loaded(false) { append_spacer(VERTICAL_SPACING); @@ -567,7 +564,7 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin void PageMaterials::reload_presets() { - list_l1->Clear(); + clear(); list_l1->append(_(L("(All)")), &EMPTY); @@ -675,7 +672,7 @@ void PageMaterials::clear() void PageMaterials::on_activate() { if (! presets_loaded) { - wizard_p()->update_materials(); + wizard_p()->update_materials(materials->technology); reload_presets(); } } @@ -753,8 +750,8 @@ PageMode::PageMode(ConfigWizard *parent) { append_text(_(L("PrusaSlicer's user interfaces comes in three variants:\nSimple, Advanced, and Expert.\n" "The Simple mode shows only the most frequently used settings relevant for regular 3D printing. " - "The other two offer progressivly more specialized fine-tuning, " - "they are suitable for advanced and expert usiser, respectively. (FIXME: review this text)"))); + "The other two offer progressivly more sophisticated fine-tuning, " + "they are suitable for advanced and expert usiser, respectively."))); radio_simple = new wxRadioButton(this, wxID_ANY, _(L("Simple mode"))); radio_advanced = new wxRadioButton(this, wxID_ANY, _(L("Advanced mode"))); @@ -1384,7 +1381,7 @@ void ConfigWizard::priv::load_vendors() pair.second.preset_bundle->load_installed_printers(appconfig_new); } - update_materials(); + update_materials(T_ANY); if (app_config->has_section(AppConfig::SECTION_FILAMENTS)) { appconfig_new.set_section(AppConfig::SECTION_FILAMENTS, app_config->get_section(AppConfig::SECTION_FILAMENTS)); @@ -1437,12 +1434,11 @@ void ConfigWizard::priv::set_run_reason(RunReason run_reason) } } -void ConfigWizard::priv::update_materials() +void ConfigWizard::priv::update_materials(Technology technology) { - filaments.clear(); - sla_materials.clear(); - - if (any_fff_selected) { + if (any_fff_selected && (technology & T_FFF)) { + filaments.clear(); + // Iterate filaments in all bundles for (const auto &pair : bundles) { for (const auto &filament : pair.second.preset_bundle->filaments) { @@ -1466,7 +1462,9 @@ void ConfigWizard::priv::update_materials() } } - if (any_sla_selected) { + if (any_sla_selected && (technology & T_SLA)) { + sla_materials.clear(); + // Iterate SLA materials in all bundles for (const auto &pair : bundles) { for (const auto &material : pair.second.preset_bundle->sla_materials) { diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 3f688adff1..995957816f 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -466,7 +466,7 @@ struct ConfigWizard::priv void set_start_page(ConfigWizard::StartPage start_page); void create_3rdparty_pages(); void set_run_reason(RunReason run_reason); - void update_materials(); + void update_materials(Technology technology); void on_custom_setup(); void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt); From 555fcc151d50a8ff9539e96c9f5c18afeae7e0ab Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 7 Oct 2019 14:10:47 +0200 Subject: [PATCH 16/23] Hotfix for broken partial arrange. --- src/libnest2d/include/libnest2d/placers/nfpplacer.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 686857a87f..0030287586 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -1122,8 +1122,6 @@ private: sl::rotate(sh, item.rotation()); Box bb = sl::boundingBox(sh); - bb.minCorner() += item.translation(); - bb.maxCorner() += item.translation(); Vertex ci, cb; auto bbin = sl::boundingBox(bin_); From 72ac8d68f0351214dfe09492bb28dc4fac194a1d Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 7 Oct 2019 17:16:40 +0200 Subject: [PATCH 17/23] Extend libnest tests, remove some warnings, faster catch2 compilation. Also, improve libnest2d::nest interface. --- src/libnest2d/include/libnest2d.h | 117 ++++++++--------- src/libnest2d/include/libnest2d/libnest2d.hpp | 13 +- src/libnest2d/src/libnest2d.cpp | 26 ++-- src/libslic3r/Arrange.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 23 ++-- tests/CMakeLists.txt | 2 +- tests/libnest2d/libnest2d_tests_main.cpp | 121 ++++++++++++------ 7 files changed, 175 insertions(+), 129 deletions(-) diff --git a/src/libnest2d/include/libnest2d.h b/src/libnest2d/include/libnest2d.h index 4661b45744..76b133f4b4 100644 --- a/src/libnest2d/include/libnest2d.h +++ b/src/libnest2d/include/libnest2d.h @@ -49,91 +49,84 @@ using BottomLeftPlacer = placers::_BottomLeftPlacer; extern template class Nester; extern template class Nester; -extern template PackGroup Nester::execute( +extern template std::size_t Nester::execute( std::vector::iterator, std::vector::iterator); -extern template PackGroup Nester::execute( +extern template std::size_t Nester::execute( std::vector::iterator, std::vector::iterator); #endif -template::iterator> -void nest(Iterator from, Iterator to, - const typename Placer::BinType& bin, - Coord dist = 0, - const typename Placer::Config& pconf = {}, - const typename Selector::Config& sconf = {}) -{ - _Nester nester(bin, dist, pconf, sconf); - nester.execute(from, to); -} +template +struct NestConfig { + typename Placer::Config placer_config; + typename Selector::Config selector_config; + using Placement = typename Placer::Config; + using Selection = typename Selector::Config; + + NestConfig() = default; + NestConfig(const typename Placer::Config &cfg) : placer_config{cfg} {} + NestConfig(const typename Selector::Config &cfg) : selector_config{cfg} {} + NestConfig(const typename Placer::Config & pcfg, + const typename Selector::Config &scfg) + : placer_config{pcfg}, selector_config{scfg} {} +}; + +struct NestControl { + ProgressFunction progressfn; + StopCondition stopcond = []{ return false; }; + + NestControl() = default; + NestControl(ProgressFunction pr) : progressfn{std::move(pr)} {} + NestControl(StopCondition sc) : stopcond{std::move(sc)} {} + NestControl(ProgressFunction pr, StopCondition sc) + : progressfn{std::move(pr)}, stopcond{std::move(sc)} + {} +}; template::iterator> -void nest(Iterator from, Iterator to, - const typename Placer::BinType& bin, - ProgressFunction prg, - StopCondition scond = []() { return false; }, - Coord dist = 0, - const typename Placer::Config& pconf = {}, - const typename Selector::Config& sconf = {}) +std::size_t nest(Iterator from, Iterator to, + const typename Placer::BinType & bin, + Coord dist = 0, + const NestConfig &cfg = {}, + NestControl ctl = {}) { - _Nester nester(bin, dist, pconf, sconf); - if(prg) nester.progressIndicator(prg); - if(scond) nester.stopCondition(scond); - nester.execute(from, to); + _Nester nester{bin, dist, cfg.placer_config, cfg.selector_config}; + if(ctl.progressfn) nester.progressIndicator(ctl.progressfn); + if(ctl.stopcond) nester.stopCondition(ctl.stopcond); + return nester.execute(from, to); } #ifdef LIBNEST2D_STATIC extern template class Nester; extern template class Nester; - -extern template void nest(std::vector::iterator from, - std::vector::iterator to, - const Box& bin, - Coord dist = 0, - const NfpPlacer::Config& pconf, - const FirstFitSelection::Config& sconf); - -extern template void nest(std::vector::iterator from, - std::vector::iterator to, - const Box& bin, - ProgressFunction prg, - StopCondition scond, - Coord dist = 0, - const NfpPlacer::Config& pconf, - const FirstFitSelection::Config& sconf); +extern template std::size_t nest(std::vector::iterator from, + std::vector::iterator from to, + const Box & bin, + Coord dist, + const NestConfig &cfg, + NestControl ctl); +extern template std::size_t nest(std::vector::iterator from, + std::vector::iterator from to, + const Box & bin, + Coord dist, + const NestConfig &cfg, + NestControl ctl); #endif template> -void nest(Container&& cont, - const typename Placer::BinType& bin, - Coord dist = 0, - const typename Placer::Config& pconf = {}, - const typename Selector::Config& sconf = {}) +std::size_t nest(Container&& cont, + const typename Placer::BinType & bin, + Coord dist = 0, + const NestConfig &cfg = {}, + NestControl ctl = {}) { - nest(cont.begin(), cont.end(), bin, dist, pconf, sconf); -} - -template> -void nest(Container&& cont, - const typename Placer::BinType& bin, - ProgressFunction prg, - StopCondition scond = []() { return false; }, - Coord dist = 0, - const typename Placer::Config& pconf = {}, - const typename Selector::Config& sconf = {}) -{ - nest(cont.begin(), cont.end(), bin, prg, scond, dist, - pconf, sconf); + return nest(cont.begin(), cont.end(), bin, dist, cfg, ctl); } } diff --git a/src/libnest2d/include/libnest2d/libnest2d.hpp b/src/libnest2d/include/libnest2d/libnest2d.hpp index 29d52c10f8..91c98c62a7 100644 --- a/src/libnest2d/include/libnest2d/libnest2d.hpp +++ b/src/libnest2d/include/libnest2d/libnest2d.hpp @@ -129,8 +129,12 @@ public: sh_(sl::create(std::move(contour), std::move(holes))) {} inline bool isFixed() const noexcept { return fixed_; } - inline void markAsFixed(bool fixed = true) { fixed_ = fixed; } - + inline void markAsFixedInBin(int binid) + { + fixed_ = binid >= 0; + binid_ = binid; + } + inline void binId(int idx) { binid_ = idx; } inline int binId() const noexcept { return binid_; } @@ -748,6 +752,7 @@ template class _Nester { using TSel = SelectionStrategyLike; TSel selector_; + public: using Item = typename PlacementStrategy::Item; using ShapeType = typename Item::ShapeType; @@ -824,7 +829,7 @@ public: * the selection algorithm. */ template - inline ItemIteratorOnly execute(It from, It to) + inline ItemIteratorOnly execute(It from, It to) { auto infl = static_cast(std::ceil(min_obj_distance_/2.0)); if(infl > 0) std::for_each(from, to, [this, infl](Item& item) { @@ -837,6 +842,8 @@ public: if(min_obj_distance_ > 0) std::for_each(from, to, [infl](Item& item) { item.inflate(-infl); }); + + return selector_.getResult().size(); } /// Set a progress indicator function object for the selector. diff --git a/src/libnest2d/src/libnest2d.cpp b/src/libnest2d/src/libnest2d.cpp index 0214587874..740f6e18d9 100644 --- a/src/libnest2d/src/libnest2d.cpp +++ b/src/libnest2d/src/libnest2d.cpp @@ -5,19 +5,17 @@ namespace libnest2d { template class Nester; template class Nester; -template PackGroup nest(std::vector::iterator from, - std::vector::iterator to, - const Box& bin, - Coord dist = 0, - const NfpPlacer::Config& pconf, - const FirstFitSelection::Config& sconf); +template std::size_t nest(std::vector::iterator from, + std::vector::iterator from to, + const Box & bin, + Coord dist, + const NestConfig &cfg, + NestControl ctl); -template PackGroup nest(std::vector::iterator from, - std::vector::iterator to, - const Box& bin, - ProgressFunction prg, - StopCondition scond, - Coord dist = 0, - const NfpPlacer::Config& pconf, - const FirstFitSelection::Config& sconf); +template std::size_t nest(std::vector::iterator from, + std::vector::iterator from to, + const Box & bin, + Coord dist, + const NestConfig &cfg, + NestControl ctl); } diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 20dfd8926f..aed6e41f73 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -375,7 +375,7 @@ public: for(unsigned idx = 0; idx < fixeditems.size(); ++idx) { Item& itm = fixeditems[idx]; - itm.markAsFixed(); + itm.markAsFixedInBin(0); } m_pck.configure(m_pconf); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e16687cd96..acf7195b19 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1571,7 +1571,8 @@ struct Plater::priv size_t count = 0; // To know how much space to reserve for (auto obj : model.objects) count += obj->instances.size(); - m_selected.clear(), m_unselected.clear(); + m_selected.clear(); + m_unselected.clear(); m_selected.reserve(count + 1 /* for optional wti */); m_unselected.reserve(count + 1 /* for optional wti */); } @@ -1585,11 +1586,12 @@ struct Plater::priv // Set up arrange polygon for a ModelInstance and Wipe tower template ArrangePolygon get_arrange_poly(T *obj) const { ArrangePolygon ap = obj->get_arrange_polygon(); - ap.priority = 0; - ap.bed_idx = ap.translation.x() / bed_stride(); - ap.setter = [obj, this](const ArrangePolygon &p) { + ap.priority = 0; + ap.bed_idx = ap.translation.x() / bed_stride(); + ap.setter = [obj, this](const ArrangePolygon &p) { if (p.is_arranged()) { - auto t = p.translation; t.x() += p.bed_idx * bed_stride(); + auto t = p.translation; + t.x() += p.bed_idx * bed_stride(); obj->apply_arrange_result(t, p.rotation); } }; @@ -1620,7 +1622,8 @@ struct Plater::priv obj_sel(model.objects.size(), nullptr); for (auto &s : plater().get_selection().get_content()) - if (s.first < int(obj_sel.size())) obj_sel[s.first] = &s.second; + if (s.first < int(obj_sel.size())) + obj_sel[size_t(s.first)] = &s.second; // Go through the objects and check if inside the selection for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) { @@ -1630,7 +1633,8 @@ struct Plater::priv std::vector inst_sel(mo->instances.size(), false); if (instlist) - for (auto inst_id : *instlist) inst_sel[inst_id] = true; + for (auto inst_id : *instlist) + inst_sel[size_t(inst_id)] = true; for (size_t i = 0; i < inst_sel.size(); ++i) { ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]); @@ -2759,9 +2763,8 @@ void Plater::priv::ArrangeJob::process() { try { arrangement::arrange(m_selected, m_unselected, min_d, bedshape, [this, count](unsigned st) { - if (st > - 0) // will not finalize after last one - update_status(count - st, arrangestr); + if (st > 0) // will not finalize after last one + update_status(int(count - st), arrangestr); }, [this]() { return was_canceled(); }); } catch (std::exception & /*e*/) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cc3fd1de72..e2eaebfb80 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,7 +11,7 @@ add_library(Catch2::Catch2 ALIAS Catch2) include(Catch) add_library(test_catch2_common INTERFACE) -target_compile_definitions(test_catch2_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)") +target_compile_definitions(test_catch2_common INTERFACE TEST_DATA_DIR=R"\(${TEST_DATA_DIR}\)" CATCH_CONFIG_FAST_COMPILE) target_link_libraries(test_catch2_common INTERFACE Catch2::Catch2) add_library(test_common INTERFACE) diff --git a/tests/libnest2d/libnest2d_tests_main.cpp b/tests/libnest2d/libnest2d_tests_main.cpp index 56f2f59c1a..298ff33af2 100644 --- a/tests/libnest2d/libnest2d_tests_main.cpp +++ b/tests/libnest2d/libnest2d_tests_main.cpp @@ -1,5 +1,7 @@ #define CATCH_CONFIG_MAIN #include +#include + #include #include @@ -224,12 +226,12 @@ TEST_CASE("Area", "[Geometry]") { using namespace libnest2d; RectangleItem rect(10, 10); - - REQUIRE(rect.area() == 100); + + REQUIRE(rect.area() == Approx(100)); RectangleItem rect2 = {100, 100}; - - REQUIRE(rect2.area() == 10000); + + REQUIRE(rect2.area() == Approx(10000)); Item item = { {61, 97}, @@ -288,11 +290,9 @@ TEST_CASE("IsPointInsidePolygon", "[Geometry]") { // REQUIRE_FALSE(ShapeLike::intersects(s1, s2)); //} -// Simple TEST_CASE, does not use gmock TEST_CASE("LeftAndDownPolygon", "[Geometry]") { using namespace libnest2d; - using namespace libnest2d; Box bin(100, 100); BottomLeftPlacer placer(bin); @@ -339,7 +339,6 @@ TEST_CASE("LeftAndDownPolygon", "[Geometry]") } } -// Simple TEST_CASE, does not use gmock TEST_CASE("ArrangeRectanglesTight", "[Nesting]") { using namespace libnest2d; @@ -449,8 +448,8 @@ TEST_CASE("ArrangeRectanglesLoose", "[Nesting]") [](const Item &i1, const Item &i2) { return i1.binId() < i2.binId(); }); - - size_t groups = max_group == rects.end() ? 0 : max_group->binId() + 1; + + auto groups = size_t(max_group == rects.end() ? 0 : max_group->binId() + 1); REQUIRE(groups == 1u); REQUIRE( @@ -477,8 +476,6 @@ using namespace libnest2d; template void exportSVG(std::vector>& result, const Bin& bin, int idx = 0) { - - std::string loc = "out"; static std::string svg_header = @@ -494,20 +491,20 @@ void exportSVG(std::vector>& result, const Bin& bin if(out.is_open()) { out << svg_header; Item rbin( RectangleItem(bin.width(), bin.height()) ); - for(unsigned i = 0; i < rbin.vertexCount(); i++) { - auto v = rbin.vertex(i); + for(unsigned j = 0; j < rbin.vertexCount(); j++) { + auto v = rbin.vertex(j); setY(v, -getY(v)/SCALE + 500 ); setX(v, getX(v)/SCALE); - rbin.setVertex(i, v); + rbin.setVertex(j, v); } out << shapelike::serialize(rbin.rawShape()) << std::endl; for(Item& sh : r) { Item tsh(sh.transformedShape()); - for(unsigned i = 0; i < tsh.vertexCount(); i++) { - auto v = tsh.vertex(i); + for(unsigned j = 0; j < tsh.vertexCount(); j++) { + auto v = tsh.vertex(j); setY(v, -getY(v)/SCALE + 500); setX(v, getX(v)/SCALE); - tsh.setVertex(i, v); + tsh.setVertex(j, v); } out << shapelike::serialize(tsh.rawShape()) << std::endl; } @@ -570,7 +567,7 @@ TEST_CASE("convexHull", "[Geometry]") { REQUIRE(chull.size() == poly.size()); } -TEST_CASE("NestPrusaPartsShouldFitIntoTwoBins", "[Nesting]") { +TEST_CASE("PrusaPartsShouldFitIntoTwoBins", "[Nesting]") { // Get the input items and define the bin. std::vector input = prusaParts(); @@ -579,21 +576,15 @@ TEST_CASE("NestPrusaPartsShouldFitIntoTwoBins", "[Nesting]") { // Do the nesting. Check in each step if the remaining items are less than // in the previous step. (Some algorithms can place more items in one step) size_t pcount = input.size(); - libnest2d::nest(input, bin, [&pcount](unsigned cnt) { - REQUIRE(cnt < pcount); - pcount = cnt; - }); - // Get the number of logical bins: search for the max binId... - auto max_binid_it = std::max_element(input.begin(), input.end(), - [](const Item &i1, const Item &i2) { - return i1.binId() < i2.binId(); - }); - - auto bins = size_t(max_binid_it == input.end() ? 0 : - max_binid_it->binId() + 1); + size_t bins = libnest2d::nest(input, bin, 0, {}, + ProgressFunction{[&pcount](unsigned cnt) { + REQUIRE(cnt < pcount); + pcount = cnt; + }}); // For prusa parts, 2 bins should be enough... + REQUIRE(bins > 0u); REQUIRE(bins <= 2u); // All parts should be processed by the algorithm @@ -617,29 +608,83 @@ TEST_CASE("NestPrusaPartsShouldFitIntoTwoBins", "[Nesting]") { } } -TEST_CASE("NestEmptyItemShouldBeUntouched", "[Nesting]") { +TEST_CASE("EmptyItemShouldBeUntouched", "[Nesting]") { auto bin = Box(250000000, 210000000); // dummy bin std::vector items; items.emplace_back(Item{}); // Emplace empty item items.emplace_back(Item{0, 200, 0}); // Emplace zero area item - libnest2d::nest(items, bin); - + size_t bins = libnest2d::nest(items, bin); + + REQUIRE(bins == 0u); for (auto &itm : items) REQUIRE(itm.binId() == BIN_ID_UNSET); } -TEST_CASE("NestLargeItemShouldBeUntouched", "[Nesting]") { +TEST_CASE("LargeItemShouldBeUntouched", "[Nesting]") { auto bin = Box(250000000, 210000000); // dummy bin std::vector items; items.emplace_back(RectangleItem{250000001, 210000001}); // Emplace large item - libnest2d::nest(items, bin); - + size_t bins = libnest2d::nest(items, bin); + + REQUIRE(bins == 0u); REQUIRE(items.front().binId() == BIN_ID_UNSET); } +TEST_CASE("Items can be preloaded", "[Nesting]") { + auto bin = Box({0, 0}, {250000000, 210000000}); // dummy bin + + std::vector items; + items.reserve(2); + + NestConfig<> cfg; + cfg.placer_config.alignment = NestConfig<>::Placement::Alignment::DONT_ALIGN; + + items.emplace_back(RectangleItem{10000000, 10000000}); + Item &fixed_rect = items.back(); + fixed_rect.translate(bin.center()); + + items.emplace_back(RectangleItem{20000000, 20000000}); + Item &movable_rect = items.back(); + movable_rect.translate(bin.center()); + + SECTION("Preloaded Item should be untouched") { + fixed_rect.markAsFixedInBin(0); + + size_t bins = libnest2d::nest(items, bin, 0, cfg); + + REQUIRE(bins == 1); + + REQUIRE(fixed_rect.binId() == 0); + REQUIRE(fixed_rect.translation().X == bin.center().X); + REQUIRE(fixed_rect.translation().Y == bin.center().Y); + + REQUIRE(movable_rect.binId() == 0); + REQUIRE(movable_rect.translation().X != bin.center().X); + REQUIRE(movable_rect.translation().Y != bin.center().Y); + } + + SECTION("Preloaded Item should not affect free bins") { + fixed_rect.markAsFixedInBin(1); + + size_t bins = libnest2d::nest(items, bin, 0, cfg); + + REQUIRE(bins == 2); + + REQUIRE(fixed_rect.binId() == 1); + REQUIRE(fixed_rect.translation().X == bin.center().X); + REQUIRE(fixed_rect.translation().Y == bin.center().Y); + + REQUIRE(movable_rect.binId() == 0); + + auto bb = movable_rect.boundingBox(); + REQUIRE(bb.center().X == bin.center().X); + REQUIRE(bb.center().Y == bin.center().Y); + } +} + namespace { struct ItemPair { @@ -969,8 +1014,8 @@ TEST_CASE("mergePileWithPolygon", "[Geometry]") { REQUIRE(result.size() == 1); RectangleItem ref(45, 15); - - REQUIRE(shapelike::area(result.front()) == ref.area()); + + REQUIRE(shapelike::area(result.front()) == Approx(ref.area())); } namespace { From 570c038eb78698aeb199aac0d5d85d9508039ff5 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 7 Oct 2019 11:25:05 +0200 Subject: [PATCH 18/23] ConfigWizard: Fix printer pre-selection on fresh config --- src/slic3r/GUI/ConfigWizard.cpp | 43 +++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 5af298cc1f..bc73e32625 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1617,24 +1617,37 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese std::string preferred_model; - // Figure out the default pre-selected printer based on the seletions in the picker. + // Figure out the default pre-selected printer based on the selections in the pickers. // The default is the first selected printer model (one with at least 1 variant selected). // The default is only applied by load_presets() if the user doesn't have a (visible) printer // selected already. -// TODO: - // const auto vendor_prusa = bundle.vendors.find("PrusaResearch"); - // const auto config_prusa = enabled_vendors.find("PrusaResearch"); - // if (vendor_prusa != bundle.vendors.end() && config_prusa != enabled_vendors.end()) { - // for (const auto &model : vendor_prusa->second.models) { - // const auto model_it = config_prusa->second.find(model.id); - // if (model_it != config_prusa->second.end() && model_it->second.size() > 0) { - // preferred_model = model.id; - // break; - // } - // } - // } + // Prusa printers are considered first, then 3rd party. + const auto config_prusa = enabled_vendors.find("PrusaResearch"); + if (config_prusa != enabled_vendors.end()) { + for (const auto &model : bundles.prusa_bundle().vendor_profile->models) { + const auto model_it = config_prusa->second.find(model.id); + if (model_it != config_prusa->second.end() && model_it->second.size() > 0) { + preferred_model = model.id; + break; + } + } + } + if (preferred_model.empty()) { + for (const auto &bundle : bundles) { + if (bundle.second.is_prusa_bundle) { continue; } - // preset_bundle->load_presets(*app_config, preferred_model); + const auto config = enabled_vendors.find(bundle.first); + for (const auto &model : bundle.second.vendor_profile->models) { + const auto model_it = config->second.find(model.id); + if (model_it != config->second.end() && model_it->second.size() > 0) { + preferred_model = model.id; + break; + } + } + } + } + + preset_bundle->load_presets(*app_config, preferred_model); if (page_custom->custom_wanted()) { page_firmware->apply_custom_config(*custom_config); @@ -1753,7 +1766,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent) p->load_pages(); p->page_fff->select_all(true, false); p->page_msla->select_all(true, false); - p->index->go_to(p->page_update); + p->index->go_to(p->page_mode); }); p->index->Bind(EVT_INDEX_PAGE, [this](const wxCommandEvent &) { From 9a9c3bac39d56673907ee995b878d51e651804f2 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 8 Oct 2019 11:05:59 +0200 Subject: [PATCH 19/23] Fixup of 47a8b49 --- src/slic3r/GUI/wxExtensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 0109f6a290..051a272204 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -455,7 +455,7 @@ Slic3r::GUI::BitmapCache* m_bitmap_cache = nullptr; std::vector bmps; std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - if (bmps.empty()) + if (colors.empty()) return bmps; unsigned char rgb[3]; From aba743de41e639c69ef8b452c964960d825498de Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Mon, 6 May 2019 23:33:09 -0400 Subject: [PATCH 20/23] Include wipe tower in skirt --- src/libslic3r/GCode/PrintExtents.cpp | 39 +++++++++++++++++++++++++++- src/libslic3r/GCode/PrintExtents.hpp | 4 +++ src/libslic3r/Print.cpp | 35 +++++++++++++++---------- 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/GCode/PrintExtents.cpp b/src/libslic3r/GCode/PrintExtents.cpp index 07a71a0ea1..aaa615c34f 100644 --- a/src/libslic3r/GCode/PrintExtents.cpp +++ b/src/libslic3r/GCode/PrintExtents.cpp @@ -138,7 +138,7 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_ // We need to get position and angle of the wipe tower to transform them to actual position. Transform2d trafo = Eigen::Translation2d(print.config().wipe_tower_x.value, print.config().wipe_tower_y.value) * - Eigen::Rotation2Dd(print.config().wipe_tower_rotation_angle.value); + Eigen::Rotation2Dd(Geometry::deg2rad(print.config().wipe_tower_rotation_angle.value)); BoundingBoxf bbox; for (const std::vector &tool_changes : print.wipe_tower_data().tool_changes) { @@ -160,6 +160,43 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_ return bbox; } +// Returns a vector of points of a projection of the wipe tower for the layers <= max_print_z. +// The projection does not contain the priming regions. +std::vector get_wipe_tower_extrusions_points(const Print &print, const coordf_t max_print_z) +{ + // Wipe tower extrusions are saved as if the tower was at the origin with no rotation + // We need to get position and angle of the wipe tower to transform them to actual position. + Transform2d trafo = + Eigen::Translation2d(print.config().wipe_tower_x.value, print.config().wipe_tower_y.value) * + Eigen::Rotation2Dd(Geometry::deg2rad(print.config().wipe_tower_rotation_angle.value)); + + BoundingBoxf bbox; + for (const std::vector &tool_changes : print.wipe_tower_data().tool_changes) { + if (!tool_changes.empty() && tool_changes.front().print_z > max_print_z) + break; + for (const WipeTower::ToolChangeResult &tcr : tool_changes) { + for (size_t i = 1; i < tcr.extrusions.size(); ++i) { + const WipeTower::Extrusion &e = tcr.extrusions[i]; + if (e.width > 0) { + Vec2d delta = 0.5 * Vec2d(e.width, e.width); + Vec2d p1 = Vec2d((&e - 1)->pos.x, (&e - 1)->pos.y); + Vec2d p2 = Vec2d(e.pos.x, e.pos.y); + bbox.merge(p1.cwiseMin(p2) - delta); + bbox.merge(p1.cwiseMax(p2) + delta); + } + } + } + } + + std::vector points; + points.push_back(trafo * Vec2d(bbox.min.x(), bbox.max.y())); + points.push_back(trafo * Vec2d(bbox.max.x(), bbox.max.y())); + points.push_back(trafo * Vec2d(bbox.max.x(), bbox.min.y())); + points.push_back(trafo * Vec2d(bbox.min.x(), bbox.min.y())); + + return points; +} + // Returns a bounding box of the wipe tower priming extrusions. BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print) { diff --git a/src/libslic3r/GCode/PrintExtents.hpp b/src/libslic3r/GCode/PrintExtents.hpp index db507689df..cb60c939b1 100644 --- a/src/libslic3r/GCode/PrintExtents.hpp +++ b/src/libslic3r/GCode/PrintExtents.hpp @@ -22,6 +22,10 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object // The projection does not contain the priming regions. BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z); +// Returns a vector of points of a projection of the wipe tower for the layers <= max_print_z. +// The projection does not contain the priming regions. +std::vector get_wipe_tower_extrusions_points(const Print &print, const coordf_t max_print_z); + // Returns a bounding box of the wipe tower priming extrusions. BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 245b79e807..4403c7b263 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -11,6 +11,7 @@ #include "SupportMaterial.hpp" #include "GCode.hpp" #include "GCode/WipeTower.hpp" +#include "GCode/PrintExtents.hpp" #include "Utils.hpp" //#include "PrintExport.hpp" @@ -143,10 +144,7 @@ bool Print::invalidate_state_by_config_options(const std::vector steps_ignore; @@ -167,7 +165,10 @@ bool Print::invalidate_state_by_config_options(const std::vector 1) { bool has_custom_layering = false; @@ -1502,6 +1506,14 @@ void Print::process() obj->infill(); for (PrintObject *obj : m_objects) obj->generate_support_material(); + if (this->set_started(psWipeTower)) { + m_wipe_tower_data.clear(); + if (this->has_wipe_tower()) { + //this->set_status(95, L("Generating wipe tower")); + this->_make_wipe_tower(); + } + this->set_done(psWipeTower); + } if (this->set_started(psSkirt)) { m_skirt.clear(); if (this->has_skirt()) { @@ -1518,14 +1530,6 @@ void Print::process() } this->set_done(psBrim); } - if (this->set_started(psWipeTower)) { - m_wipe_tower_data.clear(); - if (this->has_wipe_tower()) { - //this->set_status(95, L("Generating wipe tower")); - this->_make_wipe_tower(); - } - this->set_done(psWipeTower); - } BOOST_LOG_TRIVIAL(info) << "Slicing process finished." << log_memory_info(); } @@ -1602,6 +1606,11 @@ void Print::_make_skirt() } } + // Include the wipe tower. + if (has_wipe_tower()) + for (const Vec2d& point : get_wipe_tower_extrusions_points(*this, skirt_height_z)) + points.push_back(Point(scale_(point.x()), scale_(point.y()))); + if (points.size() < 3) // At least three points required for a convex hull. return; From fdf9272fbe377ae15e870d9c95c1d45db7cf43a7 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 8 Oct 2019 13:50:51 +0200 Subject: [PATCH 21/23] Wipe tower brim width is now part of WipeTowerData class, so it can be used wherever needed --- src/libslic3r/GCode/PrintExtents.cpp | 4 ++-- src/libslic3r/GCode/WipeTower.cpp | 8 +++++++- src/libslic3r/GCode/WipeTower.hpp | 2 ++ src/libslic3r/Print.cpp | 17 +++++++++++++++++ src/libslic3r/Print.hpp | 5 +++-- src/slic3r/GUI/GLCanvas3D.cpp | 22 +++++++++------------- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/GCode/PrintExtents.cpp b/src/libslic3r/GCode/PrintExtents.cpp index aaa615c34f..ed1d097e12 100644 --- a/src/libslic3r/GCode/PrintExtents.cpp +++ b/src/libslic3r/GCode/PrintExtents.cpp @@ -179,8 +179,8 @@ std::vector get_wipe_tower_extrusions_points(const Print &print, const co const WipeTower::Extrusion &e = tcr.extrusions[i]; if (e.width > 0) { Vec2d delta = 0.5 * Vec2d(e.width, e.width); - Vec2d p1 = Vec2d((&e - 1)->pos.x, (&e - 1)->pos.y); - Vec2d p2 = Vec2d(e.pos.x, e.pos.y); + Vec2d p1 = Vec2d((&e - 1)->pos.x(), (&e - 1)->pos.y()); + Vec2d p2 = Vec2d(e.pos.x(), e.pos.y()); bbox.merge(p1.cwiseMin(p2) - delta); bbox.merge(p1.cwiseMax(p2) + delta); } diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index ea8465f225..b464a39b82 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -787,8 +787,10 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of // The tool is supposed to be active and primed at the time when the wipe tower brim is extruded. // Extrude 4 rounds of a brim around the future wipe tower. box_coordinates box(wipeTower_box); + // the brim shall have 'normal' spacing with no extra void space + float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4); for (size_t i = 0; i < 4; ++ i) { - box.expand(m_perimeter_width - m_layer_height*float(1.-M_PI_4)); // the brim shall have 'normal' spacing with no extra void space + box.expand(spacing); writer.travel (box.ld, 7000) .extrude(box.lu, 2100).extrude(box.ru) .extrude(box.rd ).extrude(box.ld); @@ -800,6 +802,10 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of writer.append("; CP WIPE TOWER FIRST LAYER BRIM END\n" ";-----------------------------------\n"); + // Save actual brim width to be later passed to the Print object, which will use it + // for skirt calculation and pass it to GLCanvas for precise preview box + m_wipe_tower_brim_width = wipeTower_box.ld.x() - box.ld.x() + spacing/2.f; + m_print_brim = false; // Mark the brim as extruded // Ask our writer about how much material was consumed: diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 5477aa6097..c1ea3f2b56 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -92,6 +92,7 @@ public: void generate(std::vector> &result); float get_depth() const { return m_wipe_tower_depth; } + float get_brim_width() const { return m_wipe_tower_brim_width; } @@ -203,6 +204,7 @@ private: Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm. float m_wipe_tower_width; // Width of the wipe tower. float m_wipe_tower_depth = 0.f; // Depth of the wipe tower + float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis) float m_internal_rotation = 0.f; float m_y_shift = 0.f; // y shift passed to writer diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 4403c7b263..e7e8131642 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1873,6 +1873,22 @@ bool Print::has_wipe_tower() const m_config.nozzle_diameter.values.size() > 1; } +const WipeTowerData& Print::wipe_tower_data(size_t extruders_cnt, double first_layer_height, double nozzle_diameter) const +{ + // If the wipe tower wasn't created yet, make sure the depth and brim_width members are set to default. + if (! is_step_done(psWipeTower) && extruders_cnt !=0) { + + float width = m_config.wipe_tower_width; + float brim_spacing = nozzle_diameter * 1.25f - first_layer_height * (1. - M_PI_4); + + const_cast(this)->m_wipe_tower_data.depth = (900.f/width) * float(extruders_cnt - 1); + const_cast(this)->m_wipe_tower_data.brim_width = 4.5f * brim_spacing; + } + + return m_wipe_tower_data; +} + + void Print::_make_wipe_tower() { m_wipe_tower_data.clear(); @@ -1981,6 +1997,7 @@ void Print::_make_wipe_tower() m_wipe_tower_data.tool_changes.reserve(m_wipe_tower_data.tool_ordering.layer_tools().size()); wipe_tower.generate(m_wipe_tower_data.tool_changes); m_wipe_tower_data.depth = wipe_tower.get_depth(); + m_wipe_tower_data.brim_width = wipe_tower.get_brim_width(); // Unload the current filament over the purge tower. coordf_t layer_height = m_objects.front()->config().layer_height.value; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index ce616a1502..6d94a515f9 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -226,6 +226,7 @@ struct WipeTowerData // Depth of the wipe tower to pass to GLCanvas3D for exact bounding box: float depth; + float brim_width; void clear() { tool_ordering.clear(); @@ -235,6 +236,7 @@ struct WipeTowerData used_filament.clear(); number_of_toolchanges = -1; depth = 0.f; + brim_width = 0.f; } }; @@ -314,7 +316,6 @@ public: bool has_infinite_skirt() const; bool has_skirt() const; - float get_wipe_tower_depth() const { return m_wipe_tower_data.depth; } // Returns an empty string if valid, otherwise returns an error message. std::string validate() const override; @@ -353,7 +354,7 @@ public: // Wipe tower support. bool has_wipe_tower() const; - const WipeTowerData& wipe_tower_data() const { return m_wipe_tower_data; } + const WipeTowerData& wipe_tower_data(size_t extruders_cnt = 0, double first_layer_height = 0., double nozzle_diameter = 0.) const; std::string output_filename(const std::string &filename_base = std::string()) const override; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 04ef6fd423..4a845a682e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1999,19 +1999,17 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re float a = dynamic_cast(m_config->option("wipe_tower_rotation_angle"))->value; const Print *print = m_process->fff_print(); - float depth = print->get_wipe_tower_depth(); - // Calculate wipe tower brim spacing. const DynamicPrintConfig &print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; double layer_height = print_config.opt_float("layer_height"); double first_layer_height = print_config.get_abs_value("first_layer_height", layer_height); - float brim_spacing = print->config().nozzle_diameter.values[0] * 1.25f - first_layer_height * (1. - M_PI_4); + double nozzle_diameter = print->config().nozzle_diameter.values[0]; + float depth = print->wipe_tower_data(extruders_count, first_layer_height, nozzle_diameter).depth; + float brim_width = print->wipe_tower_data(extruders_count, first_layer_height, nozzle_diameter).brim_width; - if (!print->is_step_done(psWipeTower)) - depth = (900.f/w) * (float)(extruders_count - 1); int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( 1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), - brim_spacing * 4.5f, m_initialized); + brim_width, m_initialized); if (volume_idx_wipe_tower_old != -1) map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; } @@ -5284,20 +5282,18 @@ void GLCanvas3D::_load_fff_shells() // adds wipe tower's volume double max_z = print->objects()[0]->model_object()->get_model()->bounding_box().max(2); const PrintConfig& config = print->config(); - unsigned int extruders_count = config.nozzle_diameter.size(); + size_t extruders_count = config.nozzle_diameter.size(); if ((extruders_count > 1) && config.wipe_tower && !config.complete_objects) { - float depth = print->get_wipe_tower_depth(); - // Calculate wipe tower brim spacing. const DynamicPrintConfig &print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; double layer_height = print_config.opt_float("layer_height"); double first_layer_height = print_config.get_abs_value("first_layer_height", layer_height); - float brim_spacing = print->config().nozzle_diameter.values[0] * 1.25f - first_layer_height * (1. - M_PI_4); + double nozzle_diameter = print->config().nozzle_diameter.values[0]; + float depth = print->wipe_tower_data(extruders_count, first_layer_height, nozzle_diameter).depth; + float brim_width = print->wipe_tower_data(extruders_count, first_layer_height, nozzle_diameter).brim_width; - if (!print->is_step_done(psWipeTower)) - depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1); m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, - !print->is_step_done(psWipeTower), brim_spacing * 4.5f, m_initialized); + !print->is_step_done(psWipeTower), brim_width, m_initialized); } } } From cf030e89580e815f4ba622db1f8449213f124c62 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 8 Oct 2019 14:04:50 +0200 Subject: [PATCH 22/23] Simplified inclusion of the wipe tower into skirt calculation --- src/libslic3r/GCode/PrintExtents.cpp | 37 ---------------------------- src/libslic3r/GCode/PrintExtents.hpp | 4 --- src/libslic3r/Print.cpp | 13 +++++++--- 3 files changed, 9 insertions(+), 45 deletions(-) diff --git a/src/libslic3r/GCode/PrintExtents.cpp b/src/libslic3r/GCode/PrintExtents.cpp index ed1d097e12..d44ef1aad5 100644 --- a/src/libslic3r/GCode/PrintExtents.cpp +++ b/src/libslic3r/GCode/PrintExtents.cpp @@ -160,43 +160,6 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_ return bbox; } -// Returns a vector of points of a projection of the wipe tower for the layers <= max_print_z. -// The projection does not contain the priming regions. -std::vector get_wipe_tower_extrusions_points(const Print &print, const coordf_t max_print_z) -{ - // Wipe tower extrusions are saved as if the tower was at the origin with no rotation - // We need to get position and angle of the wipe tower to transform them to actual position. - Transform2d trafo = - Eigen::Translation2d(print.config().wipe_tower_x.value, print.config().wipe_tower_y.value) * - Eigen::Rotation2Dd(Geometry::deg2rad(print.config().wipe_tower_rotation_angle.value)); - - BoundingBoxf bbox; - for (const std::vector &tool_changes : print.wipe_tower_data().tool_changes) { - if (!tool_changes.empty() && tool_changes.front().print_z > max_print_z) - break; - for (const WipeTower::ToolChangeResult &tcr : tool_changes) { - for (size_t i = 1; i < tcr.extrusions.size(); ++i) { - const WipeTower::Extrusion &e = tcr.extrusions[i]; - if (e.width > 0) { - Vec2d delta = 0.5 * Vec2d(e.width, e.width); - Vec2d p1 = Vec2d((&e - 1)->pos.x(), (&e - 1)->pos.y()); - Vec2d p2 = Vec2d(e.pos.x(), e.pos.y()); - bbox.merge(p1.cwiseMin(p2) - delta); - bbox.merge(p1.cwiseMax(p2) + delta); - } - } - } - } - - std::vector points; - points.push_back(trafo * Vec2d(bbox.min.x(), bbox.max.y())); - points.push_back(trafo * Vec2d(bbox.max.x(), bbox.max.y())); - points.push_back(trafo * Vec2d(bbox.max.x(), bbox.min.y())); - points.push_back(trafo * Vec2d(bbox.min.x(), bbox.min.y())); - - return points; -} - // Returns a bounding box of the wipe tower priming extrusions. BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print) { diff --git a/src/libslic3r/GCode/PrintExtents.hpp b/src/libslic3r/GCode/PrintExtents.hpp index cb60c939b1..db507689df 100644 --- a/src/libslic3r/GCode/PrintExtents.hpp +++ b/src/libslic3r/GCode/PrintExtents.hpp @@ -22,10 +22,6 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object // The projection does not contain the priming regions. BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z); -// Returns a vector of points of a projection of the wipe tower for the layers <= max_print_z. -// The projection does not contain the priming regions. -std::vector get_wipe_tower_extrusions_points(const Print &print, const coordf_t max_print_z); - // Returns a bounding box of the wipe tower priming extrusions. BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print); diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index e7e8131642..88645df15b 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -11,7 +11,6 @@ #include "SupportMaterial.hpp" #include "GCode.hpp" #include "GCode/WipeTower.hpp" -#include "GCode/PrintExtents.hpp" #include "Utils.hpp" //#include "PrintExport.hpp" @@ -1607,9 +1606,15 @@ void Print::_make_skirt() } // Include the wipe tower. - if (has_wipe_tower()) - for (const Vec2d& point : get_wipe_tower_extrusions_points(*this, skirt_height_z)) - points.push_back(Point(scale_(point.x()), scale_(point.y()))); + if (has_wipe_tower() && ! m_wipe_tower_data.tool_changes.empty()) { + double width = m_config.wipe_tower_width + 2*m_wipe_tower_data.brim_width; + double depth = m_wipe_tower_data.depth + 2*m_wipe_tower_data.brim_width; + Vec2d pt = Vec2d(m_config.wipe_tower_x-m_wipe_tower_data.brim_width, m_config.wipe_tower_y-m_wipe_tower_data.brim_width); + points.push_back(Point(scale_(pt.x()), scale_(pt.y()))); + points.push_back(Point(scale_(pt.x()+width), scale_(pt.y()))); + points.push_back(Point(scale_(pt.x()+width), scale_(pt.y()+depth))); + points.push_back(Point(scale_(pt.x()), scale_(pt.y()+depth))); + } if (points.size() < 3) // At least three points required for a convex hull. From c1bb34cc4dc1fa491da40c5336eff0faa9992843 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 9 Oct 2019 11:22:44 +0200 Subject: [PATCH 23/23] Some changing in implementation of emulate_kill_focus according to new code architecture. + Cleaning of the code from unused parts --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 435 +--------------------- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 7 +- 2 files changed, 23 insertions(+), 419 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 747cec0f99..0b3f2b098d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -120,9 +120,6 @@ static void set_font_and_background_style(wxWindow* win, const wxFont& font) ObjectManipulation::ObjectManipulation(wxWindow* parent) : OG_Settings(parent, true) -#ifndef __APPLE__ - , m_focused_option("") -#endif // __APPLE__ { m_manifold_warning_bmp = ScalableBitmap(parent, "exclamation"); @@ -415,292 +412,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_og->sizer->Add(m_main_grid_sizer, 1, wxEXPAND | wxALL, border); } -/* -ObjectManipulation::ObjectManipulation(wxWindow* parent) : - OG_Settings(parent, true) -#ifndef __APPLE__ - , m_focused_option("") -#endif // __APPLE__ -{ - m_manifold_warning_bmp = ScalableBitmap(parent, "exclamation"); - m_og->set_name(_(L("Object Manipulation"))); - m_og->label_width = 12;//125; - m_og->set_grid_vgap(5); - - m_og->m_on_change = std::bind(&ObjectManipulation::on_change, this, std::placeholders::_1, std::placeholders::_2); - m_og->m_fill_empty_value = std::bind(&ObjectManipulation::on_fill_empty_value, this, std::placeholders::_1); - - m_og->m_set_focus = [this](const std::string& opt_key) - { -#ifndef __APPLE__ - m_focused_option = opt_key; -#endif // __APPLE__ - - // needed to show the visual hints in 3D scene - wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, true); - }; - - ConfigOptionDef def; - - Line line = Line{ "Name", "Object name" }; - - auto manifold_warning_icon = [this](wxWindow* parent) { - m_fix_throught_netfab_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap); - - if (is_windows10()) - m_fix_throught_netfab_bitmap->Bind(wxEVT_CONTEXT_MENU, [this](wxCommandEvent &e) - { - // if object/sub-object has no errors - if (m_fix_throught_netfab_bitmap->GetBitmap().GetRefData() == wxNullBitmap.GetRefData()) - return; - - wxGetApp().obj_list()->fix_through_netfabb(); - update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_list()); - }); - - return m_fix_throught_netfab_bitmap; - }; - - line.near_label_widget = manifold_warning_icon; - def.label = ""; - def.gui_type = "legend"; - def.tooltip = L("Object name"); -#ifdef __APPLE__ - def.width = 20; -#else - def.width = 22; -#endif - def.set_default_value(new ConfigOptionString{ " " }); - line.append_option(Option(def, "object_name")); - m_og->append_line(line); - - const int field_width = 5; - - // Mirror button size: - const int mirror_btn_width = 3; - - // Legend for object modification - line = Line{ "", "" }; - def.label = ""; - def.type = coString; - def.width = field_width - mirror_btn_width; - - // Load bitmaps to be used for the mirroring buttons: - m_mirror_bitmap_on = ScalableBitmap(parent, "mirroring_on"); - m_mirror_bitmap_off = ScalableBitmap(parent, "mirroring_off"); - m_mirror_bitmap_hidden = ScalableBitmap(parent, "mirroring_transparent.png"); - - static const char axes[] = { 'X', 'Y', 'Z' }; - for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++) { - const char label = axes[axis_idx]; - def.set_default_value(new ConfigOptionString{ std::string(" ") + label }); - Option option(def, std::string() + label + "_axis_legend"); - - // We will add a button to toggle mirroring to each axis: - auto mirror_button = [this, mirror_btn_width, axis_idx, label](wxWindow* parent) { - wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width); - auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); - btn->SetToolTip(wxString::Format(_(L("Toggle %c axis mirroring")), (int)label)); - btn->SetBitmapDisabled_(m_mirror_bitmap_hidden); - - m_mirror_buttons[axis_idx].first = btn; - m_mirror_buttons[axis_idx].second = mbShown; - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(btn); - - btn->Bind(wxEVT_BUTTON, [this, axis_idx](wxCommandEvent &e) { - Axis axis = (Axis)(axis_idx + X); - if (m_mirror_buttons[axis_idx].second == mbHidden) - return; - - GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); - Selection& selection = canvas->get_selection(); - - if (selection.is_single_volume() || selection.is_single_modifier()) { - GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); - volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis)); - } - else if (selection.is_single_full_instance()) { - for (unsigned int idx : selection.get_volume_idxs()){ - GLVolume* volume = const_cast(selection.get_volume(idx)); - volume->set_instance_mirror(axis, -volume->get_instance_mirror(axis)); - } - } - else - return; - - // Update mirroring at the GLVolumes. - selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); - selection.synchronize_unselected_volumes(); - // Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. - canvas->do_mirror(L("Set Mirror")); - UpdateAndShow(true); - }); - - return sizer; - }; - - option.side_widget = mirror_button; - line.append_option(option); - } - line.near_label_widget = [this](wxWindow* parent) { - wxBitmapComboBox *combo = create_word_local_combo(parent); - combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent &evt) { this->set_world_coordinates(evt.GetSelection() != 1); }), combo->GetId()); - m_word_local_combo = combo; - return combo; - }; - m_og->append_line(line); - - auto add_og_to_object_settings = [this, field_width](const std::string& option_name, const std::string& sidetext) - { - Line line = { _(option_name), "" }; - ConfigOptionDef def; - def.type = coFloat; - def.set_default_value(new ConfigOptionFloat(0.0)); - def.width = field_width; - - if (option_name == "Scale") { - // Add "uniform scaling" button in front of "Scale" option - line.near_label_widget = [this](wxWindow* parent) { - auto btn = new LockButton(parent, wxID_ANY); - btn->Bind(wxEVT_BUTTON, [btn, this](wxCommandEvent &event){ - event.Skip(); - wxTheApp->CallAfter([btn, this]() { set_uniform_scaling(btn->IsLocked()); }); - }); - m_lock_bnt = btn; - return btn; - }; - // Add reset scale button - auto reset_scale_button = [this](wxWindow* parent) { - auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); - btn->SetToolTip(_(L("Reset scale"))); - m_reset_scale_button = btn; - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(btn, wxBU_EXACTFIT); - btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Reset scale"))); - change_scale_value(0, 100.); - change_scale_value(1, 100.); - change_scale_value(2, 100.); - }); - return sizer; - }; - line.append_widget(reset_scale_button); - } - else if (option_name == "Rotation") { - // Add reset rotation button - auto reset_rotation_button = [this](wxWindow* parent) { - auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); - btn->SetToolTip(_(L("Reset rotation"))); - m_reset_rotation_button = btn; - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(btn, wxBU_EXACTFIT); - btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { - GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); - Selection& selection = canvas->get_selection(); - - if (selection.is_single_volume() || selection.is_single_modifier()) { - GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); - volume->set_volume_rotation(Vec3d::Zero()); - } - else if (selection.is_single_full_instance()) { - for (unsigned int idx : selection.get_volume_idxs()){ - GLVolume* volume = const_cast(selection.get_volume(idx)); - volume->set_instance_rotation(Vec3d::Zero()); - } - } - else - return; - - // Update rotation at the GLVolumes. - selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); - selection.synchronize_unselected_volumes(); - // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. - canvas->do_rotate(L("Reset Rotation")); - - UpdateAndShow(true); - }); - return sizer; - }; - line.append_widget(reset_rotation_button); - } - else if (option_name == "Position") { - // Add drop to bed button - auto drop_to_bed_button = [=](wxWindow* parent) { - auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "drop_to_bed")); - btn->SetToolTip(_(L("Drop to bed"))); - m_drop_to_bed_button = btn; - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(btn, wxBU_EXACTFIT); - btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { - // ??? - GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); - Selection& selection = canvas->get_selection(); - - if (selection.is_single_volume() || selection.is_single_modifier()) { - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - - const Geometry::Transformation& instance_trafo = volume->get_instance_transformation(); - Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume)); - - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Drop to bed"))); - change_position_value(0, diff.x()); - change_position_value(1, diff.y()); - change_position_value(2, diff.z()); - } - }); - return sizer; - }; - line.append_widget(drop_to_bed_button); - } - // Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment - else if (option_name == "Size") { - line.near_label_widget = [this](wxWindow* parent) { - return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, - create_scaled_bitmap(m_parent, "one_layer_lock_on.png").GetSize()); - }; - } - - const std::string lower_name = boost::algorithm::to_lower_copy(option_name); - - for (const char *axis : { "_x", "_y", "_z" }) { - if (axis[1] == 'z') - def.sidetext = sidetext; - Option option = Option(def, lower_name + axis); - option.opt.full_width = true; - line.append_option(option); - } - - return line; - }; - - // Settings table - m_og->sidetext_width = 3; - m_og->append_line(add_og_to_object_settings(L("Position"), L("mm")), &m_move_Label); - m_og->append_line(add_og_to_object_settings(L("Rotation"), "°"), &m_rotate_Label); - m_og->append_line(add_og_to_object_settings(L("Scale"), "%"), &m_scale_Label); - m_og->append_line(add_og_to_object_settings(L("Size"), "mm")); - - // call back for a rescale of button "Set uniform scale" - m_og->rescale_near_label_widget = [this](wxWindow* win) { - // rescale lock icon - auto *ctrl = dynamic_cast(win); - if (ctrl != nullptr) { - ctrl->msw_rescale(); - return; - } - - if (win == m_fix_throught_netfab_bitmap) - return; - - // rescale "place" of the empty icon (to correct layout of the "Size" and "Scale") - if (dynamic_cast(win) != nullptr) - win->SetMinSize(create_scaled_bitmap(m_parent, "one_layer_lock_on.png").GetSize()); - }; -} -*/ - - void ObjectManipulation::Show(const bool show) { if (show != IsShown()) { @@ -710,9 +421,9 @@ void ObjectManipulation::Show(const bool show) if (show && wxGetApp().get_mode() != comSimple) { // Show the label and the name of the STL in simple mode only. // Label "Name: " - /*m_og->get_grid_sizer()*/m_main_grid_sizer->Show(size_t(0), false); + m_main_grid_sizer->Show(size_t(0), false); // The actual name of the STL. - /*m_og->get_grid_sizer()*/m_main_grid_sizer->Show(size_t(1), false); + m_main_grid_sizer->Show(size_t(1), false); } } @@ -833,26 +544,6 @@ void ObjectManipulation::update_if_dirty() update_label(m_cache.rotate_label_string, m_new_rotate_label_string, m_rotate_Label); update_label(m_cache.scale_label_string, m_new_scale_label_string, m_scale_Label); - /* - char axis[2] = "x"; - for (int i = 0; i < 3; ++ i, ++ axis[0]) { - auto update = [this, i, &axis](Vec3d &cached, Vec3d &cached_rounded, const char *key, const Vec3d &new_value) { - wxString new_text = double_to_string(new_value(i), 2); - double new_rounded; - new_text.ToDouble(&new_rounded); - if (std::abs(cached_rounded(i) - new_rounded) > EPSILON) { - cached_rounded(i) = new_rounded; - m_og->set_value(std::string(key) + axis, new_text); - } - cached(i) = new_value(i); - }; - update(m_cache.position, m_cache.position_rounded, "position_", m_new_position); - update(m_cache.scale, m_cache.scale_rounded, "scale_", m_new_scale); - update(m_cache.size, m_cache.size_rounded, "size_", m_new_size); - update(m_cache.rotation, m_cache.rotation_rounded, "rotation_", m_new_rotation); - } - */ - enum ManipulationEditorKey { mePosition = 0, @@ -1007,17 +698,10 @@ void ObjectManipulation::update_mirror_buttons_visibility() #ifndef __APPLE__ void ObjectManipulation::emulate_kill_focus() { - if (m_focused_option.empty()) + if (!m_focused_editor) return; - // we need to use a copy because the value of m_focused_option is modified inside on_change() and on_fill_empty_value() - std::string option = m_focused_option; - - // see TextCtrl::propagate_value() - if (static_cast(m_og->get_fieldc(option, 0)->getWindow())->GetValue().empty()) - on_fill_empty_value(option); - else - on_change(option, 0); + m_focused_editor->kill_focus(this); } #endif // __APPLE__ @@ -1156,40 +840,6 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale")); } -void ObjectManipulation::on_change(t_config_option_key opt_key, const boost::any& value) -{ - Field* field = m_og->get_field(opt_key); - bool enter_pressed = (field != nullptr) && field->get_enter_pressed(); - if (!enter_pressed) - { - // if the change does not come from the user pressing the ENTER key - // we need to hide the visual hints in 3D scene - wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false); - -#ifndef __APPLE__ - m_focused_option = ""; -#endif // __APPLE__ - } - else - // if the change comes from the user pressing the ENTER key, restore the key state - field->set_enter_pressed(false); - - if (!m_cache.is_valid()) - return; - - int axis = opt_key.back() - 'x'; - double new_value = boost::any_cast(m_og->get_value(opt_key)); - - if (boost::starts_with(opt_key, "position_")) - change_position_value(axis, new_value); - else if (boost::starts_with(opt_key, "rotation_")) - change_rotation_value(axis, new_value); - else if (boost::starts_with(opt_key, "scale_")) - change_scale_value(axis, new_value); - else if (boost::starts_with(opt_key, "size_")) - change_size_value(axis, new_value); -} - void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value) { if (!m_cache.is_valid()) @@ -1205,42 +855,6 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double change_size_value(axis, new_value); } -void ObjectManipulation::on_fill_empty_value(const std::string& opt_key) -{ - // needed to hide the visual hints in 3D scene - wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false); -#ifndef __APPLE__ - m_focused_option = ""; -#endif // __APPLE__ - - if (!m_cache.is_valid()) - return; - - const Vec3d *vec = nullptr; - Vec3d *rounded = nullptr; - if (boost::starts_with(opt_key, "position_")) { - vec = &m_cache.position; - rounded = &m_cache.position_rounded; - } else if (boost::starts_with(opt_key, "rotation_")) { - vec = &m_cache.rotation; - rounded = &m_cache.rotation_rounded; - } else if (boost::starts_with(opt_key, "scale_")) { - vec = &m_cache.scale; - rounded = &m_cache.scale_rounded; - } else if (boost::starts_with(opt_key, "size_")) { - vec = &m_cache.size; - rounded = &m_cache.size_rounded; - } else - assert(false); - - if (vec != nullptr) { - int axis = opt_key.back() - 'x'; - wxString new_text = double_to_string((*vec)(axis)); - m_og->set_value(opt_key, new_text); - new_text.ToDouble(&(*rounded)(axis)); - } -} - void ObjectManipulation::set_uniform_scaling(const bool new_value) { const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection(); @@ -1338,43 +952,25 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent, parent->on_change(m_opt_key, m_axis, get_value()); }, this->GetId()); - this->Bind(wxEVT_KILL_FOCUS, [this, parent/*, edit_fn*/](wxFocusEvent& e) + this->Bind(wxEVT_KILL_FOCUS, [this, parent](wxFocusEvent& e) { - if (!m_enter_pressed) { - parent->on_change(m_opt_key, m_axis, get_value()); + parent->set_focused_editor(nullptr); - // if the change does not come from the user pressing the ENTER key - // we need to hide the visual hints in 3D scene - wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(m_full_opt_name, false); -// #ifndef __WXGTK__ -// /* Update data for next editor selection. -// * But under GTK it looks like there is no information about selected control at e.GetWindow(), -// * so we'll take it from wxEVT_LEFT_DOWN event -// * */ -// LayerRangeEditor* new_editor = dynamic_cast(e.GetWindow()); -// if (new_editor) -// new_editor->set_focus_data(); -// #endif // not __WXGTK__ - } + if (!m_enter_pressed) + kill_focus(parent); e.Skip(); }, this->GetId()); - this->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent& e) + this->Bind(wxEVT_SET_FOCUS, [this, parent](wxFocusEvent& e) { + parent->set_focused_editor(this); + // needed to show the visual hints in 3D scene wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(m_full_opt_name, true); e.Skip(); }, this->GetId()); -// #ifdef __WXGTK__ // Workaround! To take information about selectable range -// this->Bind(wxEVT_LEFT_DOWN, [this](wxEvent& e) -// { -// set_focus_data(); -// e.Skip(); -// }, this->GetId()); -// #endif //__WXGTK__ - this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event) { // select all text using Ctrl+A @@ -1417,5 +1013,14 @@ void ManipulationEditor::set_value(const wxString& new_value) SetValue(m_valid_value); } +void ManipulationEditor::kill_focus(ObjectManipulation* parent) +{ + parent->on_change(m_opt_key, m_axis, get_value()); + + // if the change does not come from the user pressing the ENTER key + // we need to hide the visual hints in 3D scene + wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(m_full_opt_name, false); +} + } //namespace GUI } //namespace Slic3r diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index e25aab6784..7d53034b25 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -32,6 +32,7 @@ public: void msw_rescale(); void set_value(const wxString& new_value); + void kill_focus(ObjectManipulation *parent); private: double get_value(); @@ -118,7 +119,7 @@ class ObjectManipulation : public OG_Settings #ifndef __APPLE__ // Currently focused option name (empty if none) - std::string m_focused_option; + ManipulationEditor* m_focused_editor {nullptr}; #endif // __APPLE__ wxFlexGridSizer* m_main_grid_sizer; @@ -160,6 +161,7 @@ public: void update_warning_icon_state(const wxString& tooltip); void msw_rescale(); void on_change(const std::string& opt_key, int axis, double new_value); + void set_focused_editor(ManipulationEditor* focused_editor) { m_focused_editor = focused_editor; } private: void reset_settings_value(); @@ -176,9 +178,6 @@ private: void change_scale_value(int axis, double value); void change_size_value(int axis, double value); void do_scale(int axis, const Vec3d &scale) const; - - void on_change(t_config_option_key opt_key, const boost::any& value); - void on_fill_empty_value(const std::string& opt_key); }; }}