diff --git a/.gitignore b/.gitignore index 2093364316b..a4a9356f3eb 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,7 @@ SVG src/OrcaSlicer-doc/ .idea/ /.cache/ -*.mo \ No newline at end of file +*.mo +**/process_full/ +**/machine_full/ +**/filament_full/ diff --git a/localazy.json b/localazy.json index 3556bd3f456..343d9533243 100644 --- a/localazy.json +++ b/localazy.json @@ -39,6 +39,11 @@ "pattern": "localization/i18n/hu/OrcaSlicer_hu.po", "lang": "hu" }, + { + "type": "po", + "pattern": "localization/i18n/ja/OrcaSlicer_hu.po", + "lang": "it" + }, { "type": "po", "pattern": "localization/i18n/ja/OrcaSlicer_ja.po", diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index f45e237d77c..50c3cdb284d 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -106,6 +106,9 @@ msgstr "" msgid "Support Generated" msgstr "" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "" @@ -151,7 +154,7 @@ msgstr "" msgid "Height range" msgstr "" -msgid "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" msgstr "" msgid "Toggle Wireframe" @@ -182,9 +185,15 @@ msgstr "" msgid "Move" msgstr "" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "" @@ -194,10 +203,10 @@ msgstr "" msgid "Scale" msgstr "" -msgid "Error: Please close all toolbar menus first" +msgid "Gizmo-Scale" msgstr "" -msgid "Tool-Lay on Face" +msgid "Error: Please close all toolbar menus first" msgstr "" msgid "in" @@ -489,6 +498,15 @@ msgstr "" msgid "Remove selection" msgstr "" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "" @@ -683,6 +701,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "" @@ -876,7 +902,10 @@ msgstr "" msgid "Fix model" msgstr "" -msgid "Export as STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" msgstr "" msgid "Reload from disk" @@ -1132,6 +1161,9 @@ msgstr "" msgid "Click the icon to shift this object to the bed" msgstr "" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "" @@ -1376,6 +1408,18 @@ msgstr "" msgid "Open Documentation in web browser." msgstr "" +msgid "Color" +msgstr "" + +msgid "Pause" +msgstr "" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "" + msgid "Pause:" msgstr "" @@ -1451,7 +1495,7 @@ msgstr "" msgid "Failed to connect to the server" msgstr "" -msgid "Check cloud service status" +msgid "Check the status of current system services" msgstr "" msgid "code" @@ -1690,6 +1734,14 @@ msgstr "" msgid "Sending print job through cloud service" msgstr "" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "" @@ -1900,10 +1952,10 @@ msgstr "" msgid "You need to select the material type and color first." msgstr "" -msgid "Please input a valid value (K in 0~0.5)" +msgid "Please input a valid value (K in 0~0.3)" msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" msgstr "" msgid "Other Color" @@ -2239,9 +2291,6 @@ msgstr "" msgid "Circular" msgstr "" -msgid "Custom" -msgstr "" - msgid "Load shape from STL..." msgstr "" @@ -2675,6 +2724,9 @@ msgstr "" msgid "Total" msgstr "" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "" @@ -2762,15 +2814,18 @@ msgstr "" msgid "Print" msgstr "" -msgid "Pause" -msgstr "" - msgid "Printer" msgstr "" msgid "Print settings" msgstr "" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "" @@ -2939,7 +2994,7 @@ msgstr "" msgid "Size:" msgstr "" -#, possible-c-format, possible-boost-format +#, possible-boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -2993,15 +3048,15 @@ msgstr "" msgid "Start Calibration" msgstr "" -msgid "No step selected" -msgstr "" - msgid "Completed" msgstr "" msgid "Calibrating" msgstr "" +msgid "No step selected" +msgstr "" + msgid "Auto-record Monitoring" msgstr "" @@ -3214,7 +3269,10 @@ msgstr "" msgid "Import" msgstr "" -msgid "Export all objects as STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" msgstr "" msgid "Export Generic 3MF" @@ -3484,9 +3542,6 @@ msgstr "" msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "" -msgid "Loading..." -msgstr "" - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" @@ -3544,6 +3599,9 @@ msgstr "" msgid "Load failed [%d]!" msgstr "" +msgid "Loading..." +msgstr "" + msgid "Year" msgstr "" @@ -3661,12 +3719,25 @@ msgstr "" msgid "Downloading %d%%..." msgstr "" +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "" msgid "Storage unavailable, insert SD card." msgstr "" +#, possible-c-format, possible-boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "" @@ -3995,6 +4066,12 @@ msgstr "" msgid "Details" msgstr "" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "" + msgid "Undo integration failed." msgstr "" @@ -4043,9 +4120,6 @@ msgstr "" msgid "Cancel upload" msgstr "" -msgid "Slice ok." -msgstr "" - msgid "Jump to" msgstr "" @@ -4145,6 +4219,9 @@ msgstr "" msgid "Allow Prompt Sound" msgstr "" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "" @@ -4239,6 +4316,9 @@ msgstr "" msgid "Set filaments to use" msgstr "" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4325,21 +4405,28 @@ msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "" #, possible-c-format, possible-boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -msgid "You'd better upgrade your software.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" msgstr "" msgid "Newer 3mf version" msgstr "" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, possible-c-format, possible-boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" msgid "Invalid values found in the 3mf:" @@ -4348,10 +4435,26 @@ msgstr "" msgid "Please correct them in the param tabs" msgstr "" -msgid "The 3mf is not compatible, load geometry data only!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" msgstr "" -msgid "Incompatible 3mf" +msgid "Customized Preset" msgstr "" msgid "Name of components inside step file is not UTF8 format!" @@ -4417,6 +4520,15 @@ msgstr "" msgid "Export OBJ file:" msgstr "" +#, possible-c-format, possible-boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "" @@ -4432,15 +4544,15 @@ msgstr "" msgid "Another export job is running." msgstr "" -msgid "Replace from:" -msgstr "" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "" +msgid "Replace from:" +msgstr "" + msgid "Select a new file" msgstr "" @@ -4790,6 +4902,12 @@ msgstr "" msgid "If enabled, g-code window will be displayed." msgstr "" +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "" @@ -4838,6 +4956,9 @@ msgstr "" msgid "Clear my choice on the unsaved projects." msgstr "" +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "" @@ -4989,7 +5110,10 @@ msgstr "" msgid "Add/Remove materials" msgstr "" -msgid "Add/Remove printers" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" msgstr "" msgid "Incompatible" @@ -5172,16 +5296,16 @@ msgstr "" msgid "PLA Plate" msgstr "" -msgid "Bambu Engineering Plate" +msgid "Bamabu Engineering Plate" msgstr "" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "" msgid "High temperature Plate" msgstr "" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "" msgid "Send print job to" @@ -5205,9 +5329,6 @@ msgstr "" msgid "Error code" msgstr "" -msgid "Check the status of current system services" -msgstr "" - msgid "Printer local connection failed, please try again." msgstr "" @@ -5296,8 +5417,7 @@ msgid "" msgstr "" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" msgid "Errors" @@ -5312,20 +5432,39 @@ msgid "" "type for slicing." msgstr "" -#, possible-c-format, possible-boost-format -msgid "%s is not supported by AMS." -msgstr "" - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " "start printing." msgstr "" +#, possible-c-format, possible-boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5487,6 +5626,9 @@ msgid "" "model without prime tower. Do you want to enable prime tower?" msgstr "" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5515,8 +5657,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" msgid "Line width" @@ -5756,6 +5898,9 @@ msgstr "" msgid "Machine end G-code" msgstr "" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "" @@ -5822,18 +5967,32 @@ msgstr "" msgid "Detached" msgstr "" -msgid "Following preset will be deleted too." -msgid_plural "Following presets will be deleted too." +#, possible-c-format, possible-boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." msgstr[0] "" msgstr[1] "" +#. TRN Remove/Delete #, possible-boost-format -msgid "Are you sure to %1% the selected preset?" +msgid "%1% Preset" msgstr "" -#. TRN Remove/Delete +msgid "Following preset will be deleted too." +msgid_plural "Following presets will be deleted too." +msgstr[0] "" +msgstr[1] "" + #, possible-boost-format -msgid "%1% Preset" +msgid "Are you sure to %1% the selected preset?" msgstr "" msgid "All" @@ -6057,10 +6216,16 @@ msgstr "" msgid "Auto-Calc" msgstr "" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "" -msgid "Multiplier" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" msgstr "" msgid "Flushing volume (mm³) for each filament pair." @@ -6074,6 +6239,9 @@ msgstr "" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "" +msgid "Multiplier" +msgstr "" + msgid "unloaded" msgstr "" @@ -6089,6 +6257,12 @@ msgstr "" msgid "To" msgstr "" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "" @@ -6122,6 +6296,9 @@ msgstr "" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "" @@ -6368,12 +6545,15 @@ msgstr "" msgid "New version of Orca Slicer" msgstr "" -msgid "Don't remind me of this version again" +msgid "Skip this Version" msgstr "" msgid "Done" msgstr "" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "" @@ -6395,7 +6575,21 @@ msgstr "" msgid "Where to find your printer's IP and Access Code?" msgstr "" -msgid "Error: IP or Access Code are not correct" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" msgstr "" msgid "Model:" @@ -6814,6 +7008,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7191,7 +7390,28 @@ msgstr "" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" msgid "Reverse threshold" @@ -7407,6 +7627,14 @@ msgstr "" msgid "End G-code when finish the whole printing" msgstr "" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "" @@ -7489,25 +7717,25 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "" -msgid "Order of inner wall/outer wall/infil" +msgid "Order of walls" msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " +msgid "Print sequence of inner wall and outer wall. " msgstr "" -msgid "inner/outer/infill" +msgid "inner/outer" msgstr "" -msgid "outer/inner/infill" +msgid "outer/inner" msgstr "" -msgid "infill/inner/outer" +msgid "inner wall/outer wall/inner wall" msgstr "" -msgid "infill/outer/inner" +msgid "Print infill first" msgstr "" -msgid "inner-outer-inner/infill" +msgid "Order of wall/infill. false means print wall first. " msgstr "" msgid "Height to rod" @@ -7590,9 +7818,6 @@ msgstr "" msgid "Default filament color" msgstr "" -msgid "Color" -msgstr "" - msgid "Filament notes" msgstr "" @@ -7952,10 +8177,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "" -#, possible-c-format, possible-boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "" @@ -8021,10 +8242,10 @@ msgstr "" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" msgid "Support interface fan speed" @@ -8290,6 +8511,18 @@ msgid "" "soluble support material" msgstr "" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "" @@ -8788,6 +9021,22 @@ msgid "" "print when travel move. Using spiral line to lift z can prevent stringing" msgstr "" +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "" @@ -9170,6 +9419,12 @@ msgid "" "filament for support and current filament is used" msgstr "" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." @@ -9199,6 +9454,12 @@ msgstr "" msgid "Bottom interface layers" msgstr "" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "" @@ -9765,175 +10026,41 @@ msgstr "" msgid " not in range " msgstr "" -msgid "Export 3MF" +msgid "Minimum save" msgstr "" -msgid "Export project as 3MF." +msgid "export 3mf with minimum size." msgstr "" -msgid "Export slicing data" +msgid "No check" msgstr "" -msgid "Export slicing data to a folder." +msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "" -msgid "Load slicing data" +msgid "Ensure on bed" msgstr "" -msgid "Load cached slicing data from directory" +msgid "" +"Lift the object above the bed when it is partially below. Disabled by default" msgstr "" -msgid "Export STL" +msgid "Orient Options" msgstr "" -msgid "Export the objects as multiple STL." +msgid "Orient options: 0-disable, 1-enable, others-auto" msgstr "" -msgid "Slice" +msgid "Rotation angle around the Z axis in degrees." msgstr "" -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +msgid "Rotate around Y" msgstr "" -msgid "Show command help." +msgid "Rotation angle around the Y axis in degrees." msgstr "" -msgid "UpToDate" -msgstr "" - -msgid "Update the configs values of 3mf to latest." -msgstr "" - -msgid "Load default filaments" -msgstr "" - -msgid "Load first filament as default for those not loaded" -msgstr "" - -msgid "Minimum save" -msgstr "" - -msgid "export 3mf with minimum size." -msgstr "" - -msgid "mtcpp" -msgstr "" - -msgid "max triangle count per plate for slicing." -msgstr "" - -msgid "mstpp" -msgstr "" - -msgid "max slicing time per plate in seconds." -msgstr "" - -msgid "No check" -msgstr "" - -msgid "Do not run any validity checks, such as gcode path conflicts check." -msgstr "" - -msgid "Normative check" -msgstr "" - -msgid "Check the normative items." -msgstr "" - -msgid "Output Model Info" -msgstr "" - -msgid "Output the model's information." -msgstr "" - -msgid "Export Settings" -msgstr "" - -msgid "Export settings to a file." -msgstr "" - -msgid "Send progress to pipe" -msgstr "" - -msgid "Send progress to pipe." -msgstr "" - -msgid "Arrange Options" -msgstr "" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "" - -msgid "Repetions count" -msgstr "" - -msgid "Repetions count of the whole model" -msgstr "" - -msgid "Ensure on bed" -msgstr "" - -msgid "" -"Lift the object above the bed when it is partially below. Disabled by default" -msgstr "" - -msgid "Convert Unit" -msgstr "" - -msgid "Convert the units of model" -msgstr "" - -msgid "Orient Options" -msgstr "" - -msgid "Orient options: 0-disable, 1-enable, others-auto" -msgstr "" - -msgid "Rotation angle around the Z axis in degrees." -msgstr "" - -msgid "Rotate around X" -msgstr "" - -msgid "Rotation angle around the X axis in degrees." -msgstr "" - -msgid "Rotate around Y" -msgstr "" - -msgid "Rotation angle around the Y axis in degrees." -msgstr "" - -msgid "Scale the model by a float factor" -msgstr "" - -msgid "Load General Settings" -msgstr "" - -msgid "Load process/machine settings from the specified file" -msgstr "" - -msgid "Load Filament Settings" -msgstr "" - -msgid "Load filament settings from the specified file list" -msgstr "" - -msgid "Skip Objects" -msgstr "" - -msgid "Skip some objects in this print" -msgstr "" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" - -msgid "Data directory" +msgid "Data directory" msgstr "" msgid "" @@ -9942,20 +10069,6 @@ msgid "" "storage." msgstr "" -msgid "Output directory" -msgstr "" - -msgid "Output directory for the exported files." -msgstr "" - -msgid "Debug level" -msgstr "" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" - msgid "Load custom gcode" msgstr "" @@ -10110,9 +10223,6 @@ msgstr "" msgid "Finish" msgstr "" -msgid "Wiki" -msgstr "" - msgid "How to use calibration result?" msgstr "" @@ -10128,6 +10238,12 @@ msgstr "" msgid "Calibration not supported" msgstr "" +msgid "Error desc" +msgstr "" + +msgid "Extra info" +msgstr "" + msgid "Flow Dynamics" msgstr "" @@ -10155,8 +10271,8 @@ msgstr "" msgid "The name cannot be empty." msgstr "" -#, possible-boost-format -msgid "The selected preset: %1% is not found." +#, possible-c-format, possible-boost-format +msgid "The selected preset: %s is not found." msgstr "" msgid "The name cannot be the same as the system preset name." @@ -10436,12 +10552,6 @@ msgid "" "- Different filament brand and family(Brand = Bambu, Family = Basic, Matte)" msgstr "" -msgid "Error desc" -msgstr "" - -msgid "Extra info" -msgstr "" - msgid "Pattern" msgstr "" @@ -10530,101 +10640,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "" - -msgid "Mesh Boolean" -msgstr "" - -msgid "Union" -msgstr "" - -msgid "Difference" -msgstr "" - -msgid "Intersection" -msgstr "" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "" - -msgid "Subtract with" -msgstr "" - -msgid "selected" -msgstr "" - -msgid "Part 1" -msgstr "" - -msgid "Part 2" -msgstr "" - -msgid "Delete input" -msgstr "" - -msgid "Send G-Code to printer host" -msgstr "" - -msgid "Upload to Printer Host with the following filename:" -msgstr "" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" - -msgid "Upload to storage" -msgstr "" - -#, possible-c-format, possible-boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" - -msgid "Upload" -msgstr "" - -msgid "Print host upload queue" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "" - -msgctxt "OfFile" -msgid "Size" -msgstr "" - -msgid "Filename" -msgstr "" - -msgid "Cancel selected" -msgstr "" - -msgid "Show error message" -msgstr "" - -msgid "Enqueued" -msgstr "" - -msgid "Uploading" -msgstr "" - -msgid "Cancelling" -msgstr "" - -msgid "Error uploading to print host" -msgstr "" - msgid "PA Calibration" msgstr "" @@ -10749,62 +10764,103 @@ msgstr "" msgid "mm/mm" msgstr "" -msgid "Physical Printer" +msgid "Send G-Code to printer host" +msgstr "" + +msgid "Upload to Printer Host with the following filename:" msgstr "" -msgid "Print Host upload" +msgid "Use forward slashes ( / ) as a directory separator if needed." msgstr "" -msgid "Test" +msgid "Upload to storage" msgstr "" -msgid "Could not get a valid Printer Host reference" +#, possible-c-format, possible-boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" msgstr "" -msgid "Success!" +msgid "Upload" msgstr "" -msgid "Refresh Printers" +msgid "Print host upload queue" msgstr "" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." +msgid "ID" msgstr "" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "Progress" msgstr "" -msgid "Open CA certificate file" +msgid "Host" msgstr "" -#, possible-c-format, possible-boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." +msgctxt "OfFile" +msgid "Size" msgstr "" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." +msgid "Filename" msgstr "" -msgid "Connection to printers connected via the print host failed." +msgid "Cancel selected" msgstr "" -msgid "The start, end or step is not valid value." +msgid "Show error message" msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Enqueued" +msgstr "" + +msgid "Uploading" +msgstr "" + +msgid "Cancelling" +msgstr "" + +msgid "Error uploading to print host" +msgstr "" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "" + +msgid "Mesh Boolean" +msgstr "" + +msgid "Union" msgstr "" -msgid "Need select printer" +msgid "Difference" msgstr "" -#: resources/data/hints.ini: [hint:3D Scene Operations] -msgid "3D Scene Operations\nDid you know how to control view and object/part selection with mouse and touchpanel in the 3D scene?" +msgid "Intersection" +msgstr "" + +msgid "Source Volume" +msgstr "" + +msgid "Tool Volume" +msgstr "" + +msgid "Subtract from" +msgstr "" + +msgid "Subtract with" +msgstr "" + +msgid "selected" +msgstr "" + +msgid "Part 1" +msgstr "" + +msgid "Part 2" +msgstr "" + +msgid "Delete input" +msgstr "" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] +msgid "How to use keyboard shortcuts\nDid you know that Orca Slicer offers a wide range of keyboard shortcuts and 3D scene operations." msgstr "" #: resources/data/hints.ini: [hint:Cut Tool] @@ -10812,7 +10868,7 @@ msgid "Cut Tool\nDid you know that you can cut a model at any angle and position msgstr "" #: resources/data/hints.ini: [hint:Fix Model] -msgid "Fix Model\nDid you know that you can fix a corrupted 3D model to avoid a lot of slicing problems?" +msgid "Fix Model\nDid you know that you can fix a corrupted 3D model to avoid a lot of slicing problems on the Windows system?" msgstr "" #: resources/data/hints.ini: [hint:Timelapse] @@ -10835,6 +10891,10 @@ msgstr "" msgid "Object List\nDid you know that you can view all objects/parts in a list and change settings for each object/part?" msgstr "" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "Search Functionality\nDid you know that you use the Search tool to quickly find a specific Orca Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "Simplify Model\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in the documentation." msgstr "" @@ -10904,5 +10964,9 @@ msgid "Improve strength\nDid you know that you can use more wall loops and highe msgstr "" #: resources/data/hints.ini: [hint:When need to print with the printer door opened] -msgid "When need to print with the printer door opened\nOpening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature. More info about this in the Wiki." +msgid "When need to print with the printer door opened\nDid you know that opening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "Avoid warping\nDid you know that when printing materials that are prone to warping such as ABS, appropriately increasing the heatbed temperature can reduce the probability of warping." msgstr "" diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index b5cb790fbbf..b3857c95683 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: 2023-09-30 15:15+0200\n" "Last-Translator: René Mošner \n" "Language-Team: \n" @@ -106,6 +106,9 @@ msgstr "Žádné automatické podpěry" msgid "Support Generated" msgstr "Vygenerovat podpěry" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Plochou na podložku" @@ -154,8 +157,8 @@ msgstr "Vylití barvou" msgid "Height range" msgstr "Rozsah výšky" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Přepnout drátový model" @@ -185,9 +188,15 @@ msgstr "Namalováno pomocí: Filament %1%" msgid "Move" msgstr "Přesunout" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Otočit" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Optimalizovat orientaci" @@ -197,12 +206,12 @@ msgstr "Použít" msgid "Scale" msgstr "Měřítko" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "Chyba: Nejprve prosím zavřete všechny nabídky panelu nástrojů" -msgid "Tool-Lay on Face" -msgstr "Nástroj-Plochou na podložku" - msgid "in" msgstr "v" @@ -497,6 +506,15 @@ msgstr "Malování pozice švu" msgid "Remove selection" msgstr "Odebrat výběr" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Písmo" @@ -658,7 +676,8 @@ msgid "" "Please note, application settings will be lost, but printer profiles will " "not be affected." msgstr "" -"Soubor konfigurace programu OrcaSlicer může být poškozen a nelze ho analyzovat.\n" +"Soubor konfigurace programu OrcaSlicer může být poškozen a nelze ho " +"analyzovat.\n" "OrcaSlicer se pokusil znovu vytvořit konfigurační soubor.\n" "Všimněte si, že nastavení aplikace bude ztraceno, ale profily tiskárny " "nebudou ovlivněny." @@ -715,6 +734,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Aktualizace zásad ochrany osobních údajů" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Načítání" @@ -908,8 +935,11 @@ msgstr "Tisknout objekt" msgid "Fix model" msgstr "Opravit model" -msgid "Export as STL" -msgstr "Exportovat jako STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Znovu načíst z disku" @@ -1168,6 +1198,9 @@ msgstr "Kliknutím na ikonu upravíte barevnou malbu objektu" msgid "Click the icon to shift this object to the bed" msgstr "Klikněte na ikonu pro přesunutí tohoto objektu na podložku" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Načítání souboru" @@ -1428,6 +1461,18 @@ msgstr "Otevřít další tip." msgid "Open Documentation in web browser." msgstr "Otevřít dokumentaci ve webovém prohlížeči." +msgid "Color" +msgstr "Barva" + +msgid "Pause" +msgstr "Pozastavení" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Vlastní" + msgid "Pause:" msgstr "Pauza:" @@ -1503,8 +1548,8 @@ msgstr "..." msgid "Failed to connect to the server" msgstr "Nepodařilo se připojit k serveru" -msgid "Check cloud service status" -msgstr "Zkontrolujte stav cloudové služby" +msgid "Check the status of current system services" +msgstr "Zkontrolujte stav aktuálních systémových služeb" msgid "code" msgstr "kód" @@ -1767,6 +1812,14 @@ msgstr "Odesílání tiskové úlohy přes LAN" msgid "Sending print job through cloud service" msgstr "Odesílání tiskové úlohy prostřednictvím cloudové služby" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Služba není k dispozici" @@ -1991,11 +2044,11 @@ msgstr "Jste si jistý, že chcete vymazat informace o filamentu?" msgid "You need to select the material type and color first." msgstr "Nejprve musíte vybrat typ materiálu a barvu." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Zadejte prosím platnou hodnotu (K v 0~0,5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "Zadejte platnou hodnotu (K v 0~0,5, N v 0,6~2,0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Jiná Barva" @@ -2380,9 +2433,6 @@ msgstr "Obdélníkový" msgid "Circular" msgstr "Kruhový" -msgid "Custom" -msgstr "Vlastní" - msgid "Load shape from STL..." msgstr "Načíst tvar ze souboru STL…" @@ -2888,6 +2938,9 @@ msgstr "Čištění" msgid "Total" msgstr "Celkem" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Celkový odhad" @@ -2975,15 +3028,18 @@ msgstr "Změna barvy" msgid "Print" msgstr "Tisk" -msgid "Pause" -msgstr "Pozastavení" - msgid "Printer" msgstr "Tiskárna" msgid "Print settings" msgstr "Nastavení tisku" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Časový odhad" @@ -3152,7 +3208,7 @@ msgstr "Objem:" msgid "Size:" msgstr "Velikost:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3214,15 +3270,15 @@ msgstr "Kalibrace průtoku" msgid "Start Calibration" msgstr "Spustit kalibraci" -msgid "No step selected" -msgstr "Není vybrán žádný krok" - msgid "Completed" msgstr "Dokončeno" msgid "Calibrating" msgstr "Kalibruji" +msgid "No step selected" +msgstr "Není vybrán žádný krok" + msgid "Auto-record Monitoring" msgstr "Monitorování automatického nahrávání" @@ -3437,8 +3493,11 @@ msgstr "Načíst konfigurace" msgid "Import" msgstr "Importovat" -msgid "Export all objects as STL" -msgstr "Exportovat všechny objekty jako STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Exportovat generický 3MF" @@ -3721,9 +3780,6 @@ msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "" "Tiskárna je zaneprázdněna stahováním, počkejte prosím na dokončení stahování." -msgid "Loading..." -msgstr "Načítání..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" "Inicializace se nezdařila (Není podporováno ve stávající verzi tiskárny)!" @@ -3787,6 +3843,9 @@ msgstr "Hraje..." msgid "Load failed [%d]!" msgstr "Načítání selhalo [%d]!" +msgid "Loading..." +msgstr "Načítání..." + msgid "Year" msgstr "Rok" @@ -3909,12 +3968,25 @@ msgstr "Stahování dokončeno" msgid "Downloading %d%%..." msgstr "Stahování %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "Není podporováno ve stávající verzi tiskárny." msgid "Storage unavailable, insert SD card." msgstr "Úložiště není k dispozici, vložte SD kartu." +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Rychlost:" @@ -4261,6 +4333,12 @@ msgstr "K dispozici je nový síťový zásuvný modul." msgid "Details" msgstr "Podrobnosti" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "Wiki" + msgid "Undo integration failed." msgstr "Vrácení zpět integrace se nezdařilo." @@ -4312,9 +4390,6 @@ msgstr "DOKONČENO" msgid "Cancel upload" msgstr "Zrušit nahrávání" -msgid "Slice ok." -msgstr "Slicování Dokončeno." - msgid "Jump to" msgstr "Přejít na" @@ -4419,6 +4494,9 @@ msgstr "Automatické obnovení po ztrátě kroku" msgid "Allow Prompt Sound" msgstr "Povolit zvuky upozornění" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Globální" @@ -4513,6 +4591,9 @@ msgstr "Synchronizovat seznam filamentů z AM" msgid "Set filaments to use" msgstr "Nastavit filamenty k použití" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4621,26 +4702,29 @@ msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "3mf je generován starým Orca Slicerem, načtěte pouze geometrická data." #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"Verze 3mf %s je novější než verze %s %s, byly nalezeny následující klíče " -"nerozpoznaný:" -msgid "You'd better upgrade your software.\n" -msgstr "Měli byste aktualizovat software.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Novější verze 3mf" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"Verze %s zařízení 3mf je novější než verze %s %s, navrhněte upgrade vašeho " -"software." msgid "Invalid values found in the 3mf:" msgstr "V 3mf byly nalezeny neplatné hodnoty:" @@ -4648,11 +4732,27 @@ msgstr "V 3mf byly nalezeny neplatné hodnoty:" msgid "Please correct them in the param tabs" msgstr "Opravte je prosím na kartách parametrů" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "3mf není kompatibilní, načtěte pouze geometrická data!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "Nekompatibilní 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "Názvy součástí v souboru kroku nejsou ve formátu UTF8!" @@ -4725,6 +4825,15 @@ msgstr "Uložit soubor jako:" msgid "Export OBJ file:" msgstr "Exportovat OBJ soubor:" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Odstranění objektu, který je součástí řezaného objektu" @@ -4743,15 +4852,15 @@ msgstr "Vybraný objekt nelze rozdělit." msgid "Another export job is running." msgstr "Probíhá další exportní úloha." -msgid "Replace from:" -msgstr "Nahradit z:" - msgid "Unable to replace with more than one volume" msgstr "Nelze nahradit více než jednou částí" msgid "Error during replace" msgstr "Chyba při nahrazení" +msgid "Replace from:" +msgstr "Nahradit z:" + msgid "Select a new file" msgstr "Vyberte nový soubor" @@ -5123,6 +5232,12 @@ msgstr "Zobrazit okno s G-kódem" msgid "If enabled, g-code window will be displayed." msgstr "Pokud je povoleno, zobrazí se okno s G-kódem." +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Předvolby" @@ -5178,6 +5293,9 @@ msgstr "Maximální počet nedávných projektů" msgid "Clear my choice on the unsaved projects." msgstr "Vymazat moje volby pro neuložené projekty." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Automatické zálohování" @@ -5330,8 +5448,11 @@ msgstr "Přidání/Odebrání filamentů" msgid "Add/Remove materials" msgstr "Přidání/Odebrání materiálů" -msgid "Add/Remove printers" -msgstr "Přidat/Odebrat tiskárny" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Nekompatibilní" @@ -5514,17 +5635,17 @@ msgstr "Bambu Cool Podložka" msgid "PLA Plate" msgstr "PLA Podložka" -msgid "Bambu Engineering Plate" -msgstr "Bambu Engineering Podložka" +msgid "Bamabu Engineering Plate" +msgstr "Bamabu Engineering Podložka" -msgid "Bambu Smooth PEI Plate" -msgstr "Bambu Smooth PEI Podložka" +msgid "Bamabu Smooth PEI Plate" +msgstr "" msgid "High temperature Plate" msgstr "High temperature Podložka" -msgid "Bambu Textured PEI Plate" -msgstr "Bambu Textured PEI Podložka" +msgid "Bamabu Textured PEI Plate" +msgstr "" msgid "Send print job to" msgstr "Odeslat tiskovou úlohu na" @@ -5547,9 +5668,6 @@ msgstr "odeslat dokončeno" msgid "Error code" msgstr "Chybový kód" -msgid "Check the status of current system services" -msgstr "Zkontrolujte stav aktuálních systémových služeb" - msgid "Printer local connection failed, please try again." msgstr "Lokální připojení k tiskárně selhalo, zkuste to znovu." @@ -5656,10 +5774,8 @@ msgstr "" "časosběrná videa." msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" -"Při tisku podle objektu stroje s I3 strukturou nevytvoří časosběrná videa." msgid "Errors" msgstr "Chyby" @@ -5675,10 +5791,6 @@ msgstr "" "Vybraný typ tiskárny při generování G-kódu není shodný s aktuálně vybranou " "tiskárnou. Doporučuje se použít stejný typ tiskárny pro slicování." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s není systémem AMS podporován." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5688,11 +5800,34 @@ msgstr "" "to požadované filamenty. Pokud jsou v pořádku, stiskněte \"Potvrdit\" pro " "zahájení tisku." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Pokud stále chcete pokračovat v tisku, klikněte prosím na tlačítko Potvrdit." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "Připojování k tiskárně. Nelze zrušit během procesu připojování." @@ -5877,6 +6012,9 @@ msgstr "" "Pro hladký časosběr je vyžadována čistící věž. Na model bez hlavní věže. " "Chcete aktivovat čistící věž?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5919,8 +6057,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "Při nahrávání časosběru bez nástrojové hlavy se doporučuje přidat " "\"Timelapse Wipe Tower\" \n" @@ -6193,6 +6331,9 @@ msgstr "Stroj start G-kód" msgid "Machine end G-code" msgstr "Stroj end G-kód" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "G-kód Před změnou vrstvy" @@ -6262,6 +6403,26 @@ msgstr "Firmware Retrakce" msgid "Detached" msgstr "Odpojeno" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Přednastavení" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "Následující předvolba bude také smazána." @@ -6272,11 +6433,6 @@ msgstr[2] "" msgid "Are you sure to %1% the selected preset?" msgstr "Opravdu chcete %1% vybrané předvolby?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Přednastavení" - msgid "All" msgstr "Všechny" @@ -6526,11 +6682,17 @@ msgstr "Rozestup linek při rapidní extruzi" msgid "Auto-Calc" msgstr "Automatický výpočet" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Čistící objemy pro výměnu filamentu" -msgid "Multiplier" -msgstr "Multiplikátor" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Čistící objem (mm³) pro každý pár filamentů." @@ -6543,6 +6705,9 @@ msgstr "Návrh: Objem čištění v rozsahu [%d, %d]" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "Násobitel by měl být v rozsahu [%.2f, %.2f]." +msgid "Multiplier" +msgstr "Multiplikátor" + msgid "unloaded" msgstr "vyjmuto" @@ -6558,6 +6723,12 @@ msgstr "Z" msgid "To" msgstr "Do" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Přihlášení" @@ -6591,6 +6762,9 @@ msgstr "Vložit ze schránky" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "Zobrazit / skrýt dialogové okno nastavení zařízení 3Dconnexion" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Zobrazit přehled klávesových zkratek" @@ -6842,12 +7016,15 @@ msgstr "Nový síťový plug-in (%s) k dispozici, chcete jej nainstalovat?" msgid "New version of Orca Slicer" msgstr "Nová verze Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "Tuto verzi mi znovu nepřipomínat" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Hotovo" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "Připojení k síti LAN se nezdařilo (odesílání tiskového souboru)" @@ -6872,8 +7049,22 @@ msgstr "Přístupový kód" msgid "Where to find your printer's IP and Access Code?" msgstr "Kde najít IP a přístupový kód vaší tiskárny?" -msgid "Error: IP or Access Code are not correct" -msgstr "Cchyb: IP nebo přístupový kód nejsou správné" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "Test" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Model:" @@ -7338,6 +7529,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "Výška vrstvy nemůže překročit průměr trysky" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7808,10 +8004,29 @@ msgstr "Obrácení převisu" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" -"Extrudovat perimetry, které mají část přes převis ve směru opačném na " -"lichých vrstvách. Toto střídání může výrazně zlepšit strmý převis." msgid "Reverse threshold" msgstr "Hranice obrácení" @@ -8060,6 +8275,14 @@ msgstr "Konec G-kódu" msgid "End G-code when finish the whole printing" msgstr "Konec G-kód po dokončení celého tisku" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "Konec G-kód po dokončení tisku tohoto filamentu" @@ -8156,26 +8379,26 @@ msgstr "" "Toto nastavuje hraniční hodnotu pro malou délku obvodu. Výchozí hranice je 0 " "mm" -msgid "Order of inner wall/outer wall/infil" -msgstr "Pořadí vnitřní stěny/vnější stěny/výplně" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "Tisková sekvence vnitřní stěny, vnější stěny a výplně. " +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "vnitřní/vnější/výplň" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "vnější/vnitřní/výplň" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "výplň/vnitřní/vnější" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "výplň/vnější/vnitřní" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "vnitřní-vnější-vnitřní/výplň" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Výška k Ose X" @@ -8278,9 +8501,6 @@ msgstr "Výchozí barva" msgid "Default filament color" msgstr "Výchozí barva filamentu" -msgid "Color" -msgstr "Barva" - msgid "Filament notes" msgstr "Poznámky k filamentu" @@ -8327,8 +8547,8 @@ msgid "" "Filament diameter is used to calculate extrusion in gcode, so it's important " "and should be accurate" msgstr "" -"Průměr filamentu se používá k výpočtu extruze v gkódu, takže je důležitý " -"a měl by být přesný" +"Průměr filamentu se používá k výpočtu extruze v gkódu, takže je důležitý a " +"měl by být přesný" msgid "Shrinkage" msgstr "Smrštění" @@ -8715,10 +8935,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "Klipper max_accel_to_decel bude upraven na toto %% o zrychlení" -#, c-format, boost-format -msgid "%%" -msgstr "%%" - msgid "Jerk of outer walls" msgstr "Jerk-Ryv na vnější stěny" @@ -8790,10 +9006,10 @@ msgstr "Maximální otáčky ventilátoru ve vrstvě" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" "Otáčky ventilátoru se lineárně zvýší z nuly ve vrstvě " "\"close_fan_first_layers\" na maximum ve vrstvě \"full_fan_speed_layer\". " @@ -9123,6 +9339,18 @@ msgstr "" "Užitečné pro tisk s více extrudery s průsvitnými materiály nebo ručně " "rozpustným podpůrným materiálem" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Způsob žehlení" @@ -9159,8 +9387,8 @@ msgid "" "layer height. Too high value results in overextrusion on the surface" msgstr "" "Množství materiálu, které se má vytlačit během žehlení. V poměru k průtoku " -"normální výšky vrstvy. Příliš vysoká hodnota vede k nadměrné extruzi " -"na povrchu" +"normální výšky vrstvy. Příliš vysoká hodnota vede k nadměrné extruzi na " +"povrchu" msgid "Ironing line spacing" msgstr "Řádkování žehlení" @@ -9365,22 +9593,23 @@ msgstr "" "tiskárna přechází z extruze s vysokým průtokem (vysoká rychlost/větší šířka) " "na extruzi s nižším průtokem (nižší rychlost/menší šířka) a naopak.\n" "\n" -"Definuje maximální rychlost, kterou může objemový průtok extrudovaného materiálu " -"v mm3/s měnit v čase. Vyšší hodnoty znamenají, že jsou povoleny větší změny " -"extruzní rychlosti, což vede k rychlejším přechodům rychlosti.\n" +"Definuje maximální rychlost, kterou může objemový průtok extrudovaného " +"materiálu v mm3/s měnit v čase. Vyšší hodnoty znamenají, že jsou povoleny " +"větší změny extruzní rychlosti, což vede k rychlejším přechodům rychlosti.\n" "\n" "Hodnota 0 funkci zakáže. \n" "\n" -"Pro tiskárny s přímým pohonem a vysokou rychlostí a průtokem (např. Bambu lab " -"nebo Voron) tato hodnota obvykle není potřebná. Nicméně v některých případech, " -"kde se rychlosti funkcí výrazně liší, může poskytnout marginální přínos. " -"Například při agresivních zpomaleních způsobených přesahy. V těchto případech " -"se doporučuje vysoká hodnota kolem 300-350 mm3/s2, protože to umožňuje dostatečné " -"vyhlazení pro pomoc při dosažení plynulejšího přechodu tlaku při extruzi.\n" +"Pro tiskárny s přímým pohonem a vysokou rychlostí a průtokem (např. Bambu " +"lab nebo Voron) tato hodnota obvykle není potřebná. Nicméně v některých " +"případech, kde se rychlosti funkcí výrazně liší, může poskytnout marginální " +"přínos. Například při agresivních zpomaleních způsobených přesahy. V těchto " +"případech se doporučuje vysoká hodnota kolem 300-350 mm3/s2, protože to " +"umožňuje dostatečné vyhlazení pro pomoc při dosažení plynulejšího přechodu " +"tlaku při extruzi.\n" "\n" "Pro pomalejší tiskárny bez tlakového předstihu by měla být hodnota nastavena " -"mnohem nižší. Pro přímé pohony je hodnota 10-15 mm3/s2 dobrým výchozím bodem, " -"a pro styl Bowden 5-10 mm3/s2. \n" +"mnohem nižší. Pro přímé pohony je hodnota 10-15 mm3/s2 dobrým výchozím " +"bodem, a pro styl Bowden 5-10 mm3/s2. \n" "\n" "Tato funkce je známa jako Pressure Equalizer v programu Prusa Slicer.\n" "\n" @@ -9722,6 +9951,26 @@ msgstr "" "mezera mezi tryskou a tiskem. Zabraňuje tomu, aby tryska zasáhla tisk při " "pohybu. Použití spirálové linky ke zvednutí z může zabránit stringování" +msgid "Z hop lower boundary" +msgstr "Dolní mez Z hop" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" +"Zvýšení Z bude mít vliv na Z hop pouze tehdy, pokud je hodnota Z nad touto " +"mezí a zároveň podle parametru: \"Horní mez Z hop\"" + +msgid "Z hop upper boundary" +msgstr "Horní mez Z hop" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" +"Pokud je tato hodnota kladná, Z hop bude mít vliv pouze tehdy, pokud je " +"hodnota Z nad dolní mezí Z hop a zároveň pod touto hodnotou" + msgid "Z hop type" msgstr "Typ Z hop" @@ -9870,9 +10119,9 @@ msgid "" "if a wipe action is executed immediately following an outer wall extrusion, " "the speed of the outer wall extrusion will be utilized for the wipe action." msgstr "" -"Rychlost čištění je určena rychlostí aktuální role extruze, např. pokud " -"je činnost čištění provedena bezprostředně po extruzi vnější stěny, " -"rychlost extruze vnější stěny bude využita pro činnost čištění." +"Rychlost čištění je určena rychlostí aktuální role extruze, např. pokud je " +"činnost čištění provedena bezprostředně po extruzi vnější stěny, rychlost " +"extruze vnější stěny bude využita pro činnost čištění." msgid "Wipe on loops" msgstr "Čistit na smyčce" @@ -9881,8 +10130,8 @@ msgid "" "To minimize the visibility of the seam in a closed loop extrusion, a small " "inward movement is executed before the extruder leaves the loop." msgstr "" -"Aby byla minimalizována viditelnost švu při extruzi s uzavřenou smyčkou, " -"je proveden malý pohyb dovnitř předtím, než vytlačovací stroj opustí smyčku." +"Aby byla minimalizována viditelnost švu při extruzi s uzavřenou smyčkou, je " +"proveden malý pohyb dovnitř předtím, než vytlačovací stroj opustí smyčku." msgid "Wipe speed" msgstr "Rychlost čištění" @@ -10178,7 +10427,13 @@ msgstr "" "Filament pro tiskové podpěry základen a raftu. \"Výchozí\" znamená, že pro " "podpěry není použit žádný konkrétní filament a je použit aktuální filament" -msgid "" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." msgstr "" @@ -10214,6 +10469,12 @@ msgstr "Počet nejvyšších vrstev" msgid "Bottom interface layers" msgstr "Spodní kontaktní vrstvy" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Horní rozestup" @@ -10560,9 +10821,9 @@ msgid "" "Move nozzle along the last extrusion path when retracting to clean leaked " "material on nozzle. This can minimize blob when print new part after travel" msgstr "" -"Při retrakci přesuňte trysku podél poslední dráhy extruze, abyste " -"vyčistili uniklý materiál na trysce. To může minimalizovat skvrny při tisku " -"nového dílu po cestě" +"Při retrakci přesuňte trysku podél poslední dráhy extruze, abyste vyčistili " +"uniklý materiál na trysce. To může minimalizovat skvrny při tisku nového " +"dílu po cestě" msgid "Wipe Distance" msgstr "Vzdálenost čištění" @@ -10777,10 +11038,10 @@ msgid "" "Wipe tower is only compatible with relative mode. It is always enabled on " "BambuLab printers. Default is checked" msgstr "" -"Při použití volby \"label_objects\" se doporučuje relativní extruzi. " -"Některé extrudery fungují lépe, když je tato možnost odškrtnuta (režim " -"absolutní extruze). Čistící věž je kompatibilní pouze s relativním " -"režimem. Na tiskárnách BambuLab je vždy povolen. Výchozí je zaškrtnuto" +"Při použití volby \"label_objects\" se doporučuje relativní extruzi. Některé " +"extrudery fungují lépe, když je tato možnost odškrtnuta (režim absolutní " +"extruze). Čistící věž je kompatibilní pouze s relativním režimem. Na " +"tiskárnách BambuLab je vždy povolen. Výchozí je zaškrtnuto" msgid "" "Classic wall generator produces walls with constant extrusion width and for " @@ -10922,69 +11183,12 @@ msgstr "příliš velká šířka extruze " msgid " not in range " msgstr " není v dosahu " -msgid "Export 3MF" -msgstr "Exportovat 3MF" - -msgid "Export project as 3MF." -msgstr "Exportovat projekt jako 3MF." - -msgid "Export slicing data" -msgstr "Exportovat data Slicování" - -msgid "Export slicing data to a folder." -msgstr "Exportovat data Slicování do složky." - -msgid "Load slicing data" -msgstr "Načíst data Slicování" - -msgid "Load cached slicing data from directory" -msgstr "Načíst data dělení z mezipaměti z adresáře" - -msgid "Export STL" -msgstr "Exportovat STL" - -msgid "Export the objects as multiple STL." -msgstr "Exportovat objekty jako více STL souborů." - -msgid "Slice" -msgstr "Slicovat" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "Slicovat podložky: 0-všechny podložky, i- podložku i, ostatní-neplatné" - -msgid "Show command help." -msgstr "Zobrazit nápovědu k příkazu." - -msgid "UpToDate" -msgstr "Aktualizováno" - -msgid "Update the configs values of 3mf to latest." -msgstr "Aktualizujte konfigurační hodnoty 3mf na nejnovější." - -msgid "Load default filaments" -msgstr "Načíst výchozí filamenty" - -msgid "Load first filament as default for those not loaded" -msgstr "Načíst první filament jako výchozí pro ty, které nebyly načteny" - msgid "Minimum save" msgstr "Uložit minimum" msgid "export 3mf with minimum size." msgstr "exportovat 3mf s minimální velikostí." -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "max počet trojúhelníků na podložku pro slicování." - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "max čas slicování na podložku v sekundách." - msgid "No check" msgstr "Žádná kontrola" @@ -10992,42 +11196,6 @@ msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "" "Neprovádět žádné kontrolní testy, například kontrolu konfliktů cesty g-kódu." -msgid "Normative check" -msgstr "Normativní kontrola" - -msgid "Check the normative items." -msgstr "Kontrola normativních prvků." - -msgid "Output Model Info" -msgstr "Info o výstupním modelu" - -msgid "Output the model's information." -msgstr "Vytisknout informace o modelu." - -msgid "Export Settings" -msgstr "Nastavení exportu" - -msgid "Export settings to a file." -msgstr "Exportovat nastavení do souboru." - -msgid "Send progress to pipe" -msgstr "Poslat průběh do roury" - -msgid "Send progress to pipe." -msgstr "Poslat průběh do roury." - -msgid "Arrange Options" -msgstr "Volby uspořádání" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Volby uspořádání: 0-zakázat, 1-povolit, ostatní-automaticky" - -msgid "Repetions count" -msgstr "Počet opakování" - -msgid "Repetions count of the whole model" -msgstr "Počet opakování celého modelu" - msgid "Ensure on bed" msgstr "Zajistit na podložce" @@ -11037,12 +11205,6 @@ msgstr "" "Zvedněte objekt nad podložku, když je částečně pod ní. Výchozí stav je " "vypnutý" -msgid "Convert Unit" -msgstr "Převést jednotku" - -msgid "Convert the units of model" -msgstr "Převést jednotky modelu" - msgid "Orient Options" msgstr "Orientační možnosti" @@ -11052,49 +11214,12 @@ msgstr "Orientační možnosti: 0-vypnuto, 1-zapnuto, ostatní-auto" msgid "Rotation angle around the Z axis in degrees." msgstr "Úhel rotace kolem osy Z v stupních." -msgid "Rotate around X" -msgstr "Rotace kolem osy X" - -msgid "Rotation angle around the X axis in degrees." -msgstr "Úhel rotace kolem osy X v stupních." - msgid "Rotate around Y" msgstr "Rotace kolem osy Y" msgid "Rotation angle around the Y axis in degrees." msgstr "Úhel rotace kolem osy Y v stupních." -msgid "Scale the model by a float factor" -msgstr "Měřítko modelu pomocí plovoucího faktoru" - -msgid "Load General Settings" -msgstr "Načíst obecná nastavení" - -msgid "Load process/machine settings from the specified file" -msgstr "Načíst nastavení procesu/stroje ze zadaného souboru" - -msgid "Load Filament Settings" -msgstr "Načíst nastavení filamentu" - -msgid "Load filament settings from the specified file list" -msgstr "Načíst nastavení filamentu ze zadaného seznamu souborů" - -msgid "Skip Objects" -msgstr "Přeskočit objekty" - -msgid "Skip some objects in this print" -msgstr "Přeskočit některé objekty při tisku" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "Načítat aktuální nastavení procesu/stroje při použití aktuálního" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" -"Načítat aktuální nastavení procesu/stroje ze zadaného souboru při použití " -"aktuálního" - msgid "Data directory" msgstr "Složka Data" @@ -11106,22 +11231,6 @@ msgstr "" "Načtěte a uložte nastavení z/do daného adresáře. To je užitečné pro " "udržování různých profilů nebo konfigurací ze síťového úložiště." -msgid "Output directory" -msgstr "Výstupní adresář" - -msgid "Output directory for the exported files." -msgstr "Výstupní adresář pro exportované soubory." - -msgid "Debug level" -msgstr "Úroveň ladění" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Nastaví úroveň protokolování ladění. 0:fatal, 1:error, 2:warning, 3:info, 4:" -"debug, 5:sledovat\n" - msgid "Load custom gcode" msgstr "Načíst vlastní G-kód" @@ -11286,9 +11395,6 @@ msgstr "Kalibrovat" msgid "Finish" msgstr "Dokončit" -msgid "Wiki" -msgstr "Wiki" - msgid "How to use calibration result?" msgstr "Jak použít výsledek kalibrace?" @@ -11306,6 +11412,12 @@ msgstr "" msgid "Calibration not supported" msgstr "Kalibrace není podporována" +msgid "Error desc" +msgstr "Popis chyby" + +msgid "Extra info" +msgstr "Další informace" + msgid "Flow Dynamics" msgstr "Dynamika Průtoku" @@ -11338,9 +11450,9 @@ msgstr "" msgid "The name cannot be empty." msgstr "Název nemůže být prázdný." -#, boost-format -msgid "The selected preset: %1% is not found." -msgstr "Vybraná předvolba: %1% nebyla nalezena." +#, c-format, boost-format +msgid "The selected preset: %s is not found." +msgstr "" msgid "The name cannot be the same as the system preset name." msgstr "Název nemůže být stejný jako název systémové předvolby." @@ -11696,12 +11808,6 @@ msgstr "" "- Různá značka a skupina filamentu (Značka = Bambu, Skupina = Základní, " "Matný)" -msgid "Error desc" -msgstr "Popis chyby" - -msgid "Extra info" -msgstr "Další informace" - msgid "Pattern" msgstr "Vzor" @@ -11792,101 +11898,6 @@ msgstr "" "Překlad doménového jména %1% na IP adresu je nejednoznačný.\n" "Vyberte prosím tu, která má být použita." -msgid "Unable to perform boolean operation on selected parts" -msgstr "Nelze provést booleovskou operaci na vybraných částech" - -msgid "Mesh Boolean" -msgstr "Booleovská síť" - -msgid "Union" -msgstr "Sjednocení" - -msgid "Difference" -msgstr "Rozdíl" - -msgid "Intersection" -msgstr "Průsečík" - -msgid "Source Volume" -msgstr "Zdrojový objem" - -msgid "Tool Volume" -msgstr "Objem nástroje" - -msgid "Subtract from" -msgstr "Odečíst od" - -msgid "Subtract with" -msgstr "Odečíst s" - -msgid "selected" -msgstr "vybráno" - -msgid "Part 1" -msgstr "Část 1" - -msgid "Part 2" -msgstr "Část 2" - -msgid "Delete input" -msgstr "Smazat vstup" - -msgid "Send G-Code to printer host" -msgstr "Odeslat G-Kód do tiskového serveru" - -msgid "Upload to Printer Host with the following filename:" -msgstr "Nahrát do tiskového serveru s následujícím názvem souboru:" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "Pokud je to nutné, použijte pro oddělení složek lomítko (/)." - -msgid "Upload to storage" -msgstr "Nahrát do úložiště" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "Název nahrávaného souboru neskončí s \"%s\". Přejete si pokračovat?" - -msgid "Upload" -msgstr "Nahrát" - -msgid "Print host upload queue" -msgstr "Fronta nahrávání tiskového serveru" - -msgid "ID" -msgstr "ID" - -msgid "Progress" -msgstr "Postup" - -msgid "Host" -msgstr "Hostitel" - -msgctxt "OfFile" -msgid "Size" -msgstr "Velikost" - -msgid "Filename" -msgstr "Název souboru" - -msgid "Cancel selected" -msgstr "Zrušit vybrané" - -msgid "Show error message" -msgstr "Zobrazit chybové hlášení" - -msgid "Enqueued" -msgstr "Ve frontě" - -msgid "Uploading" -msgstr "Nahrávání" - -msgid "Cancelling" -msgstr "Ruší se" - -msgid "Error uploading to print host" -msgstr "Chyba při nahrávání do tiskového serveru" - msgid "PA Calibration" msgstr "PA Kalibrace" @@ -12027,79 +12038,107 @@ msgstr "Délka retrakce na konci: " msgid "mm/mm" msgstr "mm/mm" -msgid "Physical Printer" -msgstr "Fyzická tiskárna" +msgid "Send G-Code to printer host" +msgstr "Odeslat G-Kód do tiskového serveru" -msgid "Print Host upload" -msgstr "Nahrávání do tiskového serveru" +msgid "Upload to Printer Host with the following filename:" +msgstr "Nahrát do tiskového serveru s následujícím názvem souboru:" -msgid "Test" -msgstr "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "Pokud je to nutné, použijte pro oddělení složek lomítko (/)." -msgid "Could not get a valid Printer Host reference" -msgstr "Nelze získat platný odkaz na tiskový server" +msgid "Upload to storage" +msgstr "Nahrát do úložiště" -msgid "Success!" -msgstr "Úspěch!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "Název nahrávaného souboru neskončí s \"%s\". Přejete si pokračovat?" -msgid "Refresh Printers" -msgstr "Obnovit tiskárny" +msgid "Upload" +msgstr "Nahrát" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." -msgstr "" -"Soubor HTTPS CA je volitelný. Je nutný pouze pokud použijte HTTPS certifikát " -"s vlastním podpisem." +msgid "Print host upload queue" +msgstr "Fronta nahrávání tiskového serveru" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "Soubory s certifikátem (*.crt, *.pem)|*.crt;*.pem|Všechny soubory|*.*" +msgid "ID" +msgstr "ID" -msgid "Open CA certificate file" -msgstr "Otevřít soubor s certifikátem CA" +msgid "Progress" +msgstr "Postup" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." -msgstr "" -"V tomto systému používá %s certifikáty HTTPS ze systému Certificate Store " -"nebo Keychain." +msgid "Host" +msgstr "Hostitel" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." -msgstr "" -"Chcete-li použít vlastní soubor CA, importujte soubor CA do Certificate " -"Store / Keychain." +msgctxt "OfFile" +msgid "Size" +msgstr "Velikost" -msgid "Connection to printers connected via the print host failed." -msgstr "" -"Připojení k tiskárnám připojených prostřednictvím tiskového serveru se " -"nezdařilo." +msgid "Filename" +msgstr "Název souboru" -msgid "The start, end or step is not valid value." -msgstr "Počáteční, koncová nebo kroková hodnota není platná." +msgid "Cancel selected" +msgstr "Zrušit vybrané" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" -msgstr "" -"Nelze provést kalibraci: možná je rozsah kalibračních hodnot nastaven příliš " -"velký nebo krok je příliš malý" +msgid "Show error message" +msgstr "Zobrazit chybové hlášení" + +msgid "Enqueued" +msgstr "Ve frontě" + +msgid "Uploading" +msgstr "Nahrávání" + +msgid "Cancelling" +msgstr "Ruší se" + +msgid "Error uploading to print host" +msgstr "Chyba při nahrávání do tiskového serveru" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "Nelze provést booleovskou operaci na vybraných částech" + +msgid "Mesh Boolean" +msgstr "Booleovská síť" + +msgid "Union" +msgstr "Sjednocení" + +msgid "Difference" +msgstr "Rozdíl" + +msgid "Intersection" +msgstr "Průsečík" + +msgid "Source Volume" +msgstr "Zdrojový objem" -msgid "Need select printer" -msgstr "Je nutné vybrat tiskárnu" +msgid "Tool Volume" +msgstr "Objem nástroje" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "Subtract from" +msgstr "Odečíst od" + +msgid "Subtract with" +msgstr "Odečíst s" + +msgid "selected" +msgstr "vybráno" + +msgid "Part 1" +msgstr "Část 1" + +msgid "Part 2" +msgstr "Část 2" + +msgid "Delete input" +msgstr "Smazat vstup" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"Operace v 3D scéně\n" -"Věděli jste, že můžete ovládat zobrazení a výběr objektů nebo částí pomocí " -"myši a dotykového panelu v 3D scéně?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -12115,11 +12154,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Opravit model\n" -"Věděli jste, že můžete opravit poškozený 3D model a vyhnout se tak mnoha " -"problémům při slicování?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -12157,8 +12193,8 @@ msgid "" msgstr "" "Plochou na podložku\n" "Věděli jste, že můžete rychle nastavit orientaci modelu tak, aby jedna z " -"jeho stěn spočívala na tiskovém podloží? Vyberte funkci \"Plochou na podložku" -"\" nebo stiskněte klávesu F." +"jeho stěn spočívala na tiskovém podloží? Vyberte funkci \"Plochou na " +"podložku\" nebo stiskněte klávesu F." #: resources/data/hints.ini: [hint:Object List] msgid "" @@ -12170,6 +12206,13 @@ msgstr "" "Věděli jste, že si můžete zobrazit všechny objekty/části v seznamu a upravit " "nastavení pro každý objekt/část zvlášť?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -12364,14 +12407,376 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." msgstr "" -"Kdy potřebujete tisknout s otevřenými dveřmi tiskárny\n" -"Otevření dveří tiskárny může snížit pravděpodobnost ucpaní extruderu/hotendu " -"při tisku filamentu s nižší teplotou a vyšší teplotě uzavřeného prostoru. " -"Další informace naleznete ve Wiki." + +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Nástroj-Plochou na podložku" + +#~ msgid "Export as STL" +#~ msgstr "Exportovat jako STL" + +#~ msgid "Check cloud service status" +#~ msgstr "Zkontrolujte stav cloudové služby" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Zadejte prosím platnou hodnotu (K v 0~0,5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "Zadejte platnou hodnotu (K v 0~0,5, N v 0,6~2,0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Exportovat všechny objekty jako STL" + +#~ msgid "Slice ok." +#~ msgstr "Slicování Dokončeno." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "Verze 3mf %s je novější než verze %s %s, byly nalezeny následující klíče " +#~ "nerozpoznaný:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Měli byste aktualizovat software.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "Verze %s zařízení 3mf je novější než verze %s %s, navrhněte upgrade " +#~ "vašeho software." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "3mf není kompatibilní, načtěte pouze geometrická data!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Nekompatibilní 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "Přidat/Odebrat tiskárny" + +#~ msgid "Bambu Engineering Plate" +#~ msgstr "Bambu Engineering Podložka" + +#~ msgid "Bambu Smooth PEI Plate" +#~ msgstr "Bambu Smooth PEI Podložka" + +#~ msgid "Bambu Textured PEI Plate" +#~ msgstr "Bambu Textured PEI Podložka" + +#~ msgid "" +#~ "When print by object, machines with I3 structure will not generate " +#~ "timelapse videos." +#~ msgstr "" +#~ "Při tisku podle objektu stroje s I3 strukturou nevytvoří časosběrná videa." + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s není systémem AMS podporován." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Tuto verzi mi znovu nepřipomínat" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Cchyb: IP nebo přístupový kód nejsou správné" + +#~ msgid "" +#~ "Extrude perimeters that have a part over an overhang in the reverse " +#~ "direction on odd layers. This alternating pattern can drastically improve " +#~ "steep overhang." +#~ msgstr "" +#~ "Extrudovat perimetry, které mají část přes převis ve směru opačném na " +#~ "lichých vrstvách. Toto střídání může výrazně zlepšit strmý převis." + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Pořadí vnitřní stěny/vnější stěny/výplně" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "Tisková sekvence vnitřní stěny, vnější stěny a výplně. " + +#~ msgid "inner/outer/infill" +#~ msgstr "vnitřní/vnější/výplň" + +#~ msgid "outer/inner/infill" +#~ msgstr "vnější/vnitřní/výplň" + +#~ msgid "infill/inner/outer" +#~ msgstr "výplň/vnitřní/vnější" + +#~ msgid "infill/outer/inner" +#~ msgstr "výplň/vnější/vnitřní" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "vnitřní-vnější-vnitřní/výplň" + +#, c-format, boost-format +#~ msgid "%%" +#~ msgstr "%%" + +#~ msgid "Export 3MF" +#~ msgstr "Exportovat 3MF" + +#~ msgid "Export project as 3MF." +#~ msgstr "Exportovat projekt jako 3MF." + +#~ msgid "Export slicing data" +#~ msgstr "Exportovat data Slicování" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Exportovat data Slicování do složky." + +#~ msgid "Load slicing data" +#~ msgstr "Načíst data Slicování" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Načíst data dělení z mezipaměti z adresáře" + +#~ msgid "Export STL" +#~ msgstr "Exportovat STL" + +#~ msgid "Export the objects as multiple STL." +#~ msgstr "Exportovat objekty jako více STL souborů." + +#~ msgid "Slice" +#~ msgstr "Slicovat" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "" +#~ "Slicovat podložky: 0-všechny podložky, i- podložku i, ostatní-neplatné" + +#~ msgid "Show command help." +#~ msgstr "Zobrazit nápovědu k příkazu." + +#~ msgid "UpToDate" +#~ msgstr "Aktualizováno" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Aktualizujte konfigurační hodnoty 3mf na nejnovější." + +#~ msgid "Load default filaments" +#~ msgstr "Načíst výchozí filamenty" + +#~ msgid "Load first filament as default for those not loaded" +#~ msgstr "Načíst první filament jako výchozí pro ty, které nebyly načteny" + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "max počet trojúhelníků na podložku pro slicování." + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "max čas slicování na podložku v sekundách." + +#~ msgid "Normative check" +#~ msgstr "Normativní kontrola" + +#~ msgid "Check the normative items." +#~ msgstr "Kontrola normativních prvků." + +#~ msgid "Output Model Info" +#~ msgstr "Info o výstupním modelu" + +#~ msgid "Output the model's information." +#~ msgstr "Vytisknout informace o modelu." + +#~ msgid "Export Settings" +#~ msgstr "Nastavení exportu" + +#~ msgid "Export settings to a file." +#~ msgstr "Exportovat nastavení do souboru." + +#~ msgid "Send progress to pipe" +#~ msgstr "Poslat průběh do roury" + +#~ msgid "Send progress to pipe." +#~ msgstr "Poslat průběh do roury." + +#~ msgid "Arrange Options" +#~ msgstr "Volby uspořádání" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Volby uspořádání: 0-zakázat, 1-povolit, ostatní-automaticky" + +#~ msgid "Repetions count" +#~ msgstr "Počet opakování" + +#~ msgid "Repetions count of the whole model" +#~ msgstr "Počet opakování celého modelu" + +#~ msgid "Convert Unit" +#~ msgstr "Převést jednotku" + +#~ msgid "Convert the units of model" +#~ msgstr "Převést jednotky modelu" + +#~ msgid "Rotate around X" +#~ msgstr "Rotace kolem osy X" + +#~ msgid "Rotation angle around the X axis in degrees." +#~ msgstr "Úhel rotace kolem osy X v stupních." + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Měřítko modelu pomocí plovoucího faktoru" + +#~ msgid "Load General Settings" +#~ msgstr "Načíst obecná nastavení" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Načíst nastavení procesu/stroje ze zadaného souboru" + +#~ msgid "Load Filament Settings" +#~ msgstr "Načíst nastavení filamentu" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "Načíst nastavení filamentu ze zadaného seznamu souborů" + +#~ msgid "Skip Objects" +#~ msgstr "Přeskočit objekty" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Přeskočit některé objekty při tisku" + +#~ msgid "load uptodate process/machine settings when using uptodate" +#~ msgstr "Načítat aktuální nastavení procesu/stroje při použití aktuálního" + +#~ msgid "" +#~ "load uptodate process/machine settings from the specified file when using " +#~ "uptodate" +#~ msgstr "" +#~ "Načítat aktuální nastavení procesu/stroje ze zadaného souboru při použití " +#~ "aktuálního" + +#~ msgid "Output directory" +#~ msgstr "Výstupní adresář" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Výstupní adresář pro exportované soubory." + +#~ msgid "Debug level" +#~ msgstr "Úroveň ladění" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Nastaví úroveň protokolování ladění. 0:fatal, 1:error, 2:warning, 3:info, " +#~ "4:debug, 5:sledovat\n" + +#, boost-format +#~ msgid "The selected preset: %1% is not found." +#~ msgstr "Vybraná předvolba: %1% nebyla nalezena." + +#~ msgid "Physical Printer" +#~ msgstr "Fyzická tiskárna" + +#~ msgid "Print Host upload" +#~ msgstr "Nahrávání do tiskového serveru" + +#~ msgid "Could not get a valid Printer Host reference" +#~ msgstr "Nelze získat platný odkaz na tiskový server" + +#~ msgid "Success!" +#~ msgstr "Úspěch!" + +#~ msgid "Refresh Printers" +#~ msgstr "Obnovit tiskárny" + +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "Soubor HTTPS CA je volitelný. Je nutný pouze pokud použijte HTTPS " +#~ "certifikát s vlastním podpisem." + +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "" +#~ "Soubory s certifikátem (*.crt, *.pem)|*.crt;*.pem|Všechny soubory|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "Otevřít soubor s certifikátem CA" + +#, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "" +#~ "V tomto systému používá %s certifikáty HTTPS ze systému Certificate Store " +#~ "nebo Keychain." + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "Chcete-li použít vlastní soubor CA, importujte soubor CA do Certificate " +#~ "Store / Keychain." + +#~ msgid "Connection to printers connected via the print host failed." +#~ msgstr "" +#~ "Připojení k tiskárnám připojených prostřednictvím tiskového serveru se " +#~ "nezdařilo." + +#~ msgid "The start, end or step is not valid value." +#~ msgstr "Počáteční, koncová nebo kroková hodnota není platná." + +#~ msgid "" +#~ "Unable to calibrate: maybe because the set calibration value range is too " +#~ "large, or the step is too small" +#~ msgstr "" +#~ "Nelze provést kalibraci: možná je rozsah kalibračních hodnot nastaven " +#~ "příliš velký nebo krok je příliš malý" + +#~ msgid "Need select printer" +#~ msgstr "Je nutné vybrat tiskárnu" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "Operace v 3D scéně\n" +#~ "Věděli jste, že můžete ovládat zobrazení a výběr objektů nebo částí " +#~ "pomocí myši a dotykového panelu v 3D scéně?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Opravit model\n" +#~ "Věděli jste, že můžete opravit poškozený 3D model a vyhnout se tak mnoha " +#~ "problémům při slicování?" + +#~ msgid "" +#~ "When need to print with the printer door opened\n" +#~ "Opening the printer door can reduce the probability of extruder/hotend " +#~ "clogging when printing lower temperature filament with a higher enclosure " +#~ "temperature. More info about this in the Wiki." +#~ msgstr "" +#~ "Kdy potřebujete tisknout s otevřenými dveřmi tiskárny\n" +#~ "Otevření dveří tiskárny může snížit pravděpodobnost ucpaní extruderu/" +#~ "hotendu při tisku filamentu s nižší teplotou a vyšší teplotě uzavřeného " +#~ "prostoru. Další informace naleznete ve Wiki." #~ msgid "Embeded" #~ msgstr "Vloženo" @@ -12389,26 +12794,6 @@ msgstr "" #~ msgid "Show online staff-picked models on the home page" #~ msgstr "Zobrazit online modely vybrané týmem na úvodní stránce" -#~ msgid "Z hop lower boundary" -#~ msgstr "Dolní mez Z hop" - -#~ msgid "" -#~ "Z hop will only come into effect when Z is above this value and is below " -#~ "the parameter: \"Z hop upper boundary\"" -#~ msgstr "" -#~ "Zvýšení Z bude mít vliv na Z hop pouze tehdy, pokud je hodnota Z nad " -#~ "touto mezí a zároveň podle parametru: \"Horní mez Z hop\"" - -#~ msgid "Z hop upper boundary" -#~ msgstr "Horní mez Z hop" - -#~ msgid "" -#~ "If this value is positive, Z hop will only come into effect when Z is " -#~ "above the parameter: \"Z hop lower boundary\" and is below this value" -#~ msgstr "" -#~ "Pokud je tato hodnota kladná, Z hop bude mít vliv pouze tehdy, pokud je " -#~ "hodnota Z nad dolní mezí Z hop a zároveň pod touto hodnotou" - #~ msgid "The minimum printing speed when slow down for cooling" #~ msgstr "Minimální rychlost tisku při zpomalení kvůli chlazení" @@ -12523,9 +12908,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Hodnocení" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bamabu Engineering Podložka" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu vysoká teplota Podlozky" diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index fd95f27a34b..d08ca4d82e0 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 11:25+0100\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: \n" "Last-Translator: Heiko Liebscher \n" "Language-Team: \n" @@ -102,6 +102,9 @@ msgstr "Kein automatischer Support" msgid "Support Generated" msgstr "Support generiert" +msgid "Gizmo-Place on Face" +msgstr "Gizmo auf Fläche platzieren" + msgid "Lay on face" msgstr "Auf Fläche legen" @@ -150,8 +153,8 @@ msgstr "Flächenfüllung" msgid "Height range" msgstr "Höhenbereich" -msgid "Ctrl + Shift + Enter" -msgstr "Strg + Umschalt + Eingabetaste" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Gittermodell ein-/ausblenden" @@ -181,9 +184,15 @@ msgstr "Gemalt mit: Filament %1%" msgid "Move" msgstr "Bewegen" +msgid "Gizmo-Move" +msgstr "Gizmo-Bewegen" + msgid "Rotate" msgstr "Drehen" +msgid "Gizmo-Rotate" +msgstr "Gizmo-Drehen" + msgid "Optimize orientation" msgstr "Optimiere Ausrichtung" @@ -193,12 +202,12 @@ msgstr "Anwenden" msgid "Scale" msgstr "Skalieren" +msgid "Gizmo-Scale" +msgstr "Gizmo-Skalieren" + msgid "Error: Please close all toolbar menus first" msgstr "Fehler: Bitte schließen sie zuerst alle Werkzeugleistenmenüs" -msgid "Tool-Lay on Face" -msgstr "Werkzeug-lege auf Fläche" - msgid "in" msgstr "in" @@ -494,6 +503,15 @@ msgstr "Naht aufmalen" msgid "Remove selection" msgstr "Auswahl entfernen" +msgid "Entering Seam painting" +msgstr "Beginne Naht aufmalen" + +msgid "Leaving Seam painting" +msgstr "Verlasse Naht aufmalen" + +msgid "Paint-on seam editing" +msgstr "Aufgemalte Naht bearbeiten" + msgid "Font" msgstr "Schiftart" @@ -718,6 +736,17 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Datenschutzrichtlinien-Update" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" +"Die Anzahl der im Cloud-Cache gespeicherten Benutzerprofile hat das Limit " +"überschritten. Neu erstellte Benutzerprofile können nur lokal verwendet " +"werden." + +msgid "Sync user presets" +msgstr "Benutzerprofile synchronisieren" + msgid "Loading" msgstr "Lade" @@ -912,8 +941,11 @@ msgstr "Druckbar" msgid "Fix model" msgstr "Modell reparieren" -msgid "Export as STL" -msgstr "Als STL exportieren" +msgid "Export as one STL" +msgstr "Exportieren als eine STL" + +msgid "Export as STLs" +msgstr "Exportieren als STLs" msgid "Reload from disk" msgstr "Von der Festplatte neu laden" @@ -1183,6 +1215,9 @@ msgid "Click the icon to shift this object to the bed" msgstr "" "Klicken Sie auf das Symbol, um dieses Objekt auf das Bett zu verschieben." +msgid " search results" +msgstr " Suchergebnisse" + msgid "Loading file" msgstr "Lade Datei" @@ -1444,6 +1479,18 @@ msgstr "Öffne nächsten Tip." msgid "Open Documentation in web browser." msgstr "Öffne Dokumentation im Webbrowser." +msgid "Color" +msgstr "Farbe" + +msgid "Pause" +msgstr "Pause" + +msgid "Template" +msgstr "Vorlage" + +msgid "Custom" +msgstr "Benutzerdefiniert" + msgid "Pause:" msgstr "Pause:" @@ -1523,8 +1570,8 @@ msgstr "..." msgid "Failed to connect to the server" msgstr "Verbindung zum Server fehlgeschlagen" -msgid "Check cloud service status" -msgstr "Status des Cloud-Dienstes prüfen" +msgid "Check the status of current system services" +msgstr "Überprüfen Sie den Status der aktuellen Systemdienste" msgid "code" msgstr "Code" @@ -1796,6 +1843,17 @@ msgstr "Druckauftrag über LAN senden" msgid "Sending print job through cloud service" msgstr "Druckauftrag über den Cloud-Dienst senden" +msgid "Print task sending times out." +msgstr "Zeitüberschreitung beim Senden des Druckauftrags." + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" +"Der Drucker hat beim Empfangen eines Druckauftrags eine Zeitüberschreitung " +"erhalten. Bitte überprüfen Sie, ob das Netzwerk ordnungsgemäß funktioniert, " +"und senden Sie den Druck erneut." + msgid "Service Unavailable" msgstr "Der Dienst ist nicht verfügbar" @@ -2025,13 +2083,11 @@ msgstr "Sind Sie sicher, dass Sie die Filamentinformationen löschen möchten?" msgid "You need to select the material type and color first." msgstr "Sie müssen zuerst den Materialtyp und die Farbe auswählen." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Bitte geben Sie einen gültigen Wert ein (K im Bereich von 0 bis 0,5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "Bitte geben Sie einen gültigen Wert ein (K in 0~0.3)" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "" -"Bitte geben Sie einen gültigen Wert ein (K im Bereich von 0 bis 0,5, N im " -"Bereich von 0,6 bis 2,0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "Bitte geben Sie einen gültigen Wert ein (K in 0~0.3, N in 0.6~2.0)" msgid "Other Color" msgstr "Andere Farbe" @@ -2434,9 +2490,6 @@ msgstr "Rechteckig" msgid "Circular" msgstr "Kreisförmig" -msgid "Custom" -msgstr "Benutzerdefiniert" - msgid "Load shape from STL..." msgstr "Lade Form von STL..." @@ -2959,6 +3012,9 @@ msgstr "Gereinigt" msgid "Total" msgstr "Gesamt" +msgid "Tower" +msgstr "Turm" + msgid "Total Estimation" msgstr "Gesamtschätzung" @@ -3046,15 +3102,18 @@ msgstr "Farbwechsel" msgid "Print" msgstr "aktuelle Platte drucken" -msgid "Pause" -msgstr "Pause" - msgid "Printer" msgstr "Drucker" msgid "Print settings" msgstr "Druckeinstellungen" +msgid "Custom g-code" +msgstr "Benutzerdefinierter G-Code" + +msgid "ToolChange" +msgstr "Werkzeugwechsel" + msgid "Time Estimation" msgstr "Geschätzte Zeit" @@ -3286,15 +3345,15 @@ msgstr "Durchfluss-Kalibrierung" msgid "Start Calibration" msgstr "Kalibrierung starten" -msgid "No step selected" -msgstr "Kein Schritt ausgewählt" - msgid "Completed" msgstr "Abgeschlossen" msgid "Calibrating" msgstr "Kalibrieren" +msgid "No step selected" +msgstr "Kein Schritt ausgewählt" + msgid "Auto-record Monitoring" msgstr "Überwachung automatisch aufzeichnen" @@ -3512,8 +3571,11 @@ msgstr "Konfigurationen laden" msgid "Import" msgstr "Importieren" -msgid "Export all objects as STL" -msgstr "Alle Objekte als STL exportieren" +msgid "Export all objects as one STL" +msgstr "Exportiere alle Objekte als eine STL" + +msgid "Export all objects as STLs" +msgstr "Exportiere alle Objekte als STLs" msgid "Export Generic 3MF" msgstr "Generisches 3MF exportieren" @@ -3802,9 +3864,6 @@ msgstr "" "Der Drucker ist mit dem Herunterladen beschäftigt; Bitte warten Sie, bis der " "Download beendet ist." -msgid "Loading..." -msgstr "Laden..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" "Initialisierung fehlgeschlagen (Nicht unterstützt auf der aktuellen " @@ -3869,6 +3928,9 @@ msgstr "Laufend..." msgid "Load failed [%d]!" msgstr "Laden fehlgeschlagen [%d]!" +msgid "Loading..." +msgstr "Laden..." + msgid "Year" msgstr "Jahr" @@ -3989,12 +4051,25 @@ msgstr "Herunterladen abgeschlossen" msgid "Downloading %d%%..." msgstr "%d%% wird heruntergeladen..." +msgid "Connection lost. Please retry." +msgstr "Verbindung verloren. Bitte versuchen Sie es erneut." + +msgid "File not exists." +msgstr "Datei existiert nicht." + +msgid "File checksum error. Please retry." +msgstr "Prüfsummenfehler. Bitte versuchen Sie es erneut." + msgid "Not supported on the current printer version." msgstr "Nicht unterstützt auf der aktuellen Druckerversion." msgid "Storage unavailable, insert SD card." msgstr "Speicher nicht verfügbar, MicroSD-Karte einlegen." +#, c-format, boost-format +msgid "Error code: %d" +msgstr "Fehlercode: %d" + msgid "Speed:" msgstr "Geschwindigkeit:" @@ -4348,6 +4423,12 @@ msgstr "Neues Netzwerk-Plugin verfügbar" msgid "Details" msgstr "Details" +msgid "New printer config available." +msgstr "Neue Druckerkonfiguration verfügbar." + +msgid "Wiki" +msgstr "Wiki" + msgid "Undo integration failed." msgstr "Die Integration konnte nicht rückgängig gemacht werden." @@ -4396,9 +4477,6 @@ msgstr "ERLEDIGT" msgid "Cancel upload" msgstr "Upload abbrechen" -msgid "Slice ok." -msgstr "Slice ok." - msgid "Jump to" msgstr "Wechsle zu" @@ -4505,6 +4583,9 @@ msgstr "Automatische Wiederherstellung bei Positionsverlust (Schrittverlust)" msgid "Allow Prompt Sound" msgstr "Erlaube akustische Signale" +msgid "Fliament Tangle Detect" +msgstr "Filamentverwicklung erkannt" + msgid "Global" msgstr "Allgemein" @@ -4599,6 +4680,9 @@ msgstr "Filamentliste von AMS synchronisieren" msgid "Set filaments to use" msgstr "Zu verwendende Filamente einstellen" +msgid "Search plate, object and part." +msgstr "Suche Platte, Objekt und Teil." + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4712,26 +4796,35 @@ msgstr "" "Geometriedaten." #, c-format, boost-format +msgid "This slicer file version %s is newer than %s's version:" +msgstr "Diese Slicer-Dateiversion %s ist neuer als die Version von %s:" + msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" msgstr "" -"Die Version %s von 3mf ist neuer als die Version %s von %s, folgende " -"Schlüssel wurden nicht erkannt:" - -msgid "You'd better upgrade your software.\n" -msgstr "Sie sollten Ihre Software aktualisieren.\n" +"Möchten Sie Ihre Software aktualisieren, um alle Funktionen in dieser Slicer-" +"Datei zu aktivieren?\n" msgid "Newer 3mf version" msgstr "Neuere 3mf-Version" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"Die Version %s der 3mf ist neuer als die Version %s %s. Bitte Ihre Software " -"aktualisieren." +"Diese Slicer-Dateiversion %s ist neuer als die Version von %s.\n" +"\n" +"Möchten Sie Ihre Software aktualisieren, um alle Funktionen in dieser Slicer-" +"Datei zu aktivieren?" msgid "Invalid values found in the 3mf:" msgstr "Ungültige Werte in der 3MF-Datei gefunden:" @@ -4739,11 +4832,32 @@ msgstr "Ungültige Werte in der 3MF-Datei gefunden:" msgid "Please correct them in the param tabs" msgstr "Bitte korrigieren Sie sie in den Parameter-Einstellungen." -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "Der 3mf ist nicht kompatibel, lade nur die Geometriedaten!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" +"Die 3mf hat folgende modifizierte G-Codes in Filament- oder Druckerprofilen:" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" +"Bitte bestätigen Sie, dass diese modifizierten G-Codes sicher sind, um " +"Schäden an der Maschine zu vermeiden!" + +msgid "Modified G-codes" +msgstr "Modifizierte G-Codes" -msgid "Incompatible 3mf" -msgstr "Inkompatible 3mf" +msgid "The 3mf has following customized filament or printer presets:" +msgstr "Die 3mf hat folgende benutzerdefinierte Filament- oder Druckerprofile:" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" +"Bitte bestätigen Sie, dass die G-Codes innerhalb dieser Profile sicher sind, " +"um Schäden an der Maschine zu vermeiden!" + +msgid "Customized Preset" +msgstr "Benutzerdefinierte Profile" msgid "Name of components inside step file is not UTF8 format!" msgstr "Der Name der Komponenten in der Step-Datei ist nicht im UTF8-Format!" @@ -4821,6 +4935,17 @@ msgstr "Speichere Datei als:" msgid "Export OBJ file:" msgstr "Exportiere OBJ Datei:" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" +"Die Datei %s existiert bereits\n" +"Möchten Sie sie ersetzen?" + +msgid "Comfirm Save As" +msgstr "Bestätigen Sie Speichern unter" + msgid "Delete object which is a part of cut object" msgstr "Lösche Objekt, das Teil des geschnittenen Objekts ist." @@ -4840,15 +4965,15 @@ msgstr "Das ausgewählte Objekt konnte nicht geteilt werden." msgid "Another export job is running." msgstr "Ein weiterer Exportauftrag läuft gerade." -msgid "Replace from:" -msgstr "Ersetzen von:" - msgid "Unable to replace with more than one volume" msgstr "Kann nicht mit mehr als einem Volumen ersetzt werden" msgid "Error during replace" msgstr "Fehler beim Ersetzen" +msgid "Replace from:" +msgstr "Ersetzen von:" + msgid "Select a new file" msgstr "Wählen Sie eine neue Datei aus" @@ -5231,6 +5356,12 @@ msgstr "Zeige G-Code Fenster" msgid "If enabled, g-code window will be displayed." msgstr "Wenn aktiviert, werden beim Start nützliche Hinweise angezeigt." +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "Reinigungsvolumen: Auto-Berechnung bei jeder Farbänderung." + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "Wenn aktiviert, wird bei jeder Farbänderung automatisch berechnet." + msgid "Presets" msgstr "Voreinstellungen" @@ -5285,6 +5416,9 @@ msgstr "Maximale Anzahl an zuletzt geöffneten Projekten" msgid "Clear my choice on the unsaved projects." msgstr "Meine Auswahl für nicht gespeicherte Projekte löschen." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "Keine Warnungen beim Laden von 3MF mit modifizierten G-Codes" + msgid "Auto-Backup" msgstr "Automatische Datensicherung" @@ -5438,8 +5572,11 @@ msgstr "Filament hinzufügen/entfernen" msgid "Add/Remove materials" msgstr "Materialien hinzufügen/entfernen" -msgid "Add/Remove printers" -msgstr "Drucker hinzufügen/entfernen" +msgid "Select/Remove printers(system presets)" +msgstr "Systemdrucker auswählen/entfernen" + +msgid "Create printer" +msgstr "Drucker erstellen" msgid "Incompatible" msgstr "Inkompatibel" @@ -5626,16 +5763,16 @@ msgstr "Bambu kalte Druckplatte" msgid "PLA Plate" msgstr "PLA-Platte" -msgid "Bambu Engineering Plate" -msgstr "Bambu Engineering-Platte" +msgid "Bamabu Engineering Plate" +msgstr "Bambu technische Druckplatte" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "Bambu glatte PEI-Platte" msgid "High temperature Plate" msgstr "Hochtemperaturplatte" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "Bambu strukturierte PEI-Platte" msgid "Send print job to" @@ -5660,9 +5797,6 @@ msgstr "Senden abgeschlossen" msgid "Error code" msgstr "Fehlercode" -msgid "Check the status of current system services" -msgstr "Überprüfen Sie den Status der aktuellen Systemdienste" - msgid "Printer local connection failed, please try again." msgstr "" "Die lokale Verbindung des Druckers ist fehlgeschlagen. Bitte versuchen Sie " @@ -5779,11 +5913,10 @@ msgstr "" "Struktur keine Zeitraffervideos erstellt." msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" -"Wenn nach Objekt gedruckt wird, werden bei Maschinen mit I3-Struktur keine " -"Zeitraffervideos erstellt." +"Zeitraffer wird nicht unterstützt, da die Druckreihenfolge auf \"Nach " +"Objekt\" eingestellt ist." msgid "Errors" msgstr "Fehler" @@ -5800,10 +5933,6 @@ msgstr "" "derzeit ausgewählten Drucker überein. Es wird empfohlen, für das Slicing " "denselben Druckertyp zu verwenden." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s wird von AMS nicht unterstützt." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5813,12 +5942,38 @@ msgstr "" "Sie, ob es sich um die erforderlichen Filamente handelt. Wenn diese in " "Ordnung sind, klicken Sie auf \"Bestätigen\", um den Druck zu starten." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "Düse gemerkt: %.1f %s" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" +"Ihr Düsendurchmesser im Profil stimmt nicht mit dem gemerkten " +"Düsendurchmesser überein. Haben Sie Ihre Düse kürzlich gewechselt?" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" +"*Drucken von %s Material mit %s kann zu einer Beschädigung der Düse führen" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Bitte klicken Sie auf die Bestätigungsschaltfläche, wenn Sie den " "Druckvorgang trotzdem fortsetzen möchten." +msgid "Hardened Steel" +msgstr "Gehärteter Stahl" + +msgid "Stainless Steel" +msgstr "Edelstahl" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -6018,6 +6173,9 @@ msgstr "" "Reinigungsturm kann es zu Fehlern am Modell kommen. Möchten Sie den " "Reinigungsturm aktivieren?" +msgid "Still print by object?" +msgstr "Trotzdem nach Objekt drucken?" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -6341,6 +6499,9 @@ msgstr "Maschinen Start G-Code" msgid "Machine end G-code" msgstr "Maschine Ende G-Code" +msgid "Printing by object G-code" +msgstr "Drucken nach Objekt G-Code" + msgid "Before layer change G-code" msgstr "G-Code vor dem Schichtwechsel" @@ -6410,6 +6571,29 @@ msgstr "Filament Rückzug durch Firmware" msgid "Detached" msgstr "Losgelöst" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" +"%d Filament Profil und %d Prozess Profil sind diesem Drucker zugeordnet. " +"Diese Profile werden gelöscht, wenn der Drucker gelöscht wird." + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" +"Voreinstellungen, die von anderen Voreinstellungen geerbt wurden, können " +"nicht gelöscht werden!" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "Die folgenden Profile erben dieses Profil." +msgstr[1] "Das folgende Profil erbt dieses Profil." + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Profil" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "Das folgende Profil wird ebenfalls gelöscht." @@ -6419,11 +6603,6 @@ msgstr[1] "Die folgenden Profile werden ebenfalls gelöscht." msgid "Are you sure to %1% the selected preset?" msgstr "Sind sie sicher, dass sie das ausgewählte Profil %1% wollen?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Profil" - msgid "All" msgstr "Alle" @@ -6674,11 +6853,20 @@ msgstr "Ramming-Linienabstand" msgid "Auto-Calc" msgstr "Automatisch berechnen" +msgid "Re-calculate" +msgstr "Neu berechnen" + msgid "Flushing volumes for filament change" msgstr "Reinigungsvolumen für Filamentwechsel" -msgid "Multiplier" -msgstr "Multiplikator " +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" +"Studio würde jedes Mal die Reinigungsvolumen neu berechnen, wenn sich die " +"Farbe des Filaments ändert. Sie können die automatische Berechnung in Bambu " +"Studio > Einstellungen deaktivieren" msgid "Flushing volume (mm³) for each filament pair." msgstr "Reinigungsvolumen (mm³) für jedes Filamentpaar." @@ -6691,6 +6879,9 @@ msgstr "Anmerkung: Reinigungsvolumen im Bereich [%d, %d]" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "Der Multiplikator sollte im Bereich [%.2f, %.2f] liegen." +msgid "Multiplier" +msgstr "Multiplikator " + msgid "unloaded" msgstr "entladen" @@ -6706,6 +6897,12 @@ msgstr "Von" msgid "To" msgstr "Zu" +msgid "Bambu Network plug-in not detected." +msgstr "Bambu Network-Plug-in nicht erkannt." + +msgid "Click here to download it." +msgstr "Klicken Sie hier, um es herunterzuladen." + msgid "Login" msgstr "Anmelden" @@ -6740,6 +6937,9 @@ msgstr "Aus Zwischenablage einfügen" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "Dialogfeld für 3Dconnexion Geräteeinstellungen anzeigen/ausblenden" +msgid "Switch table page" +msgstr "Seitenwechsel" + msgid "Show keyboard shortcuts list" msgstr "Liste der Tastaturkürzel anzeigen" @@ -6995,12 +7195,15 @@ msgstr "" msgid "New version of Orca Slicer" msgstr "Neue Version von Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "Erinnern Sie mich nicht mehr an diese Version." +msgid "Skip this Version" +msgstr "Überspringe diese Version" msgid "Done" msgstr "Erledigt" +msgid "Confirm and Update Nozzle" +msgstr "Bestätigen und Düse aktualisieren" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN-Verbindung fehlgeschlagen (Senden einer Druckdatei)" @@ -7026,8 +7229,24 @@ msgstr "Zugangscode" msgid "Where to find your printer's IP and Access Code?" msgstr "Wo finde ich die IP-Adresse und den Zugriffscode meines Druckers?" -msgid "Error: IP or Access Code are not correct" -msgstr "Fehler: IP oder Zugangscode sind nicht korrekt" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "Schritt 3: Pingen Sie die IP-Adresse, um Paketverlust und Latenz zu " + +msgid "Test" +msgstr "Test" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "IP und Zugriffscode verifiziert! Sie können das Fenster schließen" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "Verbindung fehlgeschlagen, bitte überprüfen Sie IP und Zugriffscode" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" +"Verbindung fehlgeschlagen! Wenn Ihre IP und Ihr Zugriffscode korrekt sind, \n" +"gehen Sie bitte zu Schritt 3, um Netzwerkprobleme zu beheben" msgid "Model:" msgstr "Modell:" @@ -7513,6 +7732,13 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "Schichthöhe darf den Düsendurchmesser nicht überschreiten." +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" +"Die Schichthöhe darf das Limit in Druckereinstellungen -> Extruder -> " +"Schichthöhenlimits nicht überschreiten" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -8004,11 +8230,49 @@ msgstr "Überhangsumkehr" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" +"Extrudieren Sie Umfänge, die einen Überhang haben in die entgegen gesetzte " +"Richtung in ungeraden Schichten. Dieses abwechselnde Muster kann steile " +"Überhänge drastisch verbessern.\n" +"\n" +"Diese Einstellung kann auch dazu beitragen, das Verziehen von Teilen zu " +"verringern, da die Spannungen in den Teilwänden reduziert werden." + +msgid "Reverse only internal perimeters" +msgstr "Nur interne Umfänge umkehren" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" -"Extrudieren Sie Umfänge, die einen Teil über einem Überhang in die entgegen " -"gesetzte Richtung in ungeraden Schichten haben. Dieses abwechselnde Muster " -"kann steile Überhänge drastisch verbessern." +"Wenden Sie die Logik der umgekehrten Umfänge nur auf interne Umfänge an.\n" +"\n" +"Diese Einstellung reduziert die Spannungen in den Teilen erheblich, da sie " +"jetzt in abwechselnden Richtungen verteilt werden. Dies sollte das Verziehen " +"von Teilen reduzieren und gleichzeitig die Qualität der Außenwand " +"sicherstellen. Diese Funktion kann für Materialien, die zum Verziehen neigen " +"wie ABS/ASA, und auch für elastische Filamente wie TPU und Silk PLA sehr " +"nützlich sein. Sie kann auch dazu beitragen, das Verziehen in schwebenden " +"Bereichen über Stützstrukturen zu reduzieren.\n" +"\n" +"Damit diese Einstellung am effektivsten ist, wird empfohlen, den " +"Umkehrschwellenwert auf 0 zu setzen, damit alle internen Wände in ungeraden " +"Schichten unabhängig von ihrem Überhangsgrad in abwechselnden Richtungen " +"gedruckt werden." msgid "Reverse threshold" msgstr "Umkehrschwelle" @@ -8268,6 +8532,16 @@ msgstr "End G-Code" msgid "End G-code when finish the whole printing" msgstr "End G-Code nach dem fertigstellen des Drucks hinzufügen." +msgid "Between Object Gcode" +msgstr "Zwischen Objekt G-Code" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" +"Füge G-Code zwischen den Objekten ein. Dieser Parameter wird nur wirksam, " +"wenn Sie Ihre Modelle Objekt für Objekt drucken." + msgid "End G-code when finish the printing of this filament" msgstr "End-G-Code hinzufügen, wenn der Druck dieses Filaments beenden ist." @@ -8367,26 +8641,28 @@ msgstr "" "Dies legt die Schwelle für eine kleine Umfangslänge fest. Der Standardwert " "für die Schwelle beträgt 0 mm." -msgid "Order of inner wall/outer wall/infil" -msgstr "Reihenfolge Innenwand/Außenwand/Füllung" +msgid "Order of walls" +msgstr "Anordnung der Wände" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "Druckreihenfolge von Innenwand, Außenwand und Füllung. " +msgid "Print sequence of inner wall and outer wall. " +msgstr "Druckreihenfolge der Innen- und Außenwand." -msgid "inner/outer/infill" -msgstr "Innen/Außen/Füllung" +msgid "inner/outer" +msgstr "Innen/Außen" -msgid "outer/inner/infill" -msgstr "Außen/Innen/Füllung" +msgid "outer/inner" +msgstr "Außen/Innen" -msgid "infill/inner/outer" -msgstr "Füllung/Innen/Außen" +msgid "inner wall/outer wall/inner wall" +msgstr "Innenwand/Außenwand/Innenwand" -msgid "infill/outer/inner" -msgstr "Füllung/Außen/Innen" +msgid "Print infill first" +msgstr "Drucke zuerst die Füllung" -msgid "inner-outer-inner/infill" -msgstr "Innen-Außen-Innen/Füllung" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" +"Reihenfolge der Wand/Füllung. false bedeutet, dass die Wand zuerst gedruckt " +"wird." msgid "Height to rod" msgstr "Höhe zur Führung" @@ -8492,9 +8768,6 @@ msgstr "Standardfarbe" msgid "Default filament color" msgstr "Standard-Filamentfarbe" -msgid "Color" -msgstr "Farbe" - msgid "Filament notes" msgstr "Filamentnotizen" @@ -8952,10 +9225,6 @@ msgid "" msgstr "" "Klipper's max_accel_to_decel wird auf diesen %% der Beschleunigung verändert" -#, c-format, boost-format -msgid "%%" -msgstr "%%" - msgid "Jerk of outer walls" msgstr "Ruckwert Außenwand" @@ -9375,6 +9644,22 @@ msgstr "" "verwendet werden kann, insbesondere bei Drucken mit durchsichtigen " "Materialien oder manuell lösbaren Unterstützungsmaterialien" +msgid "Maximum width of a segmented region" +msgstr "Maximale Breite eines segmentierten Bereichs" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" +"Maximale Breite eines segmentierten Bereichs. Null deaktiviert diese " +"Funktion." + +msgid "Interlocking depth of a segmented region" +msgstr "Verriegelungstiefe eines segmentierten Bereichs" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" +"Verriegelungstiefe eines segmentierten Bereichs. Null deaktiviert diese " +"Funktion." + msgid "Ironing Type" msgstr "Glättungsmethode" @@ -9987,6 +10272,26 @@ msgstr "" "bei der Verfahrbewegung gegen den Druck stößt. Die Verwendung einer " "Spirallinie zum Anheben von z kann Fadenbildung verhindern." +msgid "Z hop lower boundary" +msgstr "Z-Hub untere Grenze" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" +"Z-Hub wird nur wirksam, wenn Z über diesem Wert liegt und unter dem " +"Parameter: \"Z-Hub obere Grenze\" liegt" + +msgid "Z hop upper boundary" +msgstr "Z-Hub obere Grenze" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" +"Wenn dieser Wert positiv ist, wird der Z-Hub nur wirksam, wenn Z über dem " +"Parameter: \"Z-Hub untere Grenze\" liegt und unter diesem Wert liegt" + msgid "Z hop type" msgstr "Z-Hub Typ" @@ -10467,6 +10772,14 @@ msgstr "" "kein spezielles Filament für die Stützen verwendet wird, sondern das " "aktuelle Filament." +msgid "No interface filament for body" +msgstr "Kein Filament für die Schnittstelle des Körpers" + +msgid "Don't use support interface filament to print support body" +msgstr "" +"verwende kein Filament für die Stützstruktur-Schnittstelle um den Körper zu " +"drucken" + msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." @@ -10503,6 +10816,12 @@ msgstr "Anzahl der oberen Schnittstellenschichten" msgid "Bottom interface layers" msgstr "Untere Schnittstellenschichten" +msgid "Number of bottom interface layers" +msgstr "Anzahl der unteren Schnittstellenschichten" + +msgid "Same as top" +msgstr "Gleich wie oben" + msgid "Top interface spacing" msgstr "Oberer Schnittstellenabstand" @@ -11240,71 +11559,12 @@ msgstr "Zu große Linienbreite" msgid " not in range " msgstr "nicht im Bereich" -msgid "Export 3MF" -msgstr "3mf exportieren" - -msgid "Export project as 3MF." -msgstr "Projekt als 3mf exportieren." - -msgid "Export slicing data" -msgstr "Slicing-Daten exportieren" - -msgid "Export slicing data to a folder." -msgstr "Exportieren von Slicing-Daten in einen Ordner" - -msgid "Load slicing data" -msgstr "Slicing-Daten laden" - -msgid "Load cached slicing data from directory" -msgstr "Zwischengespeicherte Slicing-Daten aus dem Verzeichnis laden" - -msgid "Export STL" -msgstr "Export STL" - -msgid "Export the objects as multiple STL." -msgstr "Die Objekte als mehrere STL-Dateien exportieren." - -msgid "Slice" -msgstr "Slice" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "" -"Slicen sie die Druckplatten: 0-alle Druckplatten; i-Druckplatte i; andere " -"ungültig" - -msgid "Show command help." -msgstr "Befehlshilfe anzeigen." - -msgid "UpToDate" -msgstr "Auf dem neuesten Stand" - -msgid "Update the configs values of 3mf to latest." -msgstr "Aktualisierung der 3mf Konfigurationswerte auf die neueste Version." - -msgid "Load default filaments" -msgstr "Standard-Filamente laden" - -msgid "Load first filament as default for those not loaded" -msgstr "Das erste Filament als Standard für nicht geladene übernehmen" - msgid "Minimum save" msgstr "Minimale Speicherung" msgid "export 3mf with minimum size." msgstr "Exportieren Sie 3mf mit minimaler Größe." -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "Maximale Anzahl von Dreiecken pro Bauplattform für das Slicing." - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "Das maximale Slicing-Zeitlimit pro Plate in Sekunden." - msgid "No check" msgstr "Keine Überprüfung" @@ -11313,42 +11573,6 @@ msgstr "" "Führe keine Gültigkeitsprüfungen durch, wie beispielsweise die Überprüfung " "von G-Code-Pfadkonflikten." -msgid "Normative check" -msgstr "Normative Überprüfung" - -msgid "Check the normative items." -msgstr "Überprüfen Sie die normativen Elemente." - -msgid "Output Model Info" -msgstr "Ausgabe Modellinformationen" - -msgid "Output the model's information." -msgstr "Geben Sie die Informationen des Modells aus." - -msgid "Export Settings" -msgstr "Einstellungen exportieren" - -msgid "Export settings to a file." -msgstr "Einstellungen in eine Datei exportieren." - -msgid "Send progress to pipe" -msgstr "Fortschritt an die Leitung senden" - -msgid "Send progress to pipe." -msgstr "Fortschritt an die Leitung senden" - -msgid "Arrange Options" -msgstr "Anordnungsoptionen" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Anordnungsoptionen: 0-deaktiviert; 1-aktiviert; andere-automatisch" - -msgid "Repetions count" -msgstr "Anzahl der Wiederholungen" - -msgid "Repetions count of the whole model" -msgstr "Anzahl der Wiederholungen des gesamten Modells" - msgid "Ensure on bed" msgstr "Auf dem Bett stellen" @@ -11358,12 +11582,6 @@ msgstr "" "Heben Sie das Objekt über das Bett, wenn es teilweise darunter liegt. " "Standardmäßig deaktiviert" -msgid "Convert Unit" -msgstr "Einheit umrechnen" - -msgid "Convert the units of model" -msgstr "Einheiten des Modells umrechnen" - msgid "Orient Options" msgstr "Orientierungsoptionen" @@ -11373,50 +11591,12 @@ msgstr "Orientierungsoptionen: 0-deaktiviert; 1-aktiviert; andere-automatisch" msgid "Rotation angle around the Z axis in degrees." msgstr "Rotationswinkel um die Z-Achse in Grad." -msgid "Rotate around X" -msgstr "Rotieren um X" - -msgid "Rotation angle around the X axis in degrees." -msgstr "Rotationswinkel um die X-Achse in Grad." - msgid "Rotate around Y" msgstr "Rotieren um Y" msgid "Rotation angle around the Y axis in degrees." msgstr "Rotationswinkel um die Y-Achse in Grad." -msgid "Scale the model by a float factor" -msgstr "Skalierung des Modells um einen Faktor" - -msgid "Load General Settings" -msgstr "Allgemeine Einstellungen laden" - -msgid "Load process/machine settings from the specified file" -msgstr "Laden von Prozess-/Maschineneinstellungen aus der angegebenen Datei" - -msgid "Load Filament Settings" -msgstr "Filamenteinstellungen laden" - -msgid "Load filament settings from the specified file list" -msgstr "Filamenteinstellungen aus der angegebenen Dateiliste laden" - -msgid "Skip Objects" -msgstr "Objekte überspringen" - -msgid "Skip some objects in this print" -msgstr "Einige Objekte in diesem Druck überspringen" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" -"Aktuelle Prozess-/Maschineneinstellungen laden, wenn 'Aktuell' verwendet wird" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" -"Aktuelle Prozess-/Maschineneinstellungen aus der angegebenen Datei laden, " -"wenn Aktuell verwendet wird" - msgid "Data directory" msgstr "Datenverzeichnis" @@ -11429,27 +11609,11 @@ msgstr "" "nützlich, um verschiedene Profile beizubehalten oder Konfigurationen aus " "einem Netzwerkspeicher einzubeziehen." -msgid "Output directory" -msgstr "Ausgabeverzeichnis" - -msgid "Output directory for the exported files." -msgstr "Ausgabeverzeichnis für die exportierten Dateien." +msgid "Load custom gcode" +msgstr "Lade benutzerdefinierten G-Code" -msgid "Debug level" -msgstr "Fehlersuchstufe" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Legt die Stufe der Fehlerprotokollierung fest. 0:fatal, 1:error, 2:warning, " -"3:info, 4:debug, 5:trace\n" - -msgid "Load custom gcode" -msgstr "Lade benutzerdefinierten G-Code" - -msgid "Load custom gcode from json" -msgstr "Lade benutzerdefinierten G-Code aus json" +msgid "Load custom gcode from json" +msgstr "Lade benutzerdefinierten G-Code aus json" msgid "Error in zip archive" msgstr "Fehler im Zip-Archiv" @@ -11611,9 +11775,6 @@ msgstr "Kalibrieren" msgid "Finish" msgstr "Fertig" -msgid "Wiki" -msgstr "Wiki" - msgid "How to use calibration result?" msgstr "Wie wird das Kalibrierungsergebnis verwendet?" @@ -11632,6 +11793,12 @@ msgstr "" msgid "Calibration not supported" msgstr "Kalibrierung nicht unterstützt" +msgid "Error desc" +msgstr "Fehlerbeschreibung" + +msgid "Extra info" +msgstr "Extra Info" + msgid "Flow Dynamics" msgstr "Flussdynamik" @@ -11666,9 +11833,9 @@ msgstr "" msgid "The name cannot be empty." msgstr "Der Name darf nicht leer sein." -#, boost-format -msgid "The selected preset: %1% is not found." -msgstr "Die ausgewählte Voreinstellung: %1% wurde nicht gefunden." +#, c-format, boost-format +msgid "The selected preset: %s is not found." +msgstr "Die ausgewählte Voreinstellung: %s wurde nicht gefunden." msgid "The name cannot be the same as the system preset name." msgstr "" @@ -12038,12 +12205,6 @@ msgstr "" "- Verschiedene Filamentmarken und -familien (Marke = Bambu, Familie = Basic, " "Matte)" -msgid "Error desc" -msgstr "Fehlerbeschreibung" - -msgid "Extra info" -msgstr "Extra Info" - msgid "Pattern" msgstr "Pattern" @@ -12135,107 +12296,6 @@ msgstr "" "Es gibt mehrere IP-Adressen, die zu Hostname %1% auflösen.\n" "Bitte wählen Sie eine aus, die verwendet werden soll." -msgid "Unable to perform boolean operation on selected parts" -msgstr "" -"Die boolesche Operation kann auf den ausgewählten Teilen nicht durchgeführt " -"werden" - -msgid "Mesh Boolean" -msgstr "Mesh-Boolesche Operation" - -msgid "Union" -msgstr "Vereinigen" - -msgid "Difference" -msgstr "Differenz" - -msgid "Intersection" -msgstr "Schnittmenge" - -msgid "Source Volume" -msgstr "Quellvolumen" - -msgid "Tool Volume" -msgstr "Werkzeugvolumen" - -msgid "Subtract from" -msgstr "Abziehen von" - -msgid "Subtract with" -msgstr "Abziehen mit" - -msgid "selected" -msgstr "Ausgewählt" - -msgid "Part 1" -msgstr "Teil 1" - -msgid "Part 2" -msgstr "Teil 2" - -msgid "Delete input" -msgstr "Eingabe löschen" - -msgid "Send G-Code to printer host" -msgstr "Senden Sie G-Code an den Drucker-Host" - -msgid "Upload to Printer Host with the following filename:" -msgstr "Mit folgendem Dateinamen auf den Drucker-Host hochladen:" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" -"Verwenden Sie bei Bedarf Schrägstriche (/) als Verzeichnistrennzeichen." - -msgid "Upload to storage" -msgstr "Hochladen in den Speicher" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" -"Der Dateiname für den Upload endet nicht mit \"%s\". Möchten Sie den Vorgang " -"fortsetzen?" - -#, fuzzy -msgid "Upload" -msgstr "Entladen" - -msgid "Print host upload queue" -msgstr "Druck-Host-Upload-Warteschlange" - -msgid "ID" -msgstr "ID" - -msgid "Progress" -msgstr "Fortschritt" - -msgid "Host" -msgstr "Host" - -msgctxt "OfFile" -msgid "Size" -msgstr "Größe" - -msgid "Filename" -msgstr "Dateiname" - -msgid "Cancel selected" -msgstr "Ausgewählten abbrechen" - -msgid "Show error message" -msgstr "Fehlermeldung Anzeigen" - -msgid "Enqueued" -msgstr "In Warteschlange" - -msgid "Uploading" -msgstr "Hochladen" - -msgid "Cancelling" -msgstr "Wird abgebrochen" - -msgid "Error uploading to print host" -msgstr "Fehler beim Hochladen zum Druck-Host" - msgid "PA Calibration" msgstr "PA Kalibrierung" @@ -12378,80 +12438,113 @@ msgstr "Ende Rückzugslänge" msgid "mm/mm" msgstr "mm/mm" +msgid "Send G-Code to printer host" +msgstr "Senden Sie G-Code an den Drucker-Host" + +msgid "Upload to Printer Host with the following filename:" +msgstr "Mit folgendem Dateinamen auf den Drucker-Host hochladen:" + +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "" +"Verwenden Sie bei Bedarf Schrägstriche (/) als Verzeichnistrennzeichen." + +msgid "Upload to storage" +msgstr "Hochladen in den Speicher" + +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "" +"Der Dateiname für den Upload endet nicht mit \"%s\". Möchten Sie den Vorgang " +"fortsetzen?" + #, fuzzy -msgid "Physical Printer" -msgstr "Drucker" +msgid "Upload" +msgstr "Entladen" -msgid "Print Host upload" -msgstr "Hochladen zum Druck-Host" +msgid "Print host upload queue" +msgstr "Druck-Host-Upload-Warteschlange" -msgid "Test" -msgstr "Test" +msgid "ID" +msgstr "ID" -msgid "Could not get a valid Printer Host reference" -msgstr "Konnte keine gültige Referenz zum Druck-Host erhalten" +msgid "Progress" +msgstr "Fortschritt" -msgid "Success!" -msgstr "Erfolgreich!" +msgid "Host" +msgstr "Host" -msgid "Refresh Printers" -msgstr "Drucker aktualisieren" +msgctxt "OfFile" +msgid "Size" +msgstr "Größe" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." -msgstr "" -"Die HTTPS-CA-Datei ist optional. Sie wird nur benötigt, wenn Sie HTTPS mit " -"einem selbstsignierten Zertifikat verwenden." +msgid "Filename" +msgstr "Dateiname" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "Zertifikatdateien (*.crt, *.pem)|*.crt;*.pem|Alle Dateien|*.*" +msgid "Cancel selected" +msgstr "Ausgewählten abbrechen" -msgid "Open CA certificate file" -msgstr "Öffnen Sie die CA-Zertifikatsdatei." +msgid "Show error message" +msgstr "Fehlermeldung Anzeigen" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." -msgstr "" -"Auf diesem System verwendet %s HTTPS-Zertifikate aus dem " -"Systemzertifikatspeicher oder dem Schlüsselbund." +msgid "Enqueued" +msgstr "In Warteschlange" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." -msgstr "" -"Um eine benutzerdefinierte CA-Datei zu verwenden, importieren Sie bitte Ihre " -"CA-Datei in den Zertifikatspeicher / das Schlüsselbund." +msgid "Uploading" +msgstr "Hochladen" -msgid "Connection to printers connected via the print host failed." -msgstr "" -"Die Verbindung zu den über den Druck-Host verbundenen Druckern ist " -"fehlgeschlagen." +msgid "Cancelling" +msgstr "Wird abgebrochen" -msgid "The start, end or step is not valid value." -msgstr "Der Start, das Ende oder der Schritt ist kein gültiger Wert." +msgid "Error uploading to print host" +msgstr "Fehler beim Hochladen zum Druck-Host" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Unable to perform boolean operation on selected parts" msgstr "" -"Kalibrierung nicht möglich: Möglicherweise, weil der eingestellte " -"Kalibrierungswertebereich zu groß ist oder der Schritt zu klein ist" +"Die boolesche Operation kann auf den ausgewählten Teilen nicht durchgeführt " +"werden" + +msgid "Mesh Boolean" +msgstr "Mesh-Boolesche Operation" + +msgid "Union" +msgstr "Vereinigen" + +msgid "Difference" +msgstr "Differenz" + +msgid "Intersection" +msgstr "Schnittmenge" + +msgid "Source Volume" +msgstr "Quellvolumen" + +msgid "Tool Volume" +msgstr "Werkzeugvolumen" -msgid "Need select printer" -msgstr "Drucker auswählen" +msgid "Subtract from" +msgstr "Abziehen von" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "Subtract with" +msgstr "Abziehen mit" + +msgid "selected" +msgstr "Ausgewählt" + +msgid "Part 1" +msgstr "Teil 1" + +msgid "Part 2" +msgstr "Teil 2" + +msgid "Delete input" +msgstr "Eingabe löschen" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3D-Szenenbedienung\n" -"Wissen Sie, wie Sie die Ansicht und die Auswahl von Objekten/Teilen in der " -"3D-Szene mit der Maus und dem Touchpad steuern können?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -12467,11 +12560,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Modell reparieren\n" -"Wussten Sie, dass Sie ein beschädigtes 3D-Modell reparieren können, um viele " -"Probleme beim Slicen zu vermeiden?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -12522,6 +12612,13 @@ msgstr "" "Wussten Sie, dass Sie alle Objekte/Teile in einer Liste anzeigen und die " "Einstellungen für jedes Objekt/Teil ändern können?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -12720,15 +12817,385 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." msgstr "" -"Wenn mit geöffneter Druckertür gedruckt werden muss\n" -"Das Öffnen der Druckertür kann die Wahrscheinlichkeit einer Verstopfung des " -"Extruders/Hotends beim Drucken von Filamenten mit niedrigerer Temperatur bei " -"höherer Gehäusetemperatur verringern. Weitere Informationen dazu finden Sie " -"in der Wiki." + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." +msgstr "" + +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Strg + Umschalt + Eingabetaste" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Werkzeug-lege auf Fläche" + +#~ msgid "Export as STL" +#~ msgstr "Als STL exportieren" + +#~ msgid "Check cloud service status" +#~ msgstr "Status des Cloud-Dienstes prüfen" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "" +#~ "Bitte geben Sie einen gültigen Wert ein (K im Bereich von 0 bis 0,5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "" +#~ "Bitte geben Sie einen gültigen Wert ein (K im Bereich von 0 bis 0,5, N im " +#~ "Bereich von 0,6 bis 2,0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Alle Objekte als STL exportieren" + +#~ msgid "Slice ok." +#~ msgstr "Slice ok." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "Die Version %s von 3mf ist neuer als die Version %s von %s, folgende " +#~ "Schlüssel wurden nicht erkannt:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Sie sollten Ihre Software aktualisieren.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "Die Version %s der 3mf ist neuer als die Version %s %s. Bitte Ihre " +#~ "Software aktualisieren." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "Der 3mf ist nicht kompatibel, lade nur die Geometriedaten!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Inkompatible 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "Drucker hinzufügen/entfernen" + +#~ msgid "Bambu Engineering Plate" +#~ msgstr "Bambu Engineering-Platte" + +#~ msgid "Bambu Smooth PEI Plate" +#~ msgstr "Bambu glatte PEI-Platte" + +#~ msgid "Bambu Textured PEI Plate" +#~ msgstr "Bambu strukturierte PEI-Platte" + +#~ msgid "" +#~ "When print by object, machines with I3 structure will not generate " +#~ "timelapse videos." +#~ msgstr "" +#~ "Wenn nach Objekt gedruckt wird, werden bei Maschinen mit I3-Struktur " +#~ "keine Zeitraffervideos erstellt." + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s wird von AMS nicht unterstützt." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Erinnern Sie mich nicht mehr an diese Version." + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Fehler: IP oder Zugangscode sind nicht korrekt" + +#~ msgid "" +#~ "Extrude perimeters that have a part over an overhang in the reverse " +#~ "direction on odd layers. This alternating pattern can drastically improve " +#~ "steep overhang." +#~ msgstr "" +#~ "Extrudieren Sie Umfänge, die einen Teil über einem Überhang in die " +#~ "entgegen gesetzte Richtung in ungeraden Schichten haben. Dieses " +#~ "abwechselnde Muster kann steile Überhänge drastisch verbessern." + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Reihenfolge Innenwand/Außenwand/Füllung" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "Druckreihenfolge von Innenwand, Außenwand und Füllung. " + +#~ msgid "inner/outer/infill" +#~ msgstr "Innen/Außen/Füllung" + +#~ msgid "outer/inner/infill" +#~ msgstr "Außen/Innen/Füllung" + +#~ msgid "infill/inner/outer" +#~ msgstr "Füllung/Innen/Außen" + +#~ msgid "infill/outer/inner" +#~ msgstr "Füllung/Außen/Innen" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "Innen-Außen-Innen/Füllung" + +#, c-format, boost-format +#~ msgid "%%" +#~ msgstr "%%" + +#~ msgid "Export 3MF" +#~ msgstr "3mf exportieren" + +#~ msgid "Export project as 3MF." +#~ msgstr "Projekt als 3mf exportieren." + +#~ msgid "Export slicing data" +#~ msgstr "Slicing-Daten exportieren" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Exportieren von Slicing-Daten in einen Ordner" + +#~ msgid "Load slicing data" +#~ msgstr "Slicing-Daten laden" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Zwischengespeicherte Slicing-Daten aus dem Verzeichnis laden" + +#~ msgid "Export STL" +#~ msgstr "Export STL" + +#~ msgid "Export the objects as multiple STL." +#~ msgstr "Die Objekte als mehrere STL-Dateien exportieren." + +#~ msgid "Slice" +#~ msgstr "Slice" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "" +#~ "Slicen sie die Druckplatten: 0-alle Druckplatten; i-Druckplatte i; andere " +#~ "ungültig" + +#~ msgid "Show command help." +#~ msgstr "Befehlshilfe anzeigen." + +#~ msgid "UpToDate" +#~ msgstr "Auf dem neuesten Stand" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Aktualisierung der 3mf Konfigurationswerte auf die neueste Version." + +#~ msgid "Load default filaments" +#~ msgstr "Standard-Filamente laden" + +#~ msgid "Load first filament as default for those not loaded" +#~ msgstr "Das erste Filament als Standard für nicht geladene übernehmen" + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "Maximale Anzahl von Dreiecken pro Bauplattform für das Slicing." + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "Das maximale Slicing-Zeitlimit pro Plate in Sekunden." + +#~ msgid "Normative check" +#~ msgstr "Normative Überprüfung" + +#~ msgid "Check the normative items." +#~ msgstr "Überprüfen Sie die normativen Elemente." + +#~ msgid "Output Model Info" +#~ msgstr "Ausgabe Modellinformationen" + +#~ msgid "Output the model's information." +#~ msgstr "Geben Sie die Informationen des Modells aus." + +#~ msgid "Export Settings" +#~ msgstr "Einstellungen exportieren" + +#~ msgid "Export settings to a file." +#~ msgstr "Einstellungen in eine Datei exportieren." + +#~ msgid "Send progress to pipe" +#~ msgstr "Fortschritt an die Leitung senden" + +#~ msgid "Send progress to pipe." +#~ msgstr "Fortschritt an die Leitung senden" + +#~ msgid "Arrange Options" +#~ msgstr "Anordnungsoptionen" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Anordnungsoptionen: 0-deaktiviert; 1-aktiviert; andere-automatisch" + +#~ msgid "Repetions count" +#~ msgstr "Anzahl der Wiederholungen" + +#~ msgid "Repetions count of the whole model" +#~ msgstr "Anzahl der Wiederholungen des gesamten Modells" + +#~ msgid "Convert Unit" +#~ msgstr "Einheit umrechnen" + +#~ msgid "Convert the units of model" +#~ msgstr "Einheiten des Modells umrechnen" + +#~ msgid "Rotate around X" +#~ msgstr "Rotieren um X" + +#~ msgid "Rotation angle around the X axis in degrees." +#~ msgstr "Rotationswinkel um die X-Achse in Grad." + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Skalierung des Modells um einen Faktor" + +#~ msgid "Load General Settings" +#~ msgstr "Allgemeine Einstellungen laden" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Laden von Prozess-/Maschineneinstellungen aus der angegebenen Datei" + +#~ msgid "Load Filament Settings" +#~ msgstr "Filamenteinstellungen laden" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "Filamenteinstellungen aus der angegebenen Dateiliste laden" + +#~ msgid "Skip Objects" +#~ msgstr "Objekte überspringen" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Einige Objekte in diesem Druck überspringen" + +#~ msgid "load uptodate process/machine settings when using uptodate" +#~ msgstr "" +#~ "Aktuelle Prozess-/Maschineneinstellungen laden, wenn 'Aktuell' verwendet " +#~ "wird" + +#~ msgid "" +#~ "load uptodate process/machine settings from the specified file when using " +#~ "uptodate" +#~ msgstr "" +#~ "Aktuelle Prozess-/Maschineneinstellungen aus der angegebenen Datei laden, " +#~ "wenn Aktuell verwendet wird" + +#~ msgid "Output directory" +#~ msgstr "Ausgabeverzeichnis" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Ausgabeverzeichnis für die exportierten Dateien." + +#~ msgid "Debug level" +#~ msgstr "Fehlersuchstufe" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Legt die Stufe der Fehlerprotokollierung fest. 0:fatal, 1:error, 2:" +#~ "warning, 3:info, 4:debug, 5:trace\n" + +#, boost-format +#~ msgid "The selected preset: %1% is not found." +#~ msgstr "Die ausgewählte Voreinstellung: %1% wurde nicht gefunden." + +#, fuzzy +#~ msgid "Physical Printer" +#~ msgstr "Drucker" + +#~ msgid "Print Host upload" +#~ msgstr "Hochladen zum Druck-Host" + +#~ msgid "Could not get a valid Printer Host reference" +#~ msgstr "Konnte keine gültige Referenz zum Druck-Host erhalten" + +#~ msgid "Success!" +#~ msgstr "Erfolgreich!" + +#~ msgid "Refresh Printers" +#~ msgstr "Drucker aktualisieren" + +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "Die HTTPS-CA-Datei ist optional. Sie wird nur benötigt, wenn Sie HTTPS " +#~ "mit einem selbstsignierten Zertifikat verwenden." + +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "Zertifikatdateien (*.crt, *.pem)|*.crt;*.pem|Alle Dateien|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "Öffnen Sie die CA-Zertifikatsdatei." + +#, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "" +#~ "Auf diesem System verwendet %s HTTPS-Zertifikate aus dem " +#~ "Systemzertifikatspeicher oder dem Schlüsselbund." + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "Um eine benutzerdefinierte CA-Datei zu verwenden, importieren Sie bitte " +#~ "Ihre CA-Datei in den Zertifikatspeicher / das Schlüsselbund." + +#~ msgid "Connection to printers connected via the print host failed." +#~ msgstr "" +#~ "Die Verbindung zu den über den Druck-Host verbundenen Druckern ist " +#~ "fehlgeschlagen." + +#~ msgid "The start, end or step is not valid value." +#~ msgstr "Der Start, das Ende oder der Schritt ist kein gültiger Wert." + +#~ msgid "" +#~ "Unable to calibrate: maybe because the set calibration value range is too " +#~ "large, or the step is too small" +#~ msgstr "" +#~ "Kalibrierung nicht möglich: Möglicherweise, weil der eingestellte " +#~ "Kalibrierungswertebereich zu groß ist oder der Schritt zu klein ist" + +#~ msgid "Need select printer" +#~ msgstr "Drucker auswählen" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3D-Szenenbedienung\n" +#~ "Wissen Sie, wie Sie die Ansicht und die Auswahl von Objekten/Teilen in " +#~ "der 3D-Szene mit der Maus und dem Touchpad steuern können?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Modell reparieren\n" +#~ "Wussten Sie, dass Sie ein beschädigtes 3D-Modell reparieren können, um " +#~ "viele Probleme beim Slicen zu vermeiden?" + +#~ msgid "" +#~ "When need to print with the printer door opened\n" +#~ "Opening the printer door can reduce the probability of extruder/hotend " +#~ "clogging when printing lower temperature filament with a higher enclosure " +#~ "temperature. More info about this in the Wiki." +#~ msgstr "" +#~ "Wenn mit geöffneter Druckertür gedruckt werden muss\n" +#~ "Das Öffnen der Druckertür kann die Wahrscheinlichkeit einer Verstopfung " +#~ "des Extruders/Hotends beim Drucken von Filamenten mit niedrigerer " +#~ "Temperatur bei höherer Gehäusetemperatur verringern. Weitere " +#~ "Informationen dazu finden Sie in der Wiki." #~ msgid "Embeded" #~ msgstr "Eingebettet" @@ -12748,26 +13215,6 @@ msgstr "" #~ msgstr "" #~ "Von Mitarbeitern ausgewählte Online-Models auf der Startseite anzeigen" -#~ msgid "Z hop lower boundary" -#~ msgstr "Z-Hub untere Grenze" - -#~ msgid "" -#~ "Z hop will only come into effect when Z is above this value and is below " -#~ "the parameter: \"Z hop upper boundary\"" -#~ msgstr "" -#~ "Z-Hub wird nur wirksam, wenn Z über diesem Wert liegt und unter dem " -#~ "Parameter: \"Z-Hub obere Grenze\" liegt" - -#~ msgid "Z hop upper boundary" -#~ msgstr "Z-Hub obere Grenze" - -#~ msgid "" -#~ "If this value is positive, Z hop will only come into effect when Z is " -#~ "above the parameter: \"Z hop lower boundary\" and is below this value" -#~ msgstr "" -#~ "Wenn dieser Wert positiv ist, wird der Z-Hub nur wirksam, wenn Z über dem " -#~ "Parameter: \"Z-Hub untere Grenze\" liegt und unter diesem Wert liegt" - #~ msgid "The minimum printing speed when slow down for cooling" #~ msgstr "" #~ "Die minimale Druckgeschwindigkeit wenn diese für eine bessere Kühlung " @@ -12899,9 +13346,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Punktzahl" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bambu technische Druckplatte" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu Hochtemperaturdruckplatte" diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 21e935ffa1d..56406cf96dd 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -101,6 +101,9 @@ msgstr "No auto support" msgid "Support Generated" msgstr "Support generated" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Lay on Face" @@ -148,8 +151,8 @@ msgstr "Bucket fill" msgid "Height range" msgstr "Height range" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Toggle Wireframe" @@ -179,9 +182,15 @@ msgstr "Painted using: Filament %1%" msgid "Move" msgstr "Move" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Rotate" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Optimize orientation" @@ -191,12 +200,12 @@ msgstr "Apply" msgid "Scale" msgstr "Scale" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "Error: Please close all toolbar menus first" -msgid "Tool-Lay on Face" -msgstr "Tool-Lay on Face" - msgid "in" msgstr "in" @@ -491,6 +500,15 @@ msgstr "Seam painting" msgid "Remove selection" msgstr "Remove selection" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Font" @@ -693,6 +711,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Privacy Policy Update" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Loading" @@ -886,8 +912,11 @@ msgstr "Printable" msgid "Fix model" msgstr "Fix Model" -msgid "Export as STL" -msgstr "Export as STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Reload from disk" @@ -1142,6 +1171,9 @@ msgstr "Click the icon to edit color painting for the object" msgid "Click the icon to shift this object to the bed" msgstr "Click the icon to shift this object to the bed" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Loading file" @@ -1399,6 +1431,18 @@ msgstr "Open next tip" msgid "Open Documentation in web browser." msgstr "Open documentation in web browser" +msgid "Color" +msgstr "Color" + +msgid "Pause" +msgstr "Pause" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Custom" + msgid "Pause:" msgstr "Pause:" @@ -1474,8 +1518,8 @@ msgstr "" msgid "Failed to connect to the server" msgstr "Failed to connect to the server" -msgid "Check cloud service status" -msgstr "Check cloud service status" +msgid "Check the status of current system services" +msgstr "Check the status of current system services" msgid "code" msgstr "code" @@ -1737,6 +1781,14 @@ msgstr "Sending print job over LAN" msgid "Sending print job through cloud service" msgstr "Sending print job through cloud service" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Service Unavailable" @@ -1957,11 +2009,11 @@ msgstr "Are you sure you want to clear the filament information?" msgid "You need to select the material type and color first." msgstr "You need to select the material type and color first." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Please input a valid value (K in 0~0.5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Other Color" @@ -2344,9 +2396,6 @@ msgstr "Rectangular" msgid "Circular" msgstr "Circular" -msgid "Custom" -msgstr "Custom" - msgid "Load shape from STL..." msgstr "Load shape from STL..." @@ -2832,6 +2881,9 @@ msgstr "Flushed" msgid "Total" msgstr "Total" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Total estimation" @@ -2919,15 +2971,18 @@ msgstr "Color change" msgid "Print" msgstr "Print" -msgid "Pause" -msgstr "Pause" - msgid "Printer" msgstr "Printer" msgid "Print settings" msgstr "Print settings" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Time Estimation" @@ -3096,7 +3151,7 @@ msgstr "Volume:" msgid "Size:" msgstr "Size:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3157,15 +3212,15 @@ msgstr "Calibration Flow" msgid "Start Calibration" msgstr "Start Calibration" -msgid "No step selected" -msgstr "" - msgid "Completed" msgstr "Completed" msgid "Calibrating" msgstr "Calibrating" +msgid "No step selected" +msgstr "" + msgid "Auto-record Monitoring" msgstr "Auto-record Monitoring" @@ -3380,8 +3435,11 @@ msgstr "Load configs" msgid "Import" msgstr "Import" -msgid "Export all objects as STL" -msgstr "Export All Objects as STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Export Generic 3MF" @@ -3655,9 +3713,6 @@ msgstr "Initialization failed (No Camera Device)!" msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "Printer is busy downloading; please wait for the download to finish." -msgid "Loading..." -msgstr "Loading..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" @@ -3720,6 +3775,9 @@ msgstr "Playing..." msgid "Load failed [%d]!" msgstr "Loading failed [%d]!" +msgid "Loading..." +msgstr "Loading..." + msgid "Year" msgstr "Year" @@ -3837,12 +3895,25 @@ msgstr "Download finished" msgid "Downloading %d%%..." msgstr "Downloading %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "" msgid "Storage unavailable, insert SD card." msgstr "" +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Speed:" @@ -4173,6 +4244,12 @@ msgstr "New network plug-in available" msgid "Details" msgstr "Details" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "" + msgid "Undo integration failed." msgstr "Undo integration failed." @@ -4221,9 +4298,6 @@ msgstr "COMPLETED" msgid "Cancel upload" msgstr "Cancel upload" -msgid "Slice ok." -msgstr "Slice complete" - msgid "Jump to" msgstr "Jump to" @@ -4329,6 +4403,9 @@ msgstr "Auto-recover from step loss" msgid "Allow Prompt Sound" msgstr "" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Global" @@ -4423,6 +4500,9 @@ msgstr "Synchronize filament list from AMS" msgid "Set filaments to use" msgstr "Set filaments to use" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4520,26 +4600,29 @@ msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "" #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" -msgid "You'd better upgrade your software.\n" -msgstr "You should update your software.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Newer 3mf version" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." msgid "Invalid values found in the 3mf:" msgstr "Invalid values found in the 3mf:" @@ -4547,11 +4630,27 @@ msgstr "Invalid values found in the 3mf:" msgid "Please correct them in the param tabs" msgstr "Please correct them in the Param tabs" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "The 3mf is not compatible, loading geometry data only!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "Incompatible 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "Component name(s) inside step file not in UTF8 format!" @@ -4623,6 +4722,15 @@ msgstr "Save file as" msgid "Export OBJ file:" msgstr "" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Delete object which is a part of cut object" @@ -4641,15 +4749,15 @@ msgstr "The selected object couldn't be split." msgid "Another export job is running." msgstr "Another export job is running." -msgid "Replace from:" -msgstr "" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "Error during replacement" +msgid "Replace from:" +msgstr "" + msgid "Select a new file" msgstr "Select a new file" @@ -5018,6 +5126,12 @@ msgstr "" msgid "If enabled, g-code window will be displayed." msgstr "" +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Presets" @@ -5072,6 +5186,9 @@ msgstr "Maximum count of recent projects" msgid "Clear my choice on the unsaved projects." msgstr "Clear my choice on the unsaved projects." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Auto-Backup" @@ -5225,8 +5342,11 @@ msgstr "Add/Remove filament" msgid "Add/Remove materials" msgstr "Add/Remove materials" -msgid "Add/Remove printers" -msgstr "Add/Remove printers" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Incompatible" @@ -5409,16 +5529,16 @@ msgstr "Bambu Cool Plate" msgid "PLA Plate" msgstr "PLA Plate" -msgid "Bambu Engineering Plate" -msgstr "" +msgid "Bamabu Engineering Plate" +msgstr "Bambu Engineering Plate" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "" msgid "High temperature Plate" msgstr "" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "" msgid "Send print job to" @@ -5442,9 +5562,6 @@ msgstr "Send complete" msgid "Error code" msgstr "Error code" -msgid "Check the status of current system services" -msgstr "Check the status of current system services" - msgid "Printer local connection failed, please try again." msgstr "Printer local connection failed; please try again." @@ -5548,8 +5665,7 @@ msgid "" msgstr "" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" msgid "Errors" @@ -5567,10 +5683,6 @@ msgstr "" "currently selected printer. It is recommended that you use the same printer " "type for slicing." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s is not supported by the AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5580,11 +5692,34 @@ msgstr "" "they are the required filaments. If they are okay, click \"Confirm\" to " "start printing." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Please click the confirm button if you still want to proceed with printing." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5768,6 +5903,9 @@ msgstr "" "A prime tower is required for smooth timelapse mode. There may be flaws on " "the model without prime tower. Do you want to enable the prime tower?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -6075,6 +6213,9 @@ msgstr "Machine start G-code" msgid "Machine end G-code" msgstr "Machine end G-code" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "Before layer change G-code" @@ -6141,6 +6282,25 @@ msgstr "" msgid "Detached" msgstr "Detached" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Preset" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "The following preset will be deleted too:" @@ -6150,11 +6310,6 @@ msgstr[1] "The following presets will be deleted too:" msgid "Are you sure to %1% the selected preset?" msgstr "Are you sure you want to %1% the selected preset?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Preset" - msgid "All" msgstr "All" @@ -6395,11 +6550,17 @@ msgstr "" msgid "Auto-Calc" msgstr "Auto-Calc" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Flushing volumes for filament change" -msgid "Multiplier" -msgstr "Multiplier" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Flushing volume (mm³) for each filament pair." @@ -6412,6 +6573,9 @@ msgstr "Suggestion: Flushing Volume in range [%d, %d]" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "The multiplier should be in range [%.2f, %.2f]." +msgid "Multiplier" +msgstr "Multiplier" + msgid "unloaded" msgstr "unloaded" @@ -6427,6 +6591,12 @@ msgstr "From" msgid "To" msgstr "To" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Login" @@ -6460,6 +6630,9 @@ msgstr "Paste from clipboard" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "Show/Hide 3Dconnexion devices settings dialog" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Show keyboard shortcuts list" @@ -6710,12 +6883,15 @@ msgstr "A new network plug-in (%s) is available. Do you want to install it?" msgid "New version of Orca Slicer" msgstr "New version of Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "Don't remind me about this version again." +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Done" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN Connection Failed (Sending print file)" @@ -6740,8 +6916,22 @@ msgstr "Access Code" msgid "Where to find your printer's IP and Access Code?" msgstr "Where to find your printer's IP and Access Code?" -msgid "Error: IP or Access Code are not correct" -msgstr "Error: IP or Access Code are not correct" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Model:" @@ -7195,6 +7385,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "Layer height cannot exceed nozzle diameter." +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7640,7 +7835,28 @@ msgstr "" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" msgid "Reverse threshold" @@ -7881,6 +8097,14 @@ msgstr "End G-code" msgid "End G-code when finish the whole printing" msgstr "Add end G-Code when finishing the entire print." +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "Add end G-code when finishing the printing of this filament." @@ -7969,26 +8193,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "" -msgid "Order of inner wall/outer wall/infil" -msgstr "Order of inner wall/outer wall/infill" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "This is the print sequence of inner walls, outer walls, and infill." +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "inner/outer/infill" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "outer/inner/infill" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "infill/inner/outer" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "infill/outer/inner" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "inner-outer-inner/infill" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Height to rod" @@ -8087,9 +8311,6 @@ msgstr "Default color" msgid "Default filament color" msgstr "Default filament color" -msgid "Color" -msgstr "Color" - msgid "Filament notes" msgstr "" @@ -8470,10 +8691,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "" @@ -8835,6 +9052,18 @@ msgid "" "soluble support material" msgstr "" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Ironing type" @@ -9373,6 +9602,22 @@ msgstr "" "hitting the print when traveling more. Using spiral lines to lift z can " "prevent stringing." +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "" @@ -9789,7 +10034,13 @@ msgstr "" "Filament to print support bases and rafts. \"Default\" means no specific " "filament for support, and current filament is used" -msgid "" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." msgstr "" @@ -9822,6 +10073,12 @@ msgstr "This is the number of top interface layers." msgid "Bottom interface layers" msgstr "Bottom interface layers" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Top interface spacing" @@ -10475,111 +10732,18 @@ msgstr "too large line width " msgid " not in range " msgstr " not in range " -msgid "Export 3MF" -msgstr "Export 3mf" - -msgid "Export project as 3MF." -msgstr "This exports the project as a 3mf file." - -msgid "Export slicing data" -msgstr "Export slicing data" - -msgid "Export slicing data to a folder." -msgstr "Export slicing data to a folder" - -msgid "Load slicing data" -msgstr "Load slicing data" - -msgid "Load cached slicing data from directory" -msgstr "Load cached slicing data from directory" - -msgid "Export STL" -msgstr "" - -msgid "Export the objects as multiple STL." -msgstr "" - -msgid "Slice" -msgstr "Slice" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "Slice the plates: 0-all plates, i-plate i, others-invalid" - -msgid "Show command help." -msgstr "This shows command help." - -msgid "UpToDate" -msgstr "UpToDate" - -msgid "Update the configs values of 3mf to latest." -msgstr "Update the configs values of 3mf to latest." - -msgid "Load default filaments" -msgstr "" - -msgid "Load first filament as default for those not loaded" -msgstr "" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "" -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "max triangle count per plate for slicing" - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "max slicing time per plate in seconds" - msgid "No check" msgstr "No check" msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "Do not run any validity checks, such as G-code path conflicts check." -msgid "Normative check" -msgstr "Normative check" - -msgid "Check the normative items." -msgstr "Check the normative items." - -msgid "Output Model Info" -msgstr "Output Model Info" - -msgid "Output the model's information." -msgstr "This outputs the model’s information." - -msgid "Export Settings" -msgstr "Export Settings" - -msgid "Export settings to a file." -msgstr "This exports settings to a file." - -msgid "Send progress to pipe" -msgstr "Send progress to pipe" - -msgid "Send progress to pipe." -msgstr "Send progress to pipe." - -msgid "Arrange Options" -msgstr "Arrange Options" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Arrange options: 0-disable, 1-enable, others-auto" - -msgid "Repetions count" -msgstr "" - -msgid "Repetions count of the whole model" -msgstr "" - msgid "Ensure on bed" msgstr "" @@ -10587,12 +10751,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "" -msgid "Convert Unit" -msgstr "Convert Unit" - -msgid "Convert the units of model" -msgstr "Convert the units of model" - msgid "Orient Options" msgstr "" @@ -10602,47 +10760,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "" -msgid "Rotate around X" -msgstr "" - -msgid "Rotation angle around the X axis in degrees." -msgstr "" - msgid "Rotate around Y" msgstr "" msgid "Rotation angle around the Y axis in degrees." msgstr "" -msgid "Scale the model by a float factor" -msgstr "Scale the model by a float factor" - -msgid "Load General Settings" -msgstr "Load General Settings" - -msgid "Load process/machine settings from the specified file" -msgstr "Load process/machine settings from the specified file" - -msgid "Load Filament Settings" -msgstr "Load Filament Settings" - -msgid "Load filament settings from the specified file list" -msgstr "Load filament settings from the specified file list" - -msgid "Skip Objects" -msgstr "Skip Objects" - -msgid "Skip some objects in this print" -msgstr "Skip some objects in this print" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" - msgid "Data directory" msgstr "" @@ -10652,22 +10775,6 @@ msgid "" "storage." msgstr "" -msgid "Output directory" -msgstr "Output directory" - -msgid "Output directory for the exported files." -msgstr "This is the output directory for exported files." - -msgid "Debug level" -msgstr "Debug level" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" - msgid "Load custom gcode" msgstr "" @@ -10831,9 +10938,6 @@ msgstr "" msgid "Finish" msgstr "Finish" -msgid "Wiki" -msgstr "" - msgid "How to use calibration result?" msgstr "" @@ -10849,6 +10953,12 @@ msgstr "" msgid "Calibration not supported" msgstr "" +msgid "Error desc" +msgstr "" + +msgid "Extra info" +msgstr "" + msgid "Flow Dynamics" msgstr "" @@ -10876,8 +10986,8 @@ msgstr "" msgid "The name cannot be empty." msgstr "" -#, boost-format -msgid "The selected preset: %1% is not found." +#, c-format, boost-format +msgid "The selected preset: %s is not found." msgstr "" msgid "The name cannot be the same as the system preset name." @@ -11157,12 +11267,6 @@ msgid "" "- Different filament brand and family(Brand = Bambu, Family = Basic, Matte)" msgstr "" -msgid "Error desc" -msgstr "" - -msgid "Extra info" -msgstr "" - msgid "Pattern" msgstr "" @@ -11251,101 +11355,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "" - -msgid "Mesh Boolean" -msgstr "" - -msgid "Union" -msgstr "" - -msgid "Difference" -msgstr "" - -msgid "Intersection" -msgstr "" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "" - -msgid "Subtract with" -msgstr "" - -msgid "selected" -msgstr "" - -msgid "Part 1" -msgstr "" - -msgid "Part 2" -msgstr "" - -msgid "Delete input" -msgstr "" - -msgid "Send G-Code to printer host" -msgstr "" - -msgid "Upload to Printer Host with the following filename:" -msgstr "" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" - -msgid "Upload to storage" -msgstr "" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" - -msgid "Upload" -msgstr "" - -msgid "Print host upload queue" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "" - -msgctxt "OfFile" -msgid "Size" -msgstr "" - -msgid "Filename" -msgstr "" - -msgid "Cancel selected" -msgstr "" - -msgid "Show error message" -msgstr "" - -msgid "Enqueued" -msgstr "" - -msgid "Uploading" -msgstr "Uploading" - -msgid "Cancelling" -msgstr "" - -msgid "Error uploading to print host" -msgstr "" - msgid "PA Calibration" msgstr "" @@ -11470,66 +11479,106 @@ msgstr "" msgid "mm/mm" msgstr "" -#, fuzzy -msgid "Physical Printer" -msgstr "Printer" +msgid "Send G-Code to printer host" +msgstr "" -msgid "Print Host upload" +msgid "Upload to Printer Host with the following filename:" msgstr "" -msgid "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." msgstr "" -msgid "Could not get a valid Printer Host reference" +msgid "Upload to storage" msgstr "" -msgid "Success!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" msgstr "" -msgid "Refresh Printers" +msgid "Upload" msgstr "" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." +msgid "Print host upload queue" msgstr "" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "ID" msgstr "" -msgid "Open CA certificate file" +msgid "Progress" msgstr "" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." +msgid "Host" msgstr "" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." +msgctxt "OfFile" +msgid "Size" +msgstr "" + +msgid "Filename" msgstr "" -msgid "Connection to printers connected via the print host failed." +msgid "Cancel selected" msgstr "" -msgid "The start, end or step is not valid value." +msgid "Show error message" msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Enqueued" +msgstr "" + +msgid "Uploading" +msgstr "Uploading" + +msgid "Cancelling" +msgstr "" + +msgid "Error uploading to print host" +msgstr "" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "" + +msgid "Mesh Boolean" +msgstr "" + +msgid "Union" +msgstr "" + +msgid "Difference" +msgstr "" + +msgid "Intersection" +msgstr "" + +msgid "Source Volume" +msgstr "" + +msgid "Tool Volume" +msgstr "" + +msgid "Subtract from" +msgstr "" + +msgid "Subtract with" +msgstr "" + +msgid "selected" +msgstr "" + +msgid "Part 1" msgstr "" -msgid "Need select printer" +msgid "Part 2" +msgstr "" + +msgid "Delete input" msgstr "" -#: resources/data/hints.ini: [hint:3D Scene Operations] +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" #: resources/data/hints.ini: [hint:Cut Tool] @@ -11543,7 +11592,7 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" #: resources/data/hints.ini: [hint:Timelapse] @@ -11580,6 +11629,13 @@ msgid "" "settings for each object/part?" msgstr "" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -11713,11 +11769,224 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." msgstr "" +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." +msgstr "" + +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Tool-Lay on Face" + +#~ msgid "Export as STL" +#~ msgstr "Export as STL" + +#~ msgid "Check cloud service status" +#~ msgstr "Check cloud service status" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Please input a valid value (K in 0~0.5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Export All Objects as STL" + +#~ msgid "Slice ok." +#~ msgstr "Slice complete" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "You should update your software.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "The 3mf is not compatible, loading geometry data only!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Incompatible 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "Add/Remove printers" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s is not supported by the AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Don't remind me about this version again." + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Error: IP or Access Code are not correct" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Order of inner wall/outer wall/infill" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "This is the print sequence of inner walls, outer walls, and infill." + +#~ msgid "inner/outer/infill" +#~ msgstr "inner/outer/infill" + +#~ msgid "outer/inner/infill" +#~ msgstr "outer/inner/infill" + +#~ msgid "infill/inner/outer" +#~ msgstr "infill/inner/outer" + +#~ msgid "infill/outer/inner" +#~ msgstr "infill/outer/inner" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "inner-outer-inner/infill" + +#~ msgid "Export 3MF" +#~ msgstr "Export 3mf" + +#~ msgid "Export project as 3MF." +#~ msgstr "This exports the project as a 3mf file." + +#~ msgid "Export slicing data" +#~ msgstr "Export slicing data" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Export slicing data to a folder" + +#~ msgid "Load slicing data" +#~ msgstr "Load slicing data" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Load cached slicing data from directory" + +#~ msgid "Slice" +#~ msgstr "Slice" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "Slice the plates: 0-all plates, i-plate i, others-invalid" + +#~ msgid "Show command help." +#~ msgstr "This shows command help." + +#~ msgid "UpToDate" +#~ msgstr "UpToDate" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Update the configs values of 3mf to latest." + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "max triangle count per plate for slicing" + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "max slicing time per plate in seconds" + +#~ msgid "Normative check" +#~ msgstr "Normative check" + +#~ msgid "Check the normative items." +#~ msgstr "Check the normative items." + +#~ msgid "Output Model Info" +#~ msgstr "Output Model Info" + +#~ msgid "Output the model's information." +#~ msgstr "This outputs the model’s information." + +#~ msgid "Export Settings" +#~ msgstr "Export Settings" + +#~ msgid "Export settings to a file." +#~ msgstr "This exports settings to a file." + +#~ msgid "Send progress to pipe" +#~ msgstr "Send progress to pipe" + +#~ msgid "Send progress to pipe." +#~ msgstr "Send progress to pipe." + +#~ msgid "Arrange Options" +#~ msgstr "Arrange Options" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Arrange options: 0-disable, 1-enable, others-auto" + +#~ msgid "Convert Unit" +#~ msgstr "Convert Unit" + +#~ msgid "Convert the units of model" +#~ msgstr "Convert the units of model" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Scale the model by a float factor" + +#~ msgid "Load General Settings" +#~ msgstr "Load General Settings" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Load process/machine settings from the specified file" + +#~ msgid "Load Filament Settings" +#~ msgstr "Load Filament Settings" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "Load filament settings from the specified file list" + +#~ msgid "Skip Objects" +#~ msgstr "Skip Objects" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Skip some objects in this print" + +#~ msgid "Output directory" +#~ msgstr "Output directory" + +#~ msgid "Output directory for the exported files." +#~ msgstr "This is the output directory for exported files." + +#~ msgid "Debug level" +#~ msgstr "Debug level" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" + +#, fuzzy +#~ msgid "Physical Printer" +#~ msgstr "Printer" + #~ msgid "Embeded" #~ msgstr "Embedded" @@ -11812,9 +12081,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Score" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bambu Engineering Plate" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu High Temperature Plate" diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index 7ff0db9f6cf..e757da3b2df 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: \n" "Last-Translator: Carlos Fco. Caruncho Serrano \n" "Language-Team: \n" @@ -101,6 +101,9 @@ msgstr "No auto soportes" msgid "Support Generated" msgstr "Soportes Generados" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Tumbar boca abajo" @@ -149,8 +152,8 @@ msgstr "Relleno de cubos" msgid "Height range" msgstr "Rango de altura" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Alternar Malla Alámbrica" @@ -180,9 +183,15 @@ msgstr "Pintado con: Filamento %1%" msgid "Move" msgstr "Mover" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Rotar" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Optimizar orientación" @@ -192,13 +201,13 @@ msgstr "Aplicar" msgid "Scale" msgstr "Escalar" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "" "Error: Por favor, cierre primero todos los menús de la barra de herramientas" -msgid "Tool-Lay on Face" -msgstr "Herramienta-Tumbar Boca Abajo" - msgid "in" msgstr "pulg" @@ -494,6 +503,15 @@ msgstr "Pintar costura" msgid "Remove selection" msgstr "Borrar selección" +msgid "Entering Seam painting" +msgstr "Entrando en la sección de pintado de costura" + +msgid "Leaving Seam painting" +msgstr "Saliendo de la sección de pintado de la costura" + +msgid "Paint-on seam editing" +msgstr "Edición de costuras pintadas" + msgid "Font" msgstr "Fuente" @@ -723,6 +741,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Actualización de política de privacidad" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Cargando" @@ -916,8 +942,11 @@ msgstr "Imprimible" msgid "Fix model" msgstr "Reparar el modelo" -msgid "Export as STL" -msgstr "Exportar como STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Recargar desde el disco" @@ -1180,6 +1209,9 @@ msgstr "Haga clic en el icono para editar la pintura de color del objeto" msgid "Click the icon to shift this object to the bed" msgstr "Presionar el icono para desplazar este objeto a la cama" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Cargando archivo" @@ -1440,6 +1472,18 @@ msgstr "Abrir siguiente consejo." msgid "Open Documentation in web browser." msgstr "Abrir la Documentación en el navegador." +msgid "Color" +msgstr "Color" + +msgid "Pause" +msgstr "Pausa" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Personalizado" + msgid "Pause:" msgstr "Pausa:" @@ -1515,8 +1559,8 @@ msgstr "..." msgid "Failed to connect to the server" msgstr "No se ha podido conectar con el servidor" -msgid "Check cloud service status" -msgstr "Check cloud service status" +msgid "Check the status of current system services" +msgstr "Check the status of current system services" msgid "code" msgstr "code" @@ -1783,6 +1827,14 @@ msgstr "Enviando el trabajo de impresión a través de la LAN" msgid "Sending print job through cloud service" msgstr "Enviando trabajo de impresión a través del servicio en la nube" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Servicio No Disponible" @@ -2013,11 +2065,11 @@ msgstr "¿Estás seguro que quieres limpiar la información de filamento?" msgid "You need to select the material type and color first." msgstr "Necesitas seleccionar el tipo y el color del material primero." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Por favor, introduce un valor válido (K en 0~0.5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "Por favor, introduce un valor válido (K en 0~0.5, N en 0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Otro color" @@ -2415,9 +2467,6 @@ msgstr "Rectangular" msgid "Circular" msgstr "Circular" -msgid "Custom" -msgstr "Personalizado" - msgid "Load shape from STL..." msgstr "Cargar forma desde STL..." @@ -2935,6 +2984,9 @@ msgstr "Descargado" msgid "Total" msgstr "Total" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Estimación total" @@ -3022,15 +3074,18 @@ msgstr "Cambio de color" msgid "Print" msgstr "Imprimir" -msgid "Pause" -msgstr "Pausa" - msgid "Printer" msgstr "Impresora" msgid "Print settings" msgstr "Configuración de impresión" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Estimación de Tiempo" @@ -3199,7 +3254,7 @@ msgstr "Volumen:" msgid "Size:" msgstr "Tamaño:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3262,15 +3317,15 @@ msgstr "Calibración del Caudal" msgid "Start Calibration" msgstr "Iniciar Calibración" -msgid "No step selected" -msgstr "No se ha seleccionado paso" - msgid "Completed" msgstr "Completado" msgid "Calibrating" msgstr "Calibrando" +msgid "No step selected" +msgstr "No se ha seleccionado paso" + msgid "Auto-record Monitoring" msgstr "Monitorización de Auto-Grabado" @@ -3485,8 +3540,11 @@ msgstr "Cargar configuraciones" msgid "Import" msgstr "Importar" -msgid "Export all objects as STL" -msgstr "Exportar todos los objetos como STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Exportar 3MF genérico" @@ -3769,9 +3827,6 @@ msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "" "La impresora está ocupada descargando. Por favor, espere a que finalice." -msgid "Loading..." -msgstr "Cargando..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" "Fallo inicializando (No soportado en la actual versión de la impresora)!" @@ -3835,6 +3890,9 @@ msgstr "Reproduciendo..." msgid "Load failed [%d]!" msgstr "¡La carga ha fallado [%d]!" +msgid "Loading..." +msgstr "Cargando..." + msgid "Year" msgstr "Año" @@ -3954,12 +4012,25 @@ msgstr "Descarga finalizada" msgid "Downloading %d%%..." msgstr "Descargando %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "No soportado en la actual versión de la impresora." msgid "Storage unavailable, insert SD card." msgstr "Almacenamiento no disponible, inserte la tarjeta SD." +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Velocidad:" @@ -4312,6 +4383,12 @@ msgstr "Nuevo complemento de red disponible." msgid "Details" msgstr "Detalles" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "Wiki" + msgid "Undo integration failed." msgstr "La operación de deshacer ha fallado." @@ -4360,9 +4437,6 @@ msgstr "COMPLETADO" msgid "Cancel upload" msgstr "Carga cancelada" -msgid "Slice ok." -msgstr "Laminado correcto." - msgid "Jump to" msgstr "Ir a" @@ -4468,6 +4542,9 @@ msgstr "Autorecuperar desde pérdida de paso" msgid "Allow Prompt Sound" msgstr "Permitir Sonido de Aviso" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Global" @@ -4562,6 +4639,9 @@ msgstr "Sicronizar filamentos de la lista AMS" msgid "Set filaments to use" msgstr "Elegir filamentos para usar" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4671,26 +4751,29 @@ msgstr "" "geometría." #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"La versión de 3mf %s es más nueva que la versión de %s %s, encontradas las " -"siguientes llaves no reconocidas:" -msgid "You'd better upgrade your software.\n" -msgstr "Será mejor que actualices tu software.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Nueva versión 3mf" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"La versión de 3mf %s es más nueva que la versión de %s %s, se sugiere " -"actualizar su sofware." msgid "Invalid values found in the 3mf:" msgstr "Valores inválidos encontrados en el 3mf:" @@ -4698,11 +4781,27 @@ msgstr "Valores inválidos encontrados en el 3mf:" msgid "Please correct them in the param tabs" msgstr "Por favor, corrijalos en las pestañas de parámetros" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "¡El 3mf no es compatible, cargue solamente los datos de geometría!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "3mf Incompatible" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "" @@ -4779,6 +4878,15 @@ msgstr "Guardar archivo como:" msgid "Export OBJ file:" msgstr "Exportar archivo OBJ:" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Borrar objetos los cuales son piezas del objeto cortado" @@ -4797,15 +4905,15 @@ msgstr "El objeto seleccionado no ha podido ser dividido." msgid "Another export job is running." msgstr "Otro trabajo de exportación está en marcha." -msgid "Replace from:" -msgstr "Sustituir desde:" - msgid "Unable to replace with more than one volume" msgstr "No se puede sustituir con más de un volumen" msgid "Error during replace" msgstr "Error durante el reemplazo" +msgid "Replace from:" +msgstr "Sustituir desde:" + msgid "Select a new file" msgstr "Seleccione un nuevo archivo" @@ -5190,6 +5298,12 @@ msgstr "Mostrar la ventana de G-Code" msgid "If enabled, g-code window will be displayed." msgstr "Si está activado, se mostrará la ventana de G-Code." +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Preajustes" @@ -5246,6 +5360,9 @@ msgstr "Máxima cantidad de proyectos recientes" msgid "Clear my choice on the unsaved projects." msgstr "Limpiar mi elección de proyectos no guardados." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Copia de seguridad automática" @@ -5399,8 +5516,11 @@ msgstr "Añadir/Borrar filamentos" msgid "Add/Remove materials" msgstr "Añadir/Borrar materiales" -msgid "Add/Remove printers" -msgstr "Añadir/Borrar impresoras" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Incompatible" @@ -5587,17 +5707,17 @@ msgstr "Bandeja frío Bambu" msgid "PLA Plate" msgstr "PLA Plate" -msgid "Bambu Engineering Plate" -msgstr "Bandeja de Ingeniería Bambu" +msgid "Bamabu Engineering Plate" +msgstr "Bandeja de Ingeniería Bambú" -msgid "Bambu Smooth PEI Plate" -msgstr "Bandeja PEI lisa Bambu" +msgid "Bamabu Smooth PEI Plate" +msgstr "" msgid "High temperature Plate" msgstr "Bandeja de Alta Temperatura" -msgid "Bambu Textured PEI Plate" -msgstr "Bandeja Texturizada PEI" +msgid "Bamabu Textured PEI Plate" +msgstr "" msgid "Send print job to" msgstr "Enviar el trabajo de impresión a" @@ -5620,9 +5740,6 @@ msgstr "envío completo" msgid "Error code" msgstr "Error code" -msgid "Check the status of current system services" -msgstr "Check the status of current system services" - msgid "Printer local connection failed, please try again." msgstr "Printer local connection failed; please try again." @@ -5736,11 +5853,8 @@ msgstr "" "generará videos timelapse." msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" -"Cuando imprima por objeto, las máquinas con estructura I3 no generará videos " -"timelapse." msgid "Errors" msgstr "Errores" @@ -5757,10 +5871,6 @@ msgstr "" "consistencia con la impresora seleccionada actualmente. Es recomendable que " "use el mismo tipo de impresora para laminar." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s no está soportado por el AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5770,12 +5880,35 @@ msgstr "" "compruebe si son los filamentos requeriso. Si lo son, presione \"Confirmar\" " "para empezar a imprimir." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Por favor, presione el botón de confirmar si aún quieres proceder con la " "impresión." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "Conectando a la impresora. No es posible cancelar durante la conexión." @@ -5968,6 +6101,9 @@ msgstr "" "La torre de purga es necesaria para que el timelapse sea fluido. Puede haber " "defectos en el modelo sin torre de purga. ¿Desea activar la torre de purga?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -6288,6 +6424,9 @@ msgstr "G-Code de inicio" msgid "Machine end G-code" msgstr "G-Code final" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "G-Code para antes del cambio de capa" @@ -6358,6 +6497,25 @@ msgstr "Retracción de firmware" msgid "Detached" msgstr "Separado" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Preestablecido" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "El siguiente preajuste también se eliminará." @@ -6367,11 +6525,6 @@ msgstr[1] "Los siguientes preajustes también se eliminarán." msgid "Are you sure to %1% the selected preset?" msgstr "¿Está seguro de %1% el preajuste seleccionado?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Preestablecido" - msgid "All" msgstr "Todo" @@ -6617,11 +6770,17 @@ msgstr "Espaciado de línea de moldeado de extremo" msgid "Auto-Calc" msgstr "Auto-Calc" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Volúmenes de limpieza para el cambio de filamentos" -msgid "Multiplier" -msgstr "Multiplicador" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Volumen de limpieza (mm³) para cada par de filamentos." @@ -6634,6 +6793,9 @@ msgstr "Sugerencias: Volumen de Flujo en rango [%d, %d]" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "El multiplicador debería estar en el rango [%.2f, %.2f]." +msgid "Multiplier" +msgstr "Multiplicador" + msgid "unloaded" msgstr "descargado" @@ -6649,6 +6811,12 @@ msgstr "Desde" msgid "To" msgstr "A" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Inicio de sesión" @@ -6683,6 +6851,9 @@ msgstr "Pegar desde el portapapeles" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "Mostrar/Ocultar el diálogo de ajustes de los dispositivos 3Dconnexion" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Muestra lista de atajos de teclado" @@ -6939,12 +7110,15 @@ msgstr "Un nuevo plug-in de red(%s) está disponible. ¿Desea instalarlo?" msgid "New version of Orca Slicer" msgstr "Nueva versión de Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "No volver a recordarme está versión otra vez" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Hecho" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "Conexión de red fallida (Mandando archivo de impresión)" @@ -6970,8 +7144,22 @@ msgstr "Código de Acceso" msgid "Where to find your printer's IP and Access Code?" msgstr "¿Dónde encontrar la IP de su impresora y el Código de Acceso?" -msgid "Error: IP or Access Code are not correct" -msgstr "Error: la IP o el Código de Acceso no son correctos" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "Test" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Modelo:" @@ -7453,6 +7641,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "La altura de la capa no puede superar el diámetro de la boquilla" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7940,11 +8133,29 @@ msgstr "Inversión de voladizo" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" -"Extruya los perímetros que tienen una parte sobre un voladizo en sentido " -"inverso en las capas impares. Este patrón alterno puede mejorar " -"drásticamente los voladizos pronunciados." msgid "Reverse threshold" msgstr "Umbral inverso" @@ -8205,6 +8416,14 @@ msgstr "G-Code final" msgid "End G-code when finish the whole printing" msgstr "Finalizar el G-Code cuando termine la impresión completa" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "Terminar el G-Code cuando se termine de imprimir este filamento" @@ -8305,28 +8524,26 @@ msgstr "" "Esto configura el umbral para longitud de perímetro pequeño. El umbral por " "defecto es 0mm" -msgid "Order of inner wall/outer wall/infil" -msgstr "Orden del perímetro interior/perímetro exterior/relleno" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " +msgid "Print sequence of inner wall and outer wall. " msgstr "" -"Imprimir la secuencia del perímetro interior, el perímetro exterior y el " -"relleno. " -msgid "inner/outer/infill" -msgstr "interior/exterior/relleno" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "exterior/interior/relleno" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "relleno/interior/exterior" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "relleno/exterior/interior" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "interior-exterior-interior/relleno" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Altura a la barra" @@ -8430,9 +8647,6 @@ msgstr "Color por defecto" msgid "Default filament color" msgstr "Color de filamento por defecto" -msgid "Color" -msgstr "Color" - msgid "Filament notes" msgstr "Anotaciones de filamento" @@ -8889,10 +9103,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "El max_accel_to_decel de Klipper se ajustará a este %% de aceleración" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "Jerk de los perímetros externos" @@ -9311,6 +9521,18 @@ msgstr "" "adyacentes. Útil para impresiones multiextrusoras con materiales " "translúcidos o material de soporte soluble manualmente" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Tipo de alisado" @@ -9939,6 +10161,27 @@ msgstr "" "boquilla golpee la impresión cuando se desplaza. El uso de la línea espiral " "para levantar z puede evitar el encordado" +msgid "Z hop lower boundary" +msgstr "Límite inferior de salto Z" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" +"Z hop sólo entrará en vigor cuando Z esté por encima de este valor y se " +"encuentre por debajo del parámetro: \"Límite superior del salto Z\"" + +msgid "Z hop upper boundary" +msgstr "Límite superior de salto Z" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" +"Si este valor es positivo, Z hop sólo entrará en vigor cuando Z esté por " +"encima del parámetro \"Límite inferior de salto Z\" y esté por debajo de " +"este valor" + msgid "Z hop type" msgstr "Tipo de salto Z" @@ -10406,6 +10649,12 @@ msgstr "" "defecto\" significa que no hay filamento específico para el soporte y se " "utiliza el filamento actual" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." @@ -10442,8 +10691,14 @@ msgstr "Número de capas de interfaz superior" msgid "Bottom interface layers" msgstr "Capas de la interfaz inferior" -msgid "Top interface spacing" -msgstr "Distancia de la interfaz superior" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + +msgid "Top interface spacing" +msgstr "Distancia de la interfaz superior" msgid "Spacing of interface lines. Zero means solid interface" msgstr "" @@ -11180,70 +11435,12 @@ msgstr "demasiada anchura de línea " msgid " not in range " msgstr " fuera de rango " -msgid "Export 3MF" -msgstr "Exportar 3MF" - -msgid "Export project as 3MF." -msgstr "Exportar el proyecto como 3MF." - -msgid "Export slicing data" -msgstr "Exportar datos de laminado" - -msgid "Export slicing data to a folder." -msgstr "Exportar datos de laminado a una carpeta." - -msgid "Load slicing data" -msgstr "Cargar datos de laminado" - -msgid "Load cached slicing data from directory" -msgstr "Cargar datos de laminado en caché desde el directorio" - -msgid "Export STL" -msgstr "Exportar STL" - -msgid "Export the objects as multiple STL." -msgstr "Exportar los objectos como multiples STL." - -msgid "Slice" -msgstr "Laminar" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "" -"Cortar las bandejas: 0-todas las bandejas, i-bandeja i, otras-inválidas" - -msgid "Show command help." -msgstr "Mostrar la ayuda del comando." - -msgid "UpToDate" -msgstr "Actualizado" - -msgid "Update the configs values of 3mf to latest." -msgstr "Actualice los valores de configuración de 3mf a la última versión." - -msgid "Load default filaments" -msgstr "Cargar los filamentos por defecto" - -msgid "Load first filament as default for those not loaded" -msgstr "Carga el primer filamento por defecto para los no cargados" - msgid "Minimum save" msgstr "Salvado mínimo" msgid "export 3mf with minimum size." msgstr "exportar 3mf con el tamaño mínimo." -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "número máximo de triángulos por plato para laminar." - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "tiempo máximo de corte por bandeja en segundos." - msgid "No check" msgstr "No comprobado" @@ -11252,42 +11449,6 @@ msgstr "" "No ejecute ninguna comprobación de validez, como la comprobación de " "conflictos de ruta de G-Code." -msgid "Normative check" -msgstr "Comprobación de normativa" - -msgid "Check the normative items." -msgstr "Comprueba los elementos normativos." - -msgid "Output Model Info" -msgstr "Información del modelo de salida" - -msgid "Output the model's information." -msgstr "Salida de la información del modelo." - -msgid "Export Settings" -msgstr "Ajustes de exportación" - -msgid "Export settings to a file." -msgstr "Exporta los ajustes a un archivo." - -msgid "Send progress to pipe" -msgstr "Enviar el progreso a la tubería" - -msgid "Send progress to pipe." -msgstr "Enviar el progreso a la tubería." - -msgid "Arrange Options" -msgstr "Opciones de posicionamiento" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Opciones de posicionamiento: 0-desactivar, 1-activar, otras-auto" - -msgid "Repetions count" -msgstr "Cantidad de repeticiones" - -msgid "Repetions count of the whole model" -msgstr "Cantidad de repeticiones del modelo completo" - msgid "Ensure on bed" msgstr "Asegurar en la cama" @@ -11297,12 +11458,6 @@ msgstr "" "Eleva el objeto sobre la cama cuando está parcialmente bajo. Deshabilitado " "por defecto" -msgid "Convert Unit" -msgstr "Convertir Unidad" - -msgid "Convert the units of model" -msgstr "Convertir las unidades del modelo" - msgid "Orient Options" msgstr "Opciones de Orientación" @@ -11312,51 +11467,12 @@ msgstr "Opciones de orientación: 0-deshabilitar. 1-habilitar. otros-auto" msgid "Rotation angle around the Z axis in degrees." msgstr "El ángulo de rotación alrededor del eje Z en grados." -msgid "Rotate around X" -msgstr "Rotar alrededor de X" - -msgid "Rotation angle around the X axis in degrees." -msgstr "El ángulo de rotación alrededor del eje X en grados." - msgid "Rotate around Y" msgstr "Rotar alrededor de Y" msgid "Rotation angle around the Y axis in degrees." msgstr "El ángulo de rotación alrededor del eje Y en grados." -msgid "Scale the model by a float factor" -msgstr "Escala el modelo por un factor de flotación" - -msgid "Load General Settings" -msgstr "Cargar los ajustes generales" - -msgid "Load process/machine settings from the specified file" -msgstr "Cargar los ajustes del proceso/máquina desde el archivo especificado" - -msgid "Load Filament Settings" -msgstr "Cargar los ajustes del filamento" - -msgid "Load filament settings from the specified file list" -msgstr "" -"Cargar los ajustes del filamento desde la lista de archivos especificada" - -msgid "Skip Objects" -msgstr "Omitir objetos" - -msgid "Skip some objects in this print" -msgstr "Omitir algunos objetos en esta impresión" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" -"carga los ajustes actualizados de proceso/máquina cuando se usa actualizar" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" -"carga los ajustes actualizados de proceso/máquina desde el archivo " -"especificado cuando se usa actualizar" - msgid "Data directory" msgstr "Directorio de datos" @@ -11369,22 +11485,6 @@ msgstr "" "mantener diferentes perfiles o incluir configuraciones desde un " "almacenamiento en red." -msgid "Output directory" -msgstr "Directorio de salida" - -msgid "Output directory for the exported files." -msgstr "Directorio de salida para los archivos exportados." - -msgid "Debug level" -msgstr "Nivel de depuración" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Ajusta el nivel de registro de depuración. 0:fatal, 1:error, 2:advertencia, " -"3:información, 4:depuración, 5:rastreo\n" - msgid "Load custom gcode" msgstr "Cargar G-Code personalizado" @@ -11548,9 +11648,6 @@ msgstr "Calibración" msgid "Finish" msgstr "Finalizar" -msgid "Wiki" -msgstr "Wiki" - msgid "How to use calibration result?" msgstr "¿Cómo usar el resultado de la calibración?" @@ -11568,6 +11665,12 @@ msgstr "" msgid "Calibration not supported" msgstr "Calibración no soportada" +msgid "Error desc" +msgstr "Error en la descripción" + +msgid "Extra info" +msgstr "Información extra" + msgid "Flow Dynamics" msgstr "Dinámicas de Flujo" @@ -11600,9 +11703,9 @@ msgstr "" msgid "The name cannot be empty." msgstr "El nombre no puede estar vacío." -#, boost-format -msgid "The selected preset: %1% is not found." -msgstr "El ajuste seleccionado: %1% no encontrado." +#, c-format, boost-format +msgid "The selected preset: %s is not found." +msgstr "" msgid "The name cannot be the same as the system preset name." msgstr "El nombre no puede ser el mismo que el nombre de ajuste del sistema." @@ -11976,12 +12079,6 @@ msgstr "" "- Las diferentes marcas de filamento y familias(Marca = Bambú. Familia = " "Básica, Mate)" -msgid "Error desc" -msgstr "Error en la descripción" - -msgid "Extra info" -msgstr "Información extra" - msgid "Pattern" msgstr "Patrón" @@ -12077,105 +12174,6 @@ msgstr "" "Hay varias direcciones IP resueltas del nombre del host %1%.\n" "Por favor, seleccione la que debe usarse." -msgid "Unable to perform boolean operation on selected parts" -msgstr "" -"No es posible realizar la operación booleana en las partes selecionadas" - -msgid "Mesh Boolean" -msgstr "Malla Booleana" - -msgid "Union" -msgstr "Unión" - -msgid "Difference" -msgstr "Diferencia" - -msgid "Intersection" -msgstr "Intersección" - -msgid "Source Volume" -msgstr "Volumen de origen" - -msgid "Tool Volume" -msgstr "Volumen de herramienta" - -msgid "Subtract from" -msgstr "Restar de" - -msgid "Subtract with" -msgstr "Restar con" - -msgid "selected" -msgstr "seleccionado" - -msgid "Part 1" -msgstr "Parte 1" - -msgid "Part 2" -msgstr "Parte 2" - -msgid "Delete input" -msgstr "Borrado de entrada" - -msgid "Send G-Code to printer host" -msgstr "Enviar G-Code al host de impresión" - -msgid "Upload to Printer Host with the following filename:" -msgstr "Subido al Host de Impresión con el siguiente nombre de archivo:" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" -"Use barras oblicuas como separador de directorio \n" -"si es necesario." - -msgid "Upload to storage" -msgstr "Subir a almacenamiento" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" -"El nombre de archivo que va a cargar no acaba en \"%s\". ¿Desea continuar?" - -msgid "Upload" -msgstr "Cargar" - -msgid "Print host upload queue" -msgstr "Imprimir cola de carga del host" - -msgid "ID" -msgstr "ID" - -msgid "Progress" -msgstr "Progreso" - -msgid "Host" -msgstr "Host" - -msgctxt "OfFile" -msgid "Size" -msgstr "Tamaño" - -msgid "Filename" -msgstr "Nombre de archivo" - -msgid "Cancel selected" -msgstr "Cancelar selección" - -msgid "Show error message" -msgstr "Mostrar mensaje de error" - -msgid "Enqueued" -msgstr "En cola" - -msgid "Uploading" -msgstr "Subiendo" - -msgid "Cancelling" -msgstr "Cancelado" - -msgid "Error uploading to print host" -msgstr "Error al subir al host de impresión" - msgid "PA Calibration" msgstr "Calibración PA" @@ -12316,80 +12314,111 @@ msgstr "Finalizar " msgid "mm/mm" msgstr "mm/mm" -msgid "Physical Printer" -msgstr "Impresora física" +msgid "Send G-Code to printer host" +msgstr "Enviar G-Code al host de impresión" -msgid "Print Host upload" -msgstr "Carga de Host de Impresión" +msgid "Upload to Printer Host with the following filename:" +msgstr "Subido al Host de Impresión con el siguiente nombre de archivo:" -msgid "Test" -msgstr "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "" +"Use barras oblicuas como separador de directorio \n" +"si es necesario." -msgid "Could not get a valid Printer Host reference" -msgstr "No se ha podido obtener una referencia de host de impresora válida" +msgid "Upload to storage" +msgstr "Subir a almacenamiento" -msgid "Success!" -msgstr "¡Exitoso!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "" +"El nombre de archivo que va a cargar no acaba en \"%s\". ¿Desea continuar?" -msgid "Refresh Printers" -msgstr "Refrescar Impresoras" +msgid "Upload" +msgstr "Cargar" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." -msgstr "" -"El archivo HTTPS CA es opcional. Solo es necesario si utiliza HTTPS con un " -"certificado autofirmado." +msgid "Print host upload queue" +msgstr "Imprimir cola de carga del host" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "" -"Archivos de certificado (*.crt, *.pem)|*.crt;*.pem|Todos los archivos|*.*" +msgid "ID" +msgstr "ID" -msgid "Open CA certificate file" -msgstr "Abrir archivo de certificado CA" +msgid "Progress" +msgstr "Progreso" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." -msgstr "" -"En este sistema, %s utiliza certificados HTTPS del almacén de certificados o " -"llavero del sistema." +msgid "Host" +msgstr "Host" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." -msgstr "" -"Para utilizar un archivo de CA personalizado, importe su archivo de CA a " -"Almacén de certificados / Llavero." +msgctxt "OfFile" +msgid "Size" +msgstr "Tamaño" -msgid "Connection to printers connected via the print host failed." -msgstr "" -"Ha fallado la conexión a impresoras conectadas a través del host de " -"impresión." +msgid "Filename" +msgstr "Nombre de archivo" + +msgid "Cancel selected" +msgstr "Cancelar selección" -msgid "The start, end or step is not valid value." -msgstr "El inicio, el final o el paso no tienen un valor válido." +msgid "Show error message" +msgstr "Mostrar mensaje de error" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Enqueued" +msgstr "En cola" + +msgid "Uploading" +msgstr "Subiendo" + +msgid "Cancelling" +msgstr "Cancelado" + +msgid "Error uploading to print host" +msgstr "Error al subir al host de impresión" + +msgid "Unable to perform boolean operation on selected parts" msgstr "" -"No es posible calibrar debido a que el valor del rango de calibración es muy " -"grande, o el paso es muy pequeño" +"No es posible realizar la operación booleana en las partes selecionadas" + +msgid "Mesh Boolean" +msgstr "Malla Booleana" + +msgid "Union" +msgstr "Unión" + +msgid "Difference" +msgstr "Diferencia" -msgid "Need select printer" -msgstr "Necesario seleccionar impresora" +msgid "Intersection" +msgstr "Intersección" + +msgid "Source Volume" +msgstr "Volumen de origen" + +msgid "Tool Volume" +msgstr "Volumen de herramienta" + +msgid "Subtract from" +msgstr "Restar de" + +msgid "Subtract with" +msgstr "Restar con" + +msgid "selected" +msgstr "seleccionado" + +msgid "Part 1" +msgstr "Parte 1" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "Part 2" +msgstr "Parte 2" + +msgid "Delete input" +msgstr "Borrado de entrada" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"Operaciones de la escena 3D\n" -"¿Sabías cómo controlar la vista y la selección de objetos/partes con el " -"ratón y el panel táctil en la escena 3D?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -12405,11 +12434,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Fijar modelo\n" -"¿Sabías que puedes arreglar un modelo 3D dañado para evitar muchos problemas " -"de corte?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -12460,6 +12486,13 @@ msgstr "" "¿Sabías que puedes ver todos los objetos/piezas en una lista y cambiar los " "ajustes de cada objeto/pieza?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -12655,14 +12688,379 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." msgstr "" -"Cuando es necesario imprimir con la puerta de la impresora abierta\n" -"Abrir la puerta de la impresora puede reducir la probabilidad de atasco del " -"extrusor/hotend al imprimir filamento de baja temperatura con una " -"temperatura de carcasa más alta. Más información sobre esto en la Wiki." + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." +msgstr "" + +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Herramienta-Tumbar Boca Abajo" + +#~ msgid "Export as STL" +#~ msgstr "Exportar como STL" + +#~ msgid "Check cloud service status" +#~ msgstr "Check cloud service status" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Por favor, introduce un valor válido (K en 0~0.5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "Por favor, introduce un valor válido (K en 0~0.5, N en 0.6~2.0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Exportar todos los objetos como STL" + +#~ msgid "Slice ok." +#~ msgstr "Laminado correcto." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "La versión de 3mf %s es más nueva que la versión de %s %s, encontradas " +#~ "las siguientes llaves no reconocidas:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Será mejor que actualices tu software.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "La versión de 3mf %s es más nueva que la versión de %s %s, se sugiere " +#~ "actualizar su sofware." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "¡El 3mf no es compatible, cargue solamente los datos de geometría!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "3mf Incompatible" + +#~ msgid "Add/Remove printers" +#~ msgstr "Añadir/Borrar impresoras" + +#~ msgid "Bambu Engineering Plate" +#~ msgstr "Bandeja de Ingeniería Bambu" + +#~ msgid "Bambu Smooth PEI Plate" +#~ msgstr "Bandeja PEI lisa Bambu" + +#~ msgid "Bambu Textured PEI Plate" +#~ msgstr "Bandeja Texturizada PEI" + +#~ msgid "" +#~ "When print by object, machines with I3 structure will not generate " +#~ "timelapse videos." +#~ msgstr "" +#~ "Cuando imprima por objeto, las máquinas con estructura I3 no generará " +#~ "videos timelapse." + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s no está soportado por el AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "No volver a recordarme está versión otra vez" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Error: la IP o el Código de Acceso no son correctos" + +#~ msgid "" +#~ "Extrude perimeters that have a part over an overhang in the reverse " +#~ "direction on odd layers. This alternating pattern can drastically improve " +#~ "steep overhang." +#~ msgstr "" +#~ "Extruya los perímetros que tienen una parte sobre un voladizo en sentido " +#~ "inverso en las capas impares. Este patrón alterno puede mejorar " +#~ "drásticamente los voladizos pronunciados." + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Orden del perímetro interior/perímetro exterior/relleno" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "" +#~ "Imprimir la secuencia del perímetro interior, el perímetro exterior y el " +#~ "relleno. " + +#~ msgid "inner/outer/infill" +#~ msgstr "interior/exterior/relleno" + +#~ msgid "outer/inner/infill" +#~ msgstr "exterior/interior/relleno" + +#~ msgid "infill/inner/outer" +#~ msgstr "relleno/interior/exterior" + +#~ msgid "infill/outer/inner" +#~ msgstr "relleno/exterior/interior" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "interior-exterior-interior/relleno" + +#~ msgid "Export 3MF" +#~ msgstr "Exportar 3MF" + +#~ msgid "Export project as 3MF." +#~ msgstr "Exportar el proyecto como 3MF." + +#~ msgid "Export slicing data" +#~ msgstr "Exportar datos de laminado" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Exportar datos de laminado a una carpeta." + +#~ msgid "Load slicing data" +#~ msgstr "Cargar datos de laminado" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Cargar datos de laminado en caché desde el directorio" + +#~ msgid "Export STL" +#~ msgstr "Exportar STL" + +#~ msgid "Export the objects as multiple STL." +#~ msgstr "Exportar los objectos como multiples STL." + +#~ msgid "Slice" +#~ msgstr "Laminar" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "" +#~ "Cortar las bandejas: 0-todas las bandejas, i-bandeja i, otras-inválidas" + +#~ msgid "Show command help." +#~ msgstr "Mostrar la ayuda del comando." + +#~ msgid "UpToDate" +#~ msgstr "Actualizado" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Actualice los valores de configuración de 3mf a la última versión." + +#~ msgid "Load default filaments" +#~ msgstr "Cargar los filamentos por defecto" + +#~ msgid "Load first filament as default for those not loaded" +#~ msgstr "Carga el primer filamento por defecto para los no cargados" + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "número máximo de triángulos por plato para laminar." + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "tiempo máximo de corte por bandeja en segundos." + +#~ msgid "Normative check" +#~ msgstr "Comprobación de normativa" + +#~ msgid "Check the normative items." +#~ msgstr "Comprueba los elementos normativos." + +#~ msgid "Output Model Info" +#~ msgstr "Información del modelo de salida" + +#~ msgid "Output the model's information." +#~ msgstr "Salida de la información del modelo." + +#~ msgid "Export Settings" +#~ msgstr "Ajustes de exportación" + +#~ msgid "Export settings to a file." +#~ msgstr "Exporta los ajustes a un archivo." + +#~ msgid "Send progress to pipe" +#~ msgstr "Enviar el progreso a la tubería" + +#~ msgid "Send progress to pipe." +#~ msgstr "Enviar el progreso a la tubería." + +#~ msgid "Arrange Options" +#~ msgstr "Opciones de posicionamiento" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Opciones de posicionamiento: 0-desactivar, 1-activar, otras-auto" + +#~ msgid "Repetions count" +#~ msgstr "Cantidad de repeticiones" + +#~ msgid "Repetions count of the whole model" +#~ msgstr "Cantidad de repeticiones del modelo completo" + +#~ msgid "Convert Unit" +#~ msgstr "Convertir Unidad" + +#~ msgid "Convert the units of model" +#~ msgstr "Convertir las unidades del modelo" + +#~ msgid "Rotate around X" +#~ msgstr "Rotar alrededor de X" + +#~ msgid "Rotation angle around the X axis in degrees." +#~ msgstr "El ángulo de rotación alrededor del eje X en grados." + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Escala el modelo por un factor de flotación" + +#~ msgid "Load General Settings" +#~ msgstr "Cargar los ajustes generales" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "" +#~ "Cargar los ajustes del proceso/máquina desde el archivo especificado" + +#~ msgid "Load Filament Settings" +#~ msgstr "Cargar los ajustes del filamento" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "" +#~ "Cargar los ajustes del filamento desde la lista de archivos especificada" + +#~ msgid "Skip Objects" +#~ msgstr "Omitir objetos" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Omitir algunos objetos en esta impresión" + +#~ msgid "load uptodate process/machine settings when using uptodate" +#~ msgstr "" +#~ "carga los ajustes actualizados de proceso/máquina cuando se usa actualizar" + +#~ msgid "" +#~ "load uptodate process/machine settings from the specified file when using " +#~ "uptodate" +#~ msgstr "" +#~ "carga los ajustes actualizados de proceso/máquina desde el archivo " +#~ "especificado cuando se usa actualizar" + +#~ msgid "Output directory" +#~ msgstr "Directorio de salida" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Directorio de salida para los archivos exportados." + +#~ msgid "Debug level" +#~ msgstr "Nivel de depuración" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Ajusta el nivel de registro de depuración. 0:fatal, 1:error, 2:" +#~ "advertencia, 3:información, 4:depuración, 5:rastreo\n" + +#, boost-format +#~ msgid "The selected preset: %1% is not found." +#~ msgstr "El ajuste seleccionado: %1% no encontrado." + +#~ msgid "Physical Printer" +#~ msgstr "Impresora física" + +#~ msgid "Print Host upload" +#~ msgstr "Carga de Host de Impresión" + +#~ msgid "Could not get a valid Printer Host reference" +#~ msgstr "No se ha podido obtener una referencia de host de impresora válida" + +#~ msgid "Success!" +#~ msgstr "¡Exitoso!" + +#~ msgid "Refresh Printers" +#~ msgstr "Refrescar Impresoras" + +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "El archivo HTTPS CA es opcional. Solo es necesario si utiliza HTTPS con " +#~ "un certificado autofirmado." + +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "" +#~ "Archivos de certificado (*.crt, *.pem)|*.crt;*.pem|Todos los archivos|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "Abrir archivo de certificado CA" + +#, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "" +#~ "En este sistema, %s utiliza certificados HTTPS del almacén de " +#~ "certificados o llavero del sistema." + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "Para utilizar un archivo de CA personalizado, importe su archivo de CA a " +#~ "Almacén de certificados / Llavero." + +#~ msgid "Connection to printers connected via the print host failed." +#~ msgstr "" +#~ "Ha fallado la conexión a impresoras conectadas a través del host de " +#~ "impresión." + +#~ msgid "The start, end or step is not valid value." +#~ msgstr "El inicio, el final o el paso no tienen un valor válido." + +#~ msgid "" +#~ "Unable to calibrate: maybe because the set calibration value range is too " +#~ "large, or the step is too small" +#~ msgstr "" +#~ "No es posible calibrar debido a que el valor del rango de calibración es " +#~ "muy grande, o el paso es muy pequeño" + +#~ msgid "Need select printer" +#~ msgstr "Necesario seleccionar impresora" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "Operaciones de la escena 3D\n" +#~ "¿Sabías cómo controlar la vista y la selección de objetos/partes con el " +#~ "ratón y el panel táctil en la escena 3D?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Fijar modelo\n" +#~ "¿Sabías que puedes arreglar un modelo 3D dañado para evitar muchos " +#~ "problemas de corte?" + +#~ msgid "" +#~ "When need to print with the printer door opened\n" +#~ "Opening the printer door can reduce the probability of extruder/hotend " +#~ "clogging when printing lower temperature filament with a higher enclosure " +#~ "temperature. More info about this in the Wiki." +#~ msgstr "" +#~ "Cuando es necesario imprimir con la puerta de la impresora abierta\n" +#~ "Abrir la puerta de la impresora puede reducir la probabilidad de atasco " +#~ "del extrusor/hotend al imprimir filamento de baja temperatura con una " +#~ "temperatura de carcasa más alta. Más información sobre esto en la Wiki." #~ msgid "The minimum printing speed when slow down for cooling" #~ msgstr "" @@ -12686,27 +13084,6 @@ msgstr "" #~ "Mostrar modelos en línea seleccionados por el personal en la página de " #~ "inicio" -#~ msgid "Z hop lower boundary" -#~ msgstr "Límite inferior de salto Z" - -#~ msgid "" -#~ "Z hop will only come into effect when Z is above this value and is below " -#~ "the parameter: \"Z hop upper boundary\"" -#~ msgstr "" -#~ "Z hop sólo entrará en vigor cuando Z esté por encima de este valor y se " -#~ "encuentre por debajo del parámetro: \"Límite superior del salto Z\"" - -#~ msgid "Z hop upper boundary" -#~ msgstr "Límite superior de salto Z" - -#~ msgid "" -#~ "If this value is positive, Z hop will only come into effect when Z is " -#~ "above the parameter: \"Z hop lower boundary\" and is below this value" -#~ msgstr "" -#~ "Si este valor es positivo, Z hop sólo entrará en vigor cuando Z esté por " -#~ "encima del parámetro \"Límite inferior de salto Z\" y esté por debajo de " -#~ "este valor" - #~ msgid "" #~ "Another virtual camera is running.\n" #~ "Bambu Studio supports only a single virtual camera.\n" @@ -12837,9 +13214,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Score" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bandeja de Ingeniería Bambú" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bandeja de Alta Temperatura Bambú" @@ -14171,9 +14545,6 @@ msgstr "" #~ msgid "Edit plate setitngs" #~ msgstr "Edit plate settings" -#~ msgid "Entering Seam painting" -#~ msgstr "Entrando en la sección de pintado de costura" - #~ msgid "" #~ "Extrusion compensation calibration is not supported when using Textured " #~ "PEI Plate" @@ -14296,9 +14667,6 @@ msgstr "" #~ msgid "Layers: N/A" #~ msgstr "Capas: N/A" -#~ msgid "Leaving Seam painting" -#~ msgstr "Saliendo de la sección de pintado de la costura" - #~ msgid "Modify" #~ msgstr "Modificar" @@ -14319,9 +14687,6 @@ msgstr "" #~ "Configuración general de P1P: WLAN en la barra lateral de la pantalla " #~ "principal" -#~ msgid "Paint-on seam editing" -#~ msgstr "Edición de costuras pintadas" - #~ msgid "Plate %d: %s does not support filament %s (%s)." #~ msgstr "Placa %d: %s no admite el filamento %s (%s)." diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index 0cd391b5e28..25f36128a7f 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: Guislain Cyril\n" @@ -106,6 +106,9 @@ msgstr "Pas de support automatique" msgid "Support Generated" msgstr "Supports générés" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Poser sur la face" @@ -154,8 +157,8 @@ msgstr "Remplissage du seau" msgid "Height range" msgstr "Plage de hauteur" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Maj + Entrée" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Basculer la structure" @@ -185,9 +188,15 @@ msgstr "Peint avec : Filament %1%" msgid "Move" msgstr "Déplacer" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Rotation" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Optimiser l'orientation" @@ -197,12 +206,12 @@ msgstr "Appliquer" msgid "Scale" msgstr "Échelle" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "Erreur : Veuillez d'abord fermer tous les menus de la barre d'outils" -msgid "Tool-Lay on Face" -msgstr "Pose de l’outil sur la face" - msgid "in" msgstr "dans" @@ -498,6 +507,15 @@ msgstr "Peindre la couture" msgid "Remove selection" msgstr "Supprimer la sélection" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Police" @@ -717,6 +735,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Mise à jour de la politique de confidentialité" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Chargement" @@ -911,8 +937,11 @@ msgstr "Imprimable" msgid "Fix model" msgstr "Réparer le modèle" -msgid "Export as STL" -msgstr "Exporter en STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Recharger à partir du disque" @@ -1174,6 +1203,9 @@ msgstr "Cliquez sur l'icône pour modifier la couleur de peinture de l'objet" msgid "Click the icon to shift this object to the bed" msgstr "Cliquez sur l’icône pour déplacer cet objet vers le plateau" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Chargement du fichier" @@ -1437,6 +1469,18 @@ msgstr "Ouvrir le conseil suivant." msgid "Open Documentation in web browser." msgstr "Ouvrir la documentation dans le navigateur Web." +msgid "Color" +msgstr "Couleur" + +msgid "Pause" +msgstr "Pause" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Personnalisée" + msgid "Pause:" msgstr "Pause:" @@ -1513,8 +1557,8 @@ msgstr "…" msgid "Failed to connect to the server" msgstr "Impossible de se connecter au serveur" -msgid "Check cloud service status" -msgstr "Vérifiez l'état du service cloud" +msgid "Check the status of current system services" +msgstr "Vérifiez l'état des services système actuels" msgid "code" msgstr "code" @@ -1784,6 +1828,14 @@ msgstr "Envoi de la tâche d'impression via le réseau local" msgid "Sending print job through cloud service" msgstr "Envoi de la tâche d'impression via le service cloud" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Service non disponible" @@ -2013,13 +2065,11 @@ msgstr "Voulez-vous vraiment effacer les informations sur le filament ?" msgid "You need to select the material type and color first." msgstr "Vous devez d’abord sélectionner le type de matériau et la couleur." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Veuillez entrer une valeur valide (K dans la plage 0~0.5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" msgstr "" -"Veuillez entrer une valeur valide (K dans la plage 0~0.5, N dans la plage " -"0.6~2.0)" msgid "Other Color" msgstr "Autre couleur" @@ -2425,9 +2475,6 @@ msgstr "Rectangulaire" msgid "Circular" msgstr "Circulaire" -msgid "Custom" -msgstr "Personnalisée" - msgid "Load shape from STL..." msgstr "Charger la forme depuis un STL..." @@ -2938,6 +2985,9 @@ msgstr "Purgé" msgid "Total" msgstr "Total" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Estimation totale" @@ -3025,15 +3075,18 @@ msgstr "Changement de couleur" msgid "Print" msgstr "Impression" -msgid "Pause" -msgstr "Pause" - msgid "Printer" msgstr "Imprimante" msgid "Print settings" msgstr "Paramètres d'impression" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Durée estimée" @@ -3202,7 +3255,7 @@ msgstr "Volume :" msgid "Size:" msgstr "Taille :" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3265,15 +3318,15 @@ msgstr "Calibration du débit" msgid "Start Calibration" msgstr "Démarrer" -msgid "No step selected" -msgstr "Aucune étape sélectionnée" - msgid "Completed" msgstr "Terminé" msgid "Calibrating" msgstr "Calibration" +msgid "No step selected" +msgstr "Aucune étape sélectionnée" + msgid "Auto-record Monitoring" msgstr "Surveillance d'enregistrement automatique" @@ -3489,8 +3542,11 @@ msgstr "Charger des configurations" msgid "Import" msgstr "Importer" -msgid "Export all objects as STL" -msgstr "Exporter tous les objets au format STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Exporter au format 3MF" @@ -3775,9 +3831,6 @@ msgstr "" "L’imprimante est en cours de téléchargement, veuillez attendre la fin du " "téléchargement." -msgid "Loading..." -msgstr "Chargement..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" "Échec de l'initialisation (non pris en charge par la version actuelle de " @@ -3843,6 +3896,9 @@ msgstr "Lecture…" msgid "Load failed [%d]!" msgstr "Le chargement a échoué [%d] !" +msgid "Loading..." +msgstr "Chargement..." + msgid "Year" msgstr "Année" @@ -3961,12 +4017,25 @@ msgstr "Téléchargement terminé" msgid "Downloading %d%%..." msgstr "Téléchargement %d%%…" +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "Non pris en charge par la version actuelle de l'imprimante." msgid "Storage unavailable, insert SD card." msgstr "Stockage indisponible, insérer une carte SD." +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Vitesse:" @@ -4300,6 +4369,12 @@ msgstr "Une nouvelle version du plug-in réseau Bambu est disponible." msgid "Details" msgstr "Détails" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "" + msgid "Undo integration failed." msgstr "L'annulation de l'intégration a échoué." @@ -4348,9 +4423,6 @@ msgstr "TERMINÉ" msgid "Cancel upload" msgstr "Annuler le téléchargement" -msgid "Slice ok." -msgstr "Découpage terminé." - msgid "Jump to" msgstr "Sélectionner" @@ -4454,6 +4526,9 @@ msgstr "Récupération automatique en cas de perte de pas" msgid "Allow Prompt Sound" msgstr "Autoriser le son de l'invite" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Global" @@ -4548,6 +4623,9 @@ msgstr "Synchroniser la liste des filaments de l'AMS" msgid "Set filaments to use" msgstr "Définir les filaments à utiliser" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4657,26 +4735,29 @@ msgstr "" "chargement des données de géométrie uniquement." #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"La version %s de 3mf est plus récente que la version %s de %s, clés " -"suivantes non reconnues :" -msgid "You'd better upgrade your software.\n" -msgstr "Il est préférable de mettre à jour votre logiciel.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Nouvelle version 3mf" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"La version %s de 3mf est plus récente que la version %s de %s, nous vous " -"suggérons de mettre à jour votre logiciel." msgid "Invalid values found in the 3mf:" msgstr "Valeurs non valides trouvées dans le 3mf :" @@ -4684,12 +4765,27 @@ msgstr "Valeurs non valides trouvées dans le 3mf :" msgid "Please correct them in the param tabs" msgstr "Veuillez les corriger dans l’onglet paramètres" -msgid "The 3mf is not compatible, load geometry data only!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" msgstr "" -"Le 3mf n'est pas compatible, chargez uniquement les données de géométrie !" -msgid "Incompatible 3mf" -msgstr "Fichier 3mf incompatible" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "" @@ -4767,6 +4863,15 @@ msgstr "Enregistrer le fichier sous :" msgid "Export OBJ file:" msgstr "Exporter le fichier OBJ :" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Supprimer l’objet qui fait partie de l’objet coupé" @@ -4785,15 +4890,15 @@ msgstr "L'objet sélectionné n'a pas pu être divisé." msgid "Another export job is running." msgstr "Une autre tâche d'exportation est en cours d'exécution." -msgid "Replace from:" -msgstr "Remplacer de :" - msgid "Unable to replace with more than one volume" msgstr "Impossible de remplacer plus d'un volume" msgid "Error during replace" msgstr "Erreur lors du remplacement" +msgid "Replace from:" +msgstr "Remplacer de :" + msgid "Select a new file" msgstr "Sélectionner un nouveau fichier" @@ -5180,6 +5285,12 @@ msgstr "Afficher la fenêtre G-code" msgid "If enabled, g-code window will be displayed." msgstr "Si activé, la fenêtre avec les commandes G-code sera affichée." +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Préréglages" @@ -5236,6 +5347,9 @@ msgstr "Nombre maximal de projets récents" msgid "Clear my choice on the unsaved projects." msgstr "Effacer mon choix sur les projets non enregistrés." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Sauvegarde automatique" @@ -5389,8 +5503,11 @@ msgstr "Ajouter/Supprimer des filaments" msgid "Add/Remove materials" msgstr "Ajouter/Supprimer des matériaux" -msgid "Add/Remove printers" -msgstr "Ajouter/Supprimer des imprimantes" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Incompatible" @@ -5579,16 +5696,16 @@ msgstr "Bambu Cool Plate" msgid "PLA Plate" msgstr "Plaque PLA" -msgid "Bambu Engineering Plate" -msgstr "" +msgid "Bamabu Engineering Plate" +msgstr "Bambu Engineering Plate" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "" msgid "High temperature Plate" msgstr "" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "" msgid "Send print job to" @@ -5612,9 +5729,6 @@ msgstr "envoi terminé" msgid "Error code" msgstr "Code erreur" -msgid "Check the status of current system services" -msgstr "Vérifiez l'état des services système actuels" - msgid "Printer local connection failed, please try again." msgstr "La connexion locale de l'imprimante a échoué, veuillez réessayer." @@ -5731,8 +5845,7 @@ msgid "" msgstr "" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" msgid "Errors" @@ -5750,10 +5863,6 @@ msgstr "" "l'imprimante physique actuellement sélectionnée. Il est recommandé " "d’utiliser le même type d’imprimante pour le découpage." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s n’est pas pris en charge par l’AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5763,12 +5872,35 @@ msgstr "" "vérifier s'il s'agit des filaments requis. S'ils sont corrects, appuyez sur " "\"Confirmer\" pour lancer l'impression." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Veuillez cliquer sur le bouton de confirmation si vous souhaitez continuer " "l’impression." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5972,6 +6104,9 @@ msgstr "" "peut y avoir des défauts sur le modèle. Voulez-vous activer la tour de " "purge ?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -6023,8 +6158,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "Lors de l'enregistrement d'un Timelapse sans tête d'outil, il est recommandé " "d'ajouter une \"Tour d’essuyage Timelapse\"\n" @@ -6297,6 +6432,9 @@ msgstr "G-code de démarrage de l’imprimante" msgid "Machine end G-code" msgstr "G-code de fin de l’imprimante" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "G-code avant le changement de couche" @@ -6367,6 +6505,25 @@ msgstr "Rétraction Firmware" msgid "Detached" msgstr "Détaché" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% préréglage" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "Le préréglage suivant sera également supprimé." @@ -6376,11 +6533,6 @@ msgstr[1] "Les préréglages suivants seront également supprimés." msgid "Are you sure to %1% the selected preset?" msgstr "Êtes-vous sûr de %1% le préréglage sélectionné ?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% préréglage" - msgid "All" msgstr "Tout" @@ -6630,11 +6782,17 @@ msgstr "" msgid "Auto-Calc" msgstr "Calcul Auto" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Volumes de purge - Changement de filament" -msgid "Multiplier" -msgstr "Multiplicateur" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Volume de purge (mm³) pour chaque paire de filaments." @@ -6647,6 +6805,9 @@ msgstr "Suggestion : Volume réel dans la plage [%d, %d]" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "Le multiplicateur doit être dans la plage [%.2f, %.2f]." +msgid "Multiplier" +msgstr "Multiplicateur" + msgid "unloaded" msgstr "déchargé" @@ -6662,6 +6823,12 @@ msgstr "De" msgid "To" msgstr "À" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Connexion" @@ -6700,6 +6867,9 @@ msgstr "" "Afficher/Masquer la boîte de dialogue des paramètres des périphériques de " "connexion 3D" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Afficher la liste des raccourcis clavier" @@ -6954,12 +7124,15 @@ msgstr "" msgid "New version of Orca Slicer" msgstr "Nouvelle version de Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "Ne plus me rappeler cette version" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Terminé" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "Échec de la connexion LAN (envoi du fichier d’impression)" @@ -6985,8 +7158,22 @@ msgstr "Code d'accès" msgid "Where to find your printer's IP and Access Code?" msgstr "Où trouver l’adresse IP et le code d’accès de votre imprimante ?" -msgid "Error: IP or Access Code are not correct" -msgstr "Erreur : l’IP ou le code d’accès n’est pas correct" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "Tester" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Modèle:" @@ -7467,6 +7654,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "La hauteur de la couche ne peut pas dépasser le diamètre de la buse" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7936,7 +8128,28 @@ msgstr "Renversement de surplomb" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" msgid "Reverse threshold" @@ -8184,6 +8397,14 @@ msgstr "G-code de fin" msgid "End G-code when finish the whole printing" msgstr "G-code lorsque l'ensemble de l'impression est terminée" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "G-code lorsque l'impression de ce filament est terminée" @@ -8279,27 +8500,26 @@ msgstr "" "Cela définit le seuil pour une petite longueur de périmètre. Le seuil par " "défaut est de 0 mm" -msgid "Order of inner wall/outer wall/infil" -msgstr "Ordre des parois" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " +msgid "Print sequence of inner wall and outer wall. " msgstr "" -"Séquence d'impression de la paroi intérieure, extérieure et du remplissage. " -msgid "inner/outer/infill" -msgstr "Intérieure / Extérieure / Remplissage" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "Extérieure / Intérieure / Remplissage" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "Remplissage / Intérieure / Extérieure" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "Remplissage / Extérieure / Intérieure" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "Intérieure / Extérieure / Intérieure / Remplissage" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Hauteur à la tige" @@ -8404,9 +8624,6 @@ msgstr "Couleur par défaut" msgid "Default filament color" msgstr "Couleur du filament par défaut" -msgid "Color" -msgstr "Couleur" - msgid "Filament notes" msgstr "Notes sur le filament" @@ -8835,10 +9052,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "Le max_accel_to_decel de Klipper sera ajusté à ce %% d'accélération." -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "Jerk des parois extérieures" @@ -8912,10 +9125,10 @@ msgstr "Vitesse maximale du ventilateur à la couche" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" "La vitesse du ventilateur augmentera de manière linéaire à partir de zéro à " "la couche \"close_fan_the_first_x_layers\" jusqu’au maximum à la couche " @@ -9247,6 +9460,18 @@ msgstr "" "Utile pour les impressions multi-extrudeuses avec des matériaux translucides " "ou un matériau de support soluble" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Type de lissage" @@ -9811,6 +10036,22 @@ msgstr "" "buse de toucher l'impression lors du déplacement. L'utilisation d'une ligne " "en spirale pour soulever l’axe Z peut empêcher le stringing" +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "Type de décalage en Z" @@ -10258,9 +10499,15 @@ msgstr "" "signifie qu'aucun filament spécifique n'est utilisé pour les supports et que " "le filament actuel est utilisé" -msgid "" -"Line width of support. If expressed as a %, it will be computed over the " -"nozzle diameter." +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" +"Line width of support. If expressed as a %, it will be computed over the " +"nozzle diameter." msgstr "" msgid "Interface use loop pattern" @@ -10292,6 +10539,12 @@ msgstr "Nombre de couches des interfaces supérieures" msgid "Bottom interface layers" msgstr "Couches des interfaces inférieures" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Espacement du motif des interfaces supérieures" @@ -10973,70 +11226,12 @@ msgstr "Largeur de ligne trop grande " msgid " not in range " msgstr " pas dans la plage " -msgid "Export 3MF" -msgstr "Exporter 3mf" - -msgid "Export project as 3MF." -msgstr "Exporter le projet au format 3mf." - -msgid "Export slicing data" -msgstr "Exporter les données de découpage" - -msgid "Export slicing data to a folder." -msgstr "Exporter les données de découpage vers un dossier." - -msgid "Load slicing data" -msgstr "Charger les données de découpage" - -msgid "Load cached slicing data from directory" -msgstr "Charger les données de découpage en cache à partir d'un dossier" - -msgid "Export STL" -msgstr "" - -msgid "Export the objects as multiple STL." -msgstr "" - -msgid "Slice" -msgstr "Découper" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "" -"Découper les plateaux : 0-tous les plateaux, i-plateau i, autres-invalides" - -msgid "Show command help." -msgstr "Afficher l'aide des commandes." - -msgid "UpToDate" -msgstr "À jour" - -msgid "Update the configs values of 3mf to latest." -msgstr "Mettre à jour les dernières valeurs de configuration de 3mf." - -msgid "Load default filaments" -msgstr "" - -msgid "Load first filament as default for those not loaded" -msgstr "" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "" -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "Nombre maximum de triangles par plateau pour le découpage." - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "Durée de découpage maximum par plateau en secondes." - msgid "No check" msgstr "Pas de vérification" @@ -11045,42 +11240,6 @@ msgstr "" "N’exécuter aucune vérification de validité, telle que la vérification des " "conflits de chemin G-code." -msgid "Normative check" -msgstr "Vérification normative" - -msgid "Check the normative items." -msgstr "Vérifier les éléments normatifs." - -msgid "Output Model Info" -msgstr "Informations sur le modèle de sortie" - -msgid "Output the model's information." -msgstr "Informations sur le modèle de sortie" - -msgid "Export Settings" -msgstr "Paramètres d'exportation" - -msgid "Export settings to a file." -msgstr "Exporter les paramètres vers un fichier." - -msgid "Send progress to pipe" -msgstr "Envoyer la progression au canal" - -msgid "Send progress to pipe." -msgstr "Envoyer la progression au canal." - -msgid "Arrange Options" -msgstr "Options d'organisation" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Options d'organisation : 0-désactiver, 1-activer, autres-auto" - -msgid "Repetions count" -msgstr "" - -msgid "Repetions count of the whole model" -msgstr "" - msgid "Ensure on bed" msgstr "" @@ -11088,12 +11247,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "" -msgid "Convert Unit" -msgstr "Convertir l'unité" - -msgid "Convert the units of model" -msgstr "Convertir les unités du modèle" - msgid "Orient Options" msgstr "" @@ -11103,49 +11256,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "" -msgid "Rotate around X" -msgstr "" - -msgid "Rotation angle around the X axis in degrees." -msgstr "" - msgid "Rotate around Y" msgstr "" msgid "Rotation angle around the Y axis in degrees." msgstr "" -msgid "Scale the model by a float factor" -msgstr "Mettre à l'échelle le modèle par un facteur flottant" - -msgid "Load General Settings" -msgstr "Charger les paramètres généraux" - -msgid "Load process/machine settings from the specified file" -msgstr "" -"Charger les paramètres de processus/imprimante à partir du fichier spécifié" - -msgid "Load Filament Settings" -msgstr "Charger les paramètres de filament" - -msgid "Load filament settings from the specified file list" -msgstr "" -"Charger les paramètres de filament à partir de la liste de fichiers spécifiée" - -msgid "Skip Objects" -msgstr "Ignorer les objets" - -msgid "Skip some objects in this print" -msgstr "Ignorer certains objets de cette impression" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" - msgid "Data directory" msgstr "Répertoire de données" @@ -11158,22 +11274,6 @@ msgstr "" "pour maintenir différents profils ou inclure des configurations à partir " "d’un stockage réseau." -msgid "Output directory" -msgstr "Dossier de sortie" - -msgid "Output directory for the exported files." -msgstr "Dossier de sortie des fichiers exportés." - -msgid "Debug level" -msgstr "Niveau de débogage" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Définit le niveau de journalisation du déboggage. 0:fatal, 1:erreur, 2:" -"avertissement, 3:info, 4:déboggage, 5:tracer\n" - msgid "Load custom gcode" msgstr "" @@ -11340,9 +11440,6 @@ msgstr "" msgid "Finish" msgstr "Terminer" -msgid "Wiki" -msgstr "" - msgid "How to use calibration result?" msgstr "" @@ -11358,6 +11455,12 @@ msgstr "" msgid "Calibration not supported" msgstr "" +msgid "Error desc" +msgstr "" + +msgid "Extra info" +msgstr "" + msgid "Flow Dynamics" msgstr "" @@ -11385,8 +11488,8 @@ msgstr "" msgid "The name cannot be empty." msgstr "" -#, boost-format -msgid "The selected preset: %1% is not found." +#, c-format, boost-format +msgid "The selected preset: %s is not found." msgstr "" msgid "The name cannot be the same as the system preset name." @@ -11666,12 +11769,6 @@ msgid "" "- Different filament brand and family(Brand = Bambu, Family = Basic, Matte)" msgstr "" -msgid "Error desc" -msgstr "" - -msgid "Extra info" -msgstr "" - msgid "Pattern" msgstr "" @@ -11760,101 +11857,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "" - -msgid "Mesh Boolean" -msgstr "" - -msgid "Union" -msgstr "" - -msgid "Difference" -msgstr "" - -msgid "Intersection" -msgstr "" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "" - -msgid "Subtract with" -msgstr "" - -msgid "selected" -msgstr "" - -msgid "Part 1" -msgstr "" - -msgid "Part 2" -msgstr "" - -msgid "Delete input" -msgstr "" - -msgid "Send G-Code to printer host" -msgstr "" - -msgid "Upload to Printer Host with the following filename:" -msgstr "" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" - -msgid "Upload to storage" -msgstr "" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" - -msgid "Upload" -msgstr "" - -msgid "Print host upload queue" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "" - -msgctxt "OfFile" -msgid "Size" -msgstr "" - -msgid "Filename" -msgstr "" - -msgid "Cancel selected" -msgstr "" - -msgid "Show error message" -msgstr "" - -msgid "Enqueued" -msgstr "" - -msgid "Uploading" -msgstr "Téléversement" - -msgid "Cancelling" -msgstr "Annulation" - -msgid "Error uploading to print host" -msgstr "Erreur de téléchargement vers l'hôte d'impression" - msgid "PA Calibration" msgstr "Calibration Pressure Advance" @@ -11983,79 +11985,107 @@ msgstr "Longueur de rétraction de fin: " msgid "mm/mm" msgstr "mm/mm" -msgid "Physical Printer" -msgstr "Imprimante Physique" +msgid "Send G-Code to printer host" +msgstr "" + +msgid "Upload to Printer Host with the following filename:" +msgstr "" + +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "" -msgid "Print Host upload" -msgstr "Envoi vers l’imprimante hôte" +msgid "Upload to storage" +msgstr "" -msgid "Test" -msgstr "Tester" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "" -msgid "Could not get a valid Printer Host reference" -msgstr "Impossible d’obtenir une référence d’imprimante hôte valide" +msgid "Upload" +msgstr "" -msgid "Success!" -msgstr "Succès !" +msgid "Print host upload queue" +msgstr "" -msgid "Refresh Printers" -msgstr "Actualiser les imprimantes" +msgid "ID" +msgstr "" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." +msgid "Progress" msgstr "" -"Le fichier CA HTTPS est facultatif. Il n'est nécessaire que si vous utilisez " -"HTTPS avec un certificat auto-signé." -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "Host" msgstr "" -"Fichiers de certificat (*.crt, *.pem)|*.crt;*.pem|Tous les fichiers|*.*" -msgid "Open CA certificate file" -msgstr "Ouvrir le fichier de certificat CA" +msgctxt "OfFile" +msgid "Size" +msgstr "" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." +msgid "Filename" msgstr "" -"Sur ce système, %s utilise les certificats HTTPS du magasin de certificats " -"du système ou du trousseau." -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." +msgid "Cancel selected" +msgstr "" + +msgid "Show error message" msgstr "" -"Pour utiliser un certificat personnalisé, veuillez importer votre fichier " -"dans magasin de certificats / trousseau." -msgid "Connection to printers connected via the print host failed." +msgid "Enqueued" msgstr "" -"La connexion aux imprimantes connectées via l’hôte d’impression a échoué." -msgid "The start, end or step is not valid value." -msgstr "Le début, la fin ou le pas n'est pas une valeur valide." +msgid "Uploading" +msgstr "Téléversement" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Cancelling" +msgstr "Annulation" + +msgid "Error uploading to print host" +msgstr "Erreur de téléchargement vers l'hôte d'impression" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "" + +msgid "Mesh Boolean" +msgstr "" + +msgid "Union" msgstr "" -"Impossible d'étalonner : peut-être parce que la plage de valeurs " -"d'étalonnage est trop grande ou que le pas est trop petit." -msgid "Need select printer" -msgstr "Besoin de sélectionner l'imprimante" +msgid "Difference" +msgstr "" + +msgid "Intersection" +msgstr "" + +msgid "Source Volume" +msgstr "" + +msgid "Tool Volume" +msgstr "" + +msgid "Subtract from" +msgstr "" + +msgid "Subtract with" +msgstr "" + +msgid "selected" +msgstr "" + +msgid "Part 1" +msgstr "" + +msgid "Part 2" +msgstr "" + +msgid "Delete input" +msgstr "" -#: resources/data/hints.ini: [hint:3D Scene Operations] +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"Opérations de scène 3D\n" -"Savez-vous comment contrôler la vue et la sélection d'objets/pièces avec la " -"souris et l'écran tactile dans la scène 3D ?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -12071,11 +12101,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Réparer le modèle\n" -"Saviez-vous que vous pouvez réparer un modèle 3D corrompu pour éviter de " -"nombreux problèmes de découpage ?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -12127,6 +12154,13 @@ msgstr "" "Saviez-vous que vous pouvez afficher tous les objets/pièces dans une liste " "et modifier les paramètres de chaque objet/pièce ?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -12323,11 +12357,309 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." msgstr "" +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Maj + Entrée" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Pose de l’outil sur la face" + +#~ msgid "Export as STL" +#~ msgstr "Exporter en STL" + +#~ msgid "Check cloud service status" +#~ msgstr "Vérifiez l'état du service cloud" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Veuillez entrer une valeur valide (K dans la plage 0~0.5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "" +#~ "Veuillez entrer une valeur valide (K dans la plage 0~0.5, N dans la plage " +#~ "0.6~2.0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Exporter tous les objets au format STL" + +#~ msgid "Slice ok." +#~ msgstr "Découpage terminé." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "La version %s de 3mf est plus récente que la version %s de %s, clés " +#~ "suivantes non reconnues :" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Il est préférable de mettre à jour votre logiciel.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "La version %s de 3mf est plus récente que la version %s de %s, nous vous " +#~ "suggérons de mettre à jour votre logiciel." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "" +#~ "Le 3mf n'est pas compatible, chargez uniquement les données de géométrie !" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Fichier 3mf incompatible" + +#~ msgid "Add/Remove printers" +#~ msgstr "Ajouter/Supprimer des imprimantes" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s n’est pas pris en charge par l’AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Ne plus me rappeler cette version" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Erreur : l’IP ou le code d’accès n’est pas correct" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Ordre des parois" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "" +#~ "Séquence d'impression de la paroi intérieure, extérieure et du " +#~ "remplissage. " + +#~ msgid "inner/outer/infill" +#~ msgstr "Intérieure / Extérieure / Remplissage" + +#~ msgid "outer/inner/infill" +#~ msgstr "Extérieure / Intérieure / Remplissage" + +#~ msgid "infill/inner/outer" +#~ msgstr "Remplissage / Intérieure / Extérieure" + +#~ msgid "infill/outer/inner" +#~ msgstr "Remplissage / Extérieure / Intérieure" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "Intérieure / Extérieure / Intérieure / Remplissage" + +#~ msgid "Export 3MF" +#~ msgstr "Exporter 3mf" + +#~ msgid "Export project as 3MF." +#~ msgstr "Exporter le projet au format 3mf." + +#~ msgid "Export slicing data" +#~ msgstr "Exporter les données de découpage" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Exporter les données de découpage vers un dossier." + +#~ msgid "Load slicing data" +#~ msgstr "Charger les données de découpage" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Charger les données de découpage en cache à partir d'un dossier" + +#~ msgid "Slice" +#~ msgstr "Découper" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "" +#~ "Découper les plateaux : 0-tous les plateaux, i-plateau i, autres-invalides" + +#~ msgid "Show command help." +#~ msgstr "Afficher l'aide des commandes." + +#~ msgid "UpToDate" +#~ msgstr "À jour" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Mettre à jour les dernières valeurs de configuration de 3mf." + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "Nombre maximum de triangles par plateau pour le découpage." + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "Durée de découpage maximum par plateau en secondes." + +#~ msgid "Normative check" +#~ msgstr "Vérification normative" + +#~ msgid "Check the normative items." +#~ msgstr "Vérifier les éléments normatifs." + +#~ msgid "Output Model Info" +#~ msgstr "Informations sur le modèle de sortie" + +#~ msgid "Output the model's information." +#~ msgstr "Informations sur le modèle de sortie" + +#~ msgid "Export Settings" +#~ msgstr "Paramètres d'exportation" + +#~ msgid "Export settings to a file." +#~ msgstr "Exporter les paramètres vers un fichier." + +#~ msgid "Send progress to pipe" +#~ msgstr "Envoyer la progression au canal" + +#~ msgid "Send progress to pipe." +#~ msgstr "Envoyer la progression au canal." + +#~ msgid "Arrange Options" +#~ msgstr "Options d'organisation" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Options d'organisation : 0-désactiver, 1-activer, autres-auto" + +#~ msgid "Convert Unit" +#~ msgstr "Convertir l'unité" + +#~ msgid "Convert the units of model" +#~ msgstr "Convertir les unités du modèle" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Mettre à l'échelle le modèle par un facteur flottant" + +#~ msgid "Load General Settings" +#~ msgstr "Charger les paramètres généraux" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "" +#~ "Charger les paramètres de processus/imprimante à partir du fichier " +#~ "spécifié" + +#~ msgid "Load Filament Settings" +#~ msgstr "Charger les paramètres de filament" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "" +#~ "Charger les paramètres de filament à partir de la liste de fichiers " +#~ "spécifiée" + +#~ msgid "Skip Objects" +#~ msgstr "Ignorer les objets" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Ignorer certains objets de cette impression" + +#~ msgid "Output directory" +#~ msgstr "Dossier de sortie" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Dossier de sortie des fichiers exportés." + +#~ msgid "Debug level" +#~ msgstr "Niveau de débogage" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Définit le niveau de journalisation du déboggage. 0:fatal, 1:erreur, 2:" +#~ "avertissement, 3:info, 4:déboggage, 5:tracer\n" + +#~ msgid "Physical Printer" +#~ msgstr "Imprimante Physique" + +#~ msgid "Print Host upload" +#~ msgstr "Envoi vers l’imprimante hôte" + +#~ msgid "Could not get a valid Printer Host reference" +#~ msgstr "Impossible d’obtenir une référence d’imprimante hôte valide" + +#~ msgid "Success!" +#~ msgstr "Succès !" + +#~ msgid "Refresh Printers" +#~ msgstr "Actualiser les imprimantes" + +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "Le fichier CA HTTPS est facultatif. Il n'est nécessaire que si vous " +#~ "utilisez HTTPS avec un certificat auto-signé." + +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "" +#~ "Fichiers de certificat (*.crt, *.pem)|*.crt;*.pem|Tous les fichiers|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "Ouvrir le fichier de certificat CA" + +#, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "" +#~ "Sur ce système, %s utilise les certificats HTTPS du magasin de " +#~ "certificats du système ou du trousseau." + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "Pour utiliser un certificat personnalisé, veuillez importer votre fichier " +#~ "dans magasin de certificats / trousseau." + +#~ msgid "Connection to printers connected via the print host failed." +#~ msgstr "" +#~ "La connexion aux imprimantes connectées via l’hôte d’impression a échoué." + +#~ msgid "The start, end or step is not valid value." +#~ msgstr "Le début, la fin ou le pas n'est pas une valeur valide." + +#~ msgid "" +#~ "Unable to calibrate: maybe because the set calibration value range is too " +#~ "large, or the step is too small" +#~ msgstr "" +#~ "Impossible d'étalonner : peut-être parce que la plage de valeurs " +#~ "d'étalonnage est trop grande ou que le pas est trop petit." + +#~ msgid "Need select printer" +#~ msgstr "Besoin de sélectionner l'imprimante" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "Opérations de scène 3D\n" +#~ "Savez-vous comment contrôler la vue et la sélection d'objets/pièces avec " +#~ "la souris et l'écran tactile dans la scène 3D ?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Réparer le modèle\n" +#~ "Saviez-vous que vous pouvez réparer un modèle 3D corrompu pour éviter de " +#~ "nombreux problèmes de découpage ?" + #~ msgid "Embeded" #~ msgstr "Intégré" @@ -12466,9 +12798,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Note" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bambu Engineering Plate" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu High Temperature Plate" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index 007853c48d6..2131044d826 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -98,6 +98,9 @@ msgstr "Nincs automatikus támasz" msgid "Support Generated" msgstr "Támasz legenerálva" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Felületre fektetés" @@ -145,8 +148,8 @@ msgstr "Vödör kitöltés" msgid "Height range" msgstr "Magasságtartomány" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Drótváz-megjelenítés váltása" @@ -176,9 +179,15 @@ msgstr "A következővel festve: %1% filament" msgid "Move" msgstr "Mozgatás" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Forgatás" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Orientáció optimalizálása" @@ -188,12 +197,12 @@ msgstr "Alkalmaz" msgid "Scale" msgstr "Átméretezés" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "Hiba: Kérjük, először zárd be az összes eszköztár menüt" -msgid "Tool-Lay on Face" -msgstr "Eszköz-Felületre fektetés" - msgid "in" msgstr "in" @@ -490,6 +499,15 @@ msgstr "Varratfestés" msgid "Remove selection" msgstr "Kijelölés törlése" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Betűtípus" @@ -695,6 +713,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Privacy Policy Update" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Betöltés" @@ -888,8 +914,11 @@ msgstr "Nyomtatható" msgid "Fix model" msgstr "Model javítása" -msgid "Export as STL" -msgstr "Exportálás STL-ként" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Újratöltés lemezről" @@ -1149,6 +1178,9 @@ msgstr "Kattints az ikonra az objektum színfestésének szerkesztéséhez" msgid "Click the icon to shift this object to the bed" msgstr "Click the icon to shift this object to the bed" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Fájl betöltése" @@ -1412,6 +1444,18 @@ msgstr "Következő tipp megnyitása" msgid "Open Documentation in web browser." msgstr "Dokumentáció megnyitása webböngészőben" +msgid "Color" +msgstr "Szín" + +msgid "Pause" +msgstr "Szünet" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Egyéni" + msgid "Pause:" msgstr "Pause:" @@ -1487,8 +1531,8 @@ msgstr "" msgid "Failed to connect to the server" msgstr "Nem sikerült csatlakozni a szerverhez" -msgid "Check cloud service status" -msgstr "Check cloud service status" +msgid "Check the status of current system services" +msgstr "Check the status of current system services" msgid "code" msgstr "code" @@ -1754,6 +1798,14 @@ msgstr "Nyomtatási munka küldése LAN-on keresztül" msgid "Sending print job through cloud service" msgstr "Nyomtatási munka küldése felhőszolgáltatáson keresztül" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Szolgáltatás nem elérhető" @@ -1977,11 +2029,11 @@ msgstr "Are you sure you want to clear the filament information?" msgid "You need to select the material type and color first." msgstr "You need to select the material type and color first." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Adj meg egy érvényes értéket (K 0-0,5 között)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "Adj meg egy érvényes értéket (K 0-0,5, N 0,6-2,0 között)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Other Color" @@ -2365,9 +2417,6 @@ msgstr "Téglalap" msgid "Circular" msgstr "Kör" -msgid "Custom" -msgstr "Egyéni" - msgid "Load shape from STL..." msgstr "Forma betöltése STL-ből..." @@ -2856,6 +2905,9 @@ msgstr "Öblített" msgid "Total" msgstr "Összesen" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Összesített becslés" @@ -2943,15 +2995,18 @@ msgstr "Színváltás" msgid "Print" msgstr "Nyomtatás" -msgid "Pause" -msgstr "Szünet" - msgid "Printer" msgstr "Nyomtató" msgid "Print settings" msgstr "Nyomtatási beállítások" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Időbecslés" @@ -3120,7 +3175,7 @@ msgstr "Térfogat:" msgid "Size:" msgstr "Méret:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3181,15 +3236,15 @@ msgstr "Kalibrációs anyagáramlás" msgid "Start Calibration" msgstr "Kalibrálás" -msgid "No step selected" -msgstr "" - msgid "Completed" msgstr "Befejezve" msgid "Calibrating" msgstr "Kalibrálás" +msgid "No step selected" +msgstr "" + msgid "Auto-record Monitoring" msgstr "Automatikus felügyelet" @@ -3404,8 +3459,11 @@ msgstr "Load configs" msgid "Import" msgstr "Import" -msgid "Export all objects as STL" -msgstr "Összes objektum exportálása STL-ként" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Export Generic 3MF" @@ -3681,9 +3739,6 @@ msgstr "" "A nyomtató a letöltéssel van elfoglalva; kérjük, várd meg, amíg a letöltés " "befejeződik." -msgid "Loading..." -msgstr "Betöltés…" - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" @@ -3746,6 +3801,9 @@ msgstr "Lejátszás..." msgid "Load failed [%d]!" msgstr "A betöltés sikertelen [%d]!" +msgid "Loading..." +msgstr "Betöltés…" + msgid "Year" msgstr "Year" @@ -3863,12 +3921,25 @@ msgstr "A letöltés kész" msgid "Downloading %d%%..." msgstr "Letöltés %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "" msgid "Storage unavailable, insert SD card." msgstr "" +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Sebesség:" @@ -4199,6 +4270,12 @@ msgstr "Új hálózati bővítmény érhető el" msgid "Details" msgstr "Részletek" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "" + msgid "Undo integration failed." msgstr "Az integráció visszavonása nem sikerült." @@ -4247,9 +4324,6 @@ msgstr "KÉSZ" msgid "Cancel upload" msgstr "Feltöltés megszakítása" -msgid "Slice ok." -msgstr "Szeletelés kész." - msgid "Jump to" msgstr "Ugrás ide:" @@ -4356,6 +4430,9 @@ msgstr "Automatikus helyreállítás lépésvesztésből" msgid "Allow Prompt Sound" msgstr "" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Globális" @@ -4450,6 +4527,9 @@ msgstr "Filamentlista szinkronizálása az AMS-ből" msgid "Set filaments to use" msgstr "Használni kívánt filament beállítása" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4547,26 +4627,29 @@ msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "" #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"A 3mf fájl %s verziója újabb, mint a(z) %s verziója %s, a következő " -"ismeretlen kulcsokat találtuk:" -msgid "You'd better upgrade your software.\n" -msgstr "Jobb lenne, ha frissítenéd a szoftvert.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Újabb 3mf verzió" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"A 3mf fájl %s verziója újabb, mint a(z) %s verziója %s, javasolt a szoftver " -"frissítése." msgid "Invalid values found in the 3mf:" msgstr "Invalid values found in the 3mf:" @@ -4574,11 +4657,27 @@ msgstr "Invalid values found in the 3mf:" msgid "Please correct them in the param tabs" msgstr "Please correct them in the Param tabs" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "A 3mf nem kompatibilis, csak geometriai adatok kerülnek betöltésre!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "Nem kompatibilis 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "A STEP fájlon belüli komponens neve nem UTF-8 formátumban van!" @@ -4650,6 +4749,15 @@ msgstr "Fájl mentése mint:" msgid "Export OBJ file:" msgstr "" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Delete object which is a part of cut object" @@ -4668,15 +4776,15 @@ msgstr "A kijelölt objektumot nem lehet feldarabolni." msgid "Another export job is running." msgstr "Egy másik exportálási feladat is fut." -msgid "Replace from:" -msgstr "" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "Hiba a csere során" +msgid "Replace from:" +msgstr "" + msgid "Select a new file" msgstr "Válassz egy új fájlt" @@ -5049,6 +5157,12 @@ msgstr "" msgid "If enabled, g-code window will be displayed." msgstr "" +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Presets" @@ -5105,6 +5219,9 @@ msgstr "Maximum count of recent projects" msgid "Clear my choice on the unsaved projects." msgstr "Clear my choice on the unsaved projects." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Automatikus biztonsági mentés" @@ -5258,8 +5375,11 @@ msgstr "Filament hozzáadása/eltávolítása" msgid "Add/Remove materials" msgstr "Anyagok hozzáadása/eltávolítása" -msgid "Add/Remove printers" -msgstr "Nyomtatók hozzáadása/eltávolítása" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Incompatible" @@ -5441,16 +5561,16 @@ msgstr "Bambu Cool Plate" msgid "PLA Plate" msgstr "PLA Plate" -msgid "Bambu Engineering Plate" -msgstr "" +msgid "Bamabu Engineering Plate" +msgstr "Bambu Engineering Plate" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "" msgid "High temperature Plate" msgstr "" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "" msgid "Send print job to" @@ -5474,9 +5594,6 @@ msgstr "küldés befejezve" msgid "Error code" msgstr "Error code" -msgid "Check the status of current system services" -msgstr "Check the status of current system services" - msgid "Printer local connection failed, please try again." msgstr "Printer local connection failed; please try again." @@ -5586,8 +5703,7 @@ msgid "" msgstr "" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" msgid "Errors" @@ -5605,10 +5721,6 @@ msgstr "" "currently selected printer. It is recommended that you use the same printer " "type for slicing." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s is not supported by the AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5618,11 +5730,34 @@ msgstr "" "ezek a szükséges filamentek. Ha igen, kattints a „Megerősítés” gombra a " "nyomtatás megkezdéséhez." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Please click the confirm button if you still want to proceed with printing." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5809,6 +5944,9 @@ msgstr "" "A sima timelapse miatt szükség van a törlőtoronyra. Nélküle előfordulhatnak " "hibák a nyomtatott tárgyon. Engedélyezed a törlőtornyot?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5851,8 +5989,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "Ha a nyomtatófej nélküli timelapse engedélyezve van, javasoljuk, hogy " "helyezz el a tálcán egy „Timelapse törlőtornyot“. Ehhez kattints jobb " @@ -6121,6 +6259,9 @@ msgstr "Gép kezdő G-kód" msgid "Machine end G-code" msgstr "Gép befejező G-kód" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "Rétegváltás előtti G-kód" @@ -6187,6 +6328,25 @@ msgstr "" msgid "Detached" msgstr "Különálló" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% beállítás" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "A következő beállítás szintén törlődni fog." @@ -6196,11 +6356,6 @@ msgstr[1] "A következő beállítások szintén törlődni fognak." msgid "Are you sure to %1% the selected preset?" msgstr "Biztos, hogy %1% a kiválasztott beállítást?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% beállítás" - msgid "All" msgstr "Összes" @@ -6442,11 +6597,17 @@ msgstr "" msgid "Auto-Calc" msgstr "Automatikus számítás" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Filament csere tiszítási mennyisége" -msgid "Multiplier" -msgstr "Szorzó" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Egyes filamentpárok tiszítási mennyisége (mm³)." @@ -6459,6 +6620,9 @@ msgstr "Javaslat: öblítési érték a [%d, %d] tartományban" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "A szorzónak [%.2f, %.2f] tartományban kell lennie." +msgid "Multiplier" +msgstr "Szorzó" + msgid "unloaded" msgstr "unloaded" @@ -6474,6 +6638,12 @@ msgstr "Ettől:" msgid "To" msgstr "Eddig:" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Bejelentkezés" @@ -6507,6 +6677,9 @@ msgstr "Beillesztés a vágólapról" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "3Dconnexion-eszközbeállítások párbeszédablak megjelenítése/elrejtése" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Gyorsgombok listájának megjelenítése" @@ -6762,12 +6935,15 @@ msgstr "Új hálózati bővítmény (%s) érhető el. Szeretnéd telepíteni?" msgid "New version of Orca Slicer" msgstr "A Orca Slicer új verziója" -msgid "Don't remind me of this version again" -msgstr "Ne emlékeztessen újra erre a verzióra." +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Done" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN kapcsolódás sikertelen (nyomtatási fájl küldése)" @@ -6793,8 +6969,22 @@ msgstr "Hozzáférési kód" msgid "Where to find your printer's IP and Access Code?" msgstr "Hol találom a nyomtató IP címét és a hozzáférési kódot?" -msgid "Error: IP or Access Code are not correct" -msgstr "Hiba: az IP vagy a hozzáférési kód nem helyes" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Modell:" @@ -7263,6 +7453,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "A rétegmagasság nem lehet nagyobb a fúvóka átmérőjénél." +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7711,7 +7906,28 @@ msgstr "" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" msgid "Reverse threshold" @@ -7952,6 +8168,14 @@ msgstr "Befejező G-kód" msgid "End G-code when finish the whole printing" msgstr "Befejező G-kód az egész nyomtatás befejezésekor" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "Befejező G-kód a filament nyomtatásának befejezésekor" @@ -8038,26 +8262,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "" -msgid "Order of inner wall/outer wall/infil" -msgstr "Belső/külső fal és kitöltés sorrendje" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "A belső fal, a külső fal és a kitöltés nyomtatási sorrendje. " +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "belső/külső/kitöltés" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "külső/belső/kitöltés" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "kitöltés/belső/külső" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "kitöltés/külső/belső" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "belső-külső-belső/kitöltés" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Magasság a rúdig" @@ -8157,9 +8381,6 @@ msgstr "Alapértelmezett szín" msgid "Default filament color" msgstr "Alapértelmezett filament szín" -msgid "Color" -msgstr "Szín" - msgid "Filament notes" msgstr "" @@ -8545,10 +8766,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "" @@ -8616,10 +8833,10 @@ msgstr "Teljes ventilátor fordulatszám ennél a rétegnél" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" msgid "Support interface fan speed" @@ -8908,6 +9125,18 @@ msgid "" "soluble support material" msgstr "" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Vasalás típusa" @@ -9452,6 +9681,22 @@ msgstr "" "nagyobb mozgás közben a tárgynak ütközzön. A Z tengely emelésekor használt " "körkörös mozgás megelőzheti a szálazást." +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "" @@ -9877,7 +10122,13 @@ msgstr "" "„Alapértelmezett“ beállítás választásakor a jelenleg használt filament kerül " "felhasználásra." -msgid "" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." msgstr "" @@ -9910,6 +10161,12 @@ msgstr "A felső érintkező rétegek száma." msgid "Bottom interface layers" msgstr "Alsó érintkező rétegek" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Felső érintkező felület térköze" @@ -10568,111 +10825,18 @@ msgstr "too large line width " msgid " not in range " msgstr " not in range " -msgid "Export 3MF" -msgstr "3MF exportálása" - -msgid "Export project as 3MF." -msgstr "Projekt exportálása 3MF formátumban." - -msgid "Export slicing data" -msgstr "Szeletelési adatok exportálása" - -msgid "Export slicing data to a folder." -msgstr "Szeletelési adatok exportálása egy mappába" - -msgid "Load slicing data" -msgstr "Szeletelési adatok betöltése" - -msgid "Load cached slicing data from directory" -msgstr "Gyorsítótárazott szeletelési adatok betöltése mappából" - -msgid "Export STL" -msgstr "" - -msgid "Export the objects as multiple STL." -msgstr "" - -msgid "Slice" -msgstr "Szeletelés" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "Tálcák szeletelése: 0 - összes tálca, i - i tálca, egyéb - érvénytelen" - -msgid "Show command help." -msgstr "Parancs súgó megjelenítése." - -msgid "UpToDate" -msgstr "Naprakész" - -msgid "Update the configs values of 3mf to latest." -msgstr "Frissítsd a 3mf konfigurációs értékeit a legújabbra." - -msgid "Load default filaments" -msgstr "" - -msgid "Load first filament as default for those not loaded" -msgstr "" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "" -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "max triangle count per plate for slicing" - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "max slicing time per plate in seconds" - msgid "No check" msgstr "No check" msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "Do not run any validity checks, such as G-code path conflicts check." -msgid "Normative check" -msgstr "Normative check" - -msgid "Check the normative items." -msgstr "Check the normative items." - -msgid "Output Model Info" -msgstr "Kimeneti modell információ" - -msgid "Output the model's information." -msgstr "Kimeneti modell információ." - -msgid "Export Settings" -msgstr "Beállítások exportálása" - -msgid "Export settings to a file." -msgstr "Beállítások exportálása egy fájlba." - -msgid "Send progress to pipe" -msgstr "Folyamat elküldése" - -msgid "Send progress to pipe." -msgstr "Folyamat elküldése." - -msgid "Arrange Options" -msgstr "Elrendezési lehetőségek" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Elrendezési lehetőségek: 0-letiltás, 1-engedélyezés, egyéb-auto" - -msgid "Repetions count" -msgstr "" - -msgid "Repetions count of the whole model" -msgstr "" - msgid "Ensure on bed" msgstr "" @@ -10680,12 +10844,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "" -msgid "Convert Unit" -msgstr "Mértékegység átváltása" - -msgid "Convert the units of model" -msgstr "Modell mértékegységének átváltása" - msgid "Orient Options" msgstr "" @@ -10695,47 +10853,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "" -msgid "Rotate around X" -msgstr "" - -msgid "Rotation angle around the X axis in degrees." -msgstr "" - msgid "Rotate around Y" msgstr "" msgid "Rotation angle around the Y axis in degrees." msgstr "" -msgid "Scale the model by a float factor" -msgstr "A modell méretezése egy lebegő tényezővel" - -msgid "Load General Settings" -msgstr "Általános beállítások betöltése" - -msgid "Load process/machine settings from the specified file" -msgstr "Folyamat/gépbeállítások betöltése a megadott fájlból" - -msgid "Load Filament Settings" -msgstr "Filamentbeállítások betöltése" - -msgid "Load filament settings from the specified file list" -msgstr "Filamentbeállítások betöltése a megadott fájllistából" - -msgid "Skip Objects" -msgstr "Skip Objects" - -msgid "Skip some objects in this print" -msgstr "Skip some objects in this print" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" - msgid "Data directory" msgstr "" @@ -10745,22 +10868,6 @@ msgid "" "storage." msgstr "" -msgid "Output directory" -msgstr "Kimeneti mappa" - -msgid "Output directory for the exported files." -msgstr "Az exportált fájlok kimeneti mappája." - -msgid "Debug level" -msgstr "Hibakeresés szintje" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"A hibakeresési naplózási szint beállítása. 0:fatal, 1:error, 2:warning, 3:" -"info, 4:debug, 5:trace\n" - msgid "Load custom gcode" msgstr "" @@ -10924,9 +11031,6 @@ msgstr "" msgid "Finish" msgstr "Kész" -msgid "Wiki" -msgstr "" - msgid "How to use calibration result?" msgstr "" @@ -10942,6 +11046,12 @@ msgstr "" msgid "Calibration not supported" msgstr "" +msgid "Error desc" +msgstr "" + +msgid "Extra info" +msgstr "" + msgid "Flow Dynamics" msgstr "" @@ -10969,8 +11079,8 @@ msgstr "" msgid "The name cannot be empty." msgstr "" -#, boost-format -msgid "The selected preset: %1% is not found." +#, c-format, boost-format +msgid "The selected preset: %s is not found." msgstr "" msgid "The name cannot be the same as the system preset name." @@ -11250,12 +11360,6 @@ msgid "" "- Different filament brand and family(Brand = Bambu, Family = Basic, Matte)" msgstr "" -msgid "Error desc" -msgstr "" - -msgid "Extra info" -msgstr "" - msgid "Pattern" msgstr "" @@ -11344,101 +11448,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "" - -msgid "Mesh Boolean" -msgstr "" - -msgid "Union" -msgstr "" - -msgid "Difference" -msgstr "" - -msgid "Intersection" -msgstr "" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "" - -msgid "Subtract with" -msgstr "" - -msgid "selected" -msgstr "" - -msgid "Part 1" -msgstr "" - -msgid "Part 2" -msgstr "" - -msgid "Delete input" -msgstr "" - -msgid "Send G-Code to printer host" -msgstr "" - -msgid "Upload to Printer Host with the following filename:" -msgstr "" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" - -msgid "Upload to storage" -msgstr "" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" - -msgid "Upload" -msgstr "" - -msgid "Print host upload queue" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "" - -msgctxt "OfFile" -msgid "Size" -msgstr "" - -msgid "Filename" -msgstr "" - -msgid "Cancel selected" -msgstr "" - -msgid "Show error message" -msgstr "" - -msgid "Enqueued" -msgstr "" - -msgid "Uploading" -msgstr "Feltöltés" - -msgid "Cancelling" -msgstr "" - -msgid "Error uploading to print host" -msgstr "" - msgid "PA Calibration" msgstr "" @@ -11563,69 +11572,107 @@ msgstr "" msgid "mm/mm" msgstr "" -msgid "Physical Printer" +msgid "Send G-Code to printer host" msgstr "" -msgid "Print Host upload" +msgid "Upload to Printer Host with the following filename:" msgstr "" -msgid "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." msgstr "" -msgid "Could not get a valid Printer Host reference" +msgid "Upload to storage" msgstr "" -msgid "Success!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" msgstr "" -msgid "Refresh Printers" +msgid "Upload" msgstr "" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." +msgid "Print host upload queue" msgstr "" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "ID" msgstr "" -msgid "Open CA certificate file" +msgid "Progress" msgstr "" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." +msgid "Host" msgstr "" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." +msgctxt "OfFile" +msgid "Size" msgstr "" -msgid "Connection to printers connected via the print host failed." +msgid "Filename" msgstr "" -msgid "The start, end or step is not valid value." +msgid "Cancel selected" msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Show error message" +msgstr "" + +msgid "Enqueued" msgstr "" -msgid "Need select printer" +msgid "Uploading" +msgstr "Feltöltés" + +msgid "Cancelling" +msgstr "" + +msgid "Error uploading to print host" +msgstr "" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "" + +msgid "Mesh Boolean" +msgstr "" + +msgid "Union" +msgstr "" + +msgid "Difference" +msgstr "" + +msgid "Intersection" +msgstr "" + +msgid "Source Volume" +msgstr "" + +msgid "Tool Volume" +msgstr "" + +msgid "Subtract from" +msgstr "" + +msgid "Subtract with" +msgstr "" + +msgid "selected" +msgstr "" + +msgid "Part 1" +msgstr "" + +msgid "Part 2" +msgstr "" + +msgid "Delete input" msgstr "" -#: resources/data/hints.ini: [hint:3D Scene Operations] +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3D-jelenettel kapcsolatos műveletek\n" -"Tudod, hogyan változtathatod meg a nézetet és hogyan választhatod ki az " -"objektumot/tárgyat egérrel és érintőképernyővel a 3D-jelenetben?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -11641,11 +11688,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Modell javítása\n" -"Tudtad, hogy a sérült 3D-modelleket megjavíthatod, amivel elkerülhetsz sok " -"szeletelési problémát?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -11696,6 +11740,13 @@ msgstr "" "Tudtad, hogy megtekintheted az összes objektumot/tárgyat egy listában és " "egyesével módosíthatod a beállításaikat?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -11879,11 +11930,239 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." msgstr "" +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Eszköz-Felületre fektetés" + +#~ msgid "Export as STL" +#~ msgstr "Exportálás STL-ként" + +#~ msgid "Check cloud service status" +#~ msgstr "Check cloud service status" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Adj meg egy érvényes értéket (K 0-0,5 között)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "Adj meg egy érvényes értéket (K 0-0,5, N 0,6-2,0 között)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Összes objektum exportálása STL-ként" + +#~ msgid "Slice ok." +#~ msgstr "Szeletelés kész." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "A 3mf fájl %s verziója újabb, mint a(z) %s verziója %s, a következő " +#~ "ismeretlen kulcsokat találtuk:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Jobb lenne, ha frissítenéd a szoftvert.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "A 3mf fájl %s verziója újabb, mint a(z) %s verziója %s, javasolt a " +#~ "szoftver frissítése." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "A 3mf nem kompatibilis, csak geometriai adatok kerülnek betöltésre!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Nem kompatibilis 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "Nyomtatók hozzáadása/eltávolítása" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s is not supported by the AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Ne emlékeztessen újra erre a verzióra." + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Hiba: az IP vagy a hozzáférési kód nem helyes" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Belső/külső fal és kitöltés sorrendje" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "A belső fal, a külső fal és a kitöltés nyomtatási sorrendje. " + +#~ msgid "inner/outer/infill" +#~ msgstr "belső/külső/kitöltés" + +#~ msgid "outer/inner/infill" +#~ msgstr "külső/belső/kitöltés" + +#~ msgid "infill/inner/outer" +#~ msgstr "kitöltés/belső/külső" + +#~ msgid "infill/outer/inner" +#~ msgstr "kitöltés/külső/belső" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "belső-külső-belső/kitöltés" + +#~ msgid "Export 3MF" +#~ msgstr "3MF exportálása" + +#~ msgid "Export project as 3MF." +#~ msgstr "Projekt exportálása 3MF formátumban." + +#~ msgid "Export slicing data" +#~ msgstr "Szeletelési adatok exportálása" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Szeletelési adatok exportálása egy mappába" + +#~ msgid "Load slicing data" +#~ msgstr "Szeletelési adatok betöltése" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Gyorsítótárazott szeletelési adatok betöltése mappából" + +#~ msgid "Slice" +#~ msgstr "Szeletelés" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "" +#~ "Tálcák szeletelése: 0 - összes tálca, i - i tálca, egyéb - érvénytelen" + +#~ msgid "Show command help." +#~ msgstr "Parancs súgó megjelenítése." + +#~ msgid "UpToDate" +#~ msgstr "Naprakész" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Frissítsd a 3mf konfigurációs értékeit a legújabbra." + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "max triangle count per plate for slicing" + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "max slicing time per plate in seconds" + +#~ msgid "Normative check" +#~ msgstr "Normative check" + +#~ msgid "Check the normative items." +#~ msgstr "Check the normative items." + +#~ msgid "Output Model Info" +#~ msgstr "Kimeneti modell információ" + +#~ msgid "Output the model's information." +#~ msgstr "Kimeneti modell információ." + +#~ msgid "Export Settings" +#~ msgstr "Beállítások exportálása" + +#~ msgid "Export settings to a file." +#~ msgstr "Beállítások exportálása egy fájlba." + +#~ msgid "Send progress to pipe" +#~ msgstr "Folyamat elküldése" + +#~ msgid "Send progress to pipe." +#~ msgstr "Folyamat elküldése." + +#~ msgid "Arrange Options" +#~ msgstr "Elrendezési lehetőségek" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Elrendezési lehetőségek: 0-letiltás, 1-engedélyezés, egyéb-auto" + +#~ msgid "Convert Unit" +#~ msgstr "Mértékegység átváltása" + +#~ msgid "Convert the units of model" +#~ msgstr "Modell mértékegységének átváltása" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "A modell méretezése egy lebegő tényezővel" + +#~ msgid "Load General Settings" +#~ msgstr "Általános beállítások betöltése" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Folyamat/gépbeállítások betöltése a megadott fájlból" + +#~ msgid "Load Filament Settings" +#~ msgstr "Filamentbeállítások betöltése" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "Filamentbeállítások betöltése a megadott fájllistából" + +#~ msgid "Skip Objects" +#~ msgstr "Skip Objects" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Skip some objects in this print" + +#~ msgid "Output directory" +#~ msgstr "Kimeneti mappa" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Az exportált fájlok kimeneti mappája." + +#~ msgid "Debug level" +#~ msgstr "Hibakeresés szintje" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "A hibakeresési naplózási szint beállítása. 0:fatal, 1:error, 2:warning, 3:" +#~ "info, 4:debug, 5:trace\n" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3D-jelenettel kapcsolatos műveletek\n" +#~ "Tudod, hogyan változtathatod meg a nézetet és hogyan választhatod ki az " +#~ "objektumot/tárgyat egérrel és érintőképernyővel a 3D-jelenetben?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Modell javítása\n" +#~ "Tudtad, hogy a sérült 3D-modelleket megjavíthatod, amivel elkerülhetsz " +#~ "sok szeletelési problémát?" + #~ msgid "Embeded" #~ msgstr "Embedded" @@ -11980,9 +12259,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Score" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bambu Engineering Plate" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu High Temperature Plate" diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index e176e5ad4d3..60ed6affb9a 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-12 15:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -98,6 +98,9 @@ msgstr "Nessun supporto automatico" msgid "Support Generated" msgstr "Supporto generato" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Posiziona su faccia" @@ -146,8 +149,8 @@ msgstr "Riempimento Secchio" msgid "Height range" msgstr "Intervallo altezza" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Invio" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Attiva Wireframe" @@ -177,9 +180,15 @@ msgstr "Pitturato utilizzando: Filamento %1%" msgid "Move" msgstr "Sposta" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Ruota" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Ottimizza orientamento" @@ -189,12 +198,12 @@ msgstr "Applica" msgid "Scale" msgstr "Ridimensiona" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "Errore: chiudi prima tutti i menu della barra degli strumenti" -msgid "Tool-Lay on Face" -msgstr "Strumento-Faccia sul piatto" - msgid "in" msgstr "in" @@ -490,6 +499,15 @@ msgstr "Pittura giunzione" msgid "Remove selection" msgstr "Rimuovi selezione" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Font" @@ -611,8 +629,9 @@ msgid "" "features.\n" "Click Yes to install it now." msgstr "" -"Orca Slicer richiede il runtime di Microsoft WebView2 per utilizzare " -"determinate funzionalità.\vFai clic su Sì per installarlo ora.\v" +"Orca Slicer richiede Microsoft WebView2 Runtime per utilizzare alcune " +"funzionalità.\n" +"Fai clic su Sì per installarlo ora." msgid "WebView2 Runtime" msgstr "WebView2 Runtime" @@ -706,6 +725,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Aggiornamento dell'informativa sulla privacy" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Caricamento" @@ -899,8 +926,11 @@ msgstr "Stampabile" msgid "Fix model" msgstr "Correggi il modello" -msgid "Export as STL" -msgstr "Esporta come STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Ricarica da disco" @@ -1163,6 +1193,9 @@ msgstr "Clicca sull'icona per modificare i colori dell'oggetto" msgid "Click the icon to shift this object to the bed" msgstr "Fare clic sull'icona per spostare l'oggetto sul piano" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Caricamento file" @@ -1425,6 +1458,18 @@ msgstr "Apri suggerimento successivo" msgid "Open Documentation in web browser." msgstr "Aprire la documentazione nel browser web" +msgid "Color" +msgstr "Colore" + +msgid "Pause" +msgstr "Pausa" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Personalizzato" + msgid "Pause:" msgstr "Pausa:" @@ -1501,8 +1546,8 @@ msgstr "..." msgid "Failed to connect to the server" msgstr "Connessione al server non riuscita" -msgid "Check cloud service status" -msgstr "Verifica lo stato del servizio cloud" +msgid "Check the status of current system services" +msgstr "Verifica lo stato attuale dei servizi di sistema." msgid "code" msgstr "Codice" @@ -1767,6 +1812,14 @@ msgstr "Invia stampa tramite LAN" msgid "Sending print job through cloud service" msgstr "Invia stampa tramite servizio cloud" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Servizio non disponibile" @@ -2000,11 +2053,11 @@ msgstr "Sei sicuro di voler cancellare le informazioni del filamento?" msgid "You need to select the material type and color first." msgstr "Devi prima selezionare il tipo e il colore del materiale." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Inserisci un valore valido (K in 0~0.5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "Inserisci un valore valido (K in 0~0.5, N in 0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Altro colore" @@ -2404,9 +2457,6 @@ msgstr "Rettangolare" msgid "Circular" msgstr "Circolare" -msgid "Custom" -msgstr "Personalizzato" - msgid "Load shape from STL..." msgstr "Carica forma da STL..." @@ -2916,6 +2966,9 @@ msgstr "Spurgo" msgid "Total" msgstr "Totale" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Stima totale" @@ -3003,15 +3056,18 @@ msgstr "Cambio colore" msgid "Print" msgstr "Stampa" -msgid "Pause" -msgstr "Pausa" - msgid "Printer" msgstr "Stampante" msgid "Print settings" msgstr "Impostazioni di stampa" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Tempo stimato" @@ -3180,7 +3236,7 @@ msgstr "Volume:" msgid "Size:" msgstr "Dimensione:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3243,15 +3299,15 @@ msgstr "Calibrazione flusso" msgid "Start Calibration" msgstr "Start Calibration" -msgid "No step selected" -msgstr "Nessun Step selezionato" - msgid "Completed" msgstr "Completato" msgid "Calibrating" msgstr "Calibrazione" +msgid "No step selected" +msgstr "Nessun Step selezionato" + msgid "Auto-record Monitoring" msgstr "Monitora registrazione automatica" @@ -3466,8 +3522,11 @@ msgstr "Carica configurazioni" msgid "Import" msgstr "Importa" -msgid "Export all objects as STL" -msgstr "Esporta tutti gli oggetti come STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Esporta 3mf generico" @@ -3749,9 +3808,6 @@ msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "" "Stampante in fase di caricamento; attendi il completamento del caricamento." -msgid "Loading..." -msgstr "Caricamento…" - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" "Inizializzazione non riuscita (non supportata nella versione corrente della " @@ -3816,6 +3872,9 @@ msgstr "Riproduzione" msgid "Load failed [%d]!" msgstr "Caricamento non riuscito [%d]!" +msgid "Loading..." +msgstr "Caricamento…" + msgid "Year" msgstr "Anno" @@ -3937,12 +3996,25 @@ msgstr "Download completato" msgid "Downloading %d%%..." msgstr "Scaricamento %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "Non supportato nella versione corrente della stampante." msgid "Storage unavailable, insert SD card." msgstr "Memoria non disponibile, inserire la scheda SD." +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Velocità:" @@ -4295,6 +4367,12 @@ msgstr "Nuovo plug-in di network disponibile" msgid "Details" msgstr "Dettagli" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "Wiki" + msgid "Undo integration failed." msgstr "Annullamento integrazione non riuscito." @@ -4343,9 +4421,6 @@ msgstr "COMPLETATO" msgid "Cancel upload" msgstr "Annulla caricamento" -msgid "Slice ok." -msgstr "Slice completo" - msgid "Jump to" msgstr "Vai a" @@ -4451,6 +4526,9 @@ msgstr "Recupero automatico perdita passi" msgid "Allow Prompt Sound" msgstr "Consenti suono di richiesta" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Globale" @@ -4545,6 +4623,9 @@ msgstr "Sincronizza l'elenco filamenti da AMS" msgid "Set filaments to use" msgstr "Imposta filamenti da usare" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4655,26 +4736,29 @@ msgstr "" "solo i dati geometrici." #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"Versione del 3mf %s è più recente %s della versione %s, trovate le seguenti " -"chiavi non riconosciute:" -msgid "You'd better upgrade your software.\n" -msgstr "Devi aggiornare il software.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Versione 3mf più recente" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"Versione del 3mf %s è più recente della versione %s di %s, si consiglia di " -"aggiornare il software." msgid "Invalid values found in the 3mf:" msgstr "Valori non validi trovati in 3mf:" @@ -4682,11 +4766,27 @@ msgstr "Valori non validi trovati in 3mf:" msgid "Please correct them in the param tabs" msgstr "Si prega di correggerli nella scheda dei Parametri" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "Il 3mf non è compatibile, carica solo i dati della geometria!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "Incompatible 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "" @@ -4762,6 +4862,15 @@ msgstr "Salva come:" msgid "Export OBJ file:" msgstr "Esporta file OBJ:" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Elimina l'oggetto che fa parte dell'oggetto tagliato" @@ -4780,15 +4889,15 @@ msgstr "L'oggetto selezionato non può essere diviso." msgid "Another export job is running." msgstr "È in esecuzione un altro processo di esportazione." -msgid "Replace from:" -msgstr "Sostituisci da:" - msgid "Unable to replace with more than one volume" msgstr "Impossibile sostituire con più di un volume" msgid "Error during replace" msgstr "Errore durante la sostituzione" +msgid "Replace from:" +msgstr "Sostituisci da:" + msgid "Select a new file" msgstr "Seleziona nuovo file" @@ -5168,6 +5277,12 @@ msgstr "Mostra la finestra del codice g" msgid "If enabled, g-code window will be displayed." msgstr "Se abilitato, verrà visualizzata la finestra del codice g." +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Preset" @@ -5217,7 +5332,6 @@ msgstr "" "\"\n" "\"i file .step." - msgid "Maximum recent projects" msgstr "Numero massimo di progetti recenti" @@ -5227,6 +5341,9 @@ msgstr "Numero massimo di progetti recenti" msgid "Clear my choice on the unsaved projects." msgstr "Cancella la mia scelta sui progetti non salvati." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Backup automatico" @@ -5380,8 +5497,11 @@ msgstr "Aggiungi/rimuovi filamento" msgid "Add/Remove materials" msgstr "Aggiungi/rimuovi materiali" -msgid "Add/Remove printers" -msgstr "Aggiungi/Rimuovi stampanti" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Non compatibile" @@ -5566,17 +5686,17 @@ msgstr "Bambu Cool Plate" msgid "PLA Plate" msgstr "Piastra PLA" -msgid "Bambu Engineering Plate" +msgid "Bamabu Engineering Plate" msgstr "Bambu Engineering Plate" -msgid "Bambu Smooth PEI Plate" -msgstr "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" +msgstr "" msgid "High temperature Plate" msgstr "High Temperature Plate" -msgid "Bambu Textured PEI Plate" -msgstr "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" +msgstr "" msgid "Send print job to" msgstr "Invia stampa a" @@ -5599,9 +5719,6 @@ msgstr "Invio completo" msgid "Error code" msgstr "Codice di errore" -msgid "Check the status of current system services" -msgstr "Verifica lo stato attuale dei servizi di sistema." - msgid "Printer local connection failed, please try again." msgstr "Connessione locale della stampante fallita; Si prega di riprovare." @@ -5713,11 +5830,8 @@ msgstr "" "non genereranno video timelapse." msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" -"Quando si stampa per oggetto, le macchine con struttura I3 non genereranno " -"video timelapse." msgid "Errors" msgstr "Errori" @@ -5734,10 +5848,6 @@ msgstr "" "coerente con la stampante attualmente selezionata. Si consiglia di " "utilizzare lo stesso tipo di stampante per lo slicing." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s non è supportato da AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5747,11 +5857,34 @@ msgstr "" "verificare se sono i filamenti necessari. Se sono a posto, fai clic su " "«Conferma» per iniziare a stampare." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Fai clic sul pulsante di conferma se desideri continuare con la stampa." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5947,6 +6080,9 @@ msgstr "" "esserci dei difetti sul modello senza Prime Tower. Vuoi abilitare la Prime " "Tower?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -6262,6 +6398,9 @@ msgstr "Machine start G-code" msgid "Machine end G-code" msgstr "Machine end G-code" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "G-code prima del cambio layer" @@ -6332,6 +6471,25 @@ msgstr "Retrazione Firmware" msgid "Detached" msgstr "Distaccato" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Preset" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "Verrà eliminato anche il seguente preset:" @@ -6341,11 +6499,6 @@ msgstr[1] "The following presets will be deleted too:" msgid "Are you sure to %1% the selected preset?" msgstr "Sei sicuro di voler %1% il preset selezionato?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Preset" - msgid "All" msgstr "Tutto" @@ -6601,11 +6754,17 @@ msgstr "Spaziatura tra linee di ramming" msgid "Auto-Calc" msgstr "Calcolo automatico" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Volumi di spurgo per il cambio filamento" -msgid "Multiplier" -msgstr "Moltiplicatore" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Volume di spurgo (mm³) per ogni coppia di filamento." @@ -6618,6 +6777,9 @@ msgstr "Suggerimento: Volume di spurgo nell'intervallo [%d, %d]" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "Il moltiplicatore deve essere compreso nell'intervallo [%.2f, %.2f]." +msgid "Multiplier" +msgstr "Moltiplicatore" + msgid "unloaded" msgstr "scaricato" @@ -6633,6 +6795,12 @@ msgstr "Da" msgid "To" msgstr "A" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Login" @@ -6670,6 +6838,9 @@ msgstr "" "Mostra/nascondi la finestra di dialogo impostazioni dei dispositivi " "3Dconnexion" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Mostra elenco scorciatoie di tastiera" @@ -6925,12 +7096,15 @@ msgstr "Disponibile nuovo plug-in di rete (%s). Vuoi installarlo?" msgid "New version of Orca Slicer" msgstr "Nuova versione di Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "Non ricordarmi più questa versione." +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Fine" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "Connessione LAN fallita (invio del file di stampa)" @@ -6955,8 +7129,22 @@ msgstr "Codice di accesso" msgid "Where to find your printer's IP and Access Code?" msgstr "Dove trovo l'IP e il codice accesso della stampante?" -msgid "Error: IP or Access Code are not correct" -msgstr "Errore: l'IP o il codice di accesso non sono corretti" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "Test" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Modello:" @@ -7441,6 +7629,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "L'altezza del layer non può superare il diametro del nozzle." +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7929,11 +8122,29 @@ msgstr "Inversione di sbalzo" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" -"Estrudere i perimetri che hanno una parte su una sporgenza nella direzione " -"inversa su layer dispari. Questo schema alternato può migliorare " -"drasticamente lo strapiombo ripido." msgid "Reverse threshold" msgstr "Soglia inversa" @@ -8195,6 +8406,14 @@ msgstr "G-code finale" msgid "End G-code when finish the whole printing" msgstr "Aggiungi G-code quando si termina l'intera stampa." +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "Aggiungi G-code quando si termina la stampa di questo filamento." @@ -8297,27 +8516,26 @@ msgstr "" "In questo modo viene impostata la soglia per la lunghezza del perimetro " "ridotta. La soglia predefinita è 0 mm" -msgid "Order of inner wall/outer wall/infil" -msgstr "Ordine di parete interna/esterna/riempimento" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " +msgid "Print sequence of inner wall and outer wall. " msgstr "" -"È la sequenza di stampa di pareti interne, pareti esterne e dei riempimenti." -msgid "inner/outer/infill" -msgstr "interno/esterno/riempimento" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "esterno/interno/riempimento" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "riempimento/interno/esterno" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "riempimento/esterno/interno" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "interno-esterno-interno/riempimento" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Altezza asta" @@ -8423,9 +8641,6 @@ msgstr "Colore predefinito" msgid "Default filament color" msgstr "Colore predefinito del filamento" -msgid "Color" -msgstr "Colore" - msgid "Filament notes" msgstr "Note filamento" @@ -8884,10 +9099,6 @@ msgid "" msgstr "" "La max_accel_to_decel di Klipper sarà adattata a questo %% di accelerazione" -#, c-format, boost-format -msgid "%%" -msgstr "%%" - msgid "Jerk of outer walls" msgstr "Strappo delle pareti esterne" @@ -9305,6 +9516,18 @@ msgstr "" "Utile per stampe multi estrusore con materiali traslucidi o supporti " "solubili manuali" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Tipo di stiratura" @@ -9936,6 +10159,22 @@ msgstr "" "di colpire la stampa quando si viaggia di più. L'uso di linee a spirale per " "sollevare z può evitare che si stringano." +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "Tipo Z Hop" @@ -10408,7 +10647,13 @@ msgstr "" "non viene utilizzato alcun filamento specifico per il supporto e viene " "utilizzato il filamento corrente" -msgid "" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." msgstr "" @@ -10444,6 +10689,12 @@ msgstr "È il numero di layer di interfaccia superiore." msgid "Bottom interface layers" msgstr "Layer inferiori di interfaccia " +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Spaziatura interfaccia superiore" @@ -11159,7 +11410,6 @@ msgstr "" msgid "Detect narrow internal solid infill" msgstr "Rileva riempimento solido interno stretto" - msgid "" "This option will auto detect narrow internal solid infill area. If enabled, " "concentric pattern will be used for the area to speed printing up. " @@ -11170,7 +11420,6 @@ msgstr "" "velocizzare la stampa. Altrimenti, la trama rettilinea verrà utilizzata per " "impostazione predefinita." - msgid "invalid value " msgstr "Valore non valido" @@ -11187,69 +11436,12 @@ msgstr "larghezza della linea troppo grande " msgid " not in range " msgstr "Fuori portata" -msgid "Export 3MF" -msgstr "Esporta 3MF" - -msgid "Export project as 3MF." -msgstr "Questo esporta il progetto come file 3mf." - -msgid "Export slicing data" -msgstr "Esporta dati elaborati" - -msgid "Export slicing data to a folder." -msgstr "Esporta dati elaborati in una cartella" - -msgid "Load slicing data" -msgstr "Carica dati di slicing" - -msgid "Load cached slicing data from directory" -msgstr "Carica i dati di slicing nella cache dalla directory" - -msgid "Export STL" -msgstr "Esporta STL" - -msgid "Export the objects as multiple STL." -msgstr "Esportare gli oggetti come STL multipli." - -msgid "Slice" -msgstr "Slice" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "Slicing dei piatti: 0-tutti i piatti, i-piatto i, altri-invalidi" - -msgid "Show command help." -msgstr "Mostra la guida ai comandi." - -msgid "UpToDate" -msgstr "Aggiornato" - -msgid "Update the configs values of 3mf to latest." -msgstr "Aggiorna valori di configurazione dei 3mf ai più recenti." - -msgid "Load default filaments" -msgstr "Carica filamenti predefiniti" - -msgid "Load first filament as default for those not loaded" -msgstr "Carica il primo filamento come predefinito per quelli non caricati" - msgid "Minimum save" msgstr "Salvataggio minimo" msgid "export 3mf with minimum size." msgstr "Esporta 3MF con dimensione minima." -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "numero massimo di triangoli per piatto da elaborare" - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "Tempo massimo di slicing per piatto in secondi" - msgid "No check" msgstr "Nessun controllo" @@ -11258,42 +11450,6 @@ msgstr "" "Non eseguire alcun controllo di validità, come il controllo dei conflitti di " "percorso del G-code." -msgid "Normative check" -msgstr "Controllo normativo" - -msgid "Check the normative items." -msgstr "Controlla gli articoli normativi." - -msgid "Output Model Info" -msgstr "Info Modello di output" - -msgid "Output the model's information." -msgstr "Questo produce le informazioni del modello." - -msgid "Export Settings" -msgstr "Esporta impostazioni" - -msgid "Export settings to a file." -msgstr "Questo esporta le impostazioni in un file." - -msgid "Send progress to pipe" -msgstr "Inviare l'avanzamento al pipe" - -msgid "Send progress to pipe." -msgstr "Inviare l'avanzamento al pipe" - -msgid "Arrange Options" -msgstr "Opzioni disposizione" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Opzioni di disposizione: 0-disabilita, 1-abilita, altro-auto" - -msgid "Repetions count" -msgstr "Conteggio delle ripetizioni" - -msgid "Repetions count of the whole model" -msgstr "Numero di ripetizioni dell'intero modello" - msgid "Ensure on bed" msgstr "Accerta che sia sul piano" @@ -11303,12 +11459,6 @@ msgstr "" "Sollevare l'oggetto sopra il letto quando è parzialmente sotto. Disabilitato " "per impostazione predefinita" -msgid "Convert Unit" -msgstr "Converti unità" - -msgid "Convert the units of model" -msgstr "Converti le unità del modello" - msgid "Orient Options" msgstr "Opzioni di orientamento" @@ -11318,51 +11468,12 @@ msgstr "Opzioni di orientamento: 0-disabilita, 1-abilita, altri-auto" msgid "Rotation angle around the Z axis in degrees." msgstr "Angolo di rotazione attorno all'asse Z in gradi." -msgid "Rotate around X" -msgstr "Ruota attorno ad X" - -msgid "Rotation angle around the X axis in degrees." -msgstr "Angolo di rotazione attorno all'asse X in gradi." - msgid "Rotate around Y" msgstr "Ruota attorno ad Y" msgid "Rotation angle around the Y axis in degrees." msgstr "Angolo di rotazione sull'asse Y in gradi." -msgid "Scale the model by a float factor" -msgstr "Ridimensiona il modello in base a un fattore float" - -msgid "Load General Settings" -msgstr "Carica impostazioni generali" - -msgid "Load process/machine settings from the specified file" -msgstr "Carica le impostazioni di processo/macchina dal file specificato" - -msgid "Load Filament Settings" -msgstr "Carica impostazioni filamento" - -msgid "Load filament settings from the specified file list" -msgstr "Carica le impostazioni del filamento dall'elenco di file specificato" - -msgid "Skip Objects" -msgstr "Salta oggetti" - -msgid "Skip some objects in this print" -msgstr "Salta alcuni oggetti in questa stampa" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" -"Caricare le impostazioni di processo/macchina aggiornate quando si utilizza " -"UptoDate" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" -"Caricare le impostazioni di processo/macchina aggiornate dal file " -"specificato quando si utilizza UptoDate" - msgid "Data directory" msgstr "Directory dati" @@ -11374,22 +11485,6 @@ msgstr "" "Carica e archivia le impostazione in una data cartella. Questo è utile per " "mantenere diversi profili o aggiungere configurazioni da un archivio di rete." -msgid "Output directory" -msgstr "Output directory" - -msgid "Output directory for the exported files." -msgstr "Questa è la cartella di destinazione per i file esportati." - -msgid "Debug level" -msgstr "Livello di debug" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Imposta livello di debug. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" - msgid "Load custom gcode" msgstr "Carica gcode personalizzato" @@ -11556,9 +11651,6 @@ msgstr "Calibra" msgid "Finish" msgstr "Fine" -msgid "Wiki" -msgstr "Wiki" - msgid "How to use calibration result?" msgstr "Come utilizzare il risultato della calibrazione?" @@ -11579,6 +11671,12 @@ msgstr "" msgid "Calibration not supported" msgstr "Calibrazione non supportata" +msgid "Error desc" +msgstr "Errore desc" + +msgid "Extra info" +msgstr "Ulteriori informazioni" + msgid "Flow Dynamics" msgstr "Dinamica del flusso" @@ -11611,9 +11709,9 @@ msgstr "" msgid "The name cannot be empty." msgstr "Il nome non può essere vuoto." -#, boost-format -msgid "The selected preset: %1% is not found." -msgstr "Il preset selezionato: %1% non è stato trovato." +#, c-format, boost-format +msgid "The selected preset: %s is not found." +msgstr "" msgid "The name cannot be the same as the system preset name." msgstr "" @@ -11990,12 +12088,6 @@ msgstr "" "- Diverse marche e famiglie di filamenti (Marca = Bambu, Famiglia = Basic, " "Matte)" -msgid "Error desc" -msgstr "Errore desc" - -msgid "Extra info" -msgstr "Ulteriori informazioni" - msgid "Pattern" msgstr "Trama" @@ -12089,101 +12181,6 @@ msgstr "" "Esistono diversi indirizzi IP che risolvono il nome host %1%.\n" "Selezionare quello da utilizzare." -msgid "Unable to perform boolean operation on selected parts" -msgstr "Impossibile eseguire un'operazione booleana sulle parti selezionate" - -msgid "Mesh Boolean" -msgstr "Mesh booleano" - -msgid "Union" -msgstr "Unione" - -msgid "Difference" -msgstr "Differenza" - -msgid "Intersection" -msgstr "Intersezione" - -msgid "Source Volume" -msgstr "Volume sorgente" - -msgid "Tool Volume" -msgstr "Volume dell'utensile" - -msgid "Subtract from" -msgstr "Sottrai da" - -msgid "Subtract with" -msgstr "Sottrai" - -msgid "selected" -msgstr "selezionato" - -msgid "Part 1" -msgstr "Partita #1" - -msgid "Part 2" -msgstr "Partita #2" - -msgid "Delete input" -msgstr "Eliminare l'input" - -msgid "Send G-Code to printer host" -msgstr "Invia G-code all’host stampante" - -msgid "Upload to Printer Host with the following filename:" -msgstr "Carica all'Host di stampa con il seguente nome file:" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "Usa la barra ( / ) come separatore di cartella se necessario." - -msgid "Upload to storage" -msgstr "Carica nello spazio di archiviazione" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "Il nome del file caricato non finisce con \"%s\". Vuoi continuare?" - -msgid "Upload" -msgstr "Carica" - -msgid "Print host upload queue" -msgstr "Coda di caricamento Host di stampa" - -msgid "ID" -msgstr "ID" - -msgid "Progress" -msgstr "Progresso" - -msgid "Host" -msgstr "Host" - -msgctxt "OfFile" -msgid "Size" -msgstr "Dimensione" - -msgid "Filename" -msgstr "Nome file" - -msgid "Cancel selected" -msgstr "Cancella selezione" - -msgid "Show error message" -msgstr "Mostra messaggio d'errore" - -msgid "Enqueued" -msgstr "Messo in coda" - -msgid "Uploading" -msgstr "Caricamento" - -msgid "Cancelling" -msgstr "Annullamento" - -msgid "Error uploading to print host" -msgstr "Errore durante il caricamento dell'host di stampa" - msgid "PA Calibration" msgstr "Calibrazione PA" @@ -12324,78 +12321,107 @@ msgstr "Lunghezza di retrazione finale: " msgid "mm/mm" msgstr "mm/mm" -msgid "Physical Printer" -msgstr "Stampante Fisica" +msgid "Send G-Code to printer host" +msgstr "Invia G-code all’host stampante" -msgid "Print Host upload" -msgstr "Caricamento Host di stampa" +msgid "Upload to Printer Host with the following filename:" +msgstr "Carica all'Host di stampa con il seguente nome file:" -msgid "Test" -msgstr "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "Usa la barra ( / ) come separatore di cartella se necessario." -msgid "Could not get a valid Printer Host reference" -msgstr "Impossibile ottenere un riferimento Host Stampante valido" +msgid "Upload to storage" +msgstr "Carica nello spazio di archiviazione" -msgid "Success!" -msgstr "Successo!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "Il nome del file caricato non finisce con \"%s\". Vuoi continuare?" -msgid "Refresh Printers" -msgstr "Aggiorna Stampanti" +msgid "Upload" +msgstr "Carica" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." -msgstr "" -"File HTTPS CA opzionale. È necessario solo se si intende usare un HTTPS con " -"certificato autofirmato." +msgid "Print host upload queue" +msgstr "Coda di caricamento Host di stampa" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "File di certificato (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "ID" +msgstr "ID" -msgid "Open CA certificate file" -msgstr "Apri file di certificato CA" +msgid "Progress" +msgstr "Progresso" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." -msgstr "" -"Su questo sistema, %s utilizza certificati HTTPS provenienti dal sistema " -"Certificate Store o da Keychain." +msgid "Host" +msgstr "Host" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." -msgstr "" -"Per utilizzare un file CA personalizzato, importa il tuo file CA sul " -"Certificate Store / Keychain." +msgctxt "OfFile" +msgid "Size" +msgstr "Dimensione" -msgid "Connection to printers connected via the print host failed." -msgstr "" -"Collegamento alle stampanti collegate tramite l'host di stampa fallito." +msgid "Filename" +msgstr "Nome file" -msgid "The start, end or step is not valid value." -msgstr "L'inizio, la fine o il passo non sono valori validi." +msgid "Cancel selected" +msgstr "Cancella selezione" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" -msgstr "" -"Impossibile calibrare: forse perché l'intervallo di valori di calibrazione " -"impostato è troppo ampio o il passo è troppo piccolo" +msgid "Show error message" +msgstr "Mostra messaggio d'errore" + +msgid "Enqueued" +msgstr "Messo in coda" + +msgid "Uploading" +msgstr "Caricamento" + +msgid "Cancelling" +msgstr "Annullamento" + +msgid "Error uploading to print host" +msgstr "Errore durante il caricamento dell'host di stampa" -msgid "Need select printer" -msgstr "Hai bisogno di selezionare la stampante" +msgid "Unable to perform boolean operation on selected parts" +msgstr "Impossibile eseguire un'operazione booleana sulle parti selezionate" + +msgid "Mesh Boolean" +msgstr "Mesh booleano" + +msgid "Union" +msgstr "Unione" + +msgid "Difference" +msgstr "Differenza" + +msgid "Intersection" +msgstr "Intersezione" + +msgid "Source Volume" +msgstr "Volume sorgente" + +msgid "Tool Volume" +msgstr "Volume dell'utensile" + +msgid "Subtract from" +msgstr "Sottrai da" + +msgid "Subtract with" +msgstr "Sottrai" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "selected" +msgstr "selezionato" + +msgid "Part 1" +msgstr "Partita #1" + +msgid "Part 2" +msgstr "Partita #2" + +msgid "Delete input" +msgstr "Eliminare l'input" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"Operazioni sulla scena 3D\n" -"Sapete come controllare la vista e la selezione di oggetti/parti con il " -"mouse e il touch panel nella scena 3D?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -12411,11 +12437,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Correggi Modello\n" -"Sapevi che puoi correggere un modello 3D danneggiato per evitare molti " -"problemi di slicing?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -12465,6 +12488,13 @@ msgstr "" "Sapevate che è possibile visualizzare tutti gli oggetti/parti in un elenco e " "modificare le impostazioni per ciascun oggetto/parte?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -12660,15 +12690,381 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." msgstr "" -"Quando è necessario stampare con lo sportello della stampante aperto\n" -"L'apertura dello sportello della stampante può ridurre la probabilità di " -"intasamento dell'estrusore/hotend quando si stampa un filamento a " -"temperatura inferiore con una temperatura dell'involucro più elevata. " -"Maggiori informazioni su questo nel Wiki." + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." +msgstr "" + +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Invio" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Strumento-Faccia sul piatto" + +#~ msgid "Export as STL" +#~ msgstr "Esporta come STL" + +#~ msgid "Check cloud service status" +#~ msgstr "Verifica lo stato del servizio cloud" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Inserisci un valore valido (K in 0~0.5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "Inserisci un valore valido (K in 0~0.5, N in 0.6~2.0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Esporta tutti gli oggetti come STL" + +#~ msgid "Slice ok." +#~ msgstr "Slice completo" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "Versione del 3mf %s è più recente %s della versione %s, trovate le " +#~ "seguenti chiavi non riconosciute:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Devi aggiornare il software.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "Versione del 3mf %s è più recente della versione %s di %s, si consiglia " +#~ "di aggiornare il software." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "Il 3mf non è compatibile, carica solo i dati della geometria!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Incompatible 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "Aggiungi/Rimuovi stampanti" + +#~ msgid "Bambu Engineering Plate" +#~ msgstr "Bambu Engineering Plate" + +#~ msgid "Bambu Smooth PEI Plate" +#~ msgstr "Bambu Smooth PEI Plate" + +#~ msgid "Bambu Textured PEI Plate" +#~ msgstr "Bambu Textured PEI Plate" + +#~ msgid "" +#~ "When print by object, machines with I3 structure will not generate " +#~ "timelapse videos." +#~ msgstr "" +#~ "Quando si stampa per oggetto, le macchine con struttura I3 non " +#~ "genereranno video timelapse." + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s non è supportato da AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Non ricordarmi più questa versione." + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Errore: l'IP o il codice di accesso non sono corretti" + +#~ msgid "" +#~ "Extrude perimeters that have a part over an overhang in the reverse " +#~ "direction on odd layers. This alternating pattern can drastically improve " +#~ "steep overhang." +#~ msgstr "" +#~ "Estrudere i perimetri che hanno una parte su una sporgenza nella " +#~ "direzione inversa su layer dispari. Questo schema alternato può " +#~ "migliorare drasticamente lo strapiombo ripido." + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Ordine di parete interna/esterna/riempimento" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "" +#~ "È la sequenza di stampa di pareti interne, pareti esterne e dei " +#~ "riempimenti." + +#~ msgid "inner/outer/infill" +#~ msgstr "interno/esterno/riempimento" + +#~ msgid "outer/inner/infill" +#~ msgstr "esterno/interno/riempimento" + +#~ msgid "infill/inner/outer" +#~ msgstr "riempimento/interno/esterno" + +#~ msgid "infill/outer/inner" +#~ msgstr "riempimento/esterno/interno" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "interno-esterno-interno/riempimento" + +#, c-format, boost-format +#~ msgid "%%" +#~ msgstr "%%" + +#~ msgid "Export 3MF" +#~ msgstr "Esporta 3MF" + +#~ msgid "Export project as 3MF." +#~ msgstr "Questo esporta il progetto come file 3mf." + +#~ msgid "Export slicing data" +#~ msgstr "Esporta dati elaborati" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Esporta dati elaborati in una cartella" + +#~ msgid "Load slicing data" +#~ msgstr "Carica dati di slicing" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Carica i dati di slicing nella cache dalla directory" + +#~ msgid "Export STL" +#~ msgstr "Esporta STL" + +#~ msgid "Export the objects as multiple STL." +#~ msgstr "Esportare gli oggetti come STL multipli." + +#~ msgid "Slice" +#~ msgstr "Slice" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "Slicing dei piatti: 0-tutti i piatti, i-piatto i, altri-invalidi" + +#~ msgid "Show command help." +#~ msgstr "Mostra la guida ai comandi." + +#~ msgid "UpToDate" +#~ msgstr "Aggiornato" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Aggiorna valori di configurazione dei 3mf ai più recenti." + +#~ msgid "Load default filaments" +#~ msgstr "Carica filamenti predefiniti" + +#~ msgid "Load first filament as default for those not loaded" +#~ msgstr "Carica il primo filamento come predefinito per quelli non caricati" + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "numero massimo di triangoli per piatto da elaborare" + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "Tempo massimo di slicing per piatto in secondi" + +#~ msgid "Normative check" +#~ msgstr "Controllo normativo" + +#~ msgid "Check the normative items." +#~ msgstr "Controlla gli articoli normativi." + +#~ msgid "Output Model Info" +#~ msgstr "Info Modello di output" + +#~ msgid "Output the model's information." +#~ msgstr "Questo produce le informazioni del modello." + +#~ msgid "Export Settings" +#~ msgstr "Esporta impostazioni" + +#~ msgid "Export settings to a file." +#~ msgstr "Questo esporta le impostazioni in un file." + +#~ msgid "Send progress to pipe" +#~ msgstr "Inviare l'avanzamento al pipe" + +#~ msgid "Send progress to pipe." +#~ msgstr "Inviare l'avanzamento al pipe" + +#~ msgid "Arrange Options" +#~ msgstr "Opzioni disposizione" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Opzioni di disposizione: 0-disabilita, 1-abilita, altro-auto" + +#~ msgid "Repetions count" +#~ msgstr "Conteggio delle ripetizioni" + +#~ msgid "Repetions count of the whole model" +#~ msgstr "Numero di ripetizioni dell'intero modello" + +#~ msgid "Convert Unit" +#~ msgstr "Converti unità" + +#~ msgid "Convert the units of model" +#~ msgstr "Converti le unità del modello" + +#~ msgid "Rotate around X" +#~ msgstr "Ruota attorno ad X" + +#~ msgid "Rotation angle around the X axis in degrees." +#~ msgstr "Angolo di rotazione attorno all'asse X in gradi." + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Ridimensiona il modello in base a un fattore float" + +#~ msgid "Load General Settings" +#~ msgstr "Carica impostazioni generali" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Carica le impostazioni di processo/macchina dal file specificato" + +#~ msgid "Load Filament Settings" +#~ msgstr "Carica impostazioni filamento" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "" +#~ "Carica le impostazioni del filamento dall'elenco di file specificato" + +#~ msgid "Skip Objects" +#~ msgstr "Salta oggetti" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Salta alcuni oggetti in questa stampa" + +#~ msgid "load uptodate process/machine settings when using uptodate" +#~ msgstr "" +#~ "Caricare le impostazioni di processo/macchina aggiornate quando si " +#~ "utilizza UptoDate" + +#~ msgid "" +#~ "load uptodate process/machine settings from the specified file when using " +#~ "uptodate" +#~ msgstr "" +#~ "Caricare le impostazioni di processo/macchina aggiornate dal file " +#~ "specificato quando si utilizza UptoDate" + +#~ msgid "Output directory" +#~ msgstr "Output directory" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Questa è la cartella di destinazione per i file esportati." + +#~ msgid "Debug level" +#~ msgstr "Livello di debug" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Imposta livello di debug. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" + +#, boost-format +#~ msgid "The selected preset: %1% is not found." +#~ msgstr "Il preset selezionato: %1% non è stato trovato." + +#~ msgid "Physical Printer" +#~ msgstr "Stampante Fisica" + +#~ msgid "Print Host upload" +#~ msgstr "Caricamento Host di stampa" + +#~ msgid "Could not get a valid Printer Host reference" +#~ msgstr "Impossibile ottenere un riferimento Host Stampante valido" + +#~ msgid "Success!" +#~ msgstr "Successo!" + +#~ msgid "Refresh Printers" +#~ msgstr "Aggiorna Stampanti" + +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "File HTTPS CA opzionale. È necessario solo se si intende usare un HTTPS " +#~ "con certificato autofirmato." + +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "File di certificato (*.crt, *.pem)|*.crt;*.pem|All files|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "Apri file di certificato CA" + +#, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "" +#~ "Su questo sistema, %s utilizza certificati HTTPS provenienti dal sistema " +#~ "Certificate Store o da Keychain." + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "Per utilizzare un file CA personalizzato, importa il tuo file CA sul " +#~ "Certificate Store / Keychain." + +#~ msgid "Connection to printers connected via the print host failed." +#~ msgstr "" +#~ "Collegamento alle stampanti collegate tramite l'host di stampa fallito." + +#~ msgid "The start, end or step is not valid value." +#~ msgstr "L'inizio, la fine o il passo non sono valori validi." + +#~ msgid "" +#~ "Unable to calibrate: maybe because the set calibration value range is too " +#~ "large, or the step is too small" +#~ msgstr "" +#~ "Impossibile calibrare: forse perché l'intervallo di valori di " +#~ "calibrazione impostato è troppo ampio o il passo è troppo piccolo" + +#~ msgid "Need select printer" +#~ msgstr "Hai bisogno di selezionare la stampante" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "Operazioni sulla scena 3D\n" +#~ "Sapete come controllare la vista e la selezione di oggetti/parti con il " +#~ "mouse e il touch panel nella scena 3D?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Correggi Modello\n" +#~ "Sapevi che puoi correggere un modello 3D danneggiato per evitare molti " +#~ "problemi di slicing?" + +#~ msgid "" +#~ "When need to print with the printer door opened\n" +#~ "Opening the printer door can reduce the probability of extruder/hotend " +#~ "clogging when printing lower temperature filament with a higher enclosure " +#~ "temperature. More info about this in the Wiki." +#~ msgstr "" +#~ "Quando è necessario stampare con lo sportello della stampante aperto\n" +#~ "L'apertura dello sportello della stampante può ridurre la probabilità di " +#~ "intasamento dell'estrusore/hotend quando si stampa un filamento a " +#~ "temperatura inferiore con una temperatura dell'involucro più elevata. " +#~ "Maggiori informazioni su questo nel Wiki." #~ msgid "Embeded" #~ msgstr "Integrato" @@ -12765,9 +13161,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Punteggio" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bambu Engineering Plate" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu High Temperature Plate" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index fa406bf3955..080a316054a 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -101,6 +101,9 @@ msgstr "自動サポート無し" msgid "Support Generated" msgstr "生成されたサポート" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "底面選択" @@ -147,8 +150,8 @@ msgstr "塗りつぶしバッチ処理" msgid "Height range" msgstr "高さ範囲" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "ワイヤフレームの表示/非表示" @@ -178,9 +181,15 @@ msgstr "フィラメント %1%でペイントします" msgid "Move" msgstr "移動" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "回転" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "向きを最適化" @@ -190,12 +199,12 @@ msgstr "適用" msgid "Scale" msgstr "スケール" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "エラー: ツールバーを閉じてください" -msgid "Tool-Lay on Face" -msgstr "ツール 底面選択" - msgid "in" msgstr "に" @@ -489,6 +498,15 @@ msgstr "継ぎ目ペイント" msgid "Remove selection" msgstr "選択を削除" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "フォント" @@ -687,6 +705,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Privacy Policy Update" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "ロード中" @@ -880,8 +906,11 @@ msgstr "造形可能" msgid "Fix model" msgstr "モデルを修復" -msgid "Export as STL" -msgstr "STL形式でエクスポート" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "ディスクから再読込み" @@ -1133,6 +1162,9 @@ msgstr "オブジェクトに色塗りをします" msgid "Click the icon to shift this object to the bed" msgstr "Click the icon to shift this object to the bed" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "ファイルを読み込み中" @@ -1386,6 +1418,18 @@ msgstr "次のヒント" msgid "Open Documentation in web browser." msgstr "ブラウザで開く" +msgid "Color" +msgstr "色" + +msgid "Pause" +msgstr "一時停止" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "カスタム" + msgid "Pause:" msgstr "Pause:" @@ -1461,8 +1505,8 @@ msgstr "" msgid "Failed to connect to the server" msgstr "サーバーに接続できませんでした" -msgid "Check cloud service status" -msgstr "Check cloud service status" +msgid "Check the status of current system services" +msgstr "Check the status of current system services" msgid "code" msgstr "code" @@ -1722,6 +1766,14 @@ msgstr "LAN経由で造形タスクを送信" msgid "Sending print job through cloud service" msgstr "クラウド経由で造形タスクを送信" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "サービスは利用できません" @@ -1941,11 +1993,11 @@ msgstr "Are you sure you want to clear the filament information?" msgid "You need to select the material type and color first." msgstr "You need to select the material type and color first." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "有効な値を入力してください (0 ~ 0.5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "有効な値を入力してください (K: 0 ~ 0.5, N: 0.6 ~ 2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Other Color" @@ -2302,9 +2354,6 @@ msgstr "長方形" msgid "Circular" msgstr "円形" -msgid "Custom" -msgstr "カスタム" - msgid "Load shape from STL..." msgstr "STLからシェープデータを読込む" @@ -2774,6 +2823,9 @@ msgstr "フラッシュ" msgid "Total" msgstr "合計" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "予測合計" @@ -2861,15 +2913,18 @@ msgstr "色変更" msgid "Print" msgstr "造形する" -msgid "Pause" -msgstr "一時停止" - msgid "Printer" msgstr "プリンター" msgid "Print settings" msgstr "造形設定" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "予測時間" @@ -3038,7 +3093,7 @@ msgstr "ボリューム" msgid "Size:" msgstr "サイズ:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3096,15 +3151,15 @@ msgstr "キャリブレーション項目" msgid "Start Calibration" msgstr "キャリブレーションを開始" -msgid "No step selected" -msgstr "" - msgid "Completed" msgstr "完了" msgid "Calibrating" msgstr "キャリブレーション中" +msgid "No step selected" +msgstr "" + msgid "Auto-record Monitoring" msgstr "自動録画モニタリング" @@ -3318,8 +3373,11 @@ msgstr "構成を読み込む" msgid "Import" msgstr "インポート" -msgid "Export all objects as STL" -msgstr "全てのオブジェクト (STL)" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "汎用3MF" @@ -3590,9 +3648,6 @@ msgstr "初期化失敗 (カメラ無し)" msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "プリンターがダウンロード中、完了までお待ちください" -msgid "Loading..." -msgstr "読込み中" - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" @@ -3652,6 +3707,9 @@ msgstr "再生中..." msgid "Load failed [%d]!" msgstr "ロード失敗 [%d]!" +msgid "Loading..." +msgstr "読込み中" + msgid "Year" msgstr "年" @@ -3768,12 +3826,25 @@ msgstr "ダウンロード完了" msgid "Downloading %d%%..." msgstr "ダウンロード中 %d%%" +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "" msgid "Storage unavailable, insert SD card." msgstr "" +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "速度" @@ -4104,6 +4175,12 @@ msgstr "新しいネットワークプラグインが利用可能" msgid "Details" msgstr "詳細" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "" + msgid "Undo integration failed." msgstr "統合の取り消しに失敗しました。" @@ -4149,9 +4226,6 @@ msgstr "完了" msgid "Cancel upload" msgstr "アップロードを取消し" -msgid "Slice ok." -msgstr "スライス完了" - msgid "Jump to" msgstr "確認" @@ -4254,6 +4328,9 @@ msgstr "自動回復" msgid "Allow Prompt Sound" msgstr "" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "全般" @@ -4348,6 +4425,9 @@ msgstr "AMSと素材を同期" msgid "Set filaments to use" msgstr "フィラメントを選択" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4444,25 +4524,29 @@ msgstr "" "込みます。" #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"3mfのバージョン %s は %sのバージョン %sより新しい為、下記のキーを認識できませ" -"ん" -msgid "You'd better upgrade your software.\n" -msgstr "ソフトウェアをアップデートする必要があります。\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "新3mfバージョン" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"3mfのバージョン%sは%sの%sより新しい為、ソフトウェアを更新してください。" msgid "Invalid values found in the 3mf:" msgstr "Invalid values found in the 3mf:" @@ -4470,12 +4554,27 @@ msgstr "Invalid values found in the 3mf:" msgid "Please correct them in the param tabs" msgstr "Please correct them in the Param tabs" -msgid "The 3mf is not compatible, load geometry data only!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" msgstr "" -"この3mfファイルと互換性がありません、ジオメトリーデータのみ読込みます。" -msgid "Incompatible 3mf" -msgstr "互換性の無い 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "ファイルのエンコーディング方式はUTF8形式ではありません" @@ -4545,6 +4644,15 @@ msgstr "名前を付けて保存" msgid "Export OBJ file:" msgstr "" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Delete object which is a part of cut object" @@ -4563,15 +4671,15 @@ msgstr "選択したオブジェクトを分割できませんでした。" msgid "Another export job is running." msgstr "エクスポート中です" -msgid "Replace from:" -msgstr "" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "交換時のエラー" +msgid "Replace from:" +msgstr "" + msgid "Select a new file" msgstr "ファイルを選択" @@ -4940,6 +5048,12 @@ msgstr "" msgid "If enabled, g-code window will be displayed." msgstr "" +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Presets" @@ -4988,6 +5102,9 @@ msgstr "Maximum count of recent projects" msgid "Clear my choice on the unsaved projects." msgstr "Clear my choice on the unsaved projects." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "自動バックアップ" @@ -5141,8 +5258,11 @@ msgstr "フィラメントを追加/削除" msgid "Add/Remove materials" msgstr "素材を追加/削除" -msgid "Add/Remove printers" -msgstr "プリンターを追加/削除" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Incompatible" @@ -5324,16 +5444,16 @@ msgstr "Bambu 常温プレート" msgid "PLA Plate" msgstr "PLA Plate" -msgid "Bambu Engineering Plate" -msgstr "" +msgid "Bamabu Engineering Plate" +msgstr "Bambu エンジニアリングプレート" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "" msgid "High temperature Plate" msgstr "" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "" msgid "Send print job to" @@ -5357,9 +5477,6 @@ msgstr "送信完了" msgid "Error code" msgstr "Error code" -msgid "Check the status of current system services" -msgstr "Check the status of current system services" - msgid "Printer local connection failed, please try again." msgstr "Printer local connection failed; please try again." @@ -5449,8 +5566,7 @@ msgid "" msgstr "" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" msgid "Errors" @@ -5468,10 +5584,6 @@ msgstr "" "currently selected printer. It is recommended that you use the same printer " "type for slicing." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s is not supported by the AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5480,11 +5592,34 @@ msgstr "" "不明なフィラメントがあります、造形に必要かどうかご確認ください。引き続き造形" "する場合は、「確認」を押してください。" +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Please click the confirm button if you still want to proceed with printing." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5668,6 +5803,9 @@ msgstr "" "スムーズタイムラプスビデオを作成するにはプライムタワーが必要です。プライムタ" "ワーを有効にしますか?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5705,8 +5843,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "ヘッド無しのタイムラプスビデオを録画する時に、「タイムラプスプライムタワー」" "を追加してください。プレートで右クリックして、「プリミティブを追加」→「タイム" @@ -5962,6 +6100,9 @@ msgstr "プリンター開始G-code" msgid "Machine end G-code" msgstr "プリンター終了G-code" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "積層変更前のG-code" @@ -6028,6 +6169,24 @@ msgstr "" msgid "Detached" msgstr "分離的" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% プリセット" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "以下のプリセットも削除されます: " @@ -6036,11 +6195,6 @@ msgstr[0] "以下のプリセットも削除されます: " msgid "Are you sure to %1% the selected preset?" msgstr "選択したプリセットを %1% しますか?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% プリセット" - msgid "All" msgstr "すべて" @@ -6270,11 +6424,17 @@ msgstr "" msgid "Auto-Calc" msgstr "自動計算" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "フィラメントを入替える為のフラッシュ量" -msgid "Multiplier" -msgstr "マルチプライヤ" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "各フィラメントペアのフラッシュ量(mm³)" @@ -6287,6 +6447,9 @@ msgstr "推奨フラッシュ量範囲 [%d, %d]" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "マルチプライヤーの有効範囲は [%.2f, %.2f] です。" +msgid "Multiplier" +msgstr "マルチプライヤ" + msgid "unloaded" msgstr "アンロードしました" @@ -6302,6 +6465,12 @@ msgstr "From" msgid "To" msgstr "→" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "サインイン" @@ -6335,6 +6504,9 @@ msgstr "貼り付け" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "3Dconnexion設定を表示/非表示" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "ショートカット一覧を表示" @@ -6583,12 +6755,15 @@ msgstr "新しいプラグイン (%s) が発見しました、インストール msgid "New version of Orca Slicer" msgstr "新バージョン" -msgid "Don't remind me of this version again" -msgstr "今後このバージョンの通知をしません" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Done" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN接続失敗 (造形ファイル送信)" @@ -6610,8 +6785,22 @@ msgstr "アクセスコード" msgid "Where to find your printer's IP and Access Code?" msgstr "どこでプリンターのIPアドレスとアクセスコードを確認できますか?" -msgid "Error: IP or Access Code are not correct" -msgstr "エラー: IPアドレス或はアクセスコードが正しくありません" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "モデル" @@ -7055,6 +7244,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "積層ピッチはノズルの直径を超える為設定できません" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7469,7 +7663,28 @@ msgstr "" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" msgid "Reverse threshold" @@ -7701,6 +7916,14 @@ msgstr "終了G-code" msgid "End G-code when finish the whole printing" msgstr "造形完了時のG-codeを追加" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "このフィラメントを使用終わった時のG-codeを追加" @@ -7784,26 +8007,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "" -msgid "Order of inner wall/outer wall/infil" -msgstr "造形順番" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "内壁、外壁とインフィルの造形順序を指定します。" +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "内壁/外壁/インフィル" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "外壁/内壁/インフィル" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "インフィル/内壁/外壁" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "インフィル/外壁/内壁" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "内壁-外壁-内壁/インフィル" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "レールまでの高さ" @@ -7894,9 +8117,6 @@ msgstr "デフォルト色" msgid "Default filament color" msgstr "フィラメントのデフォルト色" -msgid "Color" -msgstr "色" - msgid "Filament notes" msgstr "" @@ -8269,10 +8489,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "" @@ -8338,10 +8554,10 @@ msgstr "最大回転速度の積層" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" msgid "Support interface fan speed" @@ -8617,6 +8833,18 @@ msgid "" "soluble support material" msgstr "" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "アイロン面" @@ -9139,6 +9367,22 @@ msgstr "" "リトラクション時に、ノズルを少し上げてから移動します。この動作でモデルとの衝" "突を回避できます。" +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "" @@ -9539,6 +9783,12 @@ msgstr "" "サポートとラフトを造形用のフィラメント。「デフォルト」では当時のフィラメント" "を使用する意味です。" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." @@ -9572,6 +9822,12 @@ msgstr "トップ接触面の層数" msgid "Bottom interface layers" msgstr "底部接触面層数" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "トップ接触面間隔" @@ -10194,111 +10450,18 @@ msgstr "too large line width " msgid " not in range " msgstr " not in range " -msgid "Export 3MF" -msgstr "3mf をエクスポート" - -msgid "Export project as 3MF." -msgstr "プロジェクトを3MF式で出力" - -msgid "Export slicing data" -msgstr "スライスデータをエクスポート" - -msgid "Export slicing data to a folder." -msgstr "スライスデータをエクスポート" - -msgid "Load slicing data" -msgstr "スライスデータを読込み" - -msgid "Load cached slicing data from directory" -msgstr "スライスデータを読込み" - -msgid "Export STL" -msgstr "" - -msgid "Export the objects as multiple STL." -msgstr "" - -msgid "Slice" -msgstr "スライス" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "プレートをスライス: 0: 全て, i:プレートi, その他: 無効" - -msgid "Show command help." -msgstr "ヘルプを表示します。" - -msgid "UpToDate" -msgstr "最新の状態です。" - -msgid "Update the configs values of 3mf to latest." -msgstr "3mfの構成値を更新" - -msgid "Load default filaments" -msgstr "" - -msgid "Load first filament as default for those not loaded" -msgstr "" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "" -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "max triangle count per plate for slicing" - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "max slicing time per plate in seconds" - msgid "No check" msgstr "No check" msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "Do not run any validity checks, such as G-code path conflicts check." -msgid "Normative check" -msgstr "Normative check" - -msgid "Check the normative items." -msgstr "Check the normative items." - -msgid "Output Model Info" -msgstr "出力モデル情報" - -msgid "Output the model's information." -msgstr "出力するモデル情報です。" - -msgid "Export Settings" -msgstr "エクスポート設定" - -msgid "Export settings to a file." -msgstr "設定をファイルにエクスポートします。" - -msgid "Send progress to pipe" -msgstr "パイプに進捗を送信" - -msgid "Send progress to pipe." -msgstr "パイプに進捗を送信" - -msgid "Arrange Options" -msgstr "レイアウト設定" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "レイアウト設定: 0: 無効 1: 有効 その他: 自動" - -msgid "Repetions count" -msgstr "" - -msgid "Repetions count of the whole model" -msgstr "" - msgid "Ensure on bed" msgstr "" @@ -10306,12 +10469,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "" -msgid "Convert Unit" -msgstr "単位変換" - -msgid "Convert the units of model" -msgstr "モデルの単位を変換" - msgid "Orient Options" msgstr "" @@ -10321,47 +10478,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "" -msgid "Rotate around X" -msgstr "" - -msgid "Rotation angle around the X axis in degrees." -msgstr "" - msgid "Rotate around Y" msgstr "" msgid "Rotation angle around the Y axis in degrees." msgstr "" -msgid "Scale the model by a float factor" -msgstr "指定した比率で伸縮する" - -msgid "Load General Settings" -msgstr "一般設定を読込む" - -msgid "Load process/machine settings from the specified file" -msgstr "指定ファイルから設定値を読込む" - -msgid "Load Filament Settings" -msgstr "フィラメント設定を読込む" - -msgid "Load filament settings from the specified file list" -msgstr "指定したファイルリストからフィラメント設定を読込む" - -msgid "Skip Objects" -msgstr "Skip Objects" - -msgid "Skip some objects in this print" -msgstr "Skip some objects in this print" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" - msgid "Data directory" msgstr "" @@ -10371,22 +10493,6 @@ msgid "" "storage." msgstr "" -msgid "Output directory" -msgstr "出力先フォルダ" - -msgid "Output directory for the exported files." -msgstr "エクスポートの出力先フォルダです。" - -msgid "Debug level" -msgstr "デバッグ レベル" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"デバッグロギングレベルを設定します。0:fatal、1:error、2:warning、3:info、4:" -"debug、5:trace。\n" - msgid "Load custom gcode" msgstr "" @@ -10550,9 +10656,6 @@ msgstr "" msgid "Finish" msgstr "完了" -msgid "Wiki" -msgstr "" - msgid "How to use calibration result?" msgstr "" @@ -10568,6 +10671,12 @@ msgstr "" msgid "Calibration not supported" msgstr "" +msgid "Error desc" +msgstr "" + +msgid "Extra info" +msgstr "" + msgid "Flow Dynamics" msgstr "" @@ -10595,8 +10704,8 @@ msgstr "" msgid "The name cannot be empty." msgstr "" -#, boost-format -msgid "The selected preset: %1% is not found." +#, c-format, boost-format +msgid "The selected preset: %s is not found." msgstr "" msgid "The name cannot be the same as the system preset name." @@ -10876,12 +10985,6 @@ msgid "" "- Different filament brand and family(Brand = Bambu, Family = Basic, Matte)" msgstr "" -msgid "Error desc" -msgstr "" - -msgid "Extra info" -msgstr "" - msgid "Pattern" msgstr "" @@ -10970,101 +11073,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "" - -msgid "Mesh Boolean" -msgstr "" - -msgid "Union" -msgstr "" - -msgid "Difference" -msgstr "" - -msgid "Intersection" -msgstr "" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "" - -msgid "Subtract with" -msgstr "" - -msgid "selected" -msgstr "" - -msgid "Part 1" -msgstr "" - -msgid "Part 2" -msgstr "" - -msgid "Delete input" -msgstr "" - -msgid "Send G-Code to printer host" -msgstr "" - -msgid "Upload to Printer Host with the following filename:" -msgstr "" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" - -msgid "Upload to storage" -msgstr "" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" - -msgid "Upload" -msgstr "" - -msgid "Print host upload queue" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "" - -msgctxt "OfFile" -msgid "Size" -msgstr "" - -msgid "Filename" -msgstr "" - -msgid "Cancel selected" -msgstr "" - -msgid "Show error message" -msgstr "" - -msgid "Enqueued" -msgstr "" - -msgid "Uploading" -msgstr "アップロード中" - -msgid "Cancelling" -msgstr "" - -msgid "Error uploading to print host" -msgstr "" - msgid "PA Calibration" msgstr "" @@ -11189,68 +11197,107 @@ msgstr "" msgid "mm/mm" msgstr "" -msgid "Physical Printer" +msgid "Send G-Code to printer host" msgstr "" -msgid "Print Host upload" +msgid "Upload to Printer Host with the following filename:" msgstr "" -msgid "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." msgstr "" -msgid "Could not get a valid Printer Host reference" +msgid "Upload to storage" msgstr "" -msgid "Success!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" msgstr "" -msgid "Refresh Printers" +msgid "Upload" msgstr "" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." +msgid "Print host upload queue" msgstr "" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "ID" msgstr "" -msgid "Open CA certificate file" +msgid "Progress" msgstr "" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." +msgid "Host" msgstr "" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." +msgctxt "OfFile" +msgid "Size" msgstr "" -msgid "Connection to printers connected via the print host failed." +msgid "Filename" msgstr "" -msgid "The start, end or step is not valid value." +msgid "Cancel selected" msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Show error message" +msgstr "" + +msgid "Enqueued" msgstr "" -msgid "Need select printer" +msgid "Uploading" +msgstr "アップロード中" + +msgid "Cancelling" msgstr "" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "Error uploading to print host" +msgstr "" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "" + +msgid "Mesh Boolean" +msgstr "" + +msgid "Union" +msgstr "" + +msgid "Difference" +msgstr "" + +msgid "Intersection" +msgstr "" + +msgid "Source Volume" +msgstr "" + +msgid "Tool Volume" +msgstr "" + +msgid "Subtract from" +msgstr "" + +msgid "Subtract with" +msgstr "" + +msgid "selected" +msgstr "" + +msgid "Part 1" +msgstr "" + +msgid "Part 2" +msgstr "" + +msgid "Delete input" +msgstr "" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3Dシーンの操作\n" -"マウスとタッチパネルで、オブジェクト/パーツの操作方法を確認しましょう" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -11265,10 +11312,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"モデル修復\n" -"破損したモデルでも修復してスライスできます。" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -11315,6 +11360,13 @@ msgstr "" "オブジェクト一覧\n" "全てのオブジェクトを確認でき、造形パラメータもオブジェクト別で設定できます" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -11481,11 +11533,236 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." msgstr "" +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "ツール 底面選択" + +#~ msgid "Export as STL" +#~ msgstr "STL形式でエクスポート" + +#~ msgid "Check cloud service status" +#~ msgstr "Check cloud service status" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "有効な値を入力してください (0 ~ 0.5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "有効な値を入力してください (K: 0 ~ 0.5, N: 0.6 ~ 2.0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "全てのオブジェクト (STL)" + +#~ msgid "Slice ok." +#~ msgstr "スライス完了" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "3mfのバージョン %s は %sのバージョン %sより新しい為、下記のキーを認識でき" +#~ "ません" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "ソフトウェアをアップデートする必要があります。\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "3mfのバージョン%sは%sの%sより新しい為、ソフトウェアを更新してください。" + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "" +#~ "この3mfファイルと互換性がありません、ジオメトリーデータのみ読込みます。" + +#~ msgid "Incompatible 3mf" +#~ msgstr "互換性の無い 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "プリンターを追加/削除" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s is not supported by the AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "今後このバージョンの通知をしません" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "エラー: IPアドレス或はアクセスコードが正しくありません" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "造形順番" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "内壁、外壁とインフィルの造形順序を指定します。" + +#~ msgid "inner/outer/infill" +#~ msgstr "内壁/外壁/インフィル" + +#~ msgid "outer/inner/infill" +#~ msgstr "外壁/内壁/インフィル" + +#~ msgid "infill/inner/outer" +#~ msgstr "インフィル/内壁/外壁" + +#~ msgid "infill/outer/inner" +#~ msgstr "インフィル/外壁/内壁" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "内壁-外壁-内壁/インフィル" + +#~ msgid "Export 3MF" +#~ msgstr "3mf をエクスポート" + +#~ msgid "Export project as 3MF." +#~ msgstr "プロジェクトを3MF式で出力" + +#~ msgid "Export slicing data" +#~ msgstr "スライスデータをエクスポート" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "スライスデータをエクスポート" + +#~ msgid "Load slicing data" +#~ msgstr "スライスデータを読込み" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "スライスデータを読込み" + +#~ msgid "Slice" +#~ msgstr "スライス" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "プレートをスライス: 0: 全て, i:プレートi, その他: 無効" + +#~ msgid "Show command help." +#~ msgstr "ヘルプを表示します。" + +#~ msgid "UpToDate" +#~ msgstr "最新の状態です。" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "3mfの構成値を更新" + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "max triangle count per plate for slicing" + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "max slicing time per plate in seconds" + +#~ msgid "Normative check" +#~ msgstr "Normative check" + +#~ msgid "Check the normative items." +#~ msgstr "Check the normative items." + +#~ msgid "Output Model Info" +#~ msgstr "出力モデル情報" + +#~ msgid "Output the model's information." +#~ msgstr "出力するモデル情報です。" + +#~ msgid "Export Settings" +#~ msgstr "エクスポート設定" + +#~ msgid "Export settings to a file." +#~ msgstr "設定をファイルにエクスポートします。" + +#~ msgid "Send progress to pipe" +#~ msgstr "パイプに進捗を送信" + +#~ msgid "Send progress to pipe." +#~ msgstr "パイプに進捗を送信" + +#~ msgid "Arrange Options" +#~ msgstr "レイアウト設定" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "レイアウト設定: 0: 無効 1: 有効 その他: 自動" + +#~ msgid "Convert Unit" +#~ msgstr "単位変換" + +#~ msgid "Convert the units of model" +#~ msgstr "モデルの単位を変換" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "指定した比率で伸縮する" + +#~ msgid "Load General Settings" +#~ msgstr "一般設定を読込む" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "指定ファイルから設定値を読込む" + +#~ msgid "Load Filament Settings" +#~ msgstr "フィラメント設定を読込む" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "指定したファイルリストからフィラメント設定を読込む" + +#~ msgid "Skip Objects" +#~ msgstr "Skip Objects" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Skip some objects in this print" + +#~ msgid "Output directory" +#~ msgstr "出力先フォルダ" + +#~ msgid "Output directory for the exported files." +#~ msgstr "エクスポートの出力先フォルダです。" + +#~ msgid "Debug level" +#~ msgstr "デバッグ レベル" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "デバッグロギングレベルを設定します。0:fatal、1:error、2:warning、3:info、" +#~ "4:debug、5:trace。\n" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3Dシーンの操作\n" +#~ "マウスとタッチパネルで、オブジェクト/パーツの操作方法を確認しましょう" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "モデル修復\n" +#~ "破損したモデルでも修復してスライスできます。" + #~ msgid "Embeded" #~ msgstr "Embedded" @@ -11574,9 +11851,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Score" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bambu エンジニアリングプレート" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu 高温プレート" diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index ae654dc9789..39b76accd5a 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: 2023-11-19 11:26+0900\n" "Last-Translator: Hotsolidinfill <138652683+Hotsolidinfill@users.noreply." "github.com>, crwusiz \n" @@ -107,6 +107,9 @@ msgstr "자동 지지대 비활성" msgid "Support Generated" msgstr "지지대 생성됨" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "바닥면 선택" @@ -154,8 +157,8 @@ msgstr "버킷 채움" msgid "Height range" msgstr "높이 범위" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "와이어프레임 전환" @@ -185,9 +188,15 @@ msgstr "칠하기에 사용한 필라멘트 %1%" msgid "Move" msgstr "이동" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "회전" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "방향 최적화" @@ -197,12 +206,12 @@ msgstr "적용" msgid "Scale" msgstr "배율" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "오류: 먼저 모든 도구 모음 메뉴를 닫으십시오." -msgid "Tool-Lay on Face" -msgstr "바닥면 선택 도구" - msgid "in" msgstr "in" @@ -496,6 +505,15 @@ msgstr "솔기 칠하기" msgid "Remove selection" msgstr "선택 삭제" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "글꼴" @@ -710,6 +728,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "개인 정보 보호 정책 업데이트" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "로드 중" @@ -904,8 +930,11 @@ msgstr "출력 가능" msgid "Fix model" msgstr "모델 수리" -msgid "Export as STL" -msgstr "STL로 내보내기" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "디스크에서 다시 불러오기" @@ -1157,6 +1186,9 @@ msgstr "아이콘을 클릭하여 개체의 색상 칠하기를 편집합니다" msgid "Click the icon to shift this object to the bed" msgstr "아이콘을 클릭하여 이 개체를 베드로 옮깁니다" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "파일 로딩 중" @@ -1408,6 +1440,18 @@ msgstr "다음 팁 열기." msgid "Open Documentation in web browser." msgstr "웹 브라우저에서 문서 열기." +msgid "Color" +msgstr "색상" + +msgid "Pause" +msgstr "일시 정지" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "사용자 설정" + msgid "Pause:" msgstr "일시 정지:" @@ -1483,8 +1527,8 @@ msgstr "..." msgid "Failed to connect to the server" msgstr "서버 연결 실패" -msgid "Check cloud service status" -msgstr "클라우드 서비스 상태 확인" +msgid "Check the status of current system services" +msgstr "현재 시스템 서비스 상태 확인" msgid "code" msgstr "코드" @@ -1742,6 +1786,14 @@ msgstr "LAN을 통해 출력 작업 전송 중" msgid "Sending print job through cloud service" msgstr "클라우드 서비스를 통해 출력 작업 전송 중" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "서비스 사용 불가" @@ -1966,11 +2018,11 @@ msgstr "정말 필라멘트 정보를 삭제하시겠습니까?" msgid "You need to select the material type and color first." msgstr "재료 유형과 색상을 먼저 선택해야 합니다." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "올바른 값을 입력하십시오 (K: 0~0.5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "올바른 값을 입력하십시오 (K: 0~0.5, N: 0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "기타 색상" @@ -2344,9 +2396,6 @@ msgstr "직사각형" msgid "Circular" msgstr "원형" -msgid "Custom" -msgstr "사용자 설정" - msgid "Load shape from STL..." msgstr "STL에서 모양 불러오기..." @@ -2840,6 +2889,9 @@ msgstr "버리기" msgid "Total" msgstr "합계" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "추정치 합계" @@ -2927,15 +2979,18 @@ msgstr "색 변경" msgid "Print" msgstr "출력" -msgid "Pause" -msgstr "일시 정지" - msgid "Printer" msgstr "프린터" msgid "Print settings" msgstr "프린터 설정" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "추정 시간" @@ -3104,7 +3159,7 @@ msgstr "용량:" msgid "Size:" msgstr "크기:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3165,15 +3220,15 @@ msgstr "유량 교정" msgid "Start Calibration" msgstr "교정 시작" -msgid "No step selected" -msgstr "선택한 단계가 없습니다" - msgid "Completed" msgstr "완료" msgid "Calibrating" msgstr "교정 중" +msgid "No step selected" +msgstr "선택한 단계가 없습니다" + msgid "Auto-record Monitoring" msgstr "모니터링 자동 기록" @@ -3388,8 +3443,11 @@ msgstr "설정 불러오기" msgid "Import" msgstr "가져오기" -msgid "Export all objects as STL" -msgstr "모든 개체를 STL로 내보내기" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "일반 3MF 내보내기" @@ -3661,9 +3719,6 @@ msgstr "초기화 실패 (카메라 없음)!" msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "프린터가 다운로드 중입니다. 다운로드가 완료될 때까지 기다리십시오." -msgid "Loading..." -msgstr "로딩 중..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "초기화 실패(현재 프린터 버전에서는 지원되지 않음)!" @@ -3726,6 +3781,9 @@ msgstr "재생중...." msgid "Load failed [%d]!" msgstr "[%d] 로드 실패!" +msgid "Loading..." +msgstr "로딩 중..." + msgid "Year" msgstr "년" @@ -3844,12 +3902,25 @@ msgstr "다운로드 완료" msgid "Downloading %d%%..." msgstr "다운로드 중 %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "현재 프린터 버전에서는 지원되지 않습니다." msgid "Storage unavailable, insert SD card." msgstr "저장소를 사용할 수 없습니다. SD 카드를 삽입하세요." +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "속도:" @@ -4195,6 +4266,12 @@ msgstr "새로운 네트워크 플러그인을 사용할 수 있습니다." msgid "Details" msgstr "세부 사항" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "위키" + msgid "Undo integration failed." msgstr "통합 실행 취소에 실패했습니다." @@ -4240,9 +4317,6 @@ msgstr "완료됨" msgid "Cancel upload" msgstr "업로드 취소" -msgid "Slice ok." -msgstr "슬라이스 완료." - msgid "Jump to" msgstr "다음으로 이동" @@ -4348,6 +4422,9 @@ msgstr "손실 단계부터 자동 복구" msgid "Allow Prompt Sound" msgstr "프롬프트 소리 허용" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "전역" @@ -4442,6 +4519,9 @@ msgstr "AMS에서 필라멘트 목록 동기화" msgid "Set filaments to use" msgstr "사용할 필라멘트 설정" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4510,8 +4590,8 @@ msgid "" "clogged when printing this filament in a closed enclosure. Please open the " "front door and/or remove the upper glass." msgstr "" -"현재 베드 온도가 상대적으로 높습니다. 닫힌 공간에서 이 필라멘트를 출력" -"할 때 노즐이 막힐 수 있습니다. 전면 도어를 열거나 상단 유리를 제거하세요." +"현재 베드 온도가 상대적으로 높습니다. 닫힌 공간에서 이 필라멘트를 출력할 때 " +"노즐이 막힐 수 있습니다. 전면 도어를 열거나 상단 유리를 제거하세요." msgid "" "The nozzle hardness required by the filament is higher than the default " @@ -4546,26 +4626,29 @@ msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "이 3mf는 이전 Orca Slicer에서 생성되었으며, 형상 데이터만 로드합니다." #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"3mf의 버전 %s이(가) %s의 버전 %s보다 최신입니다. 인식할 수 없는 다음 키를 찾" -"았습니다:" -msgid "You'd better upgrade your software.\n" -msgstr "소프트웨어를 업그레이드하는 것이 좋습니다.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "최신 3mf 버전" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"3mf의 %s 버전이 %s의 %s 버전보다 최신입니다. 소프트웨어를 업그레이드 하십시" -"오." msgid "Invalid values found in the 3mf:" msgstr "3mf에서 잘못된 값이 발견됨:" @@ -4573,11 +4656,27 @@ msgstr "3mf에서 잘못된 값이 발견됨:" msgid "Please correct them in the param tabs" msgstr "매개변수 탭에서 수정하세요" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "이 3mf는 호환되지 않습니다. 형상 데이터만 로드합니다!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "호환되지 않는 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "단계 파일 내의 구성 요소 이름이 UTF8 형식이 아닙니다!" @@ -4647,6 +4746,15 @@ msgstr "파일을 다른 이름으로 저장:" msgid "Export OBJ file:" msgstr "OBJ 파일 내보내기:" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "잘라낸 개체의 일부인 개체 삭제" @@ -4665,15 +4773,15 @@ msgstr "선택한 개체를 분할할 수 없습니다." msgid "Another export job is running." msgstr "다른 내보내기 작업이 실행 중입니다." -msgid "Replace from:" -msgstr "다음에서 교체:" - msgid "Unable to replace with more than one volume" msgstr "한 개 이상의 볼륨으로 교체할 수 없습니다" msgid "Error during replace" msgstr "교체 중 오류 발생" +msgid "Replace from:" +msgstr "다음에서 교체:" + msgid "Select a new file" msgstr "새 파일 선택" @@ -5044,6 +5152,12 @@ msgstr "G코드 창 표시" msgid "If enabled, g-code window will be displayed." msgstr "활성화된 경우 G코드 창이 표시됩니다." +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "사전 설정" @@ -5096,6 +5210,9 @@ msgstr "최근 프로젝트의 최대 표시 수" msgid "Clear my choice on the unsaved projects." msgstr "저장되지 않은 프로젝트에서 내 선택을 지웁니다." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "자동 백업" @@ -5247,8 +5364,11 @@ msgstr "필라멘트 추가/제거" msgid "Add/Remove materials" msgstr "재료 추가/제거" -msgid "Add/Remove printers" -msgstr "프린터 추가/제거" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "호환되지 않음" @@ -5430,17 +5550,17 @@ msgstr "Bambu Cool Plate" msgid "PLA Plate" msgstr "PLA 플레이트" -msgid "Bambu Engineering Plate" -msgstr "밤부 엔지니어링 플레이트" +msgid "Bamabu Engineering Plate" +msgstr "Bamabu Engineering Plate" -msgid "Bambu Smooth PEI Plate" -msgstr "밤부 스무스 PEI 플레이트" +msgid "Bamabu Smooth PEI Plate" +msgstr "" msgid "High temperature Plate" msgstr "고온 플레이트" -msgid "Bambu Textured PEI Plate" -msgstr "밤부 텍스처 PEI 플레이트" +msgid "Bamabu Textured PEI Plate" +msgstr "" msgid "Send print job to" msgstr "출력 작업 보내기" @@ -5463,9 +5583,6 @@ msgstr "전송 완료" msgid "Error code" msgstr "오류 코드" -msgid "Check the status of current system services" -msgstr "현재 시스템 서비스 상태 확인" - msgid "Printer local connection failed, please try again." msgstr "프린터 로컬 연결에 실패했습니다. 다시 시도하십시오." @@ -5568,10 +5685,8 @@ msgstr "" "습니다." msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" -"개체별로 출력할 때 I3 구조의 장치는 타임랩스 비디오를 생성하지 않습니다." msgid "Errors" msgstr "오류" @@ -5587,10 +5702,6 @@ msgstr "" "G코드를 생성할 때 선택한 프린터 유형이 현재 선택한 프린터와 일치하지 않습니" "다. 슬라이싱에 동일한 프린터 유형을 사용하는 것이 좋습니다." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s은(는) AMS에서 지원하지 않습니다." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5599,10 +5710,33 @@ msgstr "" "AMS 매핑에 알 수 없는 필라멘트가 있습니다. 필요한 필라멘트인지 확인해주세요. " "정상이면 \"확인\"을 눌러 출력을 시작하십시오." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "그래도 출력을 계속하려면 확인 버튼을 클릭하십시오." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "프린터에 연결 중입니다. 연결 진행 중에는 취소할 수 없습니다." @@ -5620,8 +5754,8 @@ msgid "" "Caution to use! Flow calibration on Textured PEI Plate may fail due to the " "scattered surface." msgstr "" -"사용상의 주의! 텍스처 PEI 플레이트의 유량 교정은 표면이 분산되어 실패할 수 " -"있습니다." +"사용상의 주의! 텍스처 PEI 플레이트의 유량 교정은 표면이 분산되어 실패할 수 있" +"습니다." msgid "Automatic flow calibration using Micro Lidar" msgstr "Micro Lidar를 사용한 자동 유량 교정" @@ -5785,6 +5919,9 @@ msgstr "" "델에는 결함이 있을 수 있습니다. 프라임 타워를 사용하지 않도록 설정하시겠습니" "까?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -6085,6 +6222,9 @@ msgstr "장치 시작 G코드" msgid "Machine end G-code" msgstr "장치 종료 G코드" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "레이어 변경 전 G코드" @@ -6154,6 +6294,24 @@ msgstr "펌웨어 퇴출" msgid "Detached" msgstr "분리됨" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "사전 설정 %1%" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "다음 사전 설정도 삭제됩니다." @@ -6162,11 +6320,6 @@ msgstr[0] "다음 사전 설정도 삭제됩니다." msgid "Are you sure to %1% the selected preset?" msgstr "선택한 사전 설정을 %1%로 설정하시겠습니까?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "사전 설정 %1%" - msgid "All" msgstr "모두" @@ -6410,11 +6563,17 @@ msgstr "래밍 선 간격" msgid "Auto-Calc" msgstr "자동 계산" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "필라멘트 교체를 위한 버리기 부피" -msgid "Multiplier" -msgstr "승수" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "각 필라멘트 쌍에 대한 버리기 부피(mm³)." @@ -6427,6 +6586,9 @@ msgstr "제안: [%d, %d] 범위의 버리기 부피" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "승수는 [%.2f, %.2f] 범위에 있어야 합니다." +msgid "Multiplier" +msgstr "승수" + msgid "unloaded" msgstr "빼냄" @@ -6442,6 +6604,12 @@ msgstr "에서" msgid "To" msgstr "으로" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "로그인" @@ -6475,6 +6643,9 @@ msgstr "클립보드에서 붙여넣기" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "3D 연결 장치 설정 표시/숨기기 대화상자" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "키보드 단축키 목록 보기" @@ -6726,12 +6897,15 @@ msgstr "새 네트워크 플러그인(%s)을 사용할 수 있습니다. 설치 msgid "New version of Orca Slicer" msgstr "Orca Slicer의 새 버전" -msgid "Don't remind me of this version again" -msgstr "이 버전을 다시 알리지 않음" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "완료" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN 연결 실패(출력 파일 전송 중)" @@ -6756,8 +6930,22 @@ msgstr "액세스 코드" msgid "Where to find your printer's IP and Access Code?" msgstr "프린터의 IP 및 액세스 코드는 어디에서 찾을 수 있습니까?" -msgid "Error: IP or Access Code are not correct" -msgstr "오류: IP 또는 액세스 코드가 올바르지 않습니다" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "테스트" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "모델:" @@ -7212,6 +7400,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "레이어 높이는 노즐 직경을 초과할 수 없습니다" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7393,8 +7586,7 @@ msgid "Avoid crossing wall" msgstr "벽 가로지름 방지" msgid "Detour and avoid to travel across wall which may cause blob on surface" -msgstr "" -"벽을 가로질러 이동하지 않고 우회하여 표면에 방울 발생을 방지합니다" +msgstr "벽을 가로질러 이동하지 않고 우회하여 표면에 방울 발생을 방지합니다" msgid "Avoid crossing wall - Max detour length" msgstr "벽 가로지름 방지 - 최대 우회 길이" @@ -7668,10 +7860,29 @@ msgstr "돌출부 반전" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" -"돌출부 위의 홀수 레이어의 둘레를 반대 방향으로 압출시킵니다. 이러한 교대 패턴" -"은 가파른 돌출부를 대폭 개선할 수 있습니다." msgid "Reverse threshold" msgstr "반전 임계값" @@ -7746,8 +7957,8 @@ msgid "" "This controls the generation of the brim at outer and/or inner side of " "models. Auto means the brim width is analysed and calculated automatically." msgstr "" -"모델의 외부 그리고/또는 내부에서 브림의 생성을 제어합니다. 자동은 브림" -"너비가 자동으로 분석 및 계산됨을 의미합니다." +"모델의 외부 그리고/또는 내부에서 브림의 생성을 제어합니다. 자동은 브림너비가 " +"자동으로 분석 및 계산됨을 의미합니다." msgid "Brim-object gap" msgstr "브림-개체 간격" @@ -7756,8 +7967,8 @@ msgid "" "A gap between innermost brim line and object can make brim be removed more " "easily" msgstr "" -"가장 안쪽 브림 라인과 개체 사이에 간격을 주어 쉽게 브림을 제거 할 수 " -"있게 합니다" +"가장 안쪽 브림 라인과 개체 사이에 간격을 주어 쉽게 브림을 제거 할 수 있게 합" +"니다" msgid "Brim ears" msgstr "브림 귀" @@ -7917,6 +8128,14 @@ msgstr "종료 G코드" msgid "End G-code when finish the whole printing" msgstr "전체 출력이 끝날때의 종료 G코드" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "이 필라멘트의 출력이 끝날때의 종료 G코드" @@ -8008,26 +8227,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "작은 둘레 길이에 대한 임계값을 설정합니다. 기본 임계값은 0mm입니다" -msgid "Order of inner wall/outer wall/infil" -msgstr "내벽/외벽/내부 채움 순서" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "내벽, 외벽 및 내부 채움 출력 순서 " +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "내벽/외벽/내부 채움" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "외벽/내벽/내부 채움" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "내부 채움/내벽/외벽" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "내부 채움/외벽/내벽" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "내벽-외벽-내벽/내부 채움" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "레일까지의 높이" @@ -8121,9 +8340,6 @@ msgstr "기본 색상" msgid "Default filament color" msgstr "기본 필라멘트 색상" -msgid "Color" -msgstr "색상" - msgid "Filament notes" msgstr "필라멘트 메모" @@ -8335,17 +8551,14 @@ msgstr "가용성 재료" msgid "" "Soluble material is commonly used to print support and support interface" msgstr "" -"가용성 재료는 일반적으로 지지대 및 지지대 접점을 출력하는 데 사용" -"됩니다" +"가용성 재료는 일반적으로 지지대 및 지지대 접점을 출력하는 데 사용됩니다" msgid "Support material" msgstr "지지대 재료" msgid "" "Support material is commonly used to print support and support interface" -msgstr "" -"지원 재료는 일반적으로 지지대 및 지지대 접점을 출력하는 데 사용됩" -"니다" +msgstr "지원 재료는 일반적으로 지지대 및 지지대 접점을 출력하는 데 사용됩니다" msgid "Softening temperature" msgstr "연화 온도" @@ -8546,10 +8759,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "Klipper의 max_accel_to_decel은 가속도의 %%로 조정됩니다" -#, c-format, boost-format -msgid "%%" -msgstr "%%" - msgid "Jerk of outer walls" msgstr "외벽 저크" @@ -8942,6 +9151,18 @@ msgstr "" "인접한 재료/체적 사이에 꽉찬 쉘을 강제로 생성합니다. 투명한 재료 또는 용해성 " "지지대 재료를 사용하는 다중 압출기 출력에 유용합니다" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "다림질 유형" @@ -9180,8 +9401,8 @@ msgstr "" "도/더 작은 너비) 압출로 또는 그 반대로 출력할 때 발생하는 급격한 압출 속도 변" "화를 완화합니다.\n" "\n" -"이는 압출된 체적 유량(mm3/초)이 시간에 따라 변할 수 있는 최대 속도를 정의합" -"니다. 값이 높을수록 더 높은 압출 속도 변경이 허용되어 속도 전환이 더 빨라진다" +"이는 압출된 체적 유량(mm3/초)이 시간에 따라 변할 수 있는 최대 속도를 정의합니" +"다. 값이 높을수록 더 높은 압출 속도 변경이 허용되어 속도 전환이 더 빨라진다" "는 의미입니다.\n" "\n" "값이 0이면 기능이 비활성화됩니다.\n" @@ -9190,12 +9411,12 @@ msgstr "" "값이 필요하지 않습니다. 그러나 기능 속도가 크게 달라지는 특정 경우에는 약간" "의 이점을 제공할 수 있습니다. 예를 들어 돌출부로 인해 급격하게 감속이 발생하" "는 경우입니다. 이러한 경우 약 300-350mm3/s2의 높은 값이 권장됩니다. 이렇게 하" -"면 프레셔 어드밴스가 더 부드러운 유량 전환을 달성하는 데 도" -"움이 될 만큼 충분히 매끄러워질 수 있기 때문입니다.\n" +"면 프레셔 어드밴스가 더 부드러운 유량 전환을 달성하는 데 도움이 될 만큼 충분" +"히 매끄러워질 수 있기 때문입니다.\n" "\n" -"프레셔 어드밴스 기능이 없는 느린 프린터의 경우 값을 훨씬 낮" -"게 설정해야 합니다. 10-15mm3/s2 값은 직접 구동 압출기의 좋은 시작점이고 보우" -"덴 스타일의 경우 5-10mm3/s2입니다.\n" +"프레셔 어드밴스 기능이 없는 느린 프린터의 경우 값을 훨씬 낮게 설정해야 합니" +"다. 10-15mm3/s2 값은 직접 구동 압출기의 좋은 시작점이고 보우덴 스타일의 경우 " +"5-10mm3/s2입니다.\n" "\n" "이 기능은 Prusa 슬라이서에서는 프레셔 이퀄라이저(Pressure Equalizer)로 알려" "져 있습니다.\n" @@ -9532,11 +9753,31 @@ msgstr "" "니다. 이동 시 노즐이 출력물에 부딪히는 것을 방지합니다. 나선 라인(Spiral " "line)을 사용하여 Z를 올리면 실 발생을 방지할 수 있습니다" -msgid "Z hop type" -msgstr "Z 올리기 유형" - -msgid "Slope" -msgstr "경사" +msgid "Z hop lower boundary" +msgstr "Z 올리기 하한 경계" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" +"Z 올리기는 Z가 이 값보다 크고 \"Z 올리기 상한 경계\" 매개변수 아래인 경우에" +"만 적용됩니다." + +msgid "Z hop upper boundary" +msgstr "Z 올리기 상한 경계" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" +"이 값이 양수인 경우 Z 올리기는 Z가 매개변수 \"Z 올리기 하한 경계\"보다 높고 " +"이 값보다 낮을 때만 적용됩니다" + +msgid "Z hop type" +msgstr "Z 올리기 유형" + +msgid "Slope" +msgstr "경사" msgid "Spiral" msgstr "나선" @@ -9597,8 +9838,8 @@ msgid "" "When the retraction is compensated after changing tool, the extruder will " "push this additional amount of filament." msgstr "" -"툴 교체 후 퇴출이 보정되면 압출기가 보정된 양 만큼의 추가 필라멘트를 밀" -"어냅니다." +"툴 교체 후 퇴출이 보정되면 압출기가 보정된 양 만큼의 추가 필라멘트를 밀어냅니" +"다." msgid "Retraction Speed" msgstr "퇴출 속도" @@ -9763,8 +10004,7 @@ msgid "" "generated model has no seam" msgstr "" "나선화는 외부 윤곽선의 z 이동을 부드럽게 합니다. 그리고 개체를 꽉찬 하단 레이" -"어가 있는 단일 벽으로 출력합니다. 최종 생성된 출력물에" -"는 솔기가 없습니다" +"어가 있는 단일 벽으로 출력합니다. 최종 생성된 출력물에는 솔기가 없습니다" msgid "" "If smooth or traditional mode is selected, a timelapse video will be " @@ -9978,6 +10218,12 @@ msgstr "" "기본 지지대 및 라프트를 출력하기 위한 필라멘트. \"기본값\"은 지원을 위한 특" "정 필라멘트가 없으며 현재 필라멘트가 사용됨을 의미합니다" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." @@ -10010,6 +10256,12 @@ msgstr "상단 접점 레이어 수" msgid "Bottom interface layers" msgstr "하단 접점 레이어" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "상단 접점 선 간격" @@ -10693,111 +10945,18 @@ msgstr "너무 넓은 선 너비 " msgid " not in range " msgstr " 범위를 벗어남 " -msgid "Export 3MF" -msgstr "3MF 내보내기" - -msgid "Export project as 3MF." -msgstr "프로젝트를 3MF로 내보내기." - -msgid "Export slicing data" -msgstr "슬라이싱 데이터 내보내기" - -msgid "Export slicing data to a folder." -msgstr "슬라이싱 데이터 폴더로 내보내기." - -msgid "Load slicing data" -msgstr "슬라이싱 데이터 로드" - -msgid "Load cached slicing data from directory" -msgstr "디렉토리에 캐시된 슬라이싱 데이터 로드" - -msgid "Export STL" -msgstr "STL 내보내기" - -msgid "Export the objects as multiple STL." -msgstr "개체를 여러개의 STL로 내보내기." - -msgid "Slice" -msgstr "슬라이스" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "플레이트 슬라이스: 0-모든 플레이트, i-플레이트 i, 기타-잘못됨" - -msgid "Show command help." -msgstr "명령 도움말을 표시합니다." - -msgid "UpToDate" -msgstr "최신 정보" - -msgid "Update the configs values of 3mf to latest." -msgstr "3mf의 구성 값을 최신으로 업데이트합니다." - -msgid "Load default filaments" -msgstr "기본 필라멘트 로드" - -msgid "Load first filament as default for those not loaded" -msgstr "로드되지 않은 경우 기본값으로 첫 번째 필라멘트 로드" - msgid "Minimum save" msgstr "최소 크기로 저장" msgid "export 3mf with minimum size." msgstr "최소 크기로 3mf를 내보냅니다." -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "슬라이싱을 위한 플레이트당 최대 삼각형 개수." - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "플레이트당 최대 슬라이싱 시간(초)" - msgid "No check" msgstr "확인 안 함" msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "G코드 경로 충돌 검사와 같은 유효성 검사를 실행하지 마십시오." -msgid "Normative check" -msgstr "표준 검사" - -msgid "Check the normative items." -msgstr "표준 항목을 확인합니다." - -msgid "Output Model Info" -msgstr "모델 정보 출력" - -msgid "Output the model's information." -msgstr "모델 정보를 출력합니다." - -msgid "Export Settings" -msgstr "설정 내보내기" - -msgid "Export settings to a file." -msgstr "설정을 파일로 내보내기." - -msgid "Send progress to pipe" -msgstr "진행 상황을 파이프로 보내기" - -msgid "Send progress to pipe." -msgstr "진행 상황을 파이프로 보내기." - -msgid "Arrange Options" -msgstr "정렬 옵션" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "정렬 옵션: 0-사용 안 함, 1-사용, 기타-자동" - -msgid "Repetions count" -msgstr "반복 횟수" - -msgid "Repetions count of the whole model" -msgstr "전체 모델의 반복 횟수" - msgid "Ensure on bed" msgstr "베드에서 확인" @@ -10807,12 +10966,6 @@ msgstr "" "개체의 일부가 베드 아래에 있을 때 베드 위로 개체를 들어올립니다. 기본적으로 " "비활성화됩니다" -msgid "Convert Unit" -msgstr "단위 변환" - -msgid "Convert the units of model" -msgstr "모델의 단위를 변환" - msgid "Orient Options" msgstr "방향 최적화 옵션" @@ -10822,48 +10975,12 @@ msgstr "방향 최적화 옵션: 0-비활성화, 1-활성화, 기타-자동" msgid "Rotation angle around the Z axis in degrees." msgstr "Z축을 중심으로 한 회전 각도입니다." -msgid "Rotate around X" -msgstr "X를 중심으로 회전" - -msgid "Rotation angle around the X axis in degrees." -msgstr "X축을 중심으로 한 회전 각도입니다." - msgid "Rotate around Y" msgstr "Y를 중심으로 회전" msgid "Rotation angle around the Y axis in degrees." msgstr "Y축을 중심으로 한 회전 각도입니다." -msgid "Scale the model by a float factor" -msgstr "부동 소수점 계수로 모델 크기 조정" - -msgid "Load General Settings" -msgstr "일반 설정 로드" - -msgid "Load process/machine settings from the specified file" -msgstr "지정된 파일에서 프로세스/기계 설정 로드" - -msgid "Load Filament Settings" -msgstr "필라멘트 설정 로드" - -msgid "Load filament settings from the specified file list" -msgstr "지정된 파일 목록에서 필라멘트 설정 불러오기" - -msgid "Skip Objects" -msgstr "개체 건너뛰기" - -msgid "Skip some objects in this print" -msgstr "이 출력에서 일부 개체를 건너뜁니다" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "uptodate 사용 시 최신 프로세스/프린터 설정 로드" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" -"uptodate를 사용할 때 지정된 파일에서 최신 프로세스/프린터 설정을 로드합니다" - msgid "Data directory" msgstr "데이터 디렉토리" @@ -10875,22 +10992,6 @@ msgstr "" "지정된 디렉토리에 설정을 로드하고 저장합니다. 이 기능은 서로 다른 프로필을 유" "지하거나 네트워크 스토리지의 구성을 포함하는 데 유용합니다." -msgid "Output directory" -msgstr "출력 디렉토리" - -msgid "Output directory for the exported files." -msgstr "내보내기 파일의 출력 디렉토리입니다." - -msgid "Debug level" -msgstr "디버그 수준" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"디버그 로깅 수준을 설정합니다. 0:치명적, 1:오류, 2:경고, 3:정보, 4:디버그, 5:" -"추적\n" - msgid "Load custom gcode" msgstr "사용자 설정 G코드 불러오기" @@ -11054,9 +11155,6 @@ msgstr "교정" msgid "Finish" msgstr "완료" -msgid "Wiki" -msgstr "위키" - msgid "How to use calibration result?" msgstr "교정 결과를 어떻게 사용하나요?" @@ -11074,6 +11172,12 @@ msgstr "" msgid "Calibration not supported" msgstr "교정이 지원되지 않음" +msgid "Error desc" +msgstr "오류 설명" + +msgid "Extra info" +msgstr "추가 정보" + msgid "Flow Dynamics" msgstr "동적 유량" @@ -11106,9 +11210,9 @@ msgstr "" msgid "The name cannot be empty." msgstr "이름은 비워둘 수 없습니다." -#, boost-format -msgid "The selected preset: %1% is not found." -msgstr "선택한 사전 설정: %1%을(를) 찾을 수 없습니다." +#, c-format, boost-format +msgid "The selected preset: %s is not found." +msgstr "" msgid "The name cannot be the same as the system preset name." msgstr "이름은 시스템 사전 설정 이름과 동일할 수 없습니다." @@ -11450,12 +11554,6 @@ msgstr "" "- 동일한 히트베드 온도를 공유할 수 있는 소재\n" "- 다양한 필라멘트 브랜드 및 제품군(브랜드 = Bambu, 제품군 = Basic, Matte)" -msgid "Error desc" -msgstr "오류 설명" - -msgid "Extra info" -msgstr "추가 정보" - msgid "Pattern" msgstr "패턴" @@ -11546,101 +11644,6 @@ msgstr "" "호스트 이름 %1%(으)로 확인되는 IP 주소가 여러 개 있습니다.\n" "사용 할 IP를 선택해 주세요." -msgid "Unable to perform boolean operation on selected parts" -msgstr "선택한 부품에서 부울 연산을 수행할 수 없습니다" - -msgid "Mesh Boolean" -msgstr "메쉬 부울" - -msgid "Union" -msgstr "합집합" - -msgid "Difference" -msgstr "차집합" - -msgid "Intersection" -msgstr "교집합" - -msgid "Source Volume" -msgstr "소스 볼륨" - -msgid "Tool Volume" -msgstr "도구 볼륨" - -msgid "Subtract from" -msgstr "다음에서 잘라내기" - -msgid "Subtract with" -msgstr "다음으로 잘라내기" - -msgid "selected" -msgstr "선택됨" - -msgid "Part 1" -msgstr "요소 1" - -msgid "Part 2" -msgstr "요소 2" - -msgid "Delete input" -msgstr "입력개체 삭제" - -msgid "Send G-Code to printer host" -msgstr "G코드를 프린터 호스트로 보내기" - -msgid "Upload to Printer Host with the following filename:" -msgstr "다음 파일 이름으로 프린터 호스트에 업로드:" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "필요한 경우 슬래시( / )를 디렉토리 구분 기호로 사용하십시오." - -msgid "Upload to storage" -msgstr "저장소에 업로드" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "업로드 파일 이름이 \"%s\"로 끝나지 않습니다. 계속하시겠습니까?" - -msgid "Upload" -msgstr "업로드" - -msgid "Print host upload queue" -msgstr "출력 호스트 업로드 대기열" - -msgid "ID" -msgstr "아이디" - -msgid "Progress" -msgstr "진행률" - -msgid "Host" -msgstr "호스트" - -msgctxt "OfFile" -msgid "Size" -msgstr "크기" - -msgid "Filename" -msgstr "파일 이름" - -msgid "Cancel selected" -msgstr "선택 취소" - -msgid "Show error message" -msgstr "오류 메시지 표시" - -msgid "Enqueued" -msgstr "대기 중" - -msgid "Uploading" -msgstr "업로드 중" - -msgid "Cancelling" -msgstr "취소 중" - -msgid "Error uploading to print host" -msgstr "출력 호스트에 업로드하는 중 오류가 발생했습니다" - msgid "PA Calibration" msgstr "PA 교정" @@ -11781,76 +11784,107 @@ msgstr "퇴출 종료 길이: " msgid "mm/mm" msgstr "mm/mm" -msgid "Physical Printer" -msgstr "물리 프린터" +msgid "Send G-Code to printer host" +msgstr "G코드를 프린터 호스트로 보내기" -msgid "Print Host upload" -msgstr "출력 호스트 업로드" +msgid "Upload to Printer Host with the following filename:" +msgstr "다음 파일 이름으로 프린터 호스트에 업로드:" -msgid "Test" -msgstr "테스트" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "필요한 경우 슬래시( / )를 디렉토리 구분 기호로 사용하십시오." -msgid "Could not get a valid Printer Host reference" -msgstr "유효한 프린터 호스트 참조를 가져올 수 없습니다" +msgid "Upload to storage" +msgstr "저장소에 업로드" -msgid "Success!" -msgstr "성공!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "업로드 파일 이름이 \"%s\"로 끝나지 않습니다. 계속하시겠습니까?" -msgid "Refresh Printers" -msgstr "프린터 새로 고침" +msgid "Upload" +msgstr "업로드" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." -msgstr "" -"HTTPS CA 파일은 선택 사항입니다. 자체 서명된 인증서와 함께 HTTPS를 사용하는 " -"경우에만 필요합니다." +msgid "Print host upload queue" +msgstr "출력 호스트 업로드 대기열" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "인증서 파일 (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "ID" +msgstr "아이디" -msgid "Open CA certificate file" -msgstr "CA 인증서 파일 열기" +msgid "Progress" +msgstr "진행률" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." -msgstr "" -"이 시스템에서 %s는 시스템 인증서 저장소나 키체인의 HTTPS 인증서를 사용합니다." +msgid "Host" +msgstr "호스트" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." -msgstr "" -"사용자 지정 CA 파일을 사용하려면 CA 파일을 인증서 저장소/키체인으로 가져오십" -"시오." +msgctxt "OfFile" +msgid "Size" +msgstr "크기" -msgid "Connection to printers connected via the print host failed." -msgstr "출력 호스트를 통해 연결된 프린터에 연결하지 못했습니다." +msgid "Filename" +msgstr "파일 이름" -msgid "The start, end or step is not valid value." -msgstr "시작, 끝 또는 단계가 유효한 값이 아닙니다." +msgid "Cancel selected" +msgstr "선택 취소" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" -msgstr "" -"교정할 수 없음: 설정된 교정 값 범위가 너무 크거나 단계가 너무 작기 때문일 수 " -"있습니다" +msgid "Show error message" +msgstr "오류 메시지 표시" + +msgid "Enqueued" +msgstr "대기 중" + +msgid "Uploading" +msgstr "업로드 중" + +msgid "Cancelling" +msgstr "취소 중" + +msgid "Error uploading to print host" +msgstr "출력 호스트에 업로드하는 중 오류가 발생했습니다" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "선택한 부품에서 부울 연산을 수행할 수 없습니다" + +msgid "Mesh Boolean" +msgstr "메쉬 부울" -msgid "Need select printer" -msgstr "프린터 선택 필요" +msgid "Union" +msgstr "합집합" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "Difference" +msgstr "차집합" + +msgid "Intersection" +msgstr "교집합" + +msgid "Source Volume" +msgstr "소스 볼륨" + +msgid "Tool Volume" +msgstr "도구 볼륨" + +msgid "Subtract from" +msgstr "다음에서 잘라내기" + +msgid "Subtract with" +msgstr "다음으로 잘라내기" + +msgid "selected" +msgstr "선택됨" + +msgid "Part 1" +msgstr "요소 1" + +msgid "Part 2" +msgstr "요소 2" + +msgid "Delete input" +msgstr "입력개체 삭제" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3D 화면 작업\n" -"3D 화면에서 마우스와 터치패널로 보기 및 개체/부품 선택을 제어하는 방법을 알" -"고 있습니까?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -11866,11 +11900,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"모델 수리\n" -"많은 슬라이싱 문제를 피하기 위해 손상된 3D 모델을 수리할 수 있다는 것을 알고 " -"있습니까?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -11920,6 +11951,13 @@ msgstr "" "목록의 모든 개체/부품을 보고 각 개체/부품에 대한 설정을 변경할 수 있다는 것" "을 알고 있습니까?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -12065,8 +12103,8 @@ msgid "" "the printing surface, it's recommended to use a brim?" msgstr "" "더 나은 안착을 위한 브림\n" -"출력 모델이 베드 표면과의 접촉면이 작을 때 브림를 사용하는 것이 좋다는 사" -"실을 알고 있습니까?" +"출력 모델이 베드 표면과의 접촉면이 작을 때 브림를 사용하는 것이 좋다는 사실" +"을 알고 있습니까?" #: resources/data/hints.ini: [hint:Set parameters for multiple objects] msgid "" @@ -12110,14 +12148,372 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." msgstr "" -"프린터 도어를 열어 놓은 상태로 출력해야 하는 경우\n" -"더 높은 내부 온도로 낮은 온도의 필라멘트를 출력할 때 프린터 도어를 열면 압출" -"기/핫엔드가 막힐 가능성을 줄일 수 있습니다. 이에 대한 자세한 내용은 Wiki에서 " -"확인하세요." + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." +msgstr "" + +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "바닥면 선택 도구" + +#~ msgid "Export as STL" +#~ msgstr "STL로 내보내기" + +#~ msgid "Check cloud service status" +#~ msgstr "클라우드 서비스 상태 확인" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "올바른 값을 입력하십시오 (K: 0~0.5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "올바른 값을 입력하십시오 (K: 0~0.5, N: 0.6~2.0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "모든 개체를 STL로 내보내기" + +#~ msgid "Slice ok." +#~ msgstr "슬라이스 완료." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "3mf의 버전 %s이(가) %s의 버전 %s보다 최신입니다. 인식할 수 없는 다음 키를 " +#~ "찾았습니다:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "소프트웨어를 업그레이드하는 것이 좋습니다.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "3mf의 %s 버전이 %s의 %s 버전보다 최신입니다. 소프트웨어를 업그레이드 하십" +#~ "시오." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "이 3mf는 호환되지 않습니다. 형상 데이터만 로드합니다!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "호환되지 않는 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "프린터 추가/제거" + +#~ msgid "Bambu Engineering Plate" +#~ msgstr "밤부 엔지니어링 플레이트" + +#~ msgid "Bambu Smooth PEI Plate" +#~ msgstr "밤부 스무스 PEI 플레이트" + +#~ msgid "Bambu Textured PEI Plate" +#~ msgstr "밤부 텍스처 PEI 플레이트" + +#~ msgid "" +#~ "When print by object, machines with I3 structure will not generate " +#~ "timelapse videos." +#~ msgstr "" +#~ "개체별로 출력할 때 I3 구조의 장치는 타임랩스 비디오를 생성하지 않습니다." + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s은(는) AMS에서 지원하지 않습니다." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "이 버전을 다시 알리지 않음" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "오류: IP 또는 액세스 코드가 올바르지 않습니다" + +#~ msgid "" +#~ "Extrude perimeters that have a part over an overhang in the reverse " +#~ "direction on odd layers. This alternating pattern can drastically improve " +#~ "steep overhang." +#~ msgstr "" +#~ "돌출부 위의 홀수 레이어의 둘레를 반대 방향으로 압출시킵니다. 이러한 교대 " +#~ "패턴은 가파른 돌출부를 대폭 개선할 수 있습니다." + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "내벽/외벽/내부 채움 순서" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "내벽, 외벽 및 내부 채움 출력 순서 " + +#~ msgid "inner/outer/infill" +#~ msgstr "내벽/외벽/내부 채움" + +#~ msgid "outer/inner/infill" +#~ msgstr "외벽/내벽/내부 채움" + +#~ msgid "infill/inner/outer" +#~ msgstr "내부 채움/내벽/외벽" + +#~ msgid "infill/outer/inner" +#~ msgstr "내부 채움/외벽/내벽" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "내벽-외벽-내벽/내부 채움" + +#, c-format, boost-format +#~ msgid "%%" +#~ msgstr "%%" + +#~ msgid "Export 3MF" +#~ msgstr "3MF 내보내기" + +#~ msgid "Export project as 3MF." +#~ msgstr "프로젝트를 3MF로 내보내기." + +#~ msgid "Export slicing data" +#~ msgstr "슬라이싱 데이터 내보내기" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "슬라이싱 데이터 폴더로 내보내기." + +#~ msgid "Load slicing data" +#~ msgstr "슬라이싱 데이터 로드" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "디렉토리에 캐시된 슬라이싱 데이터 로드" + +#~ msgid "Export STL" +#~ msgstr "STL 내보내기" + +#~ msgid "Export the objects as multiple STL." +#~ msgstr "개체를 여러개의 STL로 내보내기." + +#~ msgid "Slice" +#~ msgstr "슬라이스" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "플레이트 슬라이스: 0-모든 플레이트, i-플레이트 i, 기타-잘못됨" + +#~ msgid "Show command help." +#~ msgstr "명령 도움말을 표시합니다." + +#~ msgid "UpToDate" +#~ msgstr "최신 정보" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "3mf의 구성 값을 최신으로 업데이트합니다." + +#~ msgid "Load default filaments" +#~ msgstr "기본 필라멘트 로드" + +#~ msgid "Load first filament as default for those not loaded" +#~ msgstr "로드되지 않은 경우 기본값으로 첫 번째 필라멘트 로드" + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "슬라이싱을 위한 플레이트당 최대 삼각형 개수." + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "플레이트당 최대 슬라이싱 시간(초)" + +#~ msgid "Normative check" +#~ msgstr "표준 검사" + +#~ msgid "Check the normative items." +#~ msgstr "표준 항목을 확인합니다." + +#~ msgid "Output Model Info" +#~ msgstr "모델 정보 출력" + +#~ msgid "Output the model's information." +#~ msgstr "모델 정보를 출력합니다." + +#~ msgid "Export Settings" +#~ msgstr "설정 내보내기" + +#~ msgid "Export settings to a file." +#~ msgstr "설정을 파일로 내보내기." + +#~ msgid "Send progress to pipe" +#~ msgstr "진행 상황을 파이프로 보내기" + +#~ msgid "Send progress to pipe." +#~ msgstr "진행 상황을 파이프로 보내기." + +#~ msgid "Arrange Options" +#~ msgstr "정렬 옵션" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "정렬 옵션: 0-사용 안 함, 1-사용, 기타-자동" + +#~ msgid "Repetions count" +#~ msgstr "반복 횟수" + +#~ msgid "Repetions count of the whole model" +#~ msgstr "전체 모델의 반복 횟수" + +#~ msgid "Convert Unit" +#~ msgstr "단위 변환" + +#~ msgid "Convert the units of model" +#~ msgstr "모델의 단위를 변환" + +#~ msgid "Rotate around X" +#~ msgstr "X를 중심으로 회전" + +#~ msgid "Rotation angle around the X axis in degrees." +#~ msgstr "X축을 중심으로 한 회전 각도입니다." + +#~ msgid "Scale the model by a float factor" +#~ msgstr "부동 소수점 계수로 모델 크기 조정" + +#~ msgid "Load General Settings" +#~ msgstr "일반 설정 로드" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "지정된 파일에서 프로세스/기계 설정 로드" + +#~ msgid "Load Filament Settings" +#~ msgstr "필라멘트 설정 로드" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "지정된 파일 목록에서 필라멘트 설정 불러오기" + +#~ msgid "Skip Objects" +#~ msgstr "개체 건너뛰기" + +#~ msgid "Skip some objects in this print" +#~ msgstr "이 출력에서 일부 개체를 건너뜁니다" + +#~ msgid "load uptodate process/machine settings when using uptodate" +#~ msgstr "uptodate 사용 시 최신 프로세스/프린터 설정 로드" + +#~ msgid "" +#~ "load uptodate process/machine settings from the specified file when using " +#~ "uptodate" +#~ msgstr "" +#~ "uptodate를 사용할 때 지정된 파일에서 최신 프로세스/프린터 설정을 로드합니" +#~ "다" + +#~ msgid "Output directory" +#~ msgstr "출력 디렉토리" + +#~ msgid "Output directory for the exported files." +#~ msgstr "내보내기 파일의 출력 디렉토리입니다." + +#~ msgid "Debug level" +#~ msgstr "디버그 수준" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "디버그 로깅 수준을 설정합니다. 0:치명적, 1:오류, 2:경고, 3:정보, 4:디버" +#~ "그, 5:추적\n" + +#, boost-format +#~ msgid "The selected preset: %1% is not found." +#~ msgstr "선택한 사전 설정: %1%을(를) 찾을 수 없습니다." + +#~ msgid "Physical Printer" +#~ msgstr "물리 프린터" + +#~ msgid "Print Host upload" +#~ msgstr "출력 호스트 업로드" + +#~ msgid "Could not get a valid Printer Host reference" +#~ msgstr "유효한 프린터 호스트 참조를 가져올 수 없습니다" + +#~ msgid "Success!" +#~ msgstr "성공!" + +#~ msgid "Refresh Printers" +#~ msgstr "프린터 새로 고침" + +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "HTTPS CA 파일은 선택 사항입니다. 자체 서명된 인증서와 함께 HTTPS를 사용하" +#~ "는 경우에만 필요합니다." + +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "인증서 파일 (*.crt, *.pem)|*.crt;*.pem|All files|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "CA 인증서 파일 열기" + +#, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "" +#~ "이 시스템에서 %s는 시스템 인증서 저장소나 키체인의 HTTPS 인증서를 사용합니" +#~ "다." + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "사용자 지정 CA 파일을 사용하려면 CA 파일을 인증서 저장소/키체인으로 가져오" +#~ "십시오." + +#~ msgid "Connection to printers connected via the print host failed." +#~ msgstr "출력 호스트를 통해 연결된 프린터에 연결하지 못했습니다." + +#~ msgid "The start, end or step is not valid value." +#~ msgstr "시작, 끝 또는 단계가 유효한 값이 아닙니다." + +#~ msgid "" +#~ "Unable to calibrate: maybe because the set calibration value range is too " +#~ "large, or the step is too small" +#~ msgstr "" +#~ "교정할 수 없음: 설정된 교정 값 범위가 너무 크거나 단계가 너무 작기 때문일 " +#~ "수 있습니다" + +#~ msgid "Need select printer" +#~ msgstr "프린터 선택 필요" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3D 화면 작업\n" +#~ "3D 화면에서 마우스와 터치패널로 보기 및 개체/부품 선택을 제어하는 방법을 " +#~ "알고 있습니까?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "모델 수리\n" +#~ "많은 슬라이싱 문제를 피하기 위해 손상된 3D 모델을 수리할 수 있다는 것을 알" +#~ "고 있습니까?" + +#~ msgid "" +#~ "When need to print with the printer door opened\n" +#~ "Opening the printer door can reduce the probability of extruder/hotend " +#~ "clogging when printing lower temperature filament with a higher enclosure " +#~ "temperature. More info about this in the Wiki." +#~ msgstr "" +#~ "프린터 도어를 열어 놓은 상태로 출력해야 하는 경우\n" +#~ "더 높은 내부 온도로 낮은 온도의 필라멘트를 출력할 때 프린터 도어를 열면 압" +#~ "출기/핫엔드가 막힐 가능성을 줄일 수 있습니다. 이에 대한 자세한 내용은 Wiki" +#~ "에서 확인하세요." #~ msgid "Embeded" #~ msgstr "매입" @@ -12135,26 +12531,6 @@ msgstr "" #~ msgid "Show online staff-picked models on the home page" #~ msgstr "홈페이지에서 추천 온라인 모델 보기" -#~ msgid "Z hop lower boundary" -#~ msgstr "Z 올리기 하한 경계" - -#~ msgid "" -#~ "Z hop will only come into effect when Z is above this value and is below " -#~ "the parameter: \"Z hop upper boundary\"" -#~ msgstr "" -#~ "Z 올리기는 Z가 이 값보다 크고 \"Z 올리기 상한 경계\" 매개변수 아래인 경우" -#~ "에만 적용됩니다." - -#~ msgid "Z hop upper boundary" -#~ msgstr "Z 올리기 상한 경계" - -#~ msgid "" -#~ "If this value is positive, Z hop will only come into effect when Z is " -#~ "above the parameter: \"Z hop lower boundary\" and is below this value" -#~ msgstr "" -#~ "이 값이 양수인 경우 Z 올리기는 Z가 매개변수 \"Z 올리기 하한 경계\"보다 높" -#~ "고 이 값보다 낮을 때만 적용됩니다" - #~ msgid "The minimum printing speed when slow down for cooling" #~ msgstr "\"레이어 냉각 향상을 위한 감속\" 시 최소 출력 속도" @@ -12268,9 +12644,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "점수" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bamabu Engineering Plate" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bamabu High Temperature Plate" diff --git a/localization/i18n/list.txt b/localization/i18n/list.txt index 93ac1c1b5d5..0a5ea2dc026 100644 --- a/localization/i18n/list.txt +++ b/localization/i18n/list.txt @@ -95,12 +95,14 @@ src/slic3r/GUI/Selection.cpp src/slic3r/GUI/SelectMachine.cpp src/slic3r/GUI/SendSystemInfoDialog.cpp src/slic3r/GUI/SendToPrinter.cpp +src/slic3r/GUI/SlicingProgressNotification.cpp src/slic3r/GUI/BindDialog.cpp src/slic3r/GUI/Tab.cpp src/slic3r/GUI/Tab.hpp src/slic3r/GUI/UnsavedChangesDialog.cpp src/slic3r/GUI/Auxiliary.cpp src/slic3r/GUI/UpdateDialogs.cpp +src/slic3r/GUI/UnsavedChangesDialog.cpp src/slic3r/GUI/WipeTowerDialog.cpp src/slic3r/GUI/wxExtensions.cpp src/slic3r/GUI/WebUserLoginDialog.cpp @@ -141,8 +143,17 @@ src/slic3r/GUI/CalibrationWizardPresetPage.cpp src/slic3r/GUI/CalibrationWizardCaliPage.cpp src/slic3r/GUI/CaliHistoryDialog.cpp src/slic3r/GUI/BonjourDialog.cpp -src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp -src/slic3r/GUI/PrintHostDialogs.cpp src/slic3r/GUI/calib_dlg.cpp +src/slic3r/GUI/PrintHostDialogs.cpp +src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp +src/slic3r/GUI/NetworkTestDialog.cpp +src/slic3r/GUI/CreatePresetsDialog.cpp +src/slic3r/GUI/DailyTips.cpp +src/slic3r/Utils/CalibUtils.cpp src/slic3r/GUI/PhysicalPrinterDialog.cpp -src/slic3r/Utils/CalibUtils.cpp \ No newline at end of file +src/slic3r/Utils/AstroBox.cpp +src/slic3r/Utils/Duet.cpp +src/slic3r/Utils/FlashAir.cpp +src/slic3r/Utils/MKS.cpp +src/slic3r/Utils/OctoPrint.cpp +src/slic3r/Utils/Repetier.cpp \ No newline at end of file diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index d0cb08e6469..10a9862387d 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -98,6 +98,9 @@ msgstr "Geen automatische ondersteuning" msgid "Support Generated" msgstr "Ondersteuning gegenereerd" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Op deze zijde neerleggen." @@ -146,8 +149,8 @@ msgstr "Emmer vullen" msgid "Height range" msgstr "Hoogtebereik" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Schakel draadmodel in of uit" @@ -177,9 +180,15 @@ msgstr "Geschilderd met filament %1%" msgid "Move" msgstr "Verplaats" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Draai" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Oriëntatie optimaliseren" @@ -189,12 +198,12 @@ msgstr "Toepassen" msgid "Scale" msgstr "Schalen" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "Fout: sluit eerst alle openstaande hulpmiddelmenu's" -msgid "Tool-Lay on Face" -msgstr "Hulpmiddel op zijde plaatsen" - msgid "in" msgstr "in" @@ -492,6 +501,15 @@ msgstr "Naad schilderen" msgid "Remove selection" msgstr "Selectie verwijderen" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Lettertype" @@ -704,6 +722,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Privacy Policy Update" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Laden" @@ -897,8 +923,11 @@ msgstr "Afdrukbaar" msgid "Fix model" msgstr "Repareer model" -msgid "Export as STL" -msgstr "Exporteer als STL-bestand" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Opnieuw laden vanaf schijf" @@ -1162,6 +1191,9 @@ msgstr "Klik op het pictogram om de kleur van het object te bewerken" msgid "Click the icon to shift this object to the bed" msgstr "Klik op het pictogram om dit object te verschuiven op het printbed" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Bestand laden" @@ -1430,6 +1462,18 @@ msgstr "Volgende tip openen" msgid "Open Documentation in web browser." msgstr "Documentatie openen in een webbrowser" +msgid "Color" +msgstr "Kleur" + +msgid "Pause" +msgstr "Pauze" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Aangepast" + msgid "Pause:" msgstr "Pause:" @@ -1505,8 +1549,8 @@ msgstr "" msgid "Failed to connect to the server" msgstr "Verbinding maken met de server is mislukt" -msgid "Check cloud service status" -msgstr "Check cloud service status" +msgid "Check the status of current system services" +msgstr "Check the status of current system services" msgid "code" msgstr "code" @@ -1771,6 +1815,14 @@ msgstr "Printopdracht verzenden via LAN" msgid "Sending print job through cloud service" msgstr "Printopdracht verzenden via cloud service" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Service niet beschikbaar" @@ -1999,11 +2051,11 @@ msgstr "Are you sure you want to clear the filament information?" msgid "You need to select the material type and color first." msgstr "You need to select the material type and color first." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Voer een geldige waarde in (K in 0 ~ 0,5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "Voer een geldige waarde in (K in 0 ~ 0,5, N in 0,6 ~ 2,0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Other Color" @@ -2391,9 +2443,6 @@ msgstr "Rechthoekig" msgid "Circular" msgstr "Rond" -msgid "Custom" -msgstr "Aangepast" - msgid "Load shape from STL..." msgstr "Vorm laden vanuit het stl. bestand..." @@ -2886,6 +2935,9 @@ msgstr "Flushed" msgid "Total" msgstr "Totaal" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Schatting totaal" @@ -2973,15 +3025,18 @@ msgstr "Kleur veranderen" msgid "Print" msgstr "Print" -msgid "Pause" -msgstr "Pauze" - msgid "Printer" msgstr "Printer" msgid "Print settings" msgstr "Print instellingen" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Geschatte duur" @@ -3150,7 +3205,7 @@ msgstr "Volume:" msgid "Size:" msgstr "Maat:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3211,15 +3266,15 @@ msgstr "Flow kalibratie" msgid "Start Calibration" msgstr "Start kalibreren" -msgid "No step selected" -msgstr "" - msgid "Completed" msgstr "Voltooid" msgid "Calibrating" msgstr "Kalibreren" +msgid "No step selected" +msgstr "" + msgid "Auto-record Monitoring" msgstr "Automatische opnamebewaking" @@ -3434,8 +3489,11 @@ msgstr "Configuratie laden" msgid "Import" msgstr "Importeren" -msgid "Export all objects as STL" -msgstr "Exporteer alle objecten als STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Generiek 3MF exporteren" @@ -3710,9 +3768,6 @@ msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "" "De printer is bezig met downloaden. Wacht tot het downloaden is voltooid." -msgid "Loading..." -msgstr "Laden..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" @@ -3775,6 +3830,9 @@ msgstr "Afspelen..." msgid "Load failed [%d]!" msgstr "Laden mislukt [%d]!" +msgid "Loading..." +msgstr "Laden..." + msgid "Year" msgstr "Jaar" @@ -3892,12 +3950,25 @@ msgstr "Download voltooid" msgid "Downloading %d%%..." msgstr "%d%% downloaden..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "" msgid "Storage unavailable, insert SD card." msgstr "" +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Snelheid" @@ -4229,6 +4300,12 @@ msgstr "Nieuwe netwerk plug-in beschikbaar" msgid "Details" msgstr "Détails" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "" + msgid "Undo integration failed." msgstr "Het ongedaan maken van de integratie is mislukt." @@ -4285,9 +4362,6 @@ msgstr "VOLTOOID" msgid "Cancel upload" msgstr "Upload annuleren" -msgid "Slice ok." -msgstr "Slice gelukt" - msgid "Jump to" msgstr "Ga naar" @@ -4394,6 +4468,9 @@ msgstr "Automatisch herstel na stapverlies" msgid "Allow Prompt Sound" msgstr "" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Globale" @@ -4488,6 +4565,9 @@ msgstr "Synchroniseer filamentlijst vanuit AMS" msgid "Set filaments to use" msgstr "Stel filamenten in om te gebruiken" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4589,26 +4669,29 @@ msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "" #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"Versie %s van de 3mf is nieuwer dan versie %s van %s. De volgende sleutels " -"worden niet herkend:" -msgid "You'd better upgrade your software.\n" -msgstr "U dient de software te upgraden.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Nieuwere versie 3mf" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"Versie %s van de 3mf is nieuwer dan versie %s van %s. Wij stellen voor om uw " -"software te upgraden." msgid "Invalid values found in the 3mf:" msgstr "Invalid values found in the 3mf:" @@ -4616,12 +4699,27 @@ msgstr "Invalid values found in the 3mf:" msgid "Please correct them in the param tabs" msgstr "Please correct them in the Param tabs" -msgid "The 3mf is not compatible, load geometry data only!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" msgstr "" -"Het 3mf bestand is niet compatibel, enkel de geometrische data wordt geladen!" -msgid "Incompatible 3mf" -msgstr "Onbruikbaar 3mf bestand" +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" + +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "Naam van componenten in step-bestand is niet UTF8-formaat!" @@ -4699,6 +4797,15 @@ msgstr "Bewaar bestand als:" msgid "Export OBJ file:" msgstr "" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Delete object which is a part of cut object" @@ -4717,15 +4824,15 @@ msgstr "Het geselecteerde object kan niet opgesplitst worden." msgid "Another export job is running." msgstr "Er is reeds een export taak actief." -msgid "Replace from:" -msgstr "" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "Fout tijdens vervanging" +msgid "Replace from:" +msgstr "" + msgid "Select a new file" msgstr "Selecteer een nieuw bestand" @@ -5104,6 +5211,12 @@ msgstr "" msgid "If enabled, g-code window will be displayed." msgstr "" +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Presets" @@ -5160,6 +5273,9 @@ msgstr "Maximum count of recent projects" msgid "Clear my choice on the unsaved projects." msgstr "Clear my choice on the unsaved projects." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Automatisch backup maken" @@ -5313,8 +5429,11 @@ msgstr "Filament toevoegen/verwijderen" msgid "Add/Remove materials" msgstr "Materialen toevoegen/verwijderen" -msgid "Add/Remove printers" -msgstr "Printers toevoegen/verwijderen" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Incompatible" @@ -5504,16 +5623,16 @@ msgstr "Bambu Cool (koude) Plate" msgid "PLA Plate" msgstr "PLA Plate" -msgid "Bambu Engineering Plate" -msgstr "" +msgid "Bamabu Engineering Plate" +msgstr "Bambu Engineering (technische) plate" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "" msgid "High temperature Plate" msgstr "" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "" msgid "Send print job to" @@ -5537,9 +5656,6 @@ msgstr "Versturen gelukt" msgid "Error code" msgstr "Error code" -msgid "Check the status of current system services" -msgstr "Check the status of current system services" - msgid "Printer local connection failed, please try again." msgstr "Printer local connection failed; please try again." @@ -5650,8 +5766,7 @@ msgid "" msgstr "" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" msgid "Errors" @@ -5669,10 +5784,6 @@ msgstr "" "currently selected printer. It is recommended that you use the same printer " "type for slicing." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s is not supported by the AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5682,11 +5793,34 @@ msgstr "" "vereiste filamenten zijn. Als ze in orde zijn, klikt u op \"Bevestigen\" om " "het afdrukken te starten." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Please click the confirm button if you still want to proceed with printing." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5877,6 +6011,9 @@ msgstr "" "gebreken ontstaan aan het model zonder prime-toren. Wilt u de prime-toren " "inschakelen?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5919,8 +6056,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "Bij het opnemen van timelapse zonder toolhead is het aan te raden om een " "„Timelapse Wipe Tower” toe te voegen \n" @@ -6191,6 +6328,9 @@ msgstr "Machine start G-code" msgid "Machine end G-code" msgstr "Machine einde G-code" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "G-Code voor de laag wijziging" @@ -6257,6 +6397,25 @@ msgstr "" msgid "Detached" msgstr "Losgemaakt" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Voorinstelling" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "De volgende voorinstelling zal ook verwijderd worden@" @@ -6266,11 +6425,6 @@ msgstr[1] "De volgende voorinstelling zal ook verwijderd worden@" msgid "Are you sure to %1% the selected preset?" msgstr "Weet u zeker dat u de geselecteerde preset wilt %1%?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Voorinstelling" - msgid "All" msgstr "Alles" @@ -6519,11 +6673,17 @@ msgstr "" msgid "Auto-Calc" msgstr "Automatisch berekenen" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Volumes reinigen voor filament wijziging" -msgid "Multiplier" -msgstr "Vermenigvuldiger" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Spoelvolume (mm³) voor elk filamentpaar." @@ -6537,6 +6697,9 @@ msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "" "De vermenigvuldigingsfactor moet in het bereik liggen van [%.2f, %.2f]." +msgid "Multiplier" +msgstr "Vermenigvuldiger" + msgid "unloaded" msgstr "uitgeladen" @@ -6552,6 +6715,12 @@ msgstr "Van" msgid "To" msgstr "Naar" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Inloggen" @@ -6587,6 +6756,9 @@ msgstr "" "Dialoogvenster met instellingen voor 3Dconnexion-apparaten weergeven/" "verbergen" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Toon lijst met sneltoetsen" @@ -6842,12 +7014,15 @@ msgstr "" msgid "New version of Orca Slicer" msgstr "Nieuwe versie van Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "Herinner me niet meer aan deze versie." +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Done" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN-verbinding mislukt (verzenden afdrukbestand)" @@ -6873,8 +7048,22 @@ msgstr "Toegangscode" msgid "Where to find your printer's IP and Access Code?" msgstr "Waar vind je het IP-adres en de toegangscode van je printer?" -msgid "Error: IP or Access Code are not correct" -msgstr "Fout: IP-adres of toegangscode zijn niet correct" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Model:" @@ -7344,6 +7533,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "De laaghoogte kan niet groter zijn dan de diameter van de nozzle" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7796,7 +7990,28 @@ msgstr "" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" msgid "Reverse threshold" @@ -8040,6 +8255,14 @@ msgstr "Einde G-code" msgid "End G-code when finish the whole printing" msgstr "Voeg een eind G-code toe bij het afwerken van de hele print." +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "" "Voeg een eind G-code toe bij het afronden van het printen van dit filament." @@ -8130,27 +8353,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "" -msgid "Order of inner wall/outer wall/infil" -msgstr "Volgorde binnenwand/buitenwand/opvulling (infill)" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " +msgid "Print sequence of inner wall and outer wall. " msgstr "" -"Dit is de afdrukvolgorde van binnenwanden, buitenwanden en vulling (infill)." -msgid "inner/outer/infill" -msgstr "binnenste/buitenste/vulling (infill)" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "buitenste/binnenste/vulling (infill)" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "Vulling (infill)/binnenste/buitenste" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "Vulling (infill)/buitenste/binnenste" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "binnen-buiten-binnen/infill" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Hoogte tot geleider" @@ -8251,9 +8473,6 @@ msgstr "Standaardkleur" msgid "Default filament color" msgstr "Standaard filamentkleur" -msgid "Color" -msgstr "Kleur" - msgid "Filament notes" msgstr "" @@ -8638,10 +8857,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "" @@ -8713,10 +8928,10 @@ msgstr "Volledige snelheid op laag" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" msgid "Support interface fan speed" @@ -9007,6 +9222,18 @@ msgid "" "soluble support material" msgstr "" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Strijk type" @@ -9560,6 +9787,22 @@ msgstr "" "de nozzle de print raakt bij veplaatsen. Het gebruik van spiraallijnen om Z " "op te tillen kan stringing voorkomen." +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "" @@ -9983,9 +10226,15 @@ msgstr "" "betekent geen specifiek filament voor ondersteuning (support) en het " "huidige filament wordt gebruikt." -msgid "" -"Line width of support. If expressed as a %, it will be computed over the " -"nozzle diameter." +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" +"Line width of support. If expressed as a %, it will be computed over the " +"nozzle diameter." msgstr "" msgid "Interface use loop pattern" @@ -10017,6 +10266,12 @@ msgstr "Dit is het aantal bovenste interfacelagen." msgid "Bottom interface layers" msgstr "Onderste interfacelagen" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Bovenste interface-afstand" @@ -10686,111 +10941,18 @@ msgstr "too large line width " msgid " not in range " msgstr " not in range " -msgid "Export 3MF" -msgstr "Exporteer 3mf" - -msgid "Export project as 3MF." -msgstr "Dit exporteert het project als 3MF." - -msgid "Export slicing data" -msgstr "Exporteer slicinggegevens" - -msgid "Export slicing data to a folder." -msgstr "Exporteer slicinggegevens naar een map" - -msgid "Load slicing data" -msgstr "Laad slicinggegevens" - -msgid "Load cached slicing data from directory" -msgstr "Laad slicinggegevens in de cache uit de directory" - -msgid "Export STL" -msgstr "" - -msgid "Export the objects as multiple STL." -msgstr "" - -msgid "Slice" -msgstr "Slice" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "Slice de printbedden: 0-alle printbedden, i-printbed i, andere-onjuist" - -msgid "Show command help." -msgstr "Dit toont de command hulp." - -msgid "UpToDate" -msgstr "UpToDate" - -msgid "Update the configs values of 3mf to latest." -msgstr "Update de configuratiewaarden van 3mf naar de nieuwste versie." - -msgid "Load default filaments" -msgstr "" - -msgid "Load first filament as default for those not loaded" -msgstr "" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "" -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "max triangle count per plate for slicing" - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "max slicing time per plate in seconds" - msgid "No check" msgstr "No check" msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "Do not run any validity checks, such as G-code path conflicts check." -msgid "Normative check" -msgstr "Normative check" - -msgid "Check the normative items." -msgstr "Check the normative items." - -msgid "Output Model Info" -msgstr "Model informatie weergeven" - -msgid "Output the model's information." -msgstr "Dit geeft de informatie van het model weer." - -msgid "Export Settings" -msgstr "Exporteer instellingen" - -msgid "Export settings to a file." -msgstr "Exporteer instellingen naar een bestand" - -msgid "Send progress to pipe" -msgstr "Stuur voortgang naar pipe" - -msgid "Send progress to pipe." -msgstr "Stuur voortgang naar pipe" - -msgid "Arrange Options" -msgstr "Rangschik opties" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Rangschik opties: 0-uitzetten, 1-aanzetten, anders-automatisch" - -msgid "Repetions count" -msgstr "" - -msgid "Repetions count of the whole model" -msgstr "" - msgid "Ensure on bed" msgstr "" @@ -10798,12 +10960,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "" -msgid "Convert Unit" -msgstr "Eenheid converteren" - -msgid "Convert the units of model" -msgstr "Converteer de eenheden van het model" - msgid "Orient Options" msgstr "" @@ -10813,47 +10969,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "" -msgid "Rotate around X" -msgstr "" - -msgid "Rotation angle around the X axis in degrees." -msgstr "" - msgid "Rotate around Y" msgstr "" msgid "Rotation angle around the Y axis in degrees." msgstr "" -msgid "Scale the model by a float factor" -msgstr "Schaal het model met een float-factor" - -msgid "Load General Settings" -msgstr "Standaard instellingen laden" - -msgid "Load process/machine settings from the specified file" -msgstr "Proces/machine instellingen laden vanuit een gekozen bestand" - -msgid "Load Filament Settings" -msgstr "Filament instellingen laden" - -msgid "Load filament settings from the specified file list" -msgstr "Filament instellingen laden vanuit een bestandslijst" - -msgid "Skip Objects" -msgstr "Skip Objects" - -msgid "Skip some objects in this print" -msgstr "Skip some objects in this print" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" - msgid "Data directory" msgstr "" @@ -10863,22 +10984,6 @@ msgid "" "storage." msgstr "" -msgid "Output directory" -msgstr "Uitvoermap" - -msgid "Output directory for the exported files." -msgstr "Dit is de map waarin de geëxporteerde bestanden worden opgeslagen" - -msgid "Debug level" -msgstr "Debuggen level" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Sets debug logging level. 0:fataal, 1:error, 2:waarschuwing, 3:info, 4:" -"debug, 5:trace\n" - msgid "Load custom gcode" msgstr "" @@ -11042,9 +11147,6 @@ msgstr "" msgid "Finish" msgstr "Klaar" -msgid "Wiki" -msgstr "" - msgid "How to use calibration result?" msgstr "" @@ -11060,6 +11162,12 @@ msgstr "" msgid "Calibration not supported" msgstr "" +msgid "Error desc" +msgstr "" + +msgid "Extra info" +msgstr "" + msgid "Flow Dynamics" msgstr "" @@ -11087,8 +11195,8 @@ msgstr "" msgid "The name cannot be empty." msgstr "" -#, boost-format -msgid "The selected preset: %1% is not found." +#, c-format, boost-format +msgid "The selected preset: %s is not found." msgstr "" msgid "The name cannot be the same as the system preset name." @@ -11368,12 +11476,6 @@ msgid "" "- Different filament brand and family(Brand = Bambu, Family = Basic, Matte)" msgstr "" -msgid "Error desc" -msgstr "" - -msgid "Extra info" -msgstr "" - msgid "Pattern" msgstr "" @@ -11462,101 +11564,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "" - -msgid "Mesh Boolean" -msgstr "" - -msgid "Union" -msgstr "" - -msgid "Difference" -msgstr "" - -msgid "Intersection" -msgstr "" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "" - -msgid "Subtract with" -msgstr "" - -msgid "selected" -msgstr "" - -msgid "Part 1" -msgstr "" - -msgid "Part 2" -msgstr "" - -msgid "Delete input" -msgstr "" - -msgid "Send G-Code to printer host" -msgstr "" - -msgid "Upload to Printer Host with the following filename:" -msgstr "" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" - -msgid "Upload to storage" -msgstr "" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" - -msgid "Upload" -msgstr "" - -msgid "Print host upload queue" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "" - -msgctxt "OfFile" -msgid "Size" -msgstr "" - -msgid "Filename" -msgstr "" - -msgid "Cancel selected" -msgstr "" - -msgid "Show error message" -msgstr "" - -msgid "Enqueued" -msgstr "" - -msgid "Uploading" -msgstr "Uploaden" - -msgid "Cancelling" -msgstr "" - -msgid "Error uploading to print host" -msgstr "" - msgid "PA Calibration" msgstr "" @@ -11681,69 +11688,107 @@ msgstr "" msgid "mm/mm" msgstr "" -msgid "Physical Printer" +msgid "Send G-Code to printer host" msgstr "" -msgid "Print Host upload" +msgid "Upload to Printer Host with the following filename:" msgstr "" -msgid "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." msgstr "" -msgid "Could not get a valid Printer Host reference" +msgid "Upload to storage" msgstr "" -msgid "Success!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" msgstr "" -msgid "Refresh Printers" +msgid "Upload" msgstr "" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." +msgid "Print host upload queue" msgstr "" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "ID" msgstr "" -msgid "Open CA certificate file" +msgid "Progress" msgstr "" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." +msgid "Host" msgstr "" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." +msgctxt "OfFile" +msgid "Size" msgstr "" -msgid "Connection to printers connected via the print host failed." +msgid "Filename" msgstr "" -msgid "The start, end or step is not valid value." +msgid "Cancel selected" msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Show error message" +msgstr "" + +msgid "Enqueued" +msgstr "" + +msgid "Uploading" +msgstr "Uploaden" + +msgid "Cancelling" +msgstr "" + +msgid "Error uploading to print host" +msgstr "" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "" + +msgid "Mesh Boolean" +msgstr "" + +msgid "Union" +msgstr "" + +msgid "Difference" msgstr "" -msgid "Need select printer" +msgid "Intersection" msgstr "" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "Source Volume" +msgstr "" + +msgid "Tool Volume" +msgstr "" + +msgid "Subtract from" +msgstr "" + +msgid "Subtract with" +msgstr "" + +msgid "selected" +msgstr "" + +msgid "Part 1" +msgstr "" + +msgid "Part 2" +msgstr "" + +msgid "Delete input" +msgstr "" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3D-scènebewerkingen\n" -"Weet u hoe u de weergave en selectie van objecten/onderdelen met de muis en " -"het aanraakscherm in de 3D-scène kunt bedienen?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -11759,11 +11804,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Model repareren\n" -"Wist u dat u een beschadigd 3D-model kunt repareren om veel snijproblemen te " -"voorkomen?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -11813,6 +11855,13 @@ msgstr "" "Wist u dat u alle objecten/onderdelen in een lijst kunt bekijken en de " "instellingen voor ieder object/onderdeel kunt wijzigen?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -11997,11 +12046,243 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." msgstr "" +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Hulpmiddel op zijde plaatsen" + +#~ msgid "Export as STL" +#~ msgstr "Exporteer als STL-bestand" + +#~ msgid "Check cloud service status" +#~ msgstr "Check cloud service status" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Voer een geldige waarde in (K in 0 ~ 0,5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "Voer een geldige waarde in (K in 0 ~ 0,5, N in 0,6 ~ 2,0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Exporteer alle objecten als STL" + +#~ msgid "Slice ok." +#~ msgstr "Slice gelukt" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "Versie %s van de 3mf is nieuwer dan versie %s van %s. De volgende " +#~ "sleutels worden niet herkend:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "U dient de software te upgraden.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "Versie %s van de 3mf is nieuwer dan versie %s van %s. Wij stellen voor om " +#~ "uw software te upgraden." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "" +#~ "Het 3mf bestand is niet compatibel, enkel de geometrische data wordt " +#~ "geladen!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Onbruikbaar 3mf bestand" + +#~ msgid "Add/Remove printers" +#~ msgstr "Printers toevoegen/verwijderen" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s is not supported by the AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Herinner me niet meer aan deze versie." + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Fout: IP-adres of toegangscode zijn niet correct" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Volgorde binnenwand/buitenwand/opvulling (infill)" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "" +#~ "Dit is de afdrukvolgorde van binnenwanden, buitenwanden en vulling " +#~ "(infill)." + +#~ msgid "inner/outer/infill" +#~ msgstr "binnenste/buitenste/vulling (infill)" + +#~ msgid "outer/inner/infill" +#~ msgstr "buitenste/binnenste/vulling (infill)" + +#~ msgid "infill/inner/outer" +#~ msgstr "Vulling (infill)/binnenste/buitenste" + +#~ msgid "infill/outer/inner" +#~ msgstr "Vulling (infill)/buitenste/binnenste" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "binnen-buiten-binnen/infill" + +#~ msgid "Export 3MF" +#~ msgstr "Exporteer 3mf" + +#~ msgid "Export project as 3MF." +#~ msgstr "Dit exporteert het project als 3MF." + +#~ msgid "Export slicing data" +#~ msgstr "Exporteer slicinggegevens" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Exporteer slicinggegevens naar een map" + +#~ msgid "Load slicing data" +#~ msgstr "Laad slicinggegevens" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Laad slicinggegevens in de cache uit de directory" + +#~ msgid "Slice" +#~ msgstr "Slice" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "" +#~ "Slice de printbedden: 0-alle printbedden, i-printbed i, andere-onjuist" + +#~ msgid "Show command help." +#~ msgstr "Dit toont de command hulp." + +#~ msgid "UpToDate" +#~ msgstr "UpToDate" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Update de configuratiewaarden van 3mf naar de nieuwste versie." + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "max triangle count per plate for slicing" + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "max slicing time per plate in seconds" + +#~ msgid "Normative check" +#~ msgstr "Normative check" + +#~ msgid "Check the normative items." +#~ msgstr "Check the normative items." + +#~ msgid "Output Model Info" +#~ msgstr "Model informatie weergeven" + +#~ msgid "Output the model's information." +#~ msgstr "Dit geeft de informatie van het model weer." + +#~ msgid "Export Settings" +#~ msgstr "Exporteer instellingen" + +#~ msgid "Export settings to a file." +#~ msgstr "Exporteer instellingen naar een bestand" + +#~ msgid "Send progress to pipe" +#~ msgstr "Stuur voortgang naar pipe" + +#~ msgid "Send progress to pipe." +#~ msgstr "Stuur voortgang naar pipe" + +#~ msgid "Arrange Options" +#~ msgstr "Rangschik opties" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Rangschik opties: 0-uitzetten, 1-aanzetten, anders-automatisch" + +#~ msgid "Convert Unit" +#~ msgstr "Eenheid converteren" + +#~ msgid "Convert the units of model" +#~ msgstr "Converteer de eenheden van het model" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Schaal het model met een float-factor" + +#~ msgid "Load General Settings" +#~ msgstr "Standaard instellingen laden" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Proces/machine instellingen laden vanuit een gekozen bestand" + +#~ msgid "Load Filament Settings" +#~ msgstr "Filament instellingen laden" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "Filament instellingen laden vanuit een bestandslijst" + +#~ msgid "Skip Objects" +#~ msgstr "Skip Objects" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Skip some objects in this print" + +#~ msgid "Output directory" +#~ msgstr "Uitvoermap" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Dit is de map waarin de geëxporteerde bestanden worden opgeslagen" + +#~ msgid "Debug level" +#~ msgstr "Debuggen level" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Sets debug logging level. 0:fataal, 1:error, 2:waarschuwing, 3:info, 4:" +#~ "debug, 5:trace\n" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3D-scènebewerkingen\n" +#~ "Weet u hoe u de weergave en selectie van objecten/onderdelen met de muis " +#~ "en het aanraakscherm in de 3D-scène kunt bedienen?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Model repareren\n" +#~ "Wist u dat u een beschadigd 3D-model kunt repareren om veel snijproblemen " +#~ "te voorkomen?" + # Source and destination string both English but don't match! #~ msgid "Embeded" #~ msgstr "Embedded" @@ -12109,9 +12390,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Score" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bambu Engineering (technische) plate" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu High Temperature (hoge temperatuur) Plate" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index 58e94daf827..59cd97d4bfe 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -98,6 +98,9 @@ msgstr "Ingen auto support" msgid "Support Generated" msgstr "Support skapad" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Lägg på yta" @@ -146,8 +149,8 @@ msgstr "Hinkfyllning" msgid "Height range" msgstr "Höjd intervall" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Växla Wireframe" @@ -177,9 +180,15 @@ msgstr "Färgläggning använder: Filament %1%" msgid "Move" msgstr "Flytta" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Rotera" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Optimisera placering" @@ -189,12 +198,12 @@ msgstr "Applicera" msgid "Scale" msgstr "Skala" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "FEL: Stäng alla verktygsmenyer först" -msgid "Tool-Lay on Face" -msgstr "Ytplacerings verktyg" - msgid "in" msgstr "i" @@ -489,6 +498,15 @@ msgstr "Målning av sömmar" msgid "Remove selection" msgstr "Ta bort val" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Typsnitt" @@ -691,6 +709,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Uppdatering av integritetspolicy" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Laddar" @@ -885,8 +911,11 @@ msgstr "Utskriftsbar" msgid "Fix model" msgstr "Fixa modell" -msgid "Export as STL" -msgstr "Exportera som STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Ladda om från disk" @@ -1141,6 +1170,9 @@ msgstr "Klicka på ikonen för att redigera färgläggningen av objektet" msgid "Click the icon to shift this object to the bed" msgstr "Klicka på ikonen för att flytta detta föremål till byggplattan" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Laddar fil" @@ -1405,6 +1437,18 @@ msgstr "Öppna nästa tips" msgid "Open Documentation in web browser." msgstr "Öppna dokumentationen i webbläsaren" +msgid "Color" +msgstr "Färg" + +msgid "Pause" +msgstr "Paus" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Custom" + msgid "Pause:" msgstr "Pausa:" @@ -1480,8 +1524,8 @@ msgstr "" msgid "Failed to connect to the server" msgstr "Uppkoppling till servern misslyckades" -msgid "Check cloud service status" -msgstr "Kontrollera molntjänstens status" +msgid "Check the status of current system services" +msgstr "Kontrollera status för aktuella systemtjänster" msgid "code" msgstr "kod" @@ -1745,6 +1789,14 @@ msgstr "Skicka utskriftsjobb via LAN" msgid "Sending print job through cloud service" msgstr "Skicka utskriftsjobb via molntjänst" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Tjänsten är inte tillgänglig" @@ -1968,11 +2020,11 @@ msgstr "Är du säker på att du vill rensa filament informationen?" msgid "You need to select the material type and color first." msgstr "Du måste först välja materialtyp och färg." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Ange ett giltigt värde (K i 0 ~ 0,5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "Ange ett giltigt värde (K i 0 ~ 0,5, N i 0,6 ~ 2,0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Annan färg" @@ -2356,9 +2408,6 @@ msgstr "Rektangulär" msgid "Circular" msgstr "Cirkulär" -msgid "Custom" -msgstr "Custom" - msgid "Load shape from STL..." msgstr "Ladda form ifrån STL..." @@ -2845,6 +2894,9 @@ msgstr "Rensad" msgid "Total" msgstr "Totalt" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Total Uppskattning" @@ -2932,15 +2984,18 @@ msgstr "Färg byte" msgid "Print" msgstr "Skriv ut" -msgid "Pause" -msgstr "Paus" - msgid "Printer" msgstr "Skrivare" msgid "Print settings" msgstr "Utskrifts inställningar" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Beräknad tid" @@ -3109,7 +3164,7 @@ msgstr "Volym:" msgid "Size:" msgstr "Storlek:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3169,15 +3224,15 @@ msgstr "Kalibrerings Flöde" msgid "Start Calibration" msgstr "Starta Kalibrering" -msgid "No step selected" -msgstr "" - msgid "Completed" msgstr "Slutförd" msgid "Calibrating" msgstr "Kalibrerar" +msgid "No step selected" +msgstr "" + msgid "Auto-record Monitoring" msgstr "Automatisk inspelning av övervakning" @@ -3392,8 +3447,11 @@ msgstr "Ladda konfiguration" msgid "Import" msgstr "Importera" -msgid "Export all objects as STL" -msgstr "Exportera Alla Objekt som STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Exportera generisk 3mf" @@ -3668,9 +3726,6 @@ msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "" "Skrivaren är upptagen med att ladda ner; vänta tills nedladdningen är klar." -msgid "Loading..." -msgstr "Laddar..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" @@ -3733,6 +3788,9 @@ msgstr "Spelar..." msgid "Load failed [%d]!" msgstr "Laddning misslyckad [%d]!" +msgid "Loading..." +msgstr "Laddar..." + msgid "Year" msgstr "År" @@ -3850,12 +3908,25 @@ msgstr "Nedladdning slutförd" msgid "Downloading %d%%..." msgstr "Laddar ner %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "" msgid "Storage unavailable, insert SD card." msgstr "" +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Hastighet:" @@ -4186,6 +4257,12 @@ msgstr "Ny nätverks plugin tillgänglig" msgid "Details" msgstr "Detaljer" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "" + msgid "Undo integration failed." msgstr "Återställande av integrationen misslyckades." @@ -4234,9 +4311,6 @@ msgstr "Klar" msgid "Cancel upload" msgstr "Avbryt uppladdning" -msgid "Slice ok." -msgstr "Beredning klar." - msgid "Jump to" msgstr "Hoppa till" @@ -4341,6 +4415,9 @@ msgstr "Automatisk återhämtning vid stegförlust" msgid "Allow Prompt Sound" msgstr "" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Global" @@ -4435,6 +4512,9 @@ msgstr "Synkronisera filament listan från AMS" msgid "Set filaments to use" msgstr "Ställ in filament som ska användas" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4532,26 +4612,29 @@ msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "" #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"3mf:s version %s är nyare än %s version %s, Följande nycklar har hittats som " -"inte känns igen:" -msgid "You'd better upgrade your software.\n" -msgstr "Uppdatera mjukvaran.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Nyare 3mf version" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"3mf:s version %s är nyare än %s version %s, Föreslår att du uppdaterar din " -"programvara." msgid "Invalid values found in the 3mf:" msgstr "Ogiltiga värden hittades i 3mf:" @@ -4559,11 +4642,27 @@ msgstr "Ogiltiga värden hittades i 3mf:" msgid "Please correct them in the param tabs" msgstr "Vänligen korrigera dem i Parameter flikarna" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "3mf ej kompatibel, laddar endast geometrin !" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "Ej kompatibel 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "Komponent namnet i step filen är inte UTF8 format!" @@ -4636,6 +4735,15 @@ msgstr "Spara fil som:" msgid "Export OBJ file:" msgstr "" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Radera objekt som är en del av det utskurna objektet" @@ -4654,15 +4762,15 @@ msgstr "Det valda objektet kan inte delas." msgid "Another export job is running." msgstr "En annan exportering pågår." -msgid "Replace from:" -msgstr "" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "Fel vid byte" +msgid "Replace from:" +msgstr "" + msgid "Select a new file" msgstr "Välj en ny fil" @@ -5032,6 +5140,12 @@ msgstr "" msgid "If enabled, g-code window will be displayed." msgstr "" +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Förinställningar" @@ -5082,6 +5196,9 @@ msgstr "Maximalt antal nyligen genomförda projekt" msgid "Clear my choice on the unsaved projects." msgstr "Rensa mitt val för de osparade projekten." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Auto Säkerhetskopiera" @@ -5235,8 +5352,11 @@ msgstr "Lägg till/Ta bort filament" msgid "Add/Remove materials" msgstr "Lägg till/Ta bort material" -msgid "Add/Remove printers" -msgstr "Lägg till/Ta bort skrivare" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Inkompatibel" @@ -5421,16 +5541,16 @@ msgstr "Bambu Cool Plate" msgid "PLA Plate" msgstr "PLA platta" -msgid "Bambu Engineering Plate" -msgstr "" +msgid "Bamabu Engineering Plate" +msgstr "Bambu Engineering Plate" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "" msgid "High temperature Plate" msgstr "" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "" msgid "Send print job to" @@ -5454,9 +5574,6 @@ msgstr "Skicka komplett" msgid "Error code" msgstr "Felkod" -msgid "Check the status of current system services" -msgstr "Kontrollera status för aktuella systemtjänster" - msgid "Printer local connection failed, please try again." msgstr "Den lokala anslutningen till skrivaren misslyckades; försök igen." @@ -5564,8 +5681,7 @@ msgid "" msgstr "" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" msgid "Errors" @@ -5583,10 +5699,6 @@ msgstr "" "den för tillfället valda skrivaren. Vi rekommenderar att du använder samma " "skrivartyp för beredning." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s stöds inte av AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5596,11 +5708,34 @@ msgstr "" "filament som krävs. Om de är okej, klicka du på \"Confirm\" för att börja " "skriva ut." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Klicka på knappen Bekräfta om du fortfarande vill fortsätta med utskriften." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5787,6 +5922,9 @@ msgstr "" "Prime tower krävs för Smooth timelapse-läge. Det kan bli fel på modellen " "utan prime tower. Vill du aktivera prime tower?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5829,8 +5967,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "När du spelar in timelapse utan verktygshuvud rekommenderas att du lägger " "till ett \"Timelapse Wipe Tower\".\n" @@ -6097,6 +6235,9 @@ msgstr "Maskin start G-kod" msgid "Machine end G-code" msgstr "Maskin stop G-kod" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "Före lagerskifte G-kod" @@ -6163,6 +6304,25 @@ msgstr "" msgid "Detached" msgstr "Fristående" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Förinställning" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "" @@ -6176,11 +6336,6 @@ msgstr[1] "" msgid "Are you sure to %1% the selected preset?" msgstr "Välja %1% den valda förinställningen?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Förinställning" - msgid "All" msgstr "Allt" @@ -6422,11 +6577,17 @@ msgstr "" msgid "Auto-Calc" msgstr "Autoberäkna" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Rensnings volym för filament byte" -msgid "Multiplier" -msgstr "Multiplikator" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Rensnings volym (mm³) för varje filament." @@ -6439,6 +6600,9 @@ msgstr "Förslag: Rensnings volym i intervallet [%d, %d]" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "Multiplikatorn ska ligga inom intervallet [%.2f, %.2f]." +msgid "Multiplier" +msgstr "Multiplikator" + msgid "unloaded" msgstr "utmatad" @@ -6454,6 +6618,12 @@ msgstr "Från" msgid "To" msgstr "Till" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Logga in" @@ -6487,6 +6657,9 @@ msgstr "Klistra in ifrån urklipp" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "Visa/Dölj 3Dconnexion enheternas inställnings dialogruta" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Visa tangentbordets genvägs lista" @@ -6737,12 +6910,15 @@ msgstr "En ny nätverksplugin (%s) är tillgänglig. Vill du installera den?" msgid "New version of Orca Slicer" msgstr "Ny version av Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "Påminn mig inte om den här versionen igen." +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Klar" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN-anslutning misslyckades (skickar utskriftsfil)" @@ -6766,8 +6942,22 @@ msgstr "Behörighetskod: " msgid "Where to find your printer's IP and Access Code?" msgstr "Var hittar du skrivarens IP- och åtkomstkod?" -msgid "Error: IP or Access Code are not correct" -msgstr "Fel: IP eller Åtkomstkod är inte korrekta" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Modell:" @@ -7215,6 +7405,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "Lagerhöjden kan inte överstiga nozzel diametern" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7656,7 +7851,28 @@ msgstr "" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" msgid "Reverse threshold" @@ -7797,9 +8013,9 @@ msgid "" "quality for needle and small details" msgstr "" "Aktivera detta val för att sänka utskifts hastigheten för att göra den sista " -"lager tiden inte kortare än lager tidströskeln \"Max fläkthastighets tröskel" -"\", detta så att lager kan kylas under en längre tid. Detta kan förbättra " -"kylnings kvaliteten för små detaljer" +"lager tiden inte kortare än lager tidströskeln \"Max fläkthastighets " +"tröskel\", detta så att lager kan kylas under en längre tid. Detta kan " +"förbättra kylnings kvaliteten för små detaljer" msgid "Normal printing" msgstr "Normal utskrift" @@ -7894,6 +8110,14 @@ msgstr "Slut G-kod" msgid "End G-code when finish the whole printing" msgstr "Lägg till slut G-kod när utskriften har avslutas" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "Lägg till slut G-kod när utskriften har avslutas med detta filament" @@ -7980,26 +8204,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "" -msgid "Order of inner wall/outer wall/infil" -msgstr "Ordning på inre vägg/yttre vägg/ifyllnad" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "Utskriftsordning på inre vägg, yttre vägg och ifyllnad. " +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "inre/yttre/ifyllnad" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "yttre/inre/ifyllnad" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "ifyllnad/inre/yttre" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "ifyllnad/yttre/inre" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "inre-yttre-inre/utfyllnad" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Höjd till axel" @@ -8098,9 +8322,6 @@ msgstr "Standardfärg" msgid "Default filament color" msgstr "Standard filament färg" -msgid "Color" -msgstr "Färg" - msgid "Filament notes" msgstr "" @@ -8481,10 +8702,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "" @@ -8553,10 +8770,10 @@ msgstr "Full fläkthastighet vid lager" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" msgid "Support interface fan speed" @@ -8846,6 +9063,18 @@ msgid "" "soluble support material" msgstr "" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Stryknings typ" @@ -9387,6 +9616,22 @@ msgstr "" "den förflyttas. Att använda spirallinjer för att lyfta z kan förhindra " "strängning" +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "" @@ -9803,7 +10048,13 @@ msgstr "" "Filament för att skriva ut support och rafts. ”Standard” betyder ingen " "specifik filament för support, och nuvarande filament används" -msgid "" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." msgstr "" @@ -9837,6 +10088,12 @@ msgstr "Antal topp gränssnitts lager" msgid "Bottom interface layers" msgstr "Botten gränssnitts lager" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Topp gränssnitts avstånd" @@ -10491,69 +10748,12 @@ msgstr "för stor linjebredd " msgid " not in range " msgstr " inte inom intervallet " -msgid "Export 3MF" -msgstr "Exportera 3mf" - -msgid "Export project as 3MF." -msgstr "Exportera projekt som3mf." - -msgid "Export slicing data" -msgstr "Exportera beredningsdata" - -msgid "Export slicing data to a folder." -msgstr "Exportera beredningsdata till en mapp" - -msgid "Load slicing data" -msgstr "Ladda berednings data" - -msgid "Load cached slicing data from directory" -msgstr "Ladda cachad berednings data från katalogen" - -msgid "Export STL" -msgstr "" - -msgid "Export the objects as multiple STL." -msgstr "" - -msgid "Slice" -msgstr "Bered" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "Bered plattorna: 0-alla plattor, i-platta i, andra-ogiltiga" - -msgid "Show command help." -msgstr "Visa kommandohjälp." - -msgid "UpToDate" -msgstr "Aktuell" - -msgid "Update the configs values of 3mf to latest." -msgstr "Uppdatera konfigurations värdena i 3mf till det senaste." - -msgid "Load default filaments" -msgstr "" - -msgid "Load first filament as default for those not loaded" -msgstr "" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "" -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "max antal trianglar per platta för beredning" - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "Max berednings tid per platta i sekunder" - msgid "No check" msgstr "Ingen kontroll" @@ -10562,42 +10762,6 @@ msgstr "" "Utför inga giltighets kontroller, t.ex. kontroll av konflikter mellan G-kod " "och banor." -msgid "Normative check" -msgstr "Normativ kontroll" - -msgid "Check the normative items." -msgstr "Kontrollera de normativa objekten." - -msgid "Output Model Info" -msgstr "Mata ut modell information" - -msgid "Output the model's information." -msgstr "Mata ut modellens information." - -msgid "Export Settings" -msgstr "Exportera inställningar" - -msgid "Export settings to a file." -msgstr "Exportera inställningar till en fil." - -msgid "Send progress to pipe" -msgstr "Skicka framsteg till röret (SLA)" - -msgid "Send progress to pipe." -msgstr "Skicka framsteg till röret (SLA)" - -msgid "Arrange Options" -msgstr "Placera Val" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Placera val: 0-inaktivera, 1-aktivera, andra-auto" - -msgid "Repetions count" -msgstr "" - -msgid "Repetions count of the whole model" -msgstr "" - msgid "Ensure on bed" msgstr "" @@ -10605,12 +10769,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "" -msgid "Convert Unit" -msgstr "Konvertera enhet" - -msgid "Convert the units of model" -msgstr "Konvertera modellens enheter" - msgid "Orient Options" msgstr "" @@ -10620,47 +10778,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "" -msgid "Rotate around X" -msgstr "" - -msgid "Rotation angle around the X axis in degrees." -msgstr "" - msgid "Rotate around Y" msgstr "" msgid "Rotation angle around the Y axis in degrees." msgstr "" -msgid "Scale the model by a float factor" -msgstr "Skala modellen med en plus faktor" - -msgid "Load General Settings" -msgstr "Ladda allmänna inställningar" - -msgid "Load process/machine settings from the specified file" -msgstr "Ladda process/maskin inställningar ifrån vald fil" - -msgid "Load Filament Settings" -msgstr "Ladda filament inställningar" - -msgid "Load filament settings from the specified file list" -msgstr "Ladda filament inställningar ifrån vald fil" - -msgid "Skip Objects" -msgstr "Hoppa över objekt" - -msgid "Skip some objects in this print" -msgstr "Hoppa över vissa objekt i denna utskrift" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" - msgid "Data directory" msgstr "" @@ -10670,22 +10793,6 @@ msgid "" "storage." msgstr "" -msgid "Output directory" -msgstr "Mata ut katalog" - -msgid "Output directory for the exported files." -msgstr "Mata ut katalogen för exporterade filer." - -msgid "Debug level" -msgstr "Felsökningsnivå" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Välj felsöknings nivå. 0:allvarlig, 1:fel, 2:varning, 3:info, 4:felsök, 5:" -"spåra\n" - msgid "Load custom gcode" msgstr "" @@ -10849,9 +10956,6 @@ msgstr "" msgid "Finish" msgstr "Slutför" -msgid "Wiki" -msgstr "" - msgid "How to use calibration result?" msgstr "" @@ -10867,6 +10971,12 @@ msgstr "" msgid "Calibration not supported" msgstr "" +msgid "Error desc" +msgstr "" + +msgid "Extra info" +msgstr "" + msgid "Flow Dynamics" msgstr "" @@ -10894,8 +11004,8 @@ msgstr "" msgid "The name cannot be empty." msgstr "" -#, boost-format -msgid "The selected preset: %1% is not found." +#, c-format, boost-format +msgid "The selected preset: %s is not found." msgstr "" msgid "The name cannot be the same as the system preset name." @@ -11175,12 +11285,6 @@ msgid "" "- Different filament brand and family(Brand = Bambu, Family = Basic, Matte)" msgstr "" -msgid "Error desc" -msgstr "" - -msgid "Extra info" -msgstr "" - msgid "Pattern" msgstr "" @@ -11269,101 +11373,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "" - -msgid "Mesh Boolean" -msgstr "" - -msgid "Union" -msgstr "" - -msgid "Difference" -msgstr "" - -msgid "Intersection" -msgstr "" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "" - -msgid "Subtract with" -msgstr "" - -msgid "selected" -msgstr "" - -msgid "Part 1" -msgstr "" - -msgid "Part 2" -msgstr "" - -msgid "Delete input" -msgstr "" - -msgid "Send G-Code to printer host" -msgstr "" - -msgid "Upload to Printer Host with the following filename:" -msgstr "" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" - -msgid "Upload to storage" -msgstr "" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" - -msgid "Upload" -msgstr "" - -msgid "Print host upload queue" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "" - -msgctxt "OfFile" -msgid "Size" -msgstr "" - -msgid "Filename" -msgstr "" - -msgid "Cancel selected" -msgstr "" - -msgid "Show error message" -msgstr "" - -msgid "Enqueued" -msgstr "" - -msgid "Uploading" -msgstr "Laddar upp" - -msgid "Cancelling" -msgstr "" - -msgid "Error uploading to print host" -msgstr "" - msgid "PA Calibration" msgstr "" @@ -11488,69 +11497,107 @@ msgstr "" msgid "mm/mm" msgstr "" -msgid "Physical Printer" +msgid "Send G-Code to printer host" msgstr "" -msgid "Print Host upload" +msgid "Upload to Printer Host with the following filename:" msgstr "" -msgid "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "" + +msgid "Upload to storage" +msgstr "" + +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" msgstr "" -msgid "Could not get a valid Printer Host reference" +msgid "Upload" msgstr "" -msgid "Success!" +msgid "Print host upload queue" msgstr "" -msgid "Refresh Printers" +msgid "ID" msgstr "" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." +msgid "Progress" msgstr "" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "Host" msgstr "" -msgid "Open CA certificate file" +msgctxt "OfFile" +msgid "Size" msgstr "" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." +msgid "Filename" msgstr "" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." +msgid "Cancel selected" msgstr "" -msgid "Connection to printers connected via the print host failed." +msgid "Show error message" msgstr "" -msgid "The start, end or step is not valid value." +msgid "Enqueued" msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Uploading" +msgstr "Laddar upp" + +msgid "Cancelling" +msgstr "" + +msgid "Error uploading to print host" +msgstr "" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "" + +msgid "Mesh Boolean" +msgstr "" + +msgid "Union" +msgstr "" + +msgid "Difference" +msgstr "" + +msgid "Intersection" +msgstr "" + +msgid "Source Volume" +msgstr "" + +msgid "Tool Volume" +msgstr "" + +msgid "Subtract from" +msgstr "" + +msgid "Subtract with" msgstr "" -msgid "Need select printer" +msgid "selected" +msgstr "" + +msgid "Part 1" +msgstr "" + +msgid "Part 2" +msgstr "" + +msgid "Delete input" msgstr "" -#: resources/data/hints.ini: [hint:3D Scene Operations] +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3D Vy Operationer\n" -"Vet du hur du kontrollerar vy och objekt/delval med mus och pekskärm i 3D-" -"scenen?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -11566,11 +11613,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Fix Modell\n" -"Visste du att du kan fixa en skadad 3D-modell för att undvika många " -"berednings problem?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -11620,6 +11664,13 @@ msgstr "" "Visste du att du kan visa alla objekt/delar i en lista och ändra " "inställningar för varje objekt/del?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -11804,11 +11855,238 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." msgstr "" +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Ytplacerings verktyg" + +#~ msgid "Export as STL" +#~ msgstr "Exportera som STL" + +#~ msgid "Check cloud service status" +#~ msgstr "Kontrollera molntjänstens status" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Ange ett giltigt värde (K i 0 ~ 0,5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "Ange ett giltigt värde (K i 0 ~ 0,5, N i 0,6 ~ 2,0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Exportera Alla Objekt som STL" + +#~ msgid "Slice ok." +#~ msgstr "Beredning klar." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "3mf:s version %s är nyare än %s version %s, Följande nycklar har hittats " +#~ "som inte känns igen:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Uppdatera mjukvaran.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "3mf:s version %s är nyare än %s version %s, Föreslår att du uppdaterar " +#~ "din programvara." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "3mf ej kompatibel, laddar endast geometrin !" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Ej kompatibel 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "Lägg till/Ta bort skrivare" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s stöds inte av AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Påminn mig inte om den här versionen igen." + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Fel: IP eller Åtkomstkod är inte korrekta" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Ordning på inre vägg/yttre vägg/ifyllnad" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "Utskriftsordning på inre vägg, yttre vägg och ifyllnad. " + +#~ msgid "inner/outer/infill" +#~ msgstr "inre/yttre/ifyllnad" + +#~ msgid "outer/inner/infill" +#~ msgstr "yttre/inre/ifyllnad" + +#~ msgid "infill/inner/outer" +#~ msgstr "ifyllnad/inre/yttre" + +#~ msgid "infill/outer/inner" +#~ msgstr "ifyllnad/yttre/inre" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "inre-yttre-inre/utfyllnad" + +#~ msgid "Export 3MF" +#~ msgstr "Exportera 3mf" + +#~ msgid "Export project as 3MF." +#~ msgstr "Exportera projekt som3mf." + +#~ msgid "Export slicing data" +#~ msgstr "Exportera beredningsdata" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Exportera beredningsdata till en mapp" + +#~ msgid "Load slicing data" +#~ msgstr "Ladda berednings data" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Ladda cachad berednings data från katalogen" + +#~ msgid "Slice" +#~ msgstr "Bered" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "Bered plattorna: 0-alla plattor, i-platta i, andra-ogiltiga" + +#~ msgid "Show command help." +#~ msgstr "Visa kommandohjälp." + +#~ msgid "UpToDate" +#~ msgstr "Aktuell" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Uppdatera konfigurations värdena i 3mf till det senaste." + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "max antal trianglar per platta för beredning" + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "Max berednings tid per platta i sekunder" + +#~ msgid "Normative check" +#~ msgstr "Normativ kontroll" + +#~ msgid "Check the normative items." +#~ msgstr "Kontrollera de normativa objekten." + +#~ msgid "Output Model Info" +#~ msgstr "Mata ut modell information" + +#~ msgid "Output the model's information." +#~ msgstr "Mata ut modellens information." + +#~ msgid "Export Settings" +#~ msgstr "Exportera inställningar" + +#~ msgid "Export settings to a file." +#~ msgstr "Exportera inställningar till en fil." + +#~ msgid "Send progress to pipe" +#~ msgstr "Skicka framsteg till röret (SLA)" + +#~ msgid "Send progress to pipe." +#~ msgstr "Skicka framsteg till röret (SLA)" + +#~ msgid "Arrange Options" +#~ msgstr "Placera Val" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Placera val: 0-inaktivera, 1-aktivera, andra-auto" + +#~ msgid "Convert Unit" +#~ msgstr "Konvertera enhet" + +#~ msgid "Convert the units of model" +#~ msgstr "Konvertera modellens enheter" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Skala modellen med en plus faktor" + +#~ msgid "Load General Settings" +#~ msgstr "Ladda allmänna inställningar" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Ladda process/maskin inställningar ifrån vald fil" + +#~ msgid "Load Filament Settings" +#~ msgstr "Ladda filament inställningar" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "Ladda filament inställningar ifrån vald fil" + +#~ msgid "Skip Objects" +#~ msgstr "Hoppa över objekt" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Hoppa över vissa objekt i denna utskrift" + +#~ msgid "Output directory" +#~ msgstr "Mata ut katalog" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Mata ut katalogen för exporterade filer." + +#~ msgid "Debug level" +#~ msgstr "Felsökningsnivå" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Välj felsöknings nivå. 0:allvarlig, 1:fel, 2:varning, 3:info, 4:felsök, 5:" +#~ "spåra\n" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3D Vy Operationer\n" +#~ "Vet du hur du kontrollerar vy och objekt/delval med mus och pekskärm i 3D-" +#~ "scenen?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Fix Modell\n" +#~ "Visste du att du kan fixa en skadad 3D-modell för att undvika många " +#~ "berednings problem?" + #~ msgid "Embeded" #~ msgstr "Inbäddad" @@ -11905,9 +12183,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "Resultat" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bambu Engineering Plate" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Bambu High Temperature Plate" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index 042b8ab5d8b..b1d9ae3ee9e 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: OrcaSlicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: 2023-11-15 00:35+0300\n" "Last-Translator: Olcay ÖREN\n" "Language-Team: Türkçe\n" @@ -107,6 +107,9 @@ msgstr "Otomatik destek yok" msgid "Support Generated" msgstr "Destek Oluşturuldu" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Yüzüstü yatır" @@ -154,8 +157,8 @@ msgstr "Kova boya aracı" msgid "Height range" msgstr "Yükseklik aralığı" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Üst Karakter + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Wireframe Göster/Gizle" @@ -185,9 +188,15 @@ msgstr "Şunlar kullanılarak boyanmıştır: Filament %1%" msgid "Move" msgstr "Taşı" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Döndür" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Yönü optimize edin" @@ -197,12 +206,12 @@ msgstr "Uygula" msgid "Scale" msgstr "Ölçeklendir" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "Hata: Lütfen önce tüm araç çubuğu menülerini kapatın" -msgid "Tool-Lay on Face" -msgstr "Yüzüstü Yatırma" - msgid "in" msgstr "in" @@ -497,6 +506,15 @@ msgstr "Dikiş boyama" msgid "Remove selection" msgstr "Seçimi kaldır" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Yazı tipi" @@ -713,6 +731,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Gizlilik Politikası Güncellemesi" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Yükleniyor" @@ -906,8 +932,11 @@ msgstr "Yazdırılabilir" msgid "Fix model" msgstr "Modeli düzelt" -msgid "Export as STL" -msgstr "STL olarak dışa aktar" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Diskten yeniden yükle" @@ -1162,6 +1191,9 @@ msgstr "Nesnenin renk resmini düzenlemek için simgeye tıklayın" msgid "Click the icon to shift this object to the bed" msgstr "Bu nesneyi yatağa taşımak için simgeye tıklayın" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Dosya yükleniyor" @@ -1417,6 +1449,18 @@ msgstr "Sonraki ipucunu açın." msgid "Open Documentation in web browser." msgstr "Belgeleri web tarayıcısında açın." +msgid "Color" +msgstr "Renk" + +msgid "Pause" +msgstr "Duraklat" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Özel" + msgid "Pause:" msgstr "Duraklat:" @@ -1492,8 +1536,8 @@ msgstr "..." msgid "Failed to connect to the server" msgstr "Sunucuya bağlanırken hata oluştu" -msgid "Check cloud service status" -msgstr "Bulut hizmeti durumunu kontrol edin" +msgid "Check the status of current system services" +msgstr "Mevcut sistem hizmetlerinin durumunu kontrol edin" msgid "code" msgstr "kod" @@ -1760,6 +1804,14 @@ msgstr "Yazdırma işi LAN üzerinden gönderiliyor" msgid "Sending print job through cloud service" msgstr "Yazdırma işini bulut hizmeti aracılığıyla gönderme" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Hizmet kullanılamıyor" @@ -1988,11 +2040,11 @@ msgstr "Filament bilgisini temizlemek istediğinizden emin misiniz?" msgid "You need to select the material type and color first." msgstr "Önce malzeme türünü ve rengini seçmeniz gerekir." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Lütfen geçerli bir değer girin (0~0,5'te K)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "Lütfen geçerli bir değer girin (0~0,5'te K, 0,6~2,0'da N)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "Diğer renk" @@ -2170,7 +2222,9 @@ msgstr "Yazıcı şu anda otomatik yeniden doldurmayı desteklemiyor." msgid "" "AMS filament backup is not enabled, please enable it in the AMS settings." -msgstr "AMS filament yedekleme özelliği etkin değil, lütfen AMS ayarlarından etkinleştirin." +msgstr "" +"AMS filament yedekleme özelliği etkin değil, lütfen AMS ayarlarından " +"etkinleştirin." msgid "" "If there are two identical filaments in AMS, AMS filament backup will be " @@ -2180,8 +2234,8 @@ msgid "" msgstr "" "Eğer AMS'de iki aynı filament bulunursa, AMS filament yedekleme özelliği " "etkinleştirilecektir. \n" -"(Şu anda aynı markaya ait sarf malzemelerinin otomatik temini desteklenmektedir, " -"malzeme türü ve rengi)" +"(Şu anda aynı markaya ait sarf malzemelerinin otomatik temini " +"desteklenmektedir, malzeme türü ve rengi)" msgid "AMS Settings" msgstr "AMS Ayarları" @@ -2378,9 +2432,6 @@ msgstr "Dikdörtgen" msgid "Circular" msgstr "Dairesel" -msgid "Custom" -msgstr "Özel" - msgid "Load shape from STL..." msgstr "Şekli STL'den yükle..." @@ -2748,8 +2799,7 @@ msgstr "Yazdırma işi başlatılamadı" msgid "" "This calibration does not support the currently selected nozzle diameter" -msgstr "" -"Bu kalibrasyon, şu anda seçilen nozzle çapını desteklememektedir" +msgstr "Bu kalibrasyon, şu anda seçilen nozzle çapını desteklememektedir" msgid "Current flowrate cali param is invalid" msgstr "Geçerli akış hızı cali parametresi geçersiz" @@ -2886,6 +2936,9 @@ msgstr "Temizlenmiş" msgid "Total" msgstr "Toplam" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Toplam Tahmini" @@ -2973,15 +3026,18 @@ msgstr "Renk değişimi" msgid "Print" msgstr "Yazdır" -msgid "Pause" -msgstr "Duraklat" - msgid "Printer" msgstr "Yazıcı" msgid "Print settings" msgstr "Yazdırma ayarları" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Zaman Tahmini" @@ -3150,7 +3206,7 @@ msgstr "Hacim:" msgid "Size:" msgstr "Boyut:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3212,15 +3268,15 @@ msgstr "Kalibrasyon Akışı" msgid "Start Calibration" msgstr "Kalibrasyonu Başlat" -msgid "No step selected" -msgstr "Adım seçilmedi" - msgid "Completed" msgstr "Tamamlandı" msgid "Calibrating" msgstr "Kalibre ediliyor" +msgid "No step selected" +msgstr "Adım seçilmedi" + msgid "Auto-record Monitoring" msgstr "Otomatik Kayıt İzleme" @@ -3436,8 +3492,11 @@ msgstr "Yapılandırmaları yükle" msgid "Import" msgstr "İçe aktar" -msgid "Export all objects as STL" -msgstr "Tüm nesneleri STL olarak dışa aktar" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Genel 3MF olarak dışa aktar" @@ -3718,9 +3777,6 @@ msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "" "Yazıcı indirme işlemiyle meşgul. Lütfen indirme işleminin bitmesini bekleyin." -msgid "Loading..." -msgstr "Yükleniyor..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "Başlatma başarısız oldu (Geçerli yazıcı sürümünde desteklenmiyor)!" @@ -3783,6 +3839,9 @@ msgstr "Oynatılıyor..." msgid "Load failed [%d]!" msgstr "Yükleme başarısız [%d]!" +msgid "Loading..." +msgstr "Yükleniyor..." + msgid "Year" msgstr "Yıl" @@ -3904,12 +3963,25 @@ msgstr "İndirme tamamlandı" msgid "Downloading %d%%..." msgstr "%d%% indiriliyor..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "Geçerli yazıcı sürümünde desteklenmiyor." msgid "Storage unavailable, insert SD card." msgstr "Depolama alanı kullanılamıyor, SD kartı takın." +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Hız:" @@ -4259,6 +4331,12 @@ msgstr "Yeni ağ eklentisi mevcut." msgid "Details" msgstr "Detaylar" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "Viki" + msgid "Undo integration failed." msgstr "Entegrasyon geri alınamadı." @@ -4307,9 +4385,6 @@ msgstr "TAMAMLANDI" msgid "Cancel upload" msgstr "Yüklemeyi iptal et" -msgid "Slice ok." -msgstr "Dilimleme tamam." - msgid "Jump to" msgstr "Git" @@ -4415,6 +4490,9 @@ msgstr "Adım kaybından otomatik kurtarma" msgid "Allow Prompt Sound" msgstr "Uyarı Sesine İzin Ver" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Genel" @@ -4509,6 +4587,9 @@ msgstr "Filament listesini AMS'den senkronize edin" msgid "Set filaments to use" msgstr "Kullanılacak filamentleri ayarla" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4577,9 +4658,9 @@ msgid "" "clogged when printing this filament in a closed enclosure. Please open the " "front door and/or remove the upper glass." msgstr "" -"Mevcut sıcak yatak sıcaklığı oldukça yüksek. Bu filamenti " -"kapalı bir muhafaza içinde bastırırken nozzle tıkanabilir. " -"Lütfen ön kapağı açın ve/veya üst camı çıkarın." +"Mevcut sıcak yatak sıcaklığı oldukça yüksek. Bu filamenti kapalı bir " +"muhafaza içinde bastırırken nozzle tıkanabilir. Lütfen ön kapağı açın ve/" +"veya üst camı çıkarın." msgid "" "The nozzle hardness required by the filament is higher than the default " @@ -4602,7 +4683,9 @@ msgid "Loading file: %s" msgstr "Dosya yükleniyor: %s" msgid "The 3mf is not supported by OrcaSlicer, load geometry data only." -msgstr "OrcaSlicer, 3mf formatını desteklememektedir. Sadece geometri verilerini yükle." +msgstr "" +"OrcaSlicer, 3mf formatını desteklememektedir. Sadece geometri verilerini " +"yükle." msgid "Load 3mf" msgstr "3mf yükle" @@ -4616,26 +4699,29 @@ msgstr "" "verilerini yükleyin." #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" +msgid "This slicer file version %s is newer than %s's version:" msgstr "" -"3mf'nin %s sürümü, %s'in %s sürümünden daha yeni, Aşağıdaki anahtarlar " -"tanınmadan bulundu:" -msgid "You'd better upgrade your software.\n" -msgstr "Yazılımınızı yükseltseniz iyi olur.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Daha yeni 3mf sürümü" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"3mf'nin %s sürümü, %s'in %s sürümünden daha yeni, Yazılımınızı yükseltmenizi " -"öneririz." msgid "Invalid values found in the 3mf:" msgstr "3mf'de geçersiz değerler bulundu:" @@ -4643,11 +4729,27 @@ msgstr "3mf'de geçersiz değerler bulundu:" msgid "Please correct them in the param tabs" msgstr "Lütfen bunları parametre sekmelerinde düzeltin" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "3mf uyumlu değil, yalnızca geometri verilerini yükleyin!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "Uyumsuz 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "Adım dosyasındaki bileşenlerin adı UTF8 formatında değil!" @@ -4720,6 +4822,15 @@ msgstr "Farklı kaydet:" msgid "Export OBJ file:" msgstr "OBJ dosyasını dışa aktar:" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Kesilen nesnenin bir parçası olan nesneyi silin" @@ -4738,15 +4849,15 @@ msgstr "Seçilen nesne bölünemedi." msgid "Another export job is running." msgstr "Başka bir ihracat işi yürütülüyor." -msgid "Replace from:" -msgstr "Değiştirilecek olan:" - msgid "Unable to replace with more than one volume" msgstr "Birden fazla hacimle değiştirme yapılamıyor." msgid "Error during replace" msgstr "Değiştirme sırasında hata" +msgid "Replace from:" +msgstr "Değiştirilecek olan:" + msgid "Select a new file" msgstr "Yeni dosya seç" @@ -5099,7 +5210,9 @@ msgid "Use free camera" msgstr "Serbest kamera kullan" msgid "If enabled, use free camera. If not enabled, use constrained camera." -msgstr "Etkinleştirilirse serbest kamerayı kullanın. Etkin değilse kısıtlı kamerayı kullanın." +msgstr "" +"Etkinleştirilirse serbest kamerayı kullanın. Etkin değilse kısıtlı kamerayı " +"kullanın." msgid "Show splash screen" msgstr "Açılış ekranını göster" @@ -5119,6 +5232,12 @@ msgstr "G kodu penceresini göster" msgid "If enabled, g-code window will be displayed." msgstr "Etkinleştirilirse g kodu penceresi görüntülenecektir." +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Ön ayarlar" @@ -5173,6 +5292,9 @@ msgstr "Maksimum yeni proje sayısı" msgid "Clear my choice on the unsaved projects." msgstr "Kaydedilmemiş projelerdeki seçimimi temizle." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Otomatik yedekleme" @@ -5326,8 +5448,11 @@ msgstr "Filament Ekle/Kaldır" msgid "Add/Remove materials" msgstr "Materyal Ekle/Kaldır" -msgid "Add/Remove printers" -msgstr "Yazıcı Ekle/Kaldır" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "Uyumsuz" @@ -5509,17 +5634,17 @@ msgstr "Bambu Soğuk Plaka" msgid "PLA Plate" msgstr "PLA Plaka" -msgid "Bambu Engineering Plate" -msgstr "Bambu Mühendislik Plakası" +msgid "Bamabu Engineering Plate" +msgstr "Bamabu Mühendislik Plakası" -msgid "Bambu Smooth PEI Plate" -msgstr "Bambu Pürüzsüz PEI Plaka" +msgid "Bamabu Smooth PEI Plate" +msgstr "" msgid "High temperature Plate" msgstr "Yüksek Sıcaklık Plakası" -msgid "Bambu Textured PEI Plate" -msgstr "Bambu Dokulu PEI Plaka" +msgid "Bamabu Textured PEI Plate" +msgstr "" msgid "Send print job to" msgstr "Yazdırma işini şuraya gönder" @@ -5542,9 +5667,6 @@ msgstr "gönderme tamamlandı" msgid "Error code" msgstr "Hata kodu" -msgid "Check the status of current system services" -msgstr "Mevcut sistem hizmetlerinin durumunu kontrol edin" - msgid "Printer local connection failed, please try again." msgstr "Yazıcının yerel bağlantısı başarısız oldu, lütfen tekrar deneyin." @@ -5592,8 +5714,8 @@ msgid "" "Filaments to AMS slots mappings have been established. You can click a " "filament above to change its mapping AMS slot" msgstr "" -"AMS slot eşlemelerine yönelik filament oluşturulmuştur. Eşleme AMS " -"yuvasını değiştirmek için yukarıdaki filamentlerden birine tıklayabilirsiniz" +"AMS slot eşlemelerine yönelik filament oluşturulmuştur. Eşleme AMS yuvasını " +"değiştirmek için yukarıdaki filamentlerden birine tıklayabilirsiniz" msgid "" "Please click each filament above to specify its mapping AMS slot before " @@ -5654,11 +5776,8 @@ msgstr "" "atlamalı videolar oluşturmayacaktır." msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" -"Nesneye göre yazdırıldığında, I3 yapısına sahip makineler zaman atlamalı " -"videolar oluşturmayacaktır." msgid "Errors" msgstr "Hatalar" @@ -5674,10 +5793,6 @@ msgstr "" "G Kodu oluşturulurken seçilen yazıcı türü mevcut seçili yazıcıyla tutarlı " "değil. Dilimleme için aynı yazıcı tipini kullanmanız tavsiye edilir." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s AMS tarafından desteklenmiyor." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5687,12 +5802,35 @@ msgstr "" "filamentler olup olmadığını kontrol edin. Sorun yoksa, yazdırmayı başlatmak " "için \"Onayla\"ya basın." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "" "Hala yazdırma işlemine devam etmek istiyorsanız lütfen onayla düğmesine " "tıklayın." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "Yazıcıya bağlanılıyor. Bağlantı işlemi sırasında iptal edilemiyor." @@ -5881,6 +6019,9 @@ msgstr "" "olmayan modelde kusurlar olabilir. Prime tower'ı etkinleştirmek istiyor " "musunuz?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5922,8 +6063,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "Araç başlığı olmadan timelapse kaydederken, bir \"Timelapse Wipe Tower\" " "eklenmesi önerilir.\n" @@ -6085,9 +6226,9 @@ msgid "" "Value 0 means the filament does not support to print on the Smooth PEI Plate/" "High Temp Plate" msgstr "" -"Düz PEI Plakası/Yüksek Sıcaklık Plakası takılığın da yatak sıcaklığı. " -"0 Değeri, filamentin Düz PEI Plakası/Yüksek Sıcaklık Plakası üzerin de baskı yapmayı " -"desteklemediği anlamına gelir." +"Düz PEI Plakası/Yüksek Sıcaklık Plakası takılığın da yatak sıcaklığı. 0 " +"Değeri, filamentin Düz PEI Plakası/Yüksek Sıcaklık Plakası üzerin de baskı " +"yapmayı desteklemediği anlamına gelir." msgid "Textured PEI Plate" msgstr "Dokulu PEI Plaka" @@ -6192,6 +6333,9 @@ msgstr "Yazıcı başlangıç G-kod" msgid "Machine end G-code" msgstr "Yazıcı bitiş G-kod" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "Katman değişimi öncesi G-kod" @@ -6261,6 +6405,25 @@ msgstr "Firmware Geri Çekme" msgid "Detached" msgstr "Söküldü" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Ön Ayar" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "Aşağıdaki ön ayar da silinecektir." @@ -6270,11 +6433,6 @@ msgstr[1] "Aşağıdaki ön ayarlar da silinecektir." msgid "Are you sure to %1% the selected preset?" msgstr "Seçilen ön ayarı %1% yaptığınızdan emin misiniz?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Ön Ayar" - msgid "All" msgstr "Tümü" @@ -6523,11 +6681,17 @@ msgstr "Sıkıştırma hattı aralığı" msgid "Auto-Calc" msgstr "Otomatik Hesaplama" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Filament değişimi için temizleme hacmi" -msgid "Multiplier" -msgstr "Çarpan" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Her filament çifti için yıkama hacmi (mm³)." @@ -6540,6 +6704,9 @@ msgstr "Öneri: Yıkama Hacmi [%d, %d] aralığında" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "Çarpan [%.2f, %.2f] aralığında olmalıdır." +msgid "Multiplier" +msgstr "Çarpan" + msgid "unloaded" msgstr "boşaltılmış" @@ -6555,6 +6722,12 @@ msgstr "İtibaren" msgid "To" msgstr "İle" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Giriş yap" @@ -6588,6 +6761,9 @@ msgstr "Panodan yapıştır" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "3Dconnexion cihazları ayarları iletişim kutusunu Göster/Gizle" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Klavye kısayolları listesini göster" @@ -6839,12 +7015,15 @@ msgstr "Yeni bir Ağ eklentisi(%s) mevcut, Yüklemek istiyor musunuz?" msgid "New version of Orca Slicer" msgstr "Orca Slicer'nun yeni versiyonu" -msgid "Don't remind me of this version again" -msgstr "Bana bir daha bu versiyonu hatırlatma" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Tamamlandı" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN Bağlantısı Başarısız (Yazdırma dosyası gönderiliyor)" @@ -6869,8 +7048,22 @@ msgstr "Giriş kodu" msgid "Where to find your printer's IP and Access Code?" msgstr "Yazıcınızın IP'sini ve Erişim Kodunu nerede bulabilirsiniz?" -msgid "Error: IP or Access Code are not correct" -msgstr "Hata: IP veya Erişim Kodu doğru değil" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "Test" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Model:" @@ -7232,8 +7425,8 @@ msgid "" "Please select \"By object\" print sequence to print multiple objects in " "spiral vase mode." msgstr "" -"Birden fazla nesneyi spiral vazo modunda yazdırmak için lütfen \"Nesneye göre" -"\" yazdırma sırasını seçin." +"Birden fazla nesneyi spiral vazo modunda yazdırmak için lütfen \"Nesneye " +"göre\" yazdırma sırasını seçin." msgid "" "The spiral vase mode does not work when an object contains more than one " @@ -7342,6 +7535,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "Katman yüksekliği nozül çapını aşamaz" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7420,10 +7618,9 @@ msgid "" "the next layers will be linearly shrunk less, up to the layer indicated by " "this value." msgstr "" -"Fil ayağı telafisinin etkin olacağı katman sayısı. " -"İlk katman, fil ayak telafisi değeri tarafından küçültülecek, ardından " -"sonraki katmanlar daha az lineer olarak küçültülecek, bu değer tarafından " -"belirtilen katmana kadar." +"Fil ayağı telafisinin etkin olacağı katman sayısı. İlk katman, fil ayak " +"telafisi değeri tarafından küçültülecek, ardından sonraki katmanlar daha az " +"lineer olarak küçültülecek, bu değer tarafından belirtilen katmana kadar." msgid "layers" msgstr "katmanlar" @@ -7766,6 +7963,7 @@ msgstr "" msgid "One wall threshold" msgstr "Tek duvar eşiği" +#, fuzzy, c-format, boost-format msgid "" "If a top surface has to be printed and it's partially covered by another " "layer, it won't be considered at a top layer where its width is below this " @@ -7776,14 +7974,14 @@ msgid "" "on the next layer, like letters. Set this setting to 0 to remove these " "artifacts." msgstr "" -"Eğer bir üst yüzey basılacaksa ve kısmen başka bir katman tarafından kaplıysa " -"layer genişliği bu değerin altında olan bir üst katman olarak " -"değerlendirilmeyecek. Yalnızca çevrelerle kaplanması gereken yüzeyde 'bir çevre üstte' " -"tetiklemesine izin vermemek yararlı olabilir. Bu değer mm veya " +"Eğer bir üst yüzey basılacaksa ve kısmen başka bir katman tarafından " +"kaplıysa layer genişliği bu değerin altında olan bir üst katman olarak " +"değerlendirilmeyecek. Yalnızca çevrelerle kaplanması gereken yüzeyde 'bir " +"çevre üstte' tetiklemesine izin vermemek yararlı olabilir. Bu değer mm veya " "a % çevre ekstrüzyon genişliğinin bir yüzdesi olabilir.\n" -"Uyarı: Etkinleştirilirse bir sonraki katmanda harfler gibi bazı ince özelliklerin " -"olması durumunda yapay yapılar oluşturulabilir. Bu yapıları kaldırmak için bu ayarı 0 " -"olarak ayarlayın." +"Uyarı: Etkinleştirilirse bir sonraki katmanda harfler gibi bazı ince " +"özelliklerin olması durumunda yapay yapılar oluşturulabilir. Bu yapıları " +"kaldırmak için bu ayarı 0 olarak ayarlayın." msgid "Only one wall on first layer" msgstr "İlk katmanda yalnızca bir duvar" @@ -7814,11 +8012,29 @@ msgstr "Çıkıntıyı tersine çevir" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" -"Tek katmanlarda ters yönde bir çıkıntının üzerinde bir kısmı bulunan " -"çevreleri ekstrüzyonla çıkarın. Bu değişen desen, dik eğimli çıkıntıları önemli " -"ölçüde iyileştirebilir." msgid "Reverse threshold" msgstr "Ters eşik" @@ -7826,13 +8042,14 @@ msgstr "Ters eşik" msgid "Overhang reversal threshold" msgstr "Çıkıntıyı tersine çevirme eşiği" +#, fuzzy, c-format, boost-format msgid "" "Number of mm the overhang need to be for the reversal to be considered " "useful. Can be a % of the perimeter width.\n" "Value 0 enables reversal on every odd layers regardless." msgstr "" -"Ters çevirmenin faydalı sayılması için çıkıntının mm sayısı " -"olması gerekir. Çevre genişliğinin %'si olabilir.\n" +"Ters çevirmenin faydalı sayılması için çıkıntının mm sayısı olması gerekir. " +"Çevre genişliğinin %'si olabilir.\n" "Değer 0 her tek katmanda terslemeyi etkinleştirir." msgid "Classic mode" @@ -8005,7 +8222,8 @@ msgid "Activate air filtration" msgstr "Hava filtrelemesini etkinleştirin" msgid "Activate for better air filtration. G-code command: M106 P3 S(0-255)" -msgstr "Daha iyi hava filtrasyonu için etkinleştirin. G-kodu komutu: M106 P3 S(0-255)" +msgstr "" +"Daha iyi hava filtrasyonu için etkinleştirin. G-kodu komutu: M106 P3 S(0-255)" msgid "Fan speed" msgstr "Fan hızı" @@ -8071,6 +8289,14 @@ msgstr "Bitiş G kodu" msgid "End G-code when finish the whole printing" msgstr "Tüm yazdırmayı tamamladığında çalışacak olan G Kodu" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "Bu filament ile baskı bittiğinde çalışacak G kodu" @@ -8165,26 +8391,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "Bu, küçük çevre uzunluğu için eşiği belirler. Varsayılan eşik 0 mm'dir" -msgid "Order of inner wall/outer wall/infil" -msgstr "İç duvar/dış duvar/dolgu sırası" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "İç duvar, dış duvar ve dolgunun yazdırma sırası. " +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "iç/dış/dolgu" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "dış/iç/dolgu" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "dolgu/iç/dış" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "dolgu/dış/iç" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "iç-dış-iç/dolgu" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Çubuğa kadar olan yükseklik" @@ -8287,9 +8513,6 @@ msgstr "Varsayılan renk" msgid "Default filament color" msgstr "Varsayılan filament rengi" -msgid "Color" -msgstr "Renk" - msgid "Filament notes" msgstr "Filament Notları" @@ -8533,9 +8756,9 @@ msgid "" "equal to or greater than it, it's highly recommended to open the front door " "and/or remove the upper glass to avoid cloggings." msgstr "" -"Filament bu sıcaklıkta yumuşar, bu nedenle yatak sıcaklığı bununla " -"eşit veya daha yüksekse, tıkanmaları önlemek için ön kapağı açmanız " -"ve/veya üst camı çıkarmanız şiddetle önerilir." +"Filament bu sıcaklıkta yumuşar, bu nedenle yatak sıcaklığı bununla eşit veya " +"daha yüksekse, tıkanmaları önlemek için ön kapağı açmanız ve/veya üst camı " +"çıkarmanız şiddetle önerilir." msgid "Price" msgstr "Fiyat" @@ -8731,10 +8954,6 @@ msgid "" msgstr "" "Klipper'ın max_accel_to_decel değeri ivmenin bu %%'sine göre ayarlanacak" -#, c-format, boost-format -msgid "%%" -msgstr "%%" - msgid "Jerk of outer walls" msgstr "Dış duvar JERK değeri" @@ -8806,16 +9025,17 @@ msgstr "Maksimum fan hızı" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" "Fan hızı, \"close_fan_the_first_x_layers\" katmanında sıfırdan " "\"ful_fan_speed_layer\" katmanında maksimuma doğrusal olarak artırılacaktır. " "\"full_fan_speed_layer\", \"close_fan_the_first_x_layers\" değerinden " -"düşükse göz ardı edilecektir; bu durumda fan, \"close_fan_the_first_x_layers" -"\" + 1 katmanında izin verilen maksimum hızda çalışacaktır." +"düşükse göz ardı edilecektir; bu durumda fan, " +"\"close_fan_the_first_x_layers\" + 1 katmanında izin verilen maksimum hızda " +"çalışacaktır." msgid "Support interface fan speed" msgstr "Destekler için fan hızı" @@ -9037,7 +9257,8 @@ msgid "" "This option is enabled if machine support controlling chamber temperature\n" "G-code command: M141 S(0-255)" msgstr "" -"Bu seçenek, hazne sıcaklığını kontrol eden makine desteği varsa etkinleştirilir\n" +"Bu seçenek, hazne sıcaklığını kontrol eden makine desteği varsa " +"etkinleştirilir\n" "G-code komut: M141 S(0-255)" msgid "Support air filtration" @@ -9138,6 +9359,18 @@ msgstr "" "saydam malzemelerle veya elle çözülebilen destek malzemesiyle çoklu " "ekstruder baskıları için kullanışlıdır" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Ütüleme Tipi" @@ -9193,8 +9426,8 @@ msgid "Ironing angle" msgstr "Ütüleme açısı" msgid "" -"Ütüleme işleminin gerçekleştiği açı. Negatif bir sayı, bu işlevi devre dışı bırakır ve " -"varsayılan yöntemi kullanır." +"The angle ironing is done at. A negative number disables this function and " +"uses the default method." msgstr "" msgid "This gcode part is inserted at every layer change after lift z" @@ -9441,8 +9674,8 @@ msgstr "" "Yardımcı parça soğutma fanının hızı. Yardımcı fan, soğutma katmanlarının " "bulunmadığı ilk birkaç katman dışında, yazdırma sırasında bu hızda " "çalışacaktır.\n" -"Lütfen bu özelliği kullanmak için yazıcı ayarlarında yardımcı_fan'ı etkinleştirin. G-code " -"komut: M106 P2 S(0-255)" +"Lütfen bu özelliği kullanmak için yazıcı ayarlarında yardımcı_fan'ı " +"etkinleştirin. G-code komut: M106 P2 S(0-255)" msgid "Min" msgstr "Min" @@ -9464,8 +9697,8 @@ msgid "" "specified explicitly." msgstr "" "Daha iyi katman soğutması için yavaşlama etkinleştirildiğinde, yazdırma " -"çıkıntıları olduğunda ve özellik hızları açıkça belirtilmediğinde " -"filament için minimum yazdırma hızı." +"çıkıntıları olduğunda ve özellik hızları açıkça belirtilmediğinde filament " +"için minimum yazdırma hızı." msgid "Nozzle diameter" msgstr "Nozul çapı" @@ -9749,11 +9982,32 @@ msgstr "" "çarpmasını önler. Z'yi kaldırmak için spiral çizgi kullanmak çekmeyi " "önleyebilir" -msgid "Z hop type" -msgstr "Z sıçraması türü" +msgid "Z hop lower boundary" +msgstr "Z sıçrama alt sınırı" -msgid "Slope" -msgstr "Eğim" +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" +"Z sıçraması yalnızca Z bu değerin üzerinde ve parametrenin altında olduğunda " +"devreye girer: \"Z sıçraması üst sınırı\"" + +msgid "Z hop upper boundary" +msgstr "Z sıçrama üst sınırı" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" +"Bu değer pozitifse, Z sıçraması yalnızca Z parametresinin üzerinde olduğunda " +"etkinleşir: \"Z sıçrama alt sınırı\" parametresinin üzerinde ve bu değerin " +"altında olduğunda" + +msgid "Z hop type" +msgstr "Z sıçraması türü" + +msgid "Slope" +msgstr "Eğim" msgid "Spiral" msgstr "Sarmal" @@ -10042,11 +10296,11 @@ msgid "" "printing, where we use M600/PAUSE to trigger the manual filament change " "action." msgstr "" -"Sadece baskının başında özel Filament Değiştirme G-kodu'nu atlamak için " -"bu seçeneği etkinleştirin. Aracı değiştirme komutu (örneğin, T0), baskının " +"Sadece baskının başında özel Filament Değiştirme G-kodu'nu atlamak için bu " +"seçeneği etkinleştirin. Aracı değiştirme komutu (örneğin, T0), baskının " "tamamı boyunca atlanacaktır. Bu, manuel çoklu malzeme baskısı için " -"kullanışlıdır, burada manuel filament değişim eylemini tetiklemek için M600/PAUSE " -"kullanırız." +"kullanışlıdır, burada manuel filament değişim eylemini tetiklemek için M600/" +"PAUSE kullanırız." msgid "Purge in prime tower" msgstr "Prime Tower'da temizlik" @@ -10121,10 +10375,11 @@ msgid "" "example, if your endstop zero actually leaves the nozzle 0.3mm far from the " "print bed, set this to -0.3 (or fix your endstop)." msgstr "" -"Bu değer, çıkış G-kodu içindeki tüm Z koordinatlarına eklenir (veya çıkarılır)." -"Bu, kötü Z endstop konumunu telafi etmek için kullanılır: örneğin, endstop " -"sıfır noktanız aslında nozulu baskı tablasından 0.3mm uzakta bırakıyorsa, " -"bu değeri -0.3 olarak ayarlayın (veya endstop'unuzu düzeltin)." +"Bu değer, çıkış G-kodu içindeki tüm Z koordinatlarına eklenir (veya " +"çıkarılır).Bu, kötü Z endstop konumunu telafi etmek için kullanılır: " +"örneğin, endstop sıfır noktanız aslında nozulu baskı tablasından 0.3mm " +"uzakta bırakıyorsa, bu değeri -0.3 olarak ayarlayın (veya endstop'unuzu " +"düzeltin)." msgid "Enable support" msgstr "Desteği etkinleştir" @@ -10210,6 +10465,12 @@ msgstr "" "belirli bir filamentin olmadığı ve mevcut filamentin kullanıldığı anlamına " "gelir" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." @@ -10245,6 +10506,12 @@ msgstr "Üst arayüz katmanlarının sayısı" msgid "Bottom interface layers" msgstr "Alt arayüz katmanları" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Üst arayüz aralığı" @@ -10312,12 +10579,14 @@ msgid "" "overhangs." msgstr "" "Destek stil ve şekli. Normal destek için, destekleri düzenli bir ızgara " -"içine projelendirmek daha stabil destekler oluşturacaktır (varsayılan), " -"aynı zamanda sıkı destek kuleleri malzeme tasarrufu sağlar ve nesne üzerindeki izleri azaltır.\n" -"Ağaç destek için, ince ve organik tarz, dalları daha etkili bir şekilde birleştirir ve " -"büyük düz çıkıntılarda normal destekle benzer bir yapı oluştururken birçok malzeme " -"tasarrufu sağlar (varsayılan organik tarz). Hybrid stil, büyük düz çıkıntıların altında normal " -"destekle benzer bir yapı oluşturacaktır." +"içine projelendirmek daha stabil destekler oluşturacaktır (varsayılan), aynı " +"zamanda sıkı destek kuleleri malzeme tasarrufu sağlar ve nesne üzerindeki " +"izleri azaltır.\n" +"Ağaç destek için, ince ve organik tarz, dalları daha etkili bir şekilde " +"birleştirir ve büyük düz çıkıntılarda normal destekle benzer bir yapı " +"oluştururken birçok malzeme tasarrufu sağlar (varsayılan organik tarz). " +"Hybrid stil, büyük düz çıkıntıların altında normal destekle benzer bir yapı " +"oluşturacaktır." msgid "Snug" msgstr "Snug" @@ -10495,8 +10764,8 @@ msgid "" "added before \"machine_start_gcode\"\n" "G-code commands: M141/M191 S(0-255)" msgstr "" -"Hazne sıcaklığı kontrolü için bu seçeneği etkinleştirin. Önce bir M191 komutu " -"eklenecek \"machine_start_gcode\"\n" +"Hazne sıcaklığı kontrolü için bu seçeneği etkinleştirin. Önce bir M191 " +"komutu eklenecek \"machine_start_gcode\"\n" "G-code komut: M141/M191 S(0-255)" msgid "Chamber temperature" @@ -10953,69 +11222,12 @@ msgstr "çok büyük çizgi genişliği " msgid " not in range " msgstr " aralıkta değil " -msgid "Export 3MF" -msgstr "3MF'yi dışa aktar" - -msgid "Export project as 3MF." -msgstr "Projeyi 3MF olarak dışa aktarın." - -msgid "Export slicing data" -msgstr "Dilimleme verilerini dışa aktar" - -msgid "Export slicing data to a folder." -msgstr "Dilimleme verilerini bir klasöre aktarın." - -msgid "Load slicing data" -msgstr "Dilimleme verilerini yükle" - -msgid "Load cached slicing data from directory" -msgstr "Önbelleğe alınmış dilimleme verilerini dizinden yükle" - -msgid "Export STL" -msgstr "STL'yi dışa aktar" - -msgid "Export the objects as multiple STL." -msgstr "Nesneleri birden çok STL olarak dışa aktarın." - -msgid "Slice" -msgstr "Dilimle" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "Plakaları dilimleyin: 0-tüm plakalar, i-plaka i, diğerleri-geçersiz" - -msgid "Show command help." -msgstr "Komut yardımını göster." - -msgid "UpToDate" -msgstr "Güncel" - -msgid "Update the configs values of 3mf to latest." -msgstr "3mf'nin yapılandırma değerlerini en son sürüme güncelleyin." - -msgid "Load default filaments" -msgstr "Varsayılan filamentleri yükle" - -msgid "Load first filament as default for those not loaded" -msgstr "Yüklenmeyenler için ilk filamenti varsayılan olarak yükleyin" - msgid "Minimum save" msgstr "Minimum tasarruf" msgid "export 3mf with minimum size." msgstr "3mf'yi minimum boyutta dışa aktarın." -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "dilimleme için plaka başına maksimum üçgen sayısı." - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "saniye cinsinden plaka başına maksimum dilimleme süresi." - msgid "No check" msgstr "Kontrol yok" @@ -11024,43 +11236,6 @@ msgstr "" "Gcode yol çakışmaları kontrolü gibi herhangi bir geçerlilik kontrolü " "çalıştırmayın." -msgid "Normative check" -msgstr "Normatif kontrol" - -msgid "Check the normative items." -msgstr "Normatif maddeleri kontrol edin." - -msgid "Output Model Info" -msgstr "Çıktı Model Bilgileri" - -msgid "Output the model's information." -msgstr "Modelin bilgilerini çıktıla." - -msgid "Export Settings" -msgstr "Dışa Aktarma Ayarları" - -msgid "Export settings to a file." -msgstr "Ayarları bir dosyaya aktarın." - -msgid "Send progress to pipe" -msgstr "İlerlemeyi kanala gönder" - -msgid "Send progress to pipe." -msgstr "İlerlemeyi boruya gönder." - -msgid "Arrange Options" -msgstr "Hizalama Seçenekleri" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "" -"Hizalama seçenekleri: 0-devre dışı bırak, 1-etkinleştir, diğer-otomatik" - -msgid "Repetions count" -msgstr "Tekrar sayısı" - -msgid "Repetions count of the whole model" -msgstr "Tüm modelin tekrar sayısı" - msgid "Ensure on bed" msgstr "Baskı yatağında olduğundan emin olun" @@ -11070,12 +11245,6 @@ msgstr "" "Kısmen aşağıda olduğunda nesneyi yatağın üzerine kaldırın. Varsayılan olarak " "devre dışı" -msgid "Convert Unit" -msgstr "Birimi Dönüştür" - -msgid "Convert the units of model" -msgstr "Modelin birimlerini dönüştür" - msgid "Orient Options" msgstr "Yönlendirme Seçenekleri" @@ -11087,49 +11256,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "Z ekseni etrafında derece cinsinden dönüş açısı." -msgid "Rotate around X" -msgstr "X etrafında döndür" - -msgid "Rotation angle around the X axis in degrees." -msgstr "X ekseni etrafında derece cinsinden dönüş açısı." - msgid "Rotate around Y" msgstr "Y etrafında döndür" msgid "Rotation angle around the Y axis in degrees." msgstr "Y ekseni etrafında derece cinsinden dönüş açısı." -msgid "Scale the model by a float factor" -msgstr "Modeli kayan nokta faktörüne göre ölçeklendirin" - -msgid "Load General Settings" -msgstr "Genel Ayarları Yükle" - -msgid "Load process/machine settings from the specified file" -msgstr "Belirtilen dosyadan proses/yazıcıayarlarını yükleyin" - -msgid "Load Filament Settings" -msgstr "Filament Ayarlarını Yükle" - -msgid "Load filament settings from the specified file list" -msgstr "Filament ayarlarını belirtilen dosya listesinden yükleyin" - -msgid "Skip Objects" -msgstr "Nesneleri Atla" - -msgid "Skip some objects in this print" -msgstr "Bu baskıdaki bazı nesneleri atla" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "güncellemeyi kullanırken güncelleme işlemi/yazıcıayarlarını yükle" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" -"güncellemeyi kullanırken belirtilen dosyadan güncel işlem/yazıcıayarlarını " -"yükle" - msgid "Data directory" msgstr "Veri dizini" @@ -11142,22 +11274,6 @@ msgstr "" "veya bir ağ depolama birimindeki yapılandırmaları dahil etmek için " "kullanışlıdır." -msgid "Output directory" -msgstr "Çıkış dizini" - -msgid "Output directory for the exported files." -msgstr "Dışa aktarılan dosyalar için çıkış dizini." - -msgid "Debug level" -msgstr "Hata ayıklama düzeyi" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Hata ayıklama günlüğü düzeyini ayarlar. 0:önemli, 1:hata, 2:uyarı, 3:bilgi, " -"4:hata ayıklama, 5:izleme\n" - msgid "Load custom gcode" msgstr "Özel gcode yükle" @@ -11323,9 +11439,6 @@ msgstr "Kalibre et" msgid "Finish" msgstr "Bitir" -msgid "Wiki" -msgstr "Viki" - msgid "How to use calibration result?" msgstr "Kalibrasyon sonucu nasıl kullanılır?" @@ -11344,6 +11457,12 @@ msgstr "" msgid "Calibration not supported" msgstr "Kalibrasyon desteklenmiyor" +msgid "Error desc" +msgstr "Hata açıklaması" + +msgid "Extra info" +msgstr "Fazladan bilgi" + msgid "Flow Dynamics" msgstr "Akış Dinamiği" @@ -11376,9 +11495,9 @@ msgstr "" msgid "The name cannot be empty." msgstr "Ad boş olamaz." -#, boost-format -msgid "The selected preset: %1% is not found." -msgstr "Seçilen ön ayar: %1% bulunamadı." +#, c-format, boost-format +msgid "The selected preset: %s is not found." +msgstr "" msgid "The name cannot be the same as the system preset name." msgstr "Ad, sistem ön ayarının adıyla aynı olamaz." @@ -11736,12 +11855,6 @@ msgstr "" "- Aynı baskı yatağı sıcaklığını paylaşabilen malzemeler\n" "- Farklı filament markası ve türü(Marka = Bambu, Tür = Basic, Matte)" -msgid "Error desc" -msgstr "Hata açıklaması" - -msgid "Extra info" -msgstr "Fazladan bilgi" - msgid "Pattern" msgstr "Desen" @@ -11832,101 +11945,6 @@ msgstr "" "%1% ana bilgisayar adına çözümlenen birkaç IP adresi var.\n" "Hangisinin kullanılacağını seçin." -msgid "Unable to perform boolean operation on selected parts" -msgstr "Seçilen parçalarda bölme işlemi gerçekleştirilemiyor" - -msgid "Mesh Boolean" -msgstr "Mesh Boolean" - -msgid "Union" -msgstr "Union" - -msgid "Difference" -msgstr "Fark" - -msgid "Intersection" -msgstr "Kesişim" - -msgid "Source Volume" -msgstr "Kaynak Hacmi" - -msgid "Tool Volume" -msgstr "Araç Hacmi" - -msgid "Subtract from" -msgstr "Şundan çıkar" - -msgid "Subtract with" -msgstr "Şununla çıkar" - -msgid "selected" -msgstr "seçili" - -msgid "Part 1" -msgstr "Bölüm 1" - -msgid "Part 2" -msgstr "Bölüm 2" - -msgid "Delete input" -msgstr "Girişi sil" - -msgid "Send G-Code to printer host" -msgstr "G Kodunu yazıcı ana bilgisayarına gönder" - -msgid "Upload to Printer Host with the following filename:" -msgstr "Yazıcıya aşağıdaki dosya adıyla yükleyin:" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "Gerekirse dizin ayırıcısı olarak eğik çizgileri ( / ) kullanın." - -msgid "Upload to storage" -msgstr "Depolama alanına yükle" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "Yüklenen dosya adı \"%s\" ile bitmiyor. Devam etmek istiyor musunuz?" - -msgid "Upload" -msgstr "Yükle" - -msgid "Print host upload queue" -msgstr "Ana yazıcıyükleme kuyruğunu yazdır" - -msgid "ID" -msgstr "İD" - -msgid "Progress" -msgstr "İlerleme" - -msgid "Host" -msgstr "Host" - -msgctxt "OfFile" -msgid "Size" -msgstr "Boyut" - -msgid "Filename" -msgstr "Dosya adı" - -msgid "Cancel selected" -msgstr "Seçileni iptal et" - -msgid "Show error message" -msgstr "Hata mesajını göster" - -msgid "Enqueued" -msgstr "Sıraya alındı" - -msgid "Uploading" -msgstr "Yükleniyor" - -msgid "Cancelling" -msgstr "İptal Ediliyor" - -msgid "Error uploading to print host" -msgstr "Yazdırma ana bilgisayarına yükleme hatası" - msgid "PA Calibration" msgstr "PA Kalibrasyonu" @@ -12067,79 +12085,107 @@ msgstr "Geri çekme uzunluğu bitişi: " msgid "mm/mm" msgstr "mm/mm" -msgid "Physical Printer" -msgstr "Fiziksel Yazıcı" +msgid "Send G-Code to printer host" +msgstr "G Kodunu yazıcı ana bilgisayarına gönder" -msgid "Print Host upload" -msgstr "Yazıcı Bağlantı Ayarları" +msgid "Upload to Printer Host with the following filename:" +msgstr "Yazıcıya aşağıdaki dosya adıyla yükleyin:" -msgid "Test" -msgstr "Test" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "Gerekirse dizin ayırıcısı olarak eğik çizgileri ( / ) kullanın." -msgid "Could not get a valid Printer Host reference" -msgstr "Geçerli bir Yazıcı Ana Bilgisayarı referansı alınamadı" +msgid "Upload to storage" +msgstr "Depolama alanına yükle" -msgid "Success!" -msgstr "Başarılı!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "Yüklenen dosya adı \"%s\" ile bitmiyor. Devam etmek istiyor musunuz?" -msgid "Refresh Printers" -msgstr "Yazıcıları Yenile" +msgid "Upload" +msgstr "Yükle" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." -msgstr "" -"HTTPS CA dosyası isteğe bağlıdır. Yalnızca HTTPS'yi kendinden imzalı bir " -"sertifikayla kullanıyorsanız gereklidir." +msgid "Print host upload queue" +msgstr "Ana yazıcıyükleme kuyruğunu yazdır" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "Sertifika dosyaları (*.crt, *.pem)|*.crt;*.pem|Tüm dosyalar|*.*" +msgid "ID" +msgstr "İD" -msgid "Open CA certificate file" -msgstr "CA sertifika dosyasını aç" +msgid "Progress" +msgstr "İlerleme" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." -msgstr "" -"Bu sistemde %s, sistem Sertifika Deposu veya Anahtar Zincirinden alınan " -"HTTPS sertifikalarını kullanıyor." +msgid "Host" +msgstr "Host" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." -msgstr "" -"Özel bir CA dosyası kullanmak için lütfen CA dosyanızı Sertifika Deposuna/" -"Anahtarlığa aktarın." +msgctxt "OfFile" +msgid "Size" +msgstr "Boyut" -msgid "Connection to printers connected via the print host failed." -msgstr "" -"Yazdırma ana bilgisayarı aracılığıyla bağlanan yazıcılara bağlantı başarısız " -"oldu." +msgid "Filename" +msgstr "Dosya adı" -msgid "The start, end or step is not valid value." -msgstr "Başlangıç, bitiş veya adım geçerli bir değer değildir." +msgid "Cancel selected" +msgstr "Seçileni iptal et" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" -msgstr "" -"Kalibre edilemiyor: ayarlanan kalibrasyon değeri aralığı çok büyük veya adım " -"çok küçük olduğu için olabilir" +msgid "Show error message" +msgstr "Hata mesajını göster" + +msgid "Enqueued" +msgstr "Sıraya alındı" + +msgid "Uploading" +msgstr "Yükleniyor" + +msgid "Cancelling" +msgstr "İptal Ediliyor" -msgid "Need select printer" -msgstr "Yazıcı seçmeniz gerekiyor" +msgid "Error uploading to print host" +msgstr "Yazdırma ana bilgisayarına yükleme hatası" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "Seçilen parçalarda bölme işlemi gerçekleştirilemiyor" + +msgid "Mesh Boolean" +msgstr "Mesh Boolean" + +msgid "Union" +msgstr "Union" + +msgid "Difference" +msgstr "Fark" + +msgid "Intersection" +msgstr "Kesişim" + +msgid "Source Volume" +msgstr "Kaynak Hacmi" + +msgid "Tool Volume" +msgstr "Araç Hacmi" + +msgid "Subtract from" +msgstr "Şundan çıkar" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "Subtract with" +msgstr "Şununla çıkar" + +msgid "selected" +msgstr "seçili" + +msgid "Part 1" +msgstr "Bölüm 1" + +msgid "Part 2" +msgstr "Bölüm 2" + +msgid "Delete input" +msgstr "Girişi sil" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3D Sahne İşlemleri\n" -"3D sahnede fare ve dokunmatik panel ile görünümü ve nesne/parça seçimini " -"nasıl kontrol edeceğinizi biliyor muydunuz?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -12155,11 +12201,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Modeli Düzelt\n" -"Pek çok dilimleme sorununu önlemek için bozuk bir 3D modeli " -"düzeltebileceğinizi biliyor muydunuz?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -12210,6 +12253,13 @@ msgstr "" "Tüm nesneleri/parçaları bir listede görüntüleyebileceğinizi ve her nesne/" "parça için ayarları değiştirebileceğinizi biliyor muydunuz?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -12404,11 +12454,367 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." msgstr "" +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." +msgstr "" + +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Üst Karakter + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Yüzüstü Yatırma" + +#~ msgid "Export as STL" +#~ msgstr "STL olarak dışa aktar" + +#~ msgid "Check cloud service status" +#~ msgstr "Bulut hizmeti durumunu kontrol edin" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Lütfen geçerli bir değer girin (0~0,5'te K)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "Lütfen geçerli bir değer girin (0~0,5'te K, 0,6~2,0'da N)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Tüm nesneleri STL olarak dışa aktar" + +#~ msgid "Slice ok." +#~ msgstr "Dilimleme tamam." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "" +#~ "3mf'nin %s sürümü, %s'in %s sürümünden daha yeni, Aşağıdaki anahtarlar " +#~ "tanınmadan bulundu:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Yazılımınızı yükseltseniz iyi olur.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "3mf'nin %s sürümü, %s'in %s sürümünden daha yeni, Yazılımınızı " +#~ "yükseltmenizi öneririz." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "3mf uyumlu değil, yalnızca geometri verilerini yükleyin!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Uyumsuz 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "Yazıcı Ekle/Kaldır" + +#~ msgid "Bambu Engineering Plate" +#~ msgstr "Bambu Mühendislik Plakası" + +#~ msgid "Bambu Smooth PEI Plate" +#~ msgstr "Bambu Pürüzsüz PEI Plaka" + +#~ msgid "Bambu Textured PEI Plate" +#~ msgstr "Bambu Dokulu PEI Plaka" + +#~ msgid "" +#~ "When print by object, machines with I3 structure will not generate " +#~ "timelapse videos." +#~ msgstr "" +#~ "Nesneye göre yazdırıldığında, I3 yapısına sahip makineler zaman atlamalı " +#~ "videolar oluşturmayacaktır." + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s AMS tarafından desteklenmiyor." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Bana bir daha bu versiyonu hatırlatma" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Hata: IP veya Erişim Kodu doğru değil" + +#~ msgid "" +#~ "Extrude perimeters that have a part over an overhang in the reverse " +#~ "direction on odd layers. This alternating pattern can drastically improve " +#~ "steep overhang." +#~ msgstr "" +#~ "Tek katmanlarda ters yönde bir çıkıntının üzerinde bir kısmı bulunan " +#~ "çevreleri ekstrüzyonla çıkarın. Bu değişen desen, dik eğimli çıkıntıları " +#~ "önemli ölçüde iyileştirebilir." + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "İç duvar/dış duvar/dolgu sırası" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "İç duvar, dış duvar ve dolgunun yazdırma sırası. " + +#~ msgid "inner/outer/infill" +#~ msgstr "iç/dış/dolgu" + +#~ msgid "outer/inner/infill" +#~ msgstr "dış/iç/dolgu" + +#~ msgid "infill/inner/outer" +#~ msgstr "dolgu/iç/dış" + +#~ msgid "infill/outer/inner" +#~ msgstr "dolgu/dış/iç" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "iç-dış-iç/dolgu" + +#, c-format, boost-format +#~ msgid "%%" +#~ msgstr "%%" + +#~ msgid "Export 3MF" +#~ msgstr "3MF'yi dışa aktar" + +#~ msgid "Export project as 3MF." +#~ msgstr "Projeyi 3MF olarak dışa aktarın." + +#~ msgid "Export slicing data" +#~ msgstr "Dilimleme verilerini dışa aktar" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Dilimleme verilerini bir klasöre aktarın." + +#~ msgid "Load slicing data" +#~ msgstr "Dilimleme verilerini yükle" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Önbelleğe alınmış dilimleme verilerini dizinden yükle" + +#~ msgid "Export STL" +#~ msgstr "STL'yi dışa aktar" + +#~ msgid "Export the objects as multiple STL." +#~ msgstr "Nesneleri birden çok STL olarak dışa aktarın." + +#~ msgid "Slice" +#~ msgstr "Dilimle" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "Plakaları dilimleyin: 0-tüm plakalar, i-plaka i, diğerleri-geçersiz" + +#~ msgid "Show command help." +#~ msgstr "Komut yardımını göster." + +#~ msgid "UpToDate" +#~ msgstr "Güncel" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "3mf'nin yapılandırma değerlerini en son sürüme güncelleyin." + +#~ msgid "Load default filaments" +#~ msgstr "Varsayılan filamentleri yükle" + +#~ msgid "Load first filament as default for those not loaded" +#~ msgstr "Yüklenmeyenler için ilk filamenti varsayılan olarak yükleyin" + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "dilimleme için plaka başına maksimum üçgen sayısı." + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "saniye cinsinden plaka başına maksimum dilimleme süresi." + +#~ msgid "Normative check" +#~ msgstr "Normatif kontrol" + +#~ msgid "Check the normative items." +#~ msgstr "Normatif maddeleri kontrol edin." + +#~ msgid "Output Model Info" +#~ msgstr "Çıktı Model Bilgileri" + +#~ msgid "Output the model's information." +#~ msgstr "Modelin bilgilerini çıktıla." + +#~ msgid "Export Settings" +#~ msgstr "Dışa Aktarma Ayarları" + +#~ msgid "Export settings to a file." +#~ msgstr "Ayarları bir dosyaya aktarın." + +#~ msgid "Send progress to pipe" +#~ msgstr "İlerlemeyi kanala gönder" + +#~ msgid "Send progress to pipe." +#~ msgstr "İlerlemeyi boruya gönder." + +#~ msgid "Arrange Options" +#~ msgstr "Hizalama Seçenekleri" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "" +#~ "Hizalama seçenekleri: 0-devre dışı bırak, 1-etkinleştir, diğer-otomatik" + +#~ msgid "Repetions count" +#~ msgstr "Tekrar sayısı" + +#~ msgid "Repetions count of the whole model" +#~ msgstr "Tüm modelin tekrar sayısı" + +#~ msgid "Convert Unit" +#~ msgstr "Birimi Dönüştür" + +#~ msgid "Convert the units of model" +#~ msgstr "Modelin birimlerini dönüştür" + +#~ msgid "Rotate around X" +#~ msgstr "X etrafında döndür" + +#~ msgid "Rotation angle around the X axis in degrees." +#~ msgstr "X ekseni etrafında derece cinsinden dönüş açısı." + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Modeli kayan nokta faktörüne göre ölçeklendirin" + +#~ msgid "Load General Settings" +#~ msgstr "Genel Ayarları Yükle" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Belirtilen dosyadan proses/yazıcıayarlarını yükleyin" + +#~ msgid "Load Filament Settings" +#~ msgstr "Filament Ayarlarını Yükle" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "Filament ayarlarını belirtilen dosya listesinden yükleyin" + +#~ msgid "Skip Objects" +#~ msgstr "Nesneleri Atla" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Bu baskıdaki bazı nesneleri atla" + +#~ msgid "load uptodate process/machine settings when using uptodate" +#~ msgstr "güncellemeyi kullanırken güncelleme işlemi/yazıcıayarlarını yükle" + +#~ msgid "" +#~ "load uptodate process/machine settings from the specified file when using " +#~ "uptodate" +#~ msgstr "" +#~ "güncellemeyi kullanırken belirtilen dosyadan güncel işlem/" +#~ "yazıcıayarlarını yükle" + +#~ msgid "Output directory" +#~ msgstr "Çıkış dizini" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Dışa aktarılan dosyalar için çıkış dizini." + +#~ msgid "Debug level" +#~ msgstr "Hata ayıklama düzeyi" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Hata ayıklama günlüğü düzeyini ayarlar. 0:önemli, 1:hata, 2:uyarı, 3:" +#~ "bilgi, 4:hata ayıklama, 5:izleme\n" + +#, boost-format +#~ msgid "The selected preset: %1% is not found." +#~ msgstr "Seçilen ön ayar: %1% bulunamadı." + +#~ msgid "Physical Printer" +#~ msgstr "Fiziksel Yazıcı" + +#~ msgid "Print Host upload" +#~ msgstr "Yazıcı Bağlantı Ayarları" + +#~ msgid "Could not get a valid Printer Host reference" +#~ msgstr "Geçerli bir Yazıcı Ana Bilgisayarı referansı alınamadı" + +#~ msgid "Success!" +#~ msgstr "Başarılı!" + +#~ msgid "Refresh Printers" +#~ msgstr "Yazıcıları Yenile" + +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "HTTPS CA dosyası isteğe bağlıdır. Yalnızca HTTPS'yi kendinden imzalı bir " +#~ "sertifikayla kullanıyorsanız gereklidir." + +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "Sertifika dosyaları (*.crt, *.pem)|*.crt;*.pem|Tüm dosyalar|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "CA sertifika dosyasını aç" + +#, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "" +#~ "Bu sistemde %s, sistem Sertifika Deposu veya Anahtar Zincirinden alınan " +#~ "HTTPS sertifikalarını kullanıyor." + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "Özel bir CA dosyası kullanmak için lütfen CA dosyanızı Sertifika Deposuna/" +#~ "Anahtarlığa aktarın." + +#~ msgid "Connection to printers connected via the print host failed." +#~ msgstr "" +#~ "Yazdırma ana bilgisayarı aracılığıyla bağlanan yazıcılara bağlantı " +#~ "başarısız oldu." + +#~ msgid "The start, end or step is not valid value." +#~ msgstr "Başlangıç, bitiş veya adım geçerli bir değer değildir." + +#~ msgid "" +#~ "Unable to calibrate: maybe because the set calibration value range is too " +#~ "large, or the step is too small" +#~ msgstr "" +#~ "Kalibre edilemiyor: ayarlanan kalibrasyon değeri aralığı çok büyük veya " +#~ "adım çok küçük olduğu için olabilir" + +#~ msgid "Need select printer" +#~ msgstr "Yazıcı seçmeniz gerekiyor" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3D Sahne İşlemleri\n" +#~ "3D sahnede fare ve dokunmatik panel ile görünümü ve nesne/parça seçimini " +#~ "nasıl kontrol edeceğinizi biliyor muydunuz?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Modeli Düzelt\n" +#~ "Pek çok dilimleme sorununu önlemek için bozuk bir 3D modeli " +#~ "düzeltebileceğinizi biliyor muydunuz?" + #~ msgid "Embeded" #~ msgstr "Gömülü" @@ -12425,27 +12831,6 @@ msgstr "" #~ msgid "Show online staff-picked models on the home page" #~ msgstr "Personelin çevrimiçi olarak seçtiği modelleri ana sayfada göster" -#~ msgid "Z hop lower boundary" -#~ msgstr "Z sıçrama alt sınırı" - -#~ msgid "" -#~ "Z hop will only come into effect when Z is above this value and is below " -#~ "the parameter: \"Z hop upper boundary\"" -#~ msgstr "" -#~ "Z sıçraması yalnızca Z bu değerin üzerinde ve parametrenin altında " -#~ "olduğunda devreye girer: \"Z sıçraması üst sınırı\"" - -#~ msgid "Z hop upper boundary" -#~ msgstr "Z sıçrama üst sınırı" - -#~ msgid "" -#~ "If this value is positive, Z hop will only come into effect when Z is " -#~ "above the parameter: \"Z hop lower boundary\" and is below this value" -#~ msgstr "" -#~ "Bu değer pozitifse, Z sıçraması yalnızca Z parametresinin üzerinde " -#~ "olduğunda etkinleşir: \"Z sıçrama alt sınırı\" parametresinin üzerinde ve " -#~ "bu değerin altında olduğunda" - #~ msgid "The minimum printing speed when slow down for cooling" #~ msgstr "Soğutma için yavaşlama durumunda minimum yazdırma hızı" @@ -12526,9 +12911,6 @@ msgstr "" #~ msgid "The 3mf is not from Bambu Lab, load geometry data only." #~ msgstr "3mf, Bambu Lab'den değildir, yalnızca geometri verilerini yükleyin." -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Bamabu Mühendislik Plakası" - #~ msgid "High Temp Plate" #~ msgstr "Tabla" diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index a72fb2dfe6b..2a502898f2a 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: 2023-08-10 20:25-0400\n" "Last-Translator: \n" "Language-Team: \n" @@ -15,8 +15,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" "X-Generator: Poedit 3.3.2\n" msgid "Supports Painting" @@ -107,6 +107,9 @@ msgstr "Немає автоматичної підтримки" msgid "Support Generated" msgstr "Генерація підтримки" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "Покласти в обличчя" @@ -154,8 +157,8 @@ msgstr "Заливка відра" msgid "Height range" msgstr "Діапазон висот" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "Переключення каркасу" @@ -185,9 +188,15 @@ msgstr "Забарвлений за допомогою: Філамент %1%" msgid "Move" msgstr "Перемістити" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "Повернути" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "Оптимізувати орієнтацію" @@ -197,12 +206,12 @@ msgstr "Готово" msgid "Scale" msgstr "Масштаб" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "Помилка: будь ласка, спочатку закрийте все меню панелі інструментів" -msgid "Tool-Lay on Face" -msgstr "Інструмент-укладання на обличчя" - msgid "in" msgstr "in" @@ -495,6 +504,15 @@ msgstr "Малювання шва" msgid "Remove selection" msgstr "Видалити виділення" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "Шрифт" @@ -700,6 +718,14 @@ msgstr "" msgid "Privacy Policy Update" msgstr "Оновлення політики конфіденційності" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "Завантаження" @@ -893,8 +919,11 @@ msgstr "Доступно для друку" msgid "Fix model" msgstr "Виправити модель" -msgid "Export as STL" -msgstr "Експортувати як STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "Перезавантажити з диска" @@ -1154,6 +1183,9 @@ msgstr "Клацніть значок, щоб відредагувати кол msgid "Click the icon to shift this object to the bed" msgstr "Клацніть значок, щоб перемістити цей об'єкт на столі" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "Завантаження файлу" @@ -1418,6 +1450,18 @@ msgstr "Відкрийте наступну пораду." msgid "Open Documentation in web browser." msgstr "Відкрийте документацію у веб-браузері." +msgid "Color" +msgstr "Колір" + +msgid "Pause" +msgstr "Пауза" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "Стандартний" + msgid "Pause:" msgstr "Пауза:" @@ -1493,7 +1537,7 @@ msgstr "..." msgid "Failed to connect to the server" msgstr "Не вдалося підключитися до сервера" -msgid "Check cloud service status" +msgid "Check the status of current system services" msgstr "" msgid "code" @@ -1753,6 +1797,14 @@ msgstr "Надсилання завдання на друк локальною msgid "Sending print job through cloud service" msgstr "Надсилання завдання на друк через хмарний сервіс" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "Сервіс недоступний" @@ -1983,12 +2035,11 @@ msgstr "Ви впевнені, що хочете видалити інформа msgid "You need to select the material type and color first." msgstr "Спочатку потрібно вибрати тип матеріалу та колір." -msgid "Please input a valid value (K in 0~0.5)" -msgstr "Введіть допустиме значення (K в діапазоні 0~0,5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" msgstr "" -"Введіть допустиме значення (K у діапазоні 0~0,5, N у діапазоні 0,6~2,0)" msgid "Other Color" msgstr "Інший колір" @@ -2380,9 +2431,6 @@ msgstr "Прямокутний" msgid "Circular" msgstr "Округлий" -msgid "Custom" -msgstr "Стандартний" - msgid "Load shape from STL..." msgstr "Завантажити форму з STL..." @@ -2873,6 +2921,9 @@ msgstr "Очищення" msgid "Total" msgstr "Загальний" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "Загальна оцінка" @@ -2960,15 +3011,18 @@ msgstr "Зміна кольору" msgid "Print" msgstr "Друк" -msgid "Pause" -msgstr "Пауза" - msgid "Printer" msgstr "Принтер" msgid "Print settings" msgstr "Параметри друку" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "Оцінка часу" @@ -3137,7 +3191,7 @@ msgstr "Об'єм:" msgid "Size:" msgstr "Розмір:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3199,15 +3253,15 @@ msgstr "Калібрувальний потік" msgid "Start Calibration" msgstr "Почати калібрування" -msgid "No step selected" -msgstr "" - msgid "Completed" msgstr "Завершений" msgid "Calibrating" msgstr "Калібрування" +msgid "No step selected" +msgstr "" + msgid "Auto-record Monitoring" msgstr "Автозапис Моніторингу" @@ -3422,8 +3476,11 @@ msgstr "Завантажити конфігурацію" msgid "Import" msgstr "Імпорт" -msgid "Export all objects as STL" -msgstr "Експортувати всі об'єкти у форматі STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "Експорт спільного 3MF" @@ -3711,9 +3768,6 @@ msgstr "Помилка ініціалізації (немає камери)!" msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "Принтер зайнятий завантаженням. Дочекайтеся завершення завантаження." -msgid "Loading..." -msgstr "Завантаження..." - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "" @@ -3777,6 +3831,9 @@ msgstr "Гра..." msgid "Load failed [%d]!" msgstr "Завантаження не вдалося [%d]!" +msgid "Loading..." +msgstr "Завантаження..." + msgid "Year" msgstr "Рік" @@ -3895,12 +3952,25 @@ msgstr "Завантаження завершено" msgid "Downloading %d%%..." msgstr "Завантаження %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "" msgid "Storage unavailable, insert SD card." msgstr "" +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "Швидкість:" @@ -4233,6 +4303,12 @@ msgstr "Доступний новий мережевий плагін." msgid "Details" msgstr "Подробиці" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "" + msgid "Undo integration failed." msgstr "Скасувати інтеграцію не вдалося." @@ -4284,9 +4360,6 @@ msgstr "ВИКОНАНО" msgid "Cancel upload" msgstr "Скасувати завантаження" -msgid "Slice ok." -msgstr "Нарізка прибл." - msgid "Jump to" msgstr "Перейти до" @@ -4391,6 +4464,9 @@ msgstr "Автоматичне відновлення після втрати к msgid "Allow Prompt Sound" msgstr "" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "Глобальний" @@ -4485,6 +4561,9 @@ msgstr "Синхронізувати список ниток з AMS" msgid "Set filaments to use" msgstr "Встановіть нитки для використання" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "" @@ -4587,24 +4666,29 @@ msgstr "" "3mf генерується старим слайсером Orca, завантажувати лише дані геометрії." #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" -msgstr "Версія 3mf %s новіша, ніж версія %s %s, знайдено наступні ключі:" +msgid "This slicer file version %s is newer than %s's version:" +msgstr "" -msgid "You'd better upgrade your software.\n" -msgstr "Вам краще оновити програмне забезпечення.\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "Нова версія 3mf" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" msgstr "" -"Версія 3mf %s новіша, ніж версія %s %s, запропонуйте оновити програмне " -"забезпечення." msgid "Invalid values found in the 3mf:" msgstr "У 3mf знайдено неприпустимі значення:" @@ -4612,11 +4696,27 @@ msgstr "У 3mf знайдено неприпустимі значення:" msgid "Please correct them in the param tabs" msgstr "Будь ласка, виправте їх у вкладках параметрів" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "3mf не сумісний, завантажуйте лише дані геометрії!" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "Несумісний 3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "Ім'я компонентів всередині крокового файлу не у форматі UTF8!" @@ -4690,6 +4790,15 @@ msgstr "Зберегти файл як:" msgid "Export OBJ file:" msgstr "" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "Видалити об'єкт, який є частиною обрізаного об'єкта" @@ -4708,15 +4817,15 @@ msgstr "Вибраний об'єкт не може бути поділений." msgid "Another export job is running." msgstr "Виконується інше завдання експорту." -msgid "Replace from:" -msgstr "" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "Помилка заміни" +msgid "Replace from:" +msgstr "" + msgid "Select a new file" msgstr "Виберіть новий файл" @@ -5087,6 +5196,12 @@ msgstr "Показати вікно g-коду" msgid "If enabled, g-code window will be displayed." msgstr "Якщо увімкнено, з'явиться вікно g-коду." +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "Пресети" @@ -5142,6 +5257,9 @@ msgstr "Максимальна кількість останніх проект msgid "Clear my choice on the unsaved projects." msgstr "Очистити мій вибір для незбережених проектів." +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "Автобекап" @@ -5295,8 +5413,11 @@ msgstr "Додати/видалити філаменти" msgid "Add/Remove materials" msgstr "Додати/видалити матеріали" -msgid "Add/Remove printers" -msgstr "Додати/видалити принтери" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "" @@ -5479,16 +5600,16 @@ msgstr "Холодний стіл" msgid "PLA Plate" msgstr "" -msgid "Bambu Engineering Plate" -msgstr "" +msgid "Bamabu Engineering Plate" +msgstr "Інженерний стіл" -msgid "Bambu Smooth PEI Plate" +msgid "Bamabu Smooth PEI Plate" msgstr "" msgid "High temperature Plate" msgstr "" -msgid "Bambu Textured PEI Plate" +msgid "Bamabu Textured PEI Plate" msgstr "" msgid "Send print job to" @@ -5512,9 +5633,6 @@ msgstr "відправлення завершено" msgid "Error code" msgstr "" -msgid "Check the status of current system services" -msgstr "" - msgid "Printer local connection failed, please try again." msgstr "" @@ -5621,8 +5739,7 @@ msgid "" msgstr "" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." +"Timelapse is not supported because Print sequence is set to \"By object\"." msgstr "" msgid "Errors" @@ -5640,10 +5757,6 @@ msgstr "" "Вибраному принтеру. Рекомендується використовувати той самий тип принтера " "для нарізки." -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s не підтримується AMS." - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5653,10 +5766,33 @@ msgstr "" "необхідними нитками. Якщо вони гаразд, натисніть \"Подтвердити\", щоб почати " "друк." +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "Натисніть кнопку підтвердження, якщо ви все ще хочете продовжити друк." +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "" @@ -5825,6 +5961,9 @@ msgstr "" "Для плавного таймлапсу потрібно Prime Tower. Можуть бути недоліки в " "моделіБез головної вежі. Ви хочете включити головну вежу?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5867,8 +6006,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "При записі таймлапсу без інструментальної головки рекомендується додати " "“Timelapse Wipe Tower” \n" @@ -6138,6 +6277,9 @@ msgstr "Стартовий G-code" msgid "Machine end G-code" msgstr "Кінцевий G-code" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "G-code перед зміною шару" @@ -6207,6 +6349,26 @@ msgstr "Firmware Retraction" msgid "Detached" msgstr "Окремий" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% Передустановка" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "Наступне попереднє встановлення також буде видалено." @@ -6217,11 +6379,6 @@ msgstr[2] "Наступні стилі також будуть видалені. msgid "Are you sure to %1% the selected preset?" msgstr "Ви впевнені, що %1% вибраної установки?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% Передустановка" - msgid "All" msgstr "Все" @@ -6462,11 +6619,17 @@ msgstr "" msgid "Auto-Calc" msgstr "Автокалькулятор" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "Обсяги промивання для зміни Філаменту" -msgid "Multiplier" -msgstr "Множина" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "Об'єм промивки (мм³) для кожної пари Філаменту." @@ -6479,6 +6642,9 @@ msgstr "Пропозиція: Об'єм промивання в діапазон msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "Множина повинна знаходитися в діапазоні [%.2f, %.2f]" +msgid "Multiplier" +msgstr "Множина" + msgid "unloaded" msgstr "вивантажено" @@ -6494,6 +6660,12 @@ msgstr "Від" msgid "To" msgstr "В" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "Логін" @@ -6527,6 +6699,9 @@ msgstr "Вставити з буфера обміну" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "Показати/приховати діалог налаштувань пристроїв 3Dconnexion" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "Показати список клавіш" @@ -6776,12 +6951,15 @@ msgstr "Доступний новий мережевий плагін (%s), чи msgid "New version of Orca Slicer" msgstr "" -msgid "Don't remind me of this version again" -msgstr "Не нагадуйте мені більше про цю версію" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "Виконано" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "Помилка з’єднання LAN (Надсилання файлу друку)" @@ -6806,8 +6984,22 @@ msgstr "Код доступу" msgid "Where to find your printer's IP and Access Code?" msgstr "Де знайти IP-адресу та код доступу вашого принтера?" -msgid "Error: IP or Access Code are not correct" -msgstr "Помилка: IP або код доступу не вірні" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "Тест" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "Модель:" @@ -7265,6 +7457,11 @@ msgstr "" msgid "Layer height cannot exceed nozzle diameter" msgstr "Висота шару не може перевищувати діаметр сопла" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7723,7 +7920,28 @@ msgstr "" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" msgid "Reverse threshold" @@ -7961,6 +8179,14 @@ msgstr "Завершальний G-code" msgid "End G-code when finish the whole printing" msgstr "Завершальний G-code, коли закінчити весь друк" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "Завершальний G-code, коли закінчите друк цієї нитки" @@ -8055,28 +8281,26 @@ msgstr "" "При цьому встановлюється поріг для невеликої довжини периметра. Порігове за " "замовчуванням - 0 мм" -msgid "Order of inner wall/outer wall/infil" -msgstr "Порядок внутрішні периметри/зовнішні периметри/заповнення" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " +msgid "Print sequence of inner wall and outer wall. " msgstr "" -"Роздрукуйте послідовність внутрішнього периметра, зовнішнього периметра та " -"заповнення " -msgid "inner/outer/infill" -msgstr "внутрішній/зовнішній/заповнення" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "зовнішній/внутрішній/заповнення" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "заповнення/внутрішній/зовнішній" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "заповнення/зовнішній/внутрішній" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "внутрішній-внутрішній/заповнення" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "Висота до сопла" @@ -8179,9 +8403,6 @@ msgstr "Колір за замовчуванням" msgid "Default filament color" msgstr "Колір філаменту за замовчуванням" -msgid "Color" -msgstr "Колір" - msgid "Filament notes" msgstr "" @@ -8598,10 +8819,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "Ривок зовнішніх периметрів" @@ -8672,10 +8889,10 @@ msgstr "Повна швидкість вентилятора на шарі" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" "Швидкість вентилятора лінійно збільшується від нуля на " "рівні«close_fan_the_first_x_layers» до максимуму на рівні " @@ -8998,6 +9215,18 @@ msgstr "" "Використовується для друку в кількох екструдерах з напівпрозоримиматеріалами " "або розчинним у ручному режимі матеріалом підкладки" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "Тип Розглажування" @@ -9539,6 +9768,22 @@ msgstr "" "переміщення. Використання спіралевої лінії підняття по осі Z може " "перешкоджати появі висячих ниток" +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "Тип Z-стрибка" @@ -9982,7 +10227,13 @@ msgstr "" "відсутність конкретного філаменту для опори та використання поточного " "філаменту" -msgid "" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." msgstr "" @@ -10015,6 +10266,12 @@ msgstr "Кількість верхніх шарів підтримки" msgid "Bottom interface layers" msgstr "Нижні шари підтримки" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "Відстань між верхніми інтерфейсами" @@ -10663,69 +10920,12 @@ msgstr "надто велика ширина лінії " msgid " not in range " msgstr " не в зоні " -msgid "Export 3MF" -msgstr "Експорт 3MF" - -msgid "Export project as 3MF." -msgstr "Експортуйте проект як 3MF." - -msgid "Export slicing data" -msgstr "Експорт даних нарізки" - -msgid "Export slicing data to a folder." -msgstr "Експорт даних нарізки до папки." - -msgid "Load slicing data" -msgstr "Завантажити дані про нарізку" - -msgid "Load cached slicing data from directory" -msgstr "Завантажити кешовані дані нарізки з каталогу" - -msgid "Export STL" -msgstr "" - -msgid "Export the objects as multiple STL." -msgstr "" - -msgid "Slice" -msgstr "Нарізка" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "Нарізати пластини: 0-всі пластини, i-пластина i, інші-неприпустимі" - -msgid "Show command help." -msgstr "Показати довідку про команду." - -msgid "UpToDate" -msgstr "До цього часу" - -msgid "Update the configs values of 3mf to latest." -msgstr "Оновіть значення конфігурації 3mf до останніх." - -msgid "Load default filaments" -msgstr "" - -msgid "Load first filament as default for those not loaded" -msgstr "" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "" -msgid "mtcpp" -msgstr "mtcpp" - -msgid "max triangle count per plate for slicing." -msgstr "максимальна кількість трикутників на стіл для нарізки." - -msgid "mstpp" -msgstr "mstpp" - -msgid "max slicing time per plate in seconds." -msgstr "максимальний час нарізки на стіл у секундах." - msgid "No check" msgstr "Без перевірки" @@ -10733,42 +10933,6 @@ msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "" "Не виконуйте перевірки дійсності, наприклад, перевірку конфліктів шляхуgcode." -msgid "Normative check" -msgstr "Нормативна перевірка" - -msgid "Check the normative items." -msgstr "Перевірте нормативні позиції." - -msgid "Output Model Info" -msgstr "Вихідна інформація про модель" - -msgid "Output the model's information." -msgstr "Виведіть інформацію про модель." - -msgid "Export Settings" -msgstr "Експорт налаштувань" - -msgid "Export settings to a file." -msgstr "Експорт налаштувань у файл." - -msgid "Send progress to pipe" -msgstr "Надіслати прогрес до каналу" - -msgid "Send progress to pipe." -msgstr "Надіслати прогрес до каналу." - -msgid "Arrange Options" -msgstr "Упорядкувати параметри" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "Параметри упорядкування: 0-disable, 1-enable, інші-auto" - -msgid "Repetions count" -msgstr "" - -msgid "Repetions count of the whole model" -msgstr "" - msgid "Ensure on bed" msgstr "" @@ -10776,12 +10940,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "" -msgid "Convert Unit" -msgstr "Перетворити одиницю виміру" - -msgid "Convert the units of model" -msgstr "Перетворення одиниць моделі" - msgid "Orient Options" msgstr "" @@ -10791,47 +10949,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "" -msgid "Rotate around X" -msgstr "" - -msgid "Rotation angle around the X axis in degrees." -msgstr "" - msgid "Rotate around Y" msgstr "" msgid "Rotation angle around the Y axis in degrees." msgstr "" -msgid "Scale the model by a float factor" -msgstr "Масштабуйте модель за допомогою плаваючого коефіцієнта" - -msgid "Load General Settings" -msgstr "Завантажити загальні налаштування" - -msgid "Load process/machine settings from the specified file" -msgstr "Завантажити налаштування процесу/машини із зазначеного файлу" - -msgid "Load Filament Settings" -msgstr "Завантажити налаштування філаменту" - -msgid "Load filament settings from the specified file list" -msgstr "Завантажити налаштування філаменту із зазначеного списку файлів" - -msgid "Skip Objects" -msgstr "Пропустити об'єкти" - -msgid "Skip some objects in this print" -msgstr "Пропустити деякі об'єкти в цьому принті" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "" - msgid "Data directory" msgstr "Каталог даних" @@ -10843,22 +10966,6 @@ msgstr "" "Завантажити та зберегти налаштування в даному каталозі. Це корисно для " "підтримки різних профілів або для ввімкнення конфігурацій із сховища мережі." -msgid "Output directory" -msgstr "Вихідний каталог" - -msgid "Output directory for the exported files." -msgstr "Вихідний каталог для експортованих файлів." - -msgid "Debug level" -msgstr "Рівень налагодження" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"Встановлює рівень реєстрації налагодження. 0: непереборний, 1: помилка, 2: " -"попередження, 3: інформація, 4: налагодження, 5: трасування\n" - msgid "Load custom gcode" msgstr "" @@ -11020,9 +11127,6 @@ msgstr "" msgid "Finish" msgstr "" -msgid "Wiki" -msgstr "" - msgid "How to use calibration result?" msgstr "" @@ -11038,6 +11142,12 @@ msgstr "" msgid "Calibration not supported" msgstr "" +msgid "Error desc" +msgstr "" + +msgid "Extra info" +msgstr "" + msgid "Flow Dynamics" msgstr "" @@ -11065,8 +11175,8 @@ msgstr "" msgid "The name cannot be empty." msgstr "" -#, boost-format -msgid "The selected preset: %1% is not found." +#, c-format, boost-format +msgid "The selected preset: %s is not found." msgstr "" msgid "The name cannot be the same as the system preset name." @@ -11346,12 +11456,6 @@ msgid "" "- Different filament brand and family(Brand = Bambu, Family = Basic, Matte)" msgstr "" -msgid "Error desc" -msgstr "" - -msgid "Extra info" -msgstr "" - msgid "Pattern" msgstr "" @@ -11440,101 +11544,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "" - -msgid "Mesh Boolean" -msgstr "" - -msgid "Union" -msgstr "" - -msgid "Difference" -msgstr "" - -msgid "Intersection" -msgstr "" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "" - -msgid "Subtract with" -msgstr "" - -msgid "selected" -msgstr "" - -msgid "Part 1" -msgstr "" - -msgid "Part 2" -msgstr "" - -msgid "Delete input" -msgstr "" - -msgid "Send G-Code to printer host" -msgstr "" - -msgid "Upload to Printer Host with the following filename:" -msgstr "" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "" - -msgid "Upload to storage" -msgstr "" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "" - -msgid "Upload" -msgstr "" - -msgid "Print host upload queue" -msgstr "" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "" - -msgctxt "OfFile" -msgid "Size" -msgstr "" - -msgid "Filename" -msgstr "" - -msgid "Cancel selected" -msgstr "" - -msgid "Show error message" -msgstr "" - -msgid "Enqueued" -msgstr "" - -msgid "Uploading" -msgstr "" - -msgid "Cancelling" -msgstr "" - -msgid "Error uploading to print host" -msgstr "" - msgid "PA Calibration" msgstr "Калібрування РА" @@ -11663,75 +11672,107 @@ msgstr "Кінцева довжина ретракту: " msgid "mm/mm" msgstr "мм/мм" -msgid "Physical Printer" -msgstr "Фізичний принтер" +msgid "Send G-Code to printer host" +msgstr "" -msgid "Print Host upload" -msgstr "Завантаження хоста друку" +msgid "Upload to Printer Host with the following filename:" +msgstr "" -msgid "Test" -msgstr "Тест" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "" -msgid "Could not get a valid Printer Host reference" -msgstr "Неможливо отримати дійсне посилання на хост принтера" +msgid "Upload to storage" +msgstr "" -msgid "Success!" -msgstr "Успіх!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "" -msgid "Refresh Printers" -msgstr "Оновити принтери" +msgid "Upload" +msgstr "" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." +msgid "Print host upload queue" msgstr "" -"Файл HTTPS CA є необов'язковим. Він необхідний лише під час використання " -"HTTPS із сертифікатом." -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "Файли сертифікатів (*.crt, *.pem)|*.crt;*.pem|Всі файли|*.*" +msgid "ID" +msgstr "" -msgid "Open CA certificate file" -msgstr "Відкрити файл сертифіката ЦС" +msgid "Progress" +msgstr "" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." +msgid "Host" msgstr "" -"У цій системі %s використовує HTTPS-сертифікати із системного сховища " -"сертифікатів або Keychain." -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." +msgctxt "OfFile" +msgid "Size" +msgstr "" + +msgid "Filename" msgstr "" -"Щоб використовувати власний файл ЦС, імпортуйте файл ЦС в сховище " -"сертифікатів/Keychain." -msgid "Connection to printers connected via the print host failed." -msgstr "Не вдалося підключитися до принтерів, підключених через вузол друку." +msgid "Cancel selected" +msgstr "" -msgid "The start, end or step is not valid value." +msgid "Show error message" msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Enqueued" +msgstr "" + +msgid "Uploading" +msgstr "" + +msgid "Cancelling" +msgstr "" + +msgid "Error uploading to print host" +msgstr "" + +msgid "Unable to perform boolean operation on selected parts" msgstr "" -msgid "Need select printer" +msgid "Mesh Boolean" +msgstr "" + +msgid "Union" +msgstr "" + +msgid "Difference" +msgstr "" + +msgid "Intersection" +msgstr "" + +msgid "Source Volume" +msgstr "" + +msgid "Tool Volume" +msgstr "" + +msgid "Subtract from" +msgstr "" + +msgid "Subtract with" +msgstr "" + +msgid "selected" +msgstr "" + +msgid "Part 1" +msgstr "" + +msgid "Part 2" +msgstr "" + +msgid "Delete input" msgstr "" -#: resources/data/hints.ini: [hint:3D Scene Operations] +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"Операції з 3D сценами\n" -"Чи знаєте ви, як керувати видом та вибором об'єкта/деталі за допомогою миші " -"та Сенсорна панель у 3D сцені?" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -11747,11 +11788,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"Виправити модель\n" -"Чи знаєте ви, що ви можете виправити пошкоджену 3D-модель, щоб " -"уникнутивеликої кількості проблем із нарізкою?" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -11801,6 +11839,13 @@ msgstr "" "Чи знаєте ви, що можна переглядати всі об'єкти/деталі у списку та змінювати " "Параметри для кожного об'єкта/деталі?" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -11991,11 +12036,283 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." msgstr "" +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "Інструмент-укладання на обличчя" + +#~ msgid "Export as STL" +#~ msgstr "Експортувати як STL" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "Введіть допустиме значення (K в діапазоні 0~0,5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "" +#~ "Введіть допустиме значення (K у діапазоні 0~0,5, N у діапазоні 0,6~2,0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "Експортувати всі об'єкти у форматі STL" + +#~ msgid "Slice ok." +#~ msgstr "Нарізка прибл." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "Версія 3mf %s новіша, ніж версія %s %s, знайдено наступні ключі:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "Вам краще оновити програмне забезпечення.\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "" +#~ "Версія 3mf %s новіша, ніж версія %s %s, запропонуйте оновити програмне " +#~ "забезпечення." + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "3mf не сумісний, завантажуйте лише дані геометрії!" + +#~ msgid "Incompatible 3mf" +#~ msgstr "Несумісний 3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "Додати/видалити принтери" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s не підтримується AMS." + +#~ msgid "Don't remind me of this version again" +#~ msgstr "Не нагадуйте мені більше про цю версію" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "Помилка: IP або код доступу не вірні" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "Порядок внутрішні периметри/зовнішні периметри/заповнення" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "" +#~ "Роздрукуйте послідовність внутрішнього периметра, зовнішнього периметра " +#~ "та заповнення " + +#~ msgid "inner/outer/infill" +#~ msgstr "внутрішній/зовнішній/заповнення" + +#~ msgid "outer/inner/infill" +#~ msgstr "зовнішній/внутрішній/заповнення" + +#~ msgid "infill/inner/outer" +#~ msgstr "заповнення/внутрішній/зовнішній" + +#~ msgid "infill/outer/inner" +#~ msgstr "заповнення/зовнішній/внутрішній" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "внутрішній-внутрішній/заповнення" + +#~ msgid "Export 3MF" +#~ msgstr "Експорт 3MF" + +#~ msgid "Export project as 3MF." +#~ msgstr "Експортуйте проект як 3MF." + +#~ msgid "Export slicing data" +#~ msgstr "Експорт даних нарізки" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "Експорт даних нарізки до папки." + +#~ msgid "Load slicing data" +#~ msgstr "Завантажити дані про нарізку" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "Завантажити кешовані дані нарізки з каталогу" + +#~ msgid "Slice" +#~ msgstr "Нарізка" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "Нарізати пластини: 0-всі пластини, i-пластина i, інші-неприпустимі" + +#~ msgid "Show command help." +#~ msgstr "Показати довідку про команду." + +#~ msgid "UpToDate" +#~ msgstr "До цього часу" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "Оновіть значення конфігурації 3mf до останніх." + +#~ msgid "mtcpp" +#~ msgstr "mtcpp" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "максимальна кількість трикутників на стіл для нарізки." + +#~ msgid "mstpp" +#~ msgstr "mstpp" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "максимальний час нарізки на стіл у секундах." + +#~ msgid "Normative check" +#~ msgstr "Нормативна перевірка" + +#~ msgid "Check the normative items." +#~ msgstr "Перевірте нормативні позиції." + +#~ msgid "Output Model Info" +#~ msgstr "Вихідна інформація про модель" + +#~ msgid "Output the model's information." +#~ msgstr "Виведіть інформацію про модель." + +#~ msgid "Export Settings" +#~ msgstr "Експорт налаштувань" + +#~ msgid "Export settings to a file." +#~ msgstr "Експорт налаштувань у файл." + +#~ msgid "Send progress to pipe" +#~ msgstr "Надіслати прогрес до каналу" + +#~ msgid "Send progress to pipe." +#~ msgstr "Надіслати прогрес до каналу." + +#~ msgid "Arrange Options" +#~ msgstr "Упорядкувати параметри" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "Параметри упорядкування: 0-disable, 1-enable, інші-auto" + +#~ msgid "Convert Unit" +#~ msgstr "Перетворити одиницю виміру" + +#~ msgid "Convert the units of model" +#~ msgstr "Перетворення одиниць моделі" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "Масштабуйте модель за допомогою плаваючого коефіцієнта" + +#~ msgid "Load General Settings" +#~ msgstr "Завантажити загальні налаштування" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "Завантажити налаштування процесу/машини із зазначеного файлу" + +#~ msgid "Load Filament Settings" +#~ msgstr "Завантажити налаштування філаменту" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "Завантажити налаштування філаменту із зазначеного списку файлів" + +#~ msgid "Skip Objects" +#~ msgstr "Пропустити об'єкти" + +#~ msgid "Skip some objects in this print" +#~ msgstr "Пропустити деякі об'єкти в цьому принті" + +#~ msgid "Output directory" +#~ msgstr "Вихідний каталог" + +#~ msgid "Output directory for the exported files." +#~ msgstr "Вихідний каталог для експортованих файлів." + +#~ msgid "Debug level" +#~ msgstr "Рівень налагодження" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "Встановлює рівень реєстрації налагодження. 0: непереборний, 1: помилка, " +#~ "2: попередження, 3: інформація, 4: налагодження, 5: трасування\n" + +#~ msgid "Physical Printer" +#~ msgstr "Фізичний принтер" + +#~ msgid "Print Host upload" +#~ msgstr "Завантаження хоста друку" + +#~ msgid "Could not get a valid Printer Host reference" +#~ msgstr "Неможливо отримати дійсне посилання на хост принтера" + +#~ msgid "Success!" +#~ msgstr "Успіх!" + +#~ msgid "Refresh Printers" +#~ msgstr "Оновити принтери" + +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "Файл HTTPS CA є необов'язковим. Він необхідний лише під час використання " +#~ "HTTPS із сертифікатом." + +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "Файли сертифікатів (*.crt, *.pem)|*.crt;*.pem|Всі файли|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "Відкрити файл сертифіката ЦС" + +#, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "" +#~ "У цій системі %s використовує HTTPS-сертифікати із системного сховища " +#~ "сертифікатів або Keychain." + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "Щоб використовувати власний файл ЦС, імпортуйте файл ЦС в сховище " +#~ "сертифікатів/Keychain." + +#~ msgid "Connection to printers connected via the print host failed." +#~ msgstr "" +#~ "Не вдалося підключитися до принтерів, підключених через вузол друку." + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "Операції з 3D сценами\n" +#~ "Чи знаєте ви, як керувати видом та вибором об'єкта/деталі за допомогою " +#~ "миші та Сенсорна панель у 3D сцені?" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "Виправити модель\n" +#~ "Чи знаєте ви, що ви можете виправити пошкоджену 3D-модель, щоб " +#~ "уникнутивеликої кількості проблем із нарізкою?" + #~ msgid "Embeded" #~ msgstr "Вбудовано" @@ -12082,9 +12399,6 @@ msgstr "" #~ msgid "Resonance frequency identification" #~ msgstr "Ідентифікація резонансної частоти" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "Інженерний стіл" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "Високотемпературна пластина" diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index 5a97ebf4d34..a3ac14c6ddc 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Slic3rPE\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: 2023-04-01 13:21+0800\n" "Last-Translator: SoftFever \n" "Language-Team: \n" @@ -105,6 +105,9 @@ msgstr "无自动支撑" msgid "Support Generated" msgstr "已生成支撑" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "选择底面" @@ -151,7 +154,7 @@ msgstr "批量填充" msgid "Height range" msgstr "高度范围" -msgid "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" msgstr "" msgid "Toggle Wireframe" @@ -182,9 +185,15 @@ msgstr "绘制使用:耗材丝%1%" msgid "Move" msgstr "移动" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "旋转" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "优化朝向" @@ -194,12 +203,12 @@ msgstr "应用" msgid "Scale" msgstr "缩放" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "错误:请先关闭所有工具栏菜单" -msgid "Tool-Lay on Face" -msgstr "工具-选择底面" - msgid "in" msgstr "在" @@ -491,6 +500,15 @@ msgstr "Z缝绘制" msgid "Remove selection" msgstr "移除绘制" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "字体" @@ -689,6 +707,14 @@ msgstr "逆戟鲸版本过低,需要更新到最新版本方可正常使用" msgid "Privacy Policy Update" msgstr "隐私协议更新" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "载入中" @@ -882,8 +908,11 @@ msgstr "可打印的" msgid "Fix model" msgstr "修复模型" -msgid "Export as STL" -msgstr "导出为 STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "从磁盘重新加载" @@ -1135,6 +1164,9 @@ msgstr "点击此图标可编辑这个对象的颜色绘制" msgid "Click the icon to shift this object to the bed" msgstr "点击这个图标可将对象移动到热床上" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "载入文件中" @@ -1380,6 +1412,18 @@ msgstr "打开下一条提示" msgid "Open Documentation in web browser." msgstr "在web浏览器中打开文档。" +msgid "Color" +msgstr "颜色" + +msgid "Pause" +msgstr "暂停" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "自定义" + msgid "Pause:" msgstr "暂停" @@ -1455,8 +1499,8 @@ msgstr "" msgid "Failed to connect to the server" msgstr "无法连接服务器" -msgid "Check cloud service status" -msgstr "检查云服务状态" +msgid "Check the status of current system services" +msgstr "请检查当前系统服务状态" msgid "code" msgstr "" @@ -1702,6 +1746,14 @@ msgstr "正在通过局域网发送打印任务" msgid "Sending print job through cloud service" msgstr "正在通过云端服务发送打印任务" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "服务不可用" @@ -1913,11 +1965,11 @@ msgstr "您确定要清除耗材丝信息吗?" msgid "You need to select the material type and color first." msgstr "您需要先选择材料类型和颜色。" -msgid "Please input a valid value (K in 0~0.5)" -msgstr "请输入有效的数值(K的范围为0~0.5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "请输入有效的数值 (K的范围为0~0.5, N的范围为0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "其他颜色" @@ -2272,9 +2324,6 @@ msgstr "矩形" msgid "Circular" msgstr "圆" -msgid "Custom" -msgstr "自定义" - msgid "Load shape from STL..." msgstr "从STL文件加载形状..." @@ -2753,6 +2802,9 @@ msgstr "冲刷" msgid "Total" msgstr "总计" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "总预估" @@ -2840,15 +2892,18 @@ msgstr "颜色更换" msgid "Print" msgstr "打印" -msgid "Pause" -msgstr "暂停" - msgid "Printer" msgstr "打印机" msgid "Print settings" msgstr "打印设置" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "时间预估" @@ -3018,7 +3073,7 @@ msgstr "体积:" msgid "Size:" msgstr "尺寸:" -#, c-format, boost-format +#, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3078,15 +3133,15 @@ msgstr "校准流程" msgid "Start Calibration" msgstr "开始校准" -msgid "No step selected" -msgstr "未选择步骤" - msgid "Completed" msgstr "已完成" msgid "Calibrating" msgstr "校准中" +msgid "No step selected" +msgstr "未选择步骤" + msgid "Auto-record Monitoring" msgstr "监控录像" @@ -3301,8 +3356,11 @@ msgstr "加载配置" msgid "Import" msgstr "导入" -msgid "Export all objects as STL" -msgstr "导出所有对象为STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "导出通用 3MF" @@ -3575,9 +3633,6 @@ msgstr "初始化失败(没有摄像头)" msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "打印机正忙于下载,请等待下载完成。" -msgid "Loading..." -msgstr "正在加载视频……" - msgid "Initialize failed (Not supported on the current printer version)!" msgstr "初始化失败(当前打印机的版本不支持)!" @@ -3638,6 +3693,9 @@ msgstr "正在播放中……" msgid "Load failed [%d]!" msgstr "加载失败 [%d]!" +msgid "Loading..." +msgstr "正在加载视频……" + msgid "Year" msgstr "年" @@ -3756,12 +3814,25 @@ msgstr "下载完成" msgid "Downloading %d%%..." msgstr "下载中 %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + msgid "Not supported on the current printer version." msgstr "当前打印机的版本不支持。" msgid "Storage unavailable, insert SD card." msgstr "存储不可用,请插入SD卡。" +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "速度:" @@ -4095,6 +4166,12 @@ msgstr "新的网络插件可用。" msgid "Details" msgstr "详情" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "Wiki" + msgid "Undo integration failed." msgstr "集成取消失败。" @@ -4140,9 +4217,6 @@ msgstr "" msgid "Cancel upload" msgstr "取消上传" -msgid "Slice ok." -msgstr "切片完成." - msgid "Jump to" msgstr "跳转到" @@ -4242,6 +4316,9 @@ msgstr "自动从丢步中恢复" msgid "Allow Prompt Sound" msgstr "允许提示音" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "全局" @@ -4336,6 +4413,9 @@ msgstr "从AMS同步材料列表" msgid "Set filaments to use" msgstr "配置可选择的材料" +msgid "Search plate, object and part." +msgstr "" + msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." msgstr "没有发现AMS材料。请在“设备”页面选择打印机,将加载 AMS 信息" @@ -4426,22 +4506,29 @@ msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "该3mf文件来自旧版本的逆戟鲸切片,将只加载几何数据。" #, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" -msgstr "该3mf的版本%s比%s的版本%s新,发现以下参数键值无法识别:" +msgid "This slicer file version %s is newer than %s's version:" +msgstr "" -msgid "You'd better upgrade your software.\n" -msgstr "建议升级您的软件版本。\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "较新的3mf版本" +msgid "" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + #, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." -msgstr "该3mf的版本%s比%s的版本%s要新,建议升级你的软件。" +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" +msgstr "" msgid "Invalid values found in the 3mf:" msgstr "在3mf文件中发现无效值:" @@ -4449,11 +4536,27 @@ msgstr "在3mf文件中发现无效值:" msgid "Please correct them in the param tabs" msgstr "请在参数页更正它们" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "该3mf文件与软件不兼容,将只加载几何数据。" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "不兼容的3mf" +msgid "Customized Preset" +msgstr "" msgid "Name of components inside step file is not UTF8 format!" msgstr "step 文件中的部件名称包含非UTF8格式的字符!" @@ -4522,6 +4625,15 @@ msgstr "文件另存为:" msgid "Export OBJ file:" msgstr "导出OBJ文件:" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "删除切割对象的一部分" @@ -4539,15 +4651,15 @@ msgstr "选中的模型不可分裂。" msgid "Another export job is running." msgstr "有其他导出任务正在进行中。" -msgid "Replace from:" -msgstr "" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "替换时发生错误" +msgid "Replace from:" +msgstr "" + msgid "Select a new file" msgstr "选择新文件" @@ -4904,6 +5016,12 @@ msgstr "显示g-code窗口" msgid "If enabled, g-code window will be displayed." msgstr "如果启用,将显示g-code窗口。" +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "预设" @@ -4952,6 +5070,9 @@ msgstr "近期项目的最大计数" msgid "Clear my choice on the unsaved projects." msgstr "清除我对未保存的项目的选择。" +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "自动备份" @@ -5103,8 +5224,11 @@ msgstr "添加/删除材料" msgid "Add/Remove materials" msgstr "添加/删除材料" -msgid "Add/Remove printers" -msgstr "添加/删除打印机" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "不兼容的预设" @@ -5286,17 +5410,17 @@ msgstr "低温打印热床" msgid "PLA Plate" msgstr "PLA打印板" -msgid "Bambu Engineering Plate" -msgstr "Bambu工程材料热床" +msgid "Bamabu Engineering Plate" +msgstr "工程打印热床" -msgid "Bambu Smooth PEI Plate" -msgstr "Bambu光滑PEI热床" +msgid "Bamabu Smooth PEI Plate" +msgstr "" msgid "High temperature Plate" msgstr "高温打印热床" -msgid "Bambu Textured PEI Plate" -msgstr "Bambu纹理PEI热床" +msgid "Bamabu Textured PEI Plate" +msgstr "" msgid "Send print job to" msgstr "发送打印任务至" @@ -5319,9 +5443,6 @@ msgstr "发送完成" msgid "Error code" msgstr "错误代码" -msgid "Check the status of current system services" -msgstr "请检查当前系统服务状态" - msgid "Printer local connection failed, please try again." msgstr "打印机局域网连接失败,请重试。" @@ -5417,9 +5538,8 @@ msgid "" msgstr "当启用旋转花瓶模式时,I3结构的机器将不会生成延时摄影。" msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." -msgstr "当逐件打印时,I3结构的机器将不会生成延时摄影。" +"Timelapse is not supported because Print sequence is set to \"By object\"." +msgstr "" msgid "Errors" msgstr "错误" @@ -5435,10 +5555,6 @@ msgstr "" "生成G代码时选择的打印机类型与当前选择的打印机不一致。建议您使用相同的打印机类" "型进行切片。" -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "%s 不受AMS支持。" - msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " "they are the required filaments. If they are okay, press \"Confirm\" to " @@ -5447,10 +5563,33 @@ msgstr "" "AMS映射中存在一些未知的耗材。请检查它们是否符合预期。如果符合,按“确定”以开始" "打印任务。" +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "如果您仍然想继续打印,请单击“确定”按钮。" +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + msgid "" "Connecting to the printer. Unable to cancel during the connection process." msgstr "正在连接打印机。连接过程中无法取消。" @@ -5624,6 +5763,9 @@ msgid "" msgstr "" "平滑模式的延时摄影需要擦料塔,否则打印件上可能会有瑕疵。您想打开擦料塔吗?" +msgid "Still print by object?" +msgstr "" + msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " "support volume but weaker strength.\n" @@ -5661,8 +5803,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "在录制无工具头延时摄影视频时,建议添加“延时摄影擦料塔”\n" "右键单击打印板的空白位置,选择“添加标准模型”->“延时摄影擦料塔”。" @@ -5911,6 +6053,9 @@ msgstr "打印机起始G-code" msgid "Machine end G-code" msgstr "打印机结束G-code" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "换层前G-code" @@ -5979,6 +6124,24 @@ msgstr "固件回抽" msgid "Detached" msgstr "分离的" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% 预设" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "下列预设将被一起删除。" @@ -5987,11 +6150,6 @@ msgstr[0] "下列预设将被一起删除。" msgid "Are you sure to %1% the selected preset?" msgstr "确定要%1%所选预设吗?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% 预设" - msgid "All" msgstr "所有" @@ -6225,11 +6383,17 @@ msgstr "尖端成型线间距" msgid "Auto-Calc" msgstr "自动计算" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "耗材丝更换时的冲刷体积" -msgid "Multiplier" -msgstr "乘数" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "在两个耗材丝间切换所需的冲刷量(mm³)" @@ -6242,6 +6406,9 @@ msgstr "建议:冲刷量设置在[%d, %d]范围内" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "乘数的取值范围是[%.2f, %.2f]" +msgid "Multiplier" +msgstr "乘数" + msgid "unloaded" msgstr "卸载" @@ -6257,6 +6424,12 @@ msgstr "从" msgid "To" msgstr "到" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "登录" @@ -6290,6 +6463,9 @@ msgstr "从剪切板粘贴" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "显示/隐藏 3Dconnexion设备的设置对话框" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "显示键盘快捷键列表" @@ -6538,12 +6714,15 @@ msgstr "新的网络插件(%s) 可用,您是否需要安装它?" msgid "New version of Orca Slicer" msgstr "新版本的Orca Slicer" -msgid "Don't remind me of this version again" -msgstr "此版本不再提示" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "完成" +msgid "Confirm and Update Nozzle" +msgstr "" + msgid "LAN Connection Failed (Sending print file)" msgstr "LAN连接失败 (发送打印文件)" @@ -6565,8 +6744,22 @@ msgstr "访问码" msgid "Where to find your printer's IP and Access Code?" msgstr "在哪里可以找到打印机的IP和访问码?" -msgid "Error: IP or Access Code are not correct" -msgstr "错误:IP或访问码不正确" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "测试" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "型号:" @@ -6991,6 +7184,11 @@ msgstr "使用了支撑添加器但没有打开支撑。请打开支撑。" msgid "Layer height cannot exceed nozzle diameter" msgstr "层高不能超过喷嘴直径" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + msgid "" "Relative extruder addressing requires resetting the extruder position at " "each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to " @@ -7398,10 +7596,29 @@ msgstr "悬垂反转" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" -"在奇数层,将悬垂的打印方向反转。这种交替的模式可以大大改善陡峭悬垂的打印质" -"量。" msgid "Reverse threshold" msgstr "反转阈值" @@ -7634,6 +7851,14 @@ msgstr "结尾G-code" msgid "End G-code when finish the whole printing" msgstr "所有打印结束时的结尾G-code" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + msgid "End G-code when finish the printing of this filament" msgstr "结束使用该耗材打印时的结尾G-code" @@ -7718,26 +7943,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "这将设置微小部位周长的阈值。默认阈值为0mm" -msgid "Order of inner wall/outer wall/infil" -msgstr "内墙/外墙/填充的顺序" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "内圈墙/外圈墙/填充的打印顺序" +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "内墙/外墙/填充" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "外墙/内墙/填充" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "填充/内墙/外墙" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "填充/外墙/内墙" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "内墙/外墙/内墙/填充" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "到横杆高度" @@ -7826,9 +8051,6 @@ msgstr "缺省颜色" msgid "Default filament color" msgstr "缺省材料颜色" -msgid "Color" -msgstr "颜色" - msgid "Filament notes" msgstr "耗材注释" @@ -8219,10 +8441,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "Klipper的max_accel_to_decel将被调整为该加速度的百分比" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "外墙抖动值" @@ -8288,10 +8506,10 @@ msgstr "满速风扇在" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" "风扇速度将从“禁用第一层”的零线性上升到“全风扇速度层”的最大。如果低于“禁用风扇" "第一层”,则“全风扇速度第一层”将被忽略,在这种情况下,风扇将在“禁用风扇第一" @@ -8572,6 +8790,18 @@ msgstr "" "强制在相邻材料/体积之间生成实心壳。适用于使用半透明材料或手动可溶性支撑材料的" "多挤出机打印" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "熨烫类型" @@ -9113,6 +9343,22 @@ msgstr "" "回抽完成之后,喷嘴轻微抬升,和打印件之间产生一定间隙。这能够避免空驶时喷嘴和" "打印件剐蹭和碰撞。使用螺旋线抬升z能够减少拉丝。" +msgid "Z hop lower boundary" +msgstr "Z抬升下边界" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "只有当Z高于此值且低于参数(Z抬升上边界)时,Z抬升才会生效" + +msgid "Z hop upper boundary" +msgstr "Z抬升上边界" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "如果该值为正,则Z抬升仅在Z高于参数(Z抬升下边界)且低于该值时才会生效" + msgid "Z hop type" msgstr "抬Z类型" @@ -9517,9 +9763,15 @@ msgid "" msgstr "" "打印支撑主体和筏层的耗材丝。\"缺省\"代表不指定特定的耗材丝,并使用当前耗材" -msgid "" -"Line width of support. If expressed as a %, it will be computed over the " -"nozzle diameter." +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + +msgid "" +"Line width of support. If expressed as a %, it will be computed over the " +"nozzle diameter." msgstr "支撑的线宽。如果以%表示,它将基于喷嘴直径来计算。" msgid "Interface use loop pattern" @@ -9546,6 +9798,12 @@ msgstr "顶部接触面层数" msgid "Bottom interface layers" msgstr "底部接触面层数" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "顶部接触面线距" @@ -10180,111 +10438,18 @@ msgstr "线宽过大" msgid " not in range " msgstr " 不在合理的区间" -msgid "Export 3MF" -msgstr "导出3MF" - -msgid "Export project as 3MF." -msgstr "导出项目为3MF。" - -msgid "Export slicing data" -msgstr "导出切片数据" - -msgid "Export slicing data to a folder." -msgstr "导出切片数据到目录" - -msgid "Load slicing data" -msgstr "导入切片数据" - -msgid "Load cached slicing data from directory" -msgstr "从目录导入缓存的切片数据" - -msgid "Export STL" -msgstr "导出STL文件" - -msgid "Export the objects as multiple STL." -msgstr "将对象导出为多个STL文件" - -msgid "Slice" -msgstr "切片" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "切片平台:0-所有平台,i-第i个平台,其他-无效" - -msgid "Show command help." -msgstr "显示命令行帮助。" - -msgid "UpToDate" -msgstr "" - -msgid "Update the configs values of 3mf to latest." -msgstr "将3mf的配置值更新为最新值。" - -msgid "Load default filaments" -msgstr "加载默认打印材料" - -msgid "Load first filament as default for those not loaded" -msgstr "加载第一个打印材料为默认材料" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "以最小尺寸导出3mf。" -msgid "mtcpp" -msgstr "" - -msgid "max triangle count per plate for slicing." -msgstr "切片时每个盘的最大三角形数。" - -msgid "mstpp" -msgstr "" - -msgid "max slicing time per plate in seconds." -msgstr "每个盘的最大切片时间(秒)。" - msgid "No check" msgstr "不要检查" msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "不要运行任何有效性检查,如gcode路径冲突检查。" -msgid "Normative check" -msgstr "规范性检查" - -msgid "Check the normative items." -msgstr "检查规范性项目。" - -msgid "Output Model Info" -msgstr "输出模型信息" - -msgid "Output the model's information." -msgstr "输出模型的信息。" - -msgid "Export Settings" -msgstr "导出配置" - -msgid "Export settings to a file." -msgstr "导出配置到文件。" - -msgid "Send progress to pipe" -msgstr "将进度发送到管道" - -msgid "Send progress to pipe." -msgstr "将进度发送到管道。" - -msgid "Arrange Options" -msgstr "摆放选项" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "摆放选项:0-关闭,1-开启,其他-自动" - -msgid "Repetions count" -msgstr "重复次数" - -msgid "Repetions count of the whole model" -msgstr "整个模型的重复次数" - msgid "Ensure on bed" msgstr "确保在热床上" @@ -10292,12 +10457,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "当物体部分位于热床的下方时,将其提升到热床的上方。默认情况下禁用" -msgid "Convert Unit" -msgstr "转换单位" - -msgid "Convert the units of model" -msgstr "转换模型的单位" - msgid "Orient Options" msgstr "" @@ -10307,47 +10466,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "绕Z轴的旋转角度(以度为单位)。" -msgid "Rotate around X" -msgstr "绕X旋转" - -msgid "Rotation angle around the X axis in degrees." -msgstr "绕X轴的旋转角度(以度为单位)。" - msgid "Rotate around Y" msgstr "绕Y旋转" msgid "Rotation angle around the Y axis in degrees." msgstr "绕Y轴的旋转角度(以度为单位)" -msgid "Scale the model by a float factor" -msgstr "根据因子缩放模型" - -msgid "Load General Settings" -msgstr "加载通用设置" - -msgid "Load process/machine settings from the specified file" -msgstr "从指定文件加载工艺/打印机设置" - -msgid "Load Filament Settings" -msgstr "加载耗材丝设置" - -msgid "Load filament settings from the specified file list" -msgstr "从指定文件加载耗材丝设置" - -msgid "Skip Objects" -msgstr "零件跳过" - -msgid "Skip some objects in this print" -msgstr "打印过程中跳过一些零件" - -msgid "load uptodate process/machine settings when using uptodate" -msgstr "在使用最新设置时加载最新的进程/机器设置" - -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "在使用最新设置时,从指定的文件中加载最新的进程/机器设置。" - msgid "Data directory" msgstr "数据目录" @@ -10357,22 +10481,6 @@ msgid "" "storage." msgstr "" -msgid "Output directory" -msgstr "输出路径" - -msgid "Output directory for the exported files." -msgstr "导出文件的输出路径。" - -msgid "Debug level" -msgstr "调试等级" - -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"设置调试日志等级。0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" - msgid "Load custom gcode" msgstr "加载自定义G-code" @@ -10530,9 +10638,6 @@ msgstr "校准" msgid "Finish" msgstr "完成" -msgid "Wiki" -msgstr "Wiki" - msgid "How to use calibration result?" msgstr "如何使用校准结果?" @@ -10550,6 +10655,12 @@ msgstr "" msgid "Calibration not supported" msgstr "不支持校准" +msgid "Error desc" +msgstr "错误描述" + +msgid "Extra info" +msgstr "额外信息" + msgid "Flow Dynamics" msgstr "动态流量" @@ -10582,9 +10693,9 @@ msgstr "" msgid "The name cannot be empty." msgstr "名称不能为空。" -#, boost-format -msgid "The selected preset: %1% is not found." -msgstr "未找到选定的预设:%1%。" +#, c-format, boost-format +msgid "The selected preset: %s is not found." +msgstr "" msgid "The name cannot be the same as the system preset name." msgstr "名称不能与系统预设名称相同。" @@ -10908,12 +11019,6 @@ msgstr "" "-可以共享相同热床温度的材料\n" "-不同的耗材品牌和系列(Brand = Bambu, Family = Basic, Matte)" -msgid "Error desc" -msgstr "错误描述" - -msgid "Extra info" -msgstr "额外信息" - msgid "Pattern" msgstr "" @@ -11002,101 +11107,6 @@ msgid "" "Please select one that should be used." msgstr "" -msgid "Unable to perform boolean operation on selected parts" -msgstr "无法对所选部件执行布尔运算" - -msgid "Mesh Boolean" -msgstr "布尔运算" - -msgid "Union" -msgstr "并集" - -msgid "Difference" -msgstr "差集" - -msgid "Intersection" -msgstr "交集" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "从中减去" - -msgid "Subtract with" -msgstr "与之相减" - -msgid "selected" -msgstr "已选中" - -msgid "Part 1" -msgstr "零件 1" - -msgid "Part 2" -msgstr "零件 2" - -msgid "Delete input" -msgstr "删除输入" - -msgid "Send G-Code to printer host" -msgstr "将G-Code发送到打印机" - -msgid "Upload to Printer Host with the following filename:" -msgstr "使用下列文件名上传到打印机:" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "如有需要,请使用正斜杠( / )作为目录分隔符。" - -msgid "Upload to storage" -msgstr "上传到存储单位" - -#, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "上传文件名不以\"%s\"结尾。您是否要继续?" - -msgid "Upload" -msgstr "上传" - -msgid "Print host upload queue" -msgstr "打印主机上传队列" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "进程" - -msgid "Host" -msgstr "主机" - -msgctxt "OfFile" -msgid "Size" -msgstr "大小" - -msgid "Filename" -msgstr "文件名" - -msgid "Cancel selected" -msgstr "取消选中" - -msgid "Show error message" -msgstr "显示错误信息" - -msgid "Enqueued" -msgstr "已加入队列" - -msgid "Uploading" -msgstr "正在上传" - -msgid "Cancelling" -msgstr "取消中" - -msgid "Error uploading to print host" -msgstr "上传到打印机时错误" - msgid "PA Calibration" msgstr "PA校准" @@ -11237,68 +11247,107 @@ msgstr "结束回抽长度" msgid "mm/mm" msgstr "" -msgid "Physical Printer" -msgstr "物理打印机" +msgid "Send G-Code to printer host" +msgstr "将G-Code发送到打印机" -msgid "Print Host upload" -msgstr "" +msgid "Upload to Printer Host with the following filename:" +msgstr "使用下列文件名上传到打印机:" -msgid "Test" -msgstr "测试" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "如有需要,请使用正斜杠( / )作为目录分隔符。" -msgid "Could not get a valid Printer Host reference" -msgstr "" +msgid "Upload to storage" +msgstr "上传到存储单位" -msgid "Success!" -msgstr "成功!" +#, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "上传文件名不以\"%s\"结尾。您是否要继续?" -msgid "Refresh Printers" -msgstr "刷新打印机" +msgid "Upload" +msgstr "上传" -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." -msgstr "" +msgid "Print host upload queue" +msgstr "打印主机上传队列" -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "ID" msgstr "" -msgid "Open CA certificate file" -msgstr "" +msgid "Progress" +msgstr "进程" -#, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." -msgstr "" +msgid "Host" +msgstr "主机" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." -msgstr "" +msgctxt "OfFile" +msgid "Size" +msgstr "大小" -msgid "Connection to printers connected via the print host failed." -msgstr "" +msgid "Filename" +msgstr "文件名" + +msgid "Cancel selected" +msgstr "取消选中" + +msgid "Show error message" +msgstr "显示错误信息" + +msgid "Enqueued" +msgstr "已加入队列" + +msgid "Uploading" +msgstr "正在上传" + +msgid "Cancelling" +msgstr "取消中" + +msgid "Error uploading to print host" +msgstr "上传到打印机时错误" + +msgid "Unable to perform boolean operation on selected parts" +msgstr "无法对所选部件执行布尔运算" -msgid "The start, end or step is not valid value." +msgid "Mesh Boolean" +msgstr "布尔运算" + +msgid "Union" +msgstr "并集" + +msgid "Difference" +msgstr "差集" + +msgid "Intersection" +msgstr "交集" + +msgid "Source Volume" msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" +msgid "Tool Volume" msgstr "" -msgid "Need select printer" -msgstr "需要选择打印机" +msgid "Subtract from" +msgstr "从中减去" + +msgid "Subtract with" +msgstr "与之相减" + +msgid "selected" +msgstr "已选中" -#: resources/data/hints.ini: [hint:3D Scene Operations] +msgid "Part 1" +msgstr "零件 1" + +msgid "Part 2" +msgstr "零件 2" + +msgid "Delete input" +msgstr "删除输入" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3D场景操作\n" -"如何在3D场景中使用鼠标和触摸面板进行视角控制和对象/部件选择" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -11313,10 +11362,8 @@ msgstr "" msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"修复模型\n" -"您知道吗?您可以修复一个损坏的3D模型以避免诸多切片问题。" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -11364,6 +11411,13 @@ msgstr "" "您知道对象列表吗?您可以在其中的查看所有对象/部件,并更改每个对象/部件的设" "置。" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -11540,11 +11594,290 @@ msgstr "" #: opened] msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." msgstr "" +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." +msgstr "" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "工具-选择底面" + +#~ msgid "Export as STL" +#~ msgstr "导出为 STL" + +#~ msgid "Check cloud service status" +#~ msgstr "检查云服务状态" + +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "请输入有效的数值(K的范围为0~0.5)" + +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "请输入有效的数值 (K的范围为0~0.5, N的范围为0.6~2.0)" + +#~ msgid "Export all objects as STL" +#~ msgstr "导出所有对象为STL" + +#~ msgid "Slice ok." +#~ msgstr "切片完成." + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "该3mf的版本%s比%s的版本%s新,发现以下参数键值无法识别:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "建议升级您的软件版本。\n" + +#, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "该3mf的版本%s比%s的版本%s要新,建议升级你的软件。" + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "该3mf文件与软件不兼容,将只加载几何数据。" + +#~ msgid "Incompatible 3mf" +#~ msgstr "不兼容的3mf" + +#~ msgid "Add/Remove printers" +#~ msgstr "添加/删除打印机" + +#~ msgid "Bambu Engineering Plate" +#~ msgstr "Bambu工程材料热床" + +#~ msgid "Bambu Smooth PEI Plate" +#~ msgstr "Bambu光滑PEI热床" + +#~ msgid "Bambu Textured PEI Plate" +#~ msgstr "Bambu纹理PEI热床" + +#~ msgid "" +#~ "When print by object, machines with I3 structure will not generate " +#~ "timelapse videos." +#~ msgstr "当逐件打印时,I3结构的机器将不会生成延时摄影。" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "%s 不受AMS支持。" + +#~ msgid "Don't remind me of this version again" +#~ msgstr "此版本不再提示" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "错误:IP或访问码不正确" + +#~ msgid "" +#~ "Extrude perimeters that have a part over an overhang in the reverse " +#~ "direction on odd layers. This alternating pattern can drastically improve " +#~ "steep overhang." +#~ msgstr "" +#~ "在奇数层,将悬垂的打印方向反转。这种交替的模式可以大大改善陡峭悬垂的打印质" +#~ "量。" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "内墙/外墙/填充的顺序" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "内圈墙/外圈墙/填充的打印顺序" + +#~ msgid "inner/outer/infill" +#~ msgstr "内墙/外墙/填充" + +#~ msgid "outer/inner/infill" +#~ msgstr "外墙/内墙/填充" + +#~ msgid "infill/inner/outer" +#~ msgstr "填充/内墙/外墙" + +#~ msgid "infill/outer/inner" +#~ msgstr "填充/外墙/内墙" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "内墙/外墙/内墙/填充" + +#~ msgid "Export 3MF" +#~ msgstr "导出3MF" + +#~ msgid "Export project as 3MF." +#~ msgstr "导出项目为3MF。" + +#~ msgid "Export slicing data" +#~ msgstr "导出切片数据" + +#~ msgid "Export slicing data to a folder." +#~ msgstr "导出切片数据到目录" + +#~ msgid "Load slicing data" +#~ msgstr "导入切片数据" + +#~ msgid "Load cached slicing data from directory" +#~ msgstr "从目录导入缓存的切片数据" + +#~ msgid "Export STL" +#~ msgstr "导出STL文件" + +#~ msgid "Export the objects as multiple STL." +#~ msgstr "将对象导出为多个STL文件" + +#~ msgid "Slice" +#~ msgstr "切片" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "切片平台:0-所有平台,i-第i个平台,其他-无效" + +#~ msgid "Show command help." +#~ msgstr "显示命令行帮助。" + +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "将3mf的配置值更新为最新值。" + +#~ msgid "Load default filaments" +#~ msgstr "加载默认打印材料" + +#~ msgid "Load first filament as default for those not loaded" +#~ msgstr "加载第一个打印材料为默认材料" + +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "切片时每个盘的最大三角形数。" + +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "每个盘的最大切片时间(秒)。" + +#~ msgid "Normative check" +#~ msgstr "规范性检查" + +#~ msgid "Check the normative items." +#~ msgstr "检查规范性项目。" + +#~ msgid "Output Model Info" +#~ msgstr "输出模型信息" + +#~ msgid "Output the model's information." +#~ msgstr "输出模型的信息。" + +#~ msgid "Export Settings" +#~ msgstr "导出配置" + +#~ msgid "Export settings to a file." +#~ msgstr "导出配置到文件。" + +#~ msgid "Send progress to pipe" +#~ msgstr "将进度发送到管道" + +#~ msgid "Send progress to pipe." +#~ msgstr "将进度发送到管道。" + +#~ msgid "Arrange Options" +#~ msgstr "摆放选项" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "摆放选项:0-关闭,1-开启,其他-自动" + +#~ msgid "Repetions count" +#~ msgstr "重复次数" + +#~ msgid "Repetions count of the whole model" +#~ msgstr "整个模型的重复次数" + +#~ msgid "Convert Unit" +#~ msgstr "转换单位" + +#~ msgid "Convert the units of model" +#~ msgstr "转换模型的单位" + +#~ msgid "Rotate around X" +#~ msgstr "绕X旋转" + +#~ msgid "Rotation angle around the X axis in degrees." +#~ msgstr "绕X轴的旋转角度(以度为单位)。" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "根据因子缩放模型" + +#~ msgid "Load General Settings" +#~ msgstr "加载通用设置" + +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "从指定文件加载工艺/打印机设置" + +#~ msgid "Load Filament Settings" +#~ msgstr "加载耗材丝设置" + +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "从指定文件加载耗材丝设置" + +#~ msgid "Skip Objects" +#~ msgstr "零件跳过" + +#~ msgid "Skip some objects in this print" +#~ msgstr "打印过程中跳过一些零件" + +#~ msgid "load uptodate process/machine settings when using uptodate" +#~ msgstr "在使用最新设置时加载最新的进程/机器设置" + +#~ msgid "" +#~ "load uptodate process/machine settings from the specified file when using " +#~ "uptodate" +#~ msgstr "在使用最新设置时,从指定的文件中加载最新的进程/机器设置。" + +#~ msgid "Output directory" +#~ msgstr "输出路径" + +#~ msgid "Output directory for the exported files." +#~ msgstr "导出文件的输出路径。" + +#~ msgid "Debug level" +#~ msgstr "调试等级" + +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "设置调试日志等级。0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" + +#, boost-format +#~ msgid "The selected preset: %1% is not found." +#~ msgstr "未找到选定的预设:%1%。" + +#~ msgid "Physical Printer" +#~ msgstr "物理打印机" + +#~ msgid "Success!" +#~ msgstr "成功!" + +#~ msgid "Refresh Printers" +#~ msgstr "刷新打印机" + +#~ msgid "Need select printer" +#~ msgstr "需要选择打印机" + +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3D场景操作\n" +#~ "如何在3D场景中使用鼠标和触摸面板进行视角控制和对象/部件选择" + +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "修复模型\n" +#~ "您知道吗?您可以修复一个损坏的3D模型以避免诸多切片问题。" + #~ msgid "Embeded" #~ msgstr "嵌入的" @@ -11561,22 +11894,6 @@ msgstr "" #~ msgid "Show online staff-picked models on the home page" #~ msgstr "在主页上显示工作人员挑选的在线模型" -#~ msgid "Z hop lower boundary" -#~ msgstr "Z抬升下边界" - -#~ msgid "" -#~ "Z hop will only come into effect when Z is above this value and is below " -#~ "the parameter: \"Z hop upper boundary\"" -#~ msgstr "只有当Z高于此值且低于参数(Z抬升上边界)时,Z抬升才会生效" - -#~ msgid "Z hop upper boundary" -#~ msgstr "Z抬升上边界" - -#~ msgid "" -#~ "If this value is positive, Z hop will only come into effect when Z is " -#~ "above the parameter: \"Z hop lower boundary\" and is below this value" -#~ msgstr "如果该值为正,则Z抬升仅在Z高于参数(Z抬升下边界)且低于该值时才会生效" - #~ msgid "The minimum printing speed when slow down for cooling" #~ msgstr "自动冷却降速的最小打印速度" @@ -11680,9 +11997,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "打分" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "工程打印热床" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "高温打印热床" diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index 9c572230d7c..0d657c53103 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-10 14:54+0800\n" +"POT-Creation-Date: 2023-11-24 18:09+0100\n" "PO-Revision-Date: 2023-11-06 14:37+0800\n" "Last-Translator: ablegods \n" "Language-Team: \n" @@ -116,6 +116,9 @@ msgstr "無自動支撐" msgid "Support Generated" msgstr "已產生支撐" +msgid "Gizmo-Place on Face" +msgstr "" + msgid "Lay on face" msgstr "選擇底面" @@ -166,8 +169,8 @@ msgstr "批次填充" msgid "Height range" msgstr "高度範圍" -msgid "Ctrl + Shift + Enter" -msgstr "Ctrl + Shift + Enter" +msgid "Alt + Shift + Enter" +msgstr "" msgid "Toggle Wireframe" msgstr "顯示/隱藏線框" @@ -197,9 +200,15 @@ msgstr "使用:線材 %1% 上色" msgid "Move" msgstr "移動" +msgid "Gizmo-Move" +msgstr "" + msgid "Rotate" msgstr "旋轉" +msgid "Gizmo-Rotate" +msgstr "" + msgid "Optimize orientation" msgstr "最佳化方向" @@ -209,12 +218,12 @@ msgstr "套用" msgid "Scale" msgstr "縮放" +msgid "Gizmo-Scale" +msgstr "" + msgid "Error: Please close all toolbar menus first" msgstr "錯誤:請先關閉所有工具欄選單" -msgid "Tool-Lay on Face" -msgstr "工具-選擇底面" - msgid "in" msgstr "" @@ -517,6 +526,15 @@ msgstr "自訂Z縫" msgid "Remove selection" msgstr "移除繪製" +msgid "Entering Seam painting" +msgstr "" + +msgid "Leaving Seam painting" +msgstr "" + +msgid "Paint-on seam editing" +msgstr "" + msgid "Font" msgstr "字體" @@ -732,6 +750,14 @@ msgstr " Orca Slicer 版本過低,需要更新到最新版本方可正常使 msgid "Privacy Policy Update" msgstr "隱私協議更新" +msgid "" +"The number of user presets cached in the cloud has exceeded the upper limit, " +"newly created user presets can only be used locally." +msgstr "" + +msgid "Sync user presets" +msgstr "" + msgid "Loading" msgstr "載入中" @@ -933,8 +959,11 @@ msgstr "可列印的" msgid "Fix model" msgstr "修復模型" -msgid "Export as STL" -msgstr "匯出為 STL" +msgid "Export as one STL" +msgstr "" + +msgid "Export as STLs" +msgstr "" msgid "Reload from disk" msgstr "從磁碟重新載入" @@ -1207,6 +1236,9 @@ msgstr "滑鼠左鍵點擊此圖示可編輯這個物件的顏色繪製" msgid "Click the icon to shift this object to the bed" msgstr "滑鼠左鍵點擊這個圖示可將物件移動到列印板上" +msgid " search results" +msgstr "" + msgid "Loading file" msgstr "載入檔案中" @@ -1461,6 +1493,18 @@ msgstr "打開下一條提示" msgid "Open Documentation in web browser." msgstr "在網頁瀏覽器中打開檔案。" +msgid "Color" +msgstr "顏色" + +msgid "Pause" +msgstr "暫停" + +msgid "Template" +msgstr "" + +msgid "Custom" +msgstr "自訂" + msgid "Pause:" msgstr "暫停" @@ -1538,8 +1582,9 @@ msgstr "" msgid "Failed to connect to the server" msgstr "無法連接伺服器" -msgid "Check cloud service status" -msgstr "檢查雲端服務狀態" +#, fuzzy +msgid "Check the status of current system services" +msgstr "請檢查目前系統服務狀態" msgid "code" msgstr "" @@ -1795,6 +1840,14 @@ msgstr "正在通過區域網路傳送列印作業" msgid "Sending print job through cloud service" msgstr "正在通過雲端服務傳送列印作業" +msgid "Print task sending times out." +msgstr "" + +msgid "" +"The printer timed out while receiving a print job. Please check if the " +"network is functioning properly and send the print again." +msgstr "" + msgid "Service Unavailable" msgstr "暫停服務" @@ -2016,13 +2069,11 @@ msgstr "您確定要清除線材資訊嗎?" msgid "You need to select the material type and color first." msgstr "您需要先選擇線材類型和顏色。" -#, fuzzy -msgid "Please input a valid value (K in 0~0.5)" -msgstr "請輸入有效的數值(K 值的範圍為 0~0.5)" +msgid "Please input a valid value (K in 0~0.3)" +msgstr "" -#, fuzzy -msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" -msgstr "請輸入有效的數值(K 值的範圍為 0~0.5, N 值的範圍為 0.6~2.0)" +msgid "Please input a valid value (K in 0~0.3, N in 0.6~2.0)" +msgstr "" msgid "Other Color" msgstr "其他顏色" @@ -2403,9 +2454,6 @@ msgstr "矩形" msgid "Circular" msgstr "圓" -msgid "Custom" -msgstr "自訂" - msgid "Load shape from STL..." msgstr "從 STL 檔案載入形狀..." @@ -2921,6 +2969,9 @@ msgstr "廢料" msgid "Total" msgstr "總計" +msgid "Tower" +msgstr "" + msgid "Total Estimation" msgstr "總預估" @@ -3012,9 +3063,6 @@ msgstr "顏色更換" msgid "Print" msgstr "列印" -msgid "Pause" -msgstr "暫停" - #, fuzzy msgid "Printer" msgstr "列印設備" @@ -3022,6 +3070,12 @@ msgstr "列印設備" msgid "Print settings" msgstr "列印設定" +msgid "Custom g-code" +msgstr "" + +msgid "ToolChange" +msgstr "" + msgid "Time Estimation" msgstr "時間預估" @@ -3195,7 +3249,7 @@ msgstr "體積:" msgid "Size:" msgstr "尺寸:" -#, fuzzy, c-format, boost-format +#, fuzzy, boost-format msgid "" "Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please " "separate the conflicted objects farther (%s <-> %s)." @@ -3256,15 +3310,15 @@ msgstr "校準流程" msgid "Start Calibration" msgstr "開始校準" -msgid "No step selected" -msgstr "未選擇任何步驟" - msgid "Completed" msgstr "已完成" msgid "Calibrating" msgstr "校準中" +msgid "No step selected" +msgstr "未選擇任何步驟" + msgid "Auto-record Monitoring" msgstr "監控錄影" @@ -3492,9 +3546,11 @@ msgstr "載入設定檔" msgid "Import" msgstr "匯入" -#, fuzzy -msgid "Export all objects as STL" -msgstr "匯出所有物件為 STL" +msgid "Export all objects as one STL" +msgstr "" + +msgid "Export all objects as STLs" +msgstr "" msgid "Export Generic 3MF" msgstr "匯出通用 3MF" @@ -3779,9 +3835,6 @@ msgstr "初始化失敗(沒有攝影機)" msgid "Printer is busy downloading, Please wait for the downloading to finish." msgstr "列印設備正忙於下載,請等待下載完成。" -msgid "Loading..." -msgstr "正在載入影片……" - #, fuzzy msgid "Initialize failed (Not supported on the current printer version)!" msgstr "初始化失敗(目前列印設備的版本不支援)!" @@ -3845,6 +3898,9 @@ msgstr "正在播放中……" msgid "Load failed [%d]!" msgstr "載入失敗 [%d]!" +msgid "Loading..." +msgstr "正在載入影片……" + msgid "Year" msgstr "年" @@ -3967,6 +4023,15 @@ msgstr "下載完成" msgid "Downloading %d%%..." msgstr "下載中 %d%%..." +msgid "Connection lost. Please retry." +msgstr "" + +msgid "File not exists." +msgstr "" + +msgid "File checksum error. Please retry." +msgstr "" + #, fuzzy msgid "Not supported on the current printer version." msgstr "目前列印設備的版本不支援。" @@ -3975,6 +4040,10 @@ msgstr "目前列印設備的版本不支援。" msgid "Storage unavailable, insert SD card." msgstr "儲存不可用,請插入 SD 記憶卡。" +#, c-format, boost-format +msgid "Error code: %d" +msgstr "" + msgid "Speed:" msgstr "速度:" @@ -4324,6 +4393,12 @@ msgstr "新的網路套件可用。" msgid "Details" msgstr "詳細" +msgid "New printer config available." +msgstr "" + +msgid "Wiki" +msgstr "Wiki" + msgid "Undo integration failed." msgstr "整合取消失敗。" @@ -4369,9 +4444,6 @@ msgstr "已完成" msgid "Cancel upload" msgstr "取消上傳" -msgid "Slice ok." -msgstr "切片完成." - msgid "Jump to" msgstr "轉換到" @@ -4474,6 +4546,9 @@ msgstr "自動從丟步中恢復" msgid "Allow Prompt Sound" msgstr "允許提示音效" +msgid "Fliament Tangle Detect" +msgstr "" + msgid "Global" msgstr "全局" @@ -4582,6 +4657,9 @@ msgstr "從 AMS 同步線材清單" msgid "Set filaments to use" msgstr "設定可選擇的線材" +msgid "Search plate, object and part." +msgstr "" + #, fuzzy msgid "" "No AMS filaments. Please select a printer in 'Device' page to load AMS info." @@ -4680,23 +4758,30 @@ msgstr "設定檔無法載入。" msgid "The 3mf is generated by old Orca Slicer, load geometry data only." msgstr "該 3mf 檔案來自舊版本的 Orca Slicer" -#, fuzzy, c-format, boost-format -msgid "" -"The 3mf's version %s is newer than %s's version %s, Found following keys " -"unrecognized:" -msgstr "該 3mf 的版本 %s 比 %s 的版本 %s 新,發現以下參數值無法識別:" +#, c-format, boost-format +msgid "This slicer file version %s is newer than %s's version:" +msgstr "" -msgid "You'd better upgrade your software.\n" -msgstr "建議升級您的軟體版本。\n" +msgid "" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?\n" +msgstr "" msgid "Newer 3mf version" msgstr "較新的 3mf 版本" -#, fuzzy, c-format, boost-format msgid "" -"The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your " -"software." -msgstr "該 3mf 的版本 %s 比 %s 的版本 %s 要新,建議升級你的軟體。" +"you can always update Bambu Studio at your convenience. The slicer file will " +"now be loaded without full functionality." +msgstr "" + +#, c-format, boost-format +msgid "" +"This slicer file version %s is newer than %s's version.\n" +"\n" +"Would you like to update your Bambu Studio software to enable all " +"functionality in this slicer file?" +msgstr "" msgid "Invalid values found in the 3mf:" msgstr "在 3mf 檔案中發現無效值:" @@ -4705,11 +4790,27 @@ msgstr "在 3mf 檔案中發現無效值:" msgid "Please correct them in the param tabs" msgstr "請在參數設定頁更正它們" -msgid "The 3mf is not compatible, load geometry data only!" -msgstr "該 3mf 檔案與軟體不相容,將只載入幾何數據。" +msgid "The 3mf has following modified G-codes in filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that these modified G-codes are safe to prevent any damage to " +"the machine!" +msgstr "" + +msgid "Modified G-codes" +msgstr "" + +msgid "The 3mf has following customized filament or printer presets:" +msgstr "" + +msgid "" +"Please confirm that the G-codes within these presets are safe to prevent any " +"damage to the machine!" +msgstr "" -msgid "Incompatible 3mf" -msgstr "不相容的 3mf" +msgid "Customized Preset" +msgstr "" #, fuzzy msgid "Name of components inside step file is not UTF8 format!" @@ -4780,6 +4881,15 @@ msgstr "檔案另存為:" msgid "Export OBJ file:" msgstr "匯出 OBJ 檔案:" +#, c-format, boost-format +msgid "" +"The file %s already exists\n" +"Do you want to replace it?" +msgstr "" + +msgid "Comfirm Save As" +msgstr "" + msgid "Delete object which is a part of cut object" msgstr "刪除切割物件的一部分" @@ -4797,15 +4907,15 @@ msgstr "選中的模型不可分割。" msgid "Another export job is running." msgstr "有其他匯出任務正在進行中。" -msgid "Replace from:" -msgstr "替換自:" - msgid "Unable to replace with more than one volume" msgstr "" msgid "Error during replace" msgstr "替換時發生錯誤" +msgid "Replace from:" +msgstr "替換自:" + msgid "Select a new file" msgstr "選擇新檔案" @@ -5182,6 +5292,12 @@ msgstr "顯示 G-code 視窗" msgid "If enabled, g-code window will be displayed." msgstr "如果啟用,將顯示 G-Code 視窗。" +msgid "Flushing volumes: Auto-calculate everytime the color changed." +msgstr "" + +msgid "If enabled, auto-calculate everytime the color changed." +msgstr "" + msgid "Presets" msgstr "預設" @@ -5238,6 +5354,9 @@ msgstr "近期專案項目的最大統計" msgid "Clear my choice on the unsaved projects." msgstr "清除我對未儲存的專案項目的選擇。" +msgid "No warnings when loading 3MF with modified G-codes" +msgstr "" + msgid "Auto-Backup" msgstr "自動備份" @@ -5399,9 +5518,11 @@ msgstr "新增/刪除線材" msgid "Add/Remove materials" msgstr "新增/刪除材料" -#, fuzzy -msgid "Add/Remove printers" -msgstr "新增/刪除列印設備" +msgid "Select/Remove printers(system presets)" +msgstr "" + +msgid "Create printer" +msgstr "" msgid "Incompatible" msgstr "不相容的預設" @@ -5591,20 +5712,18 @@ msgstr "低溫列印版" msgid "PLA Plate" msgstr "PLA 列印板" -#, fuzzy -msgid "Bambu Engineering Plate" -msgstr "Bambu 高溫工程列印板" +msgid "Bamabu Engineering Plate" +msgstr "工程列印熱床" -#, fuzzy -msgid "Bambu Smooth PEI Plate" -msgstr "Bambu 光滑面列印板" +msgid "Bamabu Smooth PEI Plate" +msgstr "" #, fuzzy msgid "High temperature Plate" msgstr "高溫列印板" -msgid "Bambu Textured PEI Plate" -msgstr "Bambu 金屬紋理列印板" +msgid "Bamabu Textured PEI Plate" +msgstr "" msgid "Send print job to" msgstr "傳送列印作業至" @@ -5627,10 +5746,6 @@ msgstr "傳送完成" msgid "Error code" msgstr "錯誤代碼" -#, fuzzy -msgid "Check the status of current system services" -msgstr "請檢查目前系統服務狀態" - #, fuzzy msgid "Printer local connection failed, please try again." msgstr "列印設備區域網路連接失敗,請重試。" @@ -5742,11 +5857,9 @@ msgid "" "timelapse videos." msgstr "當啟用花瓶模式時,龍門結構的設備不會產生縮時攝影影片" -#, fuzzy msgid "" -"When print by object, machines with I3 structure will not generate timelapse " -"videos." -msgstr "按物件列印時,龍門結構的設備不會產生縮時攝影影片" +"Timelapse is not supported because Print sequence is set to \"By object\"." +msgstr "" msgid "Errors" msgstr "錯誤" @@ -5763,10 +5876,6 @@ msgstr "" "產生 G-code 時選擇的列印設備類型與目前選擇的列印設備不一致。建議您使用相同的" "列印設備類型進行切片。" -#, c-format, boost-format -msgid "%s is not supported by AMS." -msgstr "AMS 不支援 %s 。" - #, fuzzy msgid "" "There are some unknown filaments in the AMS mappings. Please check whether " @@ -5776,10 +5885,33 @@ msgstr "" "AMS 映射中存在一些未知的線材。請檢查是否符合預期線材。如果符合,按“確定”以開" "始列印作業。" +#, c-format, boost-format +msgid "nozzle in preset: %s %s" +msgstr "" + +#, c-format, boost-format +msgid "nozzle memorized: %.1f %s" +msgstr "" + +msgid "" +"Your nozzle diameter in preset is not consistent with memorized nozzle " +"diameter. Did you change your nozzle lately?" +msgstr "" + +#, c-format, boost-format +msgid "*Printing %s material with %s may cause nozzle damage" +msgstr "" + msgid "" "Please click the confirm button if you still want to proceed with printing." msgstr "如果您仍然想繼續列印,請滑鼠左鍵點擊 確定 按鈕。" +msgid "Hardened Steel" +msgstr "" + +msgid "Stainless Steel" +msgstr "" + #, fuzzy msgid "" "Connecting to the printer. Unable to cancel during the connection process." @@ -5971,6 +6103,9 @@ msgid "" msgstr "" "平滑模式的縮時錄影需要擦拭塔,否則列印物件上可能會有瑕疵。要打開擦拭塔嗎?" +msgid "Still print by object?" +msgstr "" + #, fuzzy msgid "" "We have added an experimental style \"Tree Slim\" that features smaller " @@ -6014,8 +6149,8 @@ msgstr "" msgid "" "When recording timelapse without toolhead, it is recommended to add a " "\"Timelapse Wipe Tower\" \n" -"by right-click the empty position of build plate and choose \"Add Primitive" -"\"->\"Timelapse Wipe Tower\"." +"by right-click the empty position of build plate and choose \"Add " +"Primitive\"->\"Timelapse Wipe Tower\"." msgstr "" "在錄製無工具頭縮時錄影影片時,建議增加“縮時錄影擦拭塔”\n" "右鍵單擊列印板的空白位置,選擇“新增標準模型”->“縮時錄影擦拭塔”。" @@ -6294,6 +6429,9 @@ msgstr "列印設備起始 G-code" msgid "Machine end G-code" msgstr "列印設備結束 G-code" +msgid "Printing by object G-code" +msgstr "" + msgid "Before layer change G-code" msgstr "換層前 G-code" @@ -6363,6 +6501,24 @@ msgstr "韌體回抽" msgid "Detached" msgstr "分離的" +#, c-format, boost-format +msgid "" +"%d Filament Preset and %d Process Preset is attached to this printer. Those " +"presets would be deleted if the printer is deleted." +msgstr "" + +msgid "Presets inherited by other presets can not be deleted!" +msgstr "" + +msgid "The following presets inherit this preset." +msgid_plural "The following preset inherits this preset." +msgstr[0] "" + +#. TRN Remove/Delete +#, boost-format +msgid "%1% Preset" +msgstr "%1% 預設" + msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." msgstr[0] "下列預設將被一起刪除。" @@ -6371,11 +6527,6 @@ msgstr[0] "下列預設將被一起刪除。" msgid "Are you sure to %1% the selected preset?" msgstr "確定要 %1% 所選預設嗎?" -#. TRN Remove/Delete -#, boost-format -msgid "%1% Preset" -msgstr "%1% 預設" - msgid "All" msgstr "所有" @@ -6630,12 +6781,17 @@ msgstr "尖端成型線間距" msgid "Auto-Calc" msgstr "自動計算" +msgid "Re-calculate" +msgstr "" + msgid "Flushing volumes for filament change" msgstr "線材更換時產生的廢料體積" -#, fuzzy -msgid "Multiplier" -msgstr "倍數" +msgid "" +"Studio would re-calculate your flushing volumes everytime the filaments " +"color changed. You could disable the auto-calculate in Bambu Studio > " +"Preferences" +msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "在兩個線材間切換所需的廢料體積(mm³)" @@ -6648,6 +6804,10 @@ msgstr "建議:廢料體積量應設定在[ %d, %d ]範圍內" msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "倍數的數值範圍是[%.2f, %.2f]" +#, fuzzy +msgid "Multiplier" +msgstr "倍數" + msgid "unloaded" msgstr "退料" @@ -6663,6 +6823,12 @@ msgstr "從" msgid "To" msgstr "" +msgid "Bambu Network plug-in not detected." +msgstr "" + +msgid "Click here to download it." +msgstr "" + msgid "Login" msgstr "登入" @@ -6700,6 +6866,9 @@ msgstr "從剪貼簿貼上" msgid "Show/Hide 3Dconnexion devices settings dialog" msgstr "顯示/隱藏 3Dconnexion 設備的設定對話框" +msgid "Switch table page" +msgstr "" + msgid "Show keyboard shortcuts list" msgstr "顯示鍵盤快捷鍵清單" @@ -6964,13 +7133,15 @@ msgstr "新的網路套件( %s) 可用,您是否需要安裝它?" msgid "New version of Orca Slicer" msgstr "新版本的 Orca Slicer" -#, fuzzy -msgid "Don't remind me of this version again" -msgstr "不要再提醒我這個版本" +msgid "Skip this Version" +msgstr "" msgid "Done" msgstr "完成" +msgid "Confirm and Update Nozzle" +msgstr "" + #, fuzzy msgid "LAN Connection Failed (Sending print file)" msgstr "區域網路連接失敗(傳送列印作業)" @@ -6997,8 +7168,22 @@ msgstr "訪問碼" msgid "Where to find your printer's IP and Access Code?" msgstr "在哪裡可以找到列印設備的 IP 和訪問碼?" -msgid "Error: IP or Access Code are not correct" -msgstr "錯誤:IP 或訪問碼不正確" +msgid "Step 3: Ping the IP address to check for packet loss and latency." +msgstr "" + +msgid "Test" +msgstr "測試" + +msgid "IP and Access Code Verified! You may close the window" +msgstr "" + +msgid "Connection failed, please double check IP and Access Code" +msgstr "" + +msgid "" +"Connection failed! If your IP and Access Code is correct, \n" +"please move to step 3 for troubleshooting network issues" +msgstr "" msgid "Model:" msgstr "型號:" @@ -7436,6 +7621,11 @@ msgstr "使用支撐添加器但沒有打開支撐。請打開支撐。" msgid "Layer height cannot exceed nozzle diameter" msgstr "層高不能超過噴嘴直徑" +msgid "" +"Layer height cannot exceed the limit in Printer Settings -> Extruder -> " +"Layer height limits" +msgstr "" + #, fuzzy msgid "" "Relative extruder addressing requires resetting the extruder position at " @@ -7889,10 +8079,29 @@ msgstr "懸空反轉" msgid "" "Extrude perimeters that have a part over an overhang in the reverse " "direction on odd layers. This alternating pattern can drastically improve " -"steep overhang." +"steep overhangs.\n" +"\n" +"This setting can also help reduce part warping due to the reduction of " +"stresses in the part walls." +msgstr "" + +msgid "Reverse only internal perimeters" +msgstr "" + +msgid "" +"Apply the reverse perimeters logic only on internal perimeters. \n" +"\n" +"This setting greatly reduces part stresses as they are now distributed in " +"alternating directions. This should reduce part warping while also " +"maintaining external wall quality. This feature can be very useful for warp " +"prone material, like ABS/ASA, and also for elastic filaments, like TPU and " +"Silk PLA. It can also help reduce warping on floating regions over " +"supports.\n" +"\n" +"For this setting to be the most effective, it is recomended to set the " +"Reverse Threshold to 0 so that all internal walls print in alternating " +"directions on odd layers irrespective of their overhang degree." msgstr "" -"在奇數層上以相反方向列印懸空部位。 這種交替模式的可以大大改善陡峭的懸空列印品" -"質。" msgid "Reverse threshold" msgstr "反轉臨界值" @@ -8158,6 +8367,14 @@ msgstr "結尾 G-code" msgid "End G-code when finish the whole printing" msgstr "所有列印結束時的結尾 G-code" +msgid "Between Object Gcode" +msgstr "" + +msgid "" +"Insert Gcode between objects. This parameter will only come into effect when " +"you print your models object by object" +msgstr "" + #, fuzzy msgid "End G-code when finish the printing of this filament" msgstr "結束使用該耗材列印時的結尾 G-code" @@ -8247,26 +8464,26 @@ msgid "" "This sets the threshold for small perimeter length. Default threshold is 0mm" msgstr "這設定了微小部位周長的臨界值。 預設臨界值是 0mm" -msgid "Order of inner wall/outer wall/infil" -msgstr "內牆/外牆/填充的順序" +msgid "Order of walls" +msgstr "" -msgid "Print sequence of inner wall, outer wall and infill. " -msgstr "內圈牆/外圈牆/填充的列印順序" +msgid "Print sequence of inner wall and outer wall. " +msgstr "" -msgid "inner/outer/infill" -msgstr "內牆/外牆/填充" +msgid "inner/outer" +msgstr "" -msgid "outer/inner/infill" -msgstr "外牆/內牆/填充" +msgid "outer/inner" +msgstr "" -msgid "infill/inner/outer" -msgstr "填充/內牆/外牆" +msgid "inner wall/outer wall/inner wall" +msgstr "" -msgid "infill/outer/inner" -msgstr "填充/外牆/內牆" +msgid "Print infill first" +msgstr "" -msgid "inner-outer-inner/infill" -msgstr "內牆/外牆/內牆/填充" +msgid "Order of wall/infill. false means print wall first. " +msgstr "" msgid "Height to rod" msgstr "到橫杆高度" @@ -8362,9 +8579,6 @@ msgstr "預設顏色" msgid "Default filament color" msgstr "預設線材顏色" -msgid "Color" -msgstr "顏色" - msgid "Filament notes" msgstr "線材備註" @@ -8773,10 +8987,6 @@ msgid "" "Klipper's max_accel_to_decel will be adjusted to this %% of acceleration" msgstr "Klipper 的最大煞車速度將調整為加速度的 %%" -#, c-format, boost-format -msgid "%%" -msgstr "" - msgid "Jerk of outer walls" msgstr "外牆抖動值" @@ -8842,10 +9052,10 @@ msgstr "滿速風扇在" msgid "" "Fan speed will be ramped up linearly from zero at layer " -"\"close_fan_the_first_x_layers\" to maximum at layer \"full_fan_speed_layer" -"\". \"full_fan_speed_layer\" will be ignored if lower than " -"\"close_fan_the_first_x_layers\", in which case the fan will be running at " -"maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." +"\"close_fan_the_first_x_layers\" to maximum at layer " +"\"full_fan_speed_layer\". \"full_fan_speed_layer\" will be ignored if lower " +"than \"close_fan_the_first_x_layers\", in which case the fan will be running " +"at maximum allowed speed at layer \"close_fan_the_first_x_layers\" + 1." msgstr "" "風扇速度將從“禁用第一層”的零線性上升到“全風扇速度層”的最大。如果低於“禁用風扇" "第一層”,則“全風扇速度第一層”將被忽略,在這種情況下,風扇將在“禁用風扇第一" @@ -9157,6 +9367,18 @@ msgstr "" "強制在相鄰材料/體積之間產生實體殼。 適用於使用半透明材料或手動可溶支撐材料的" "多擠出機列印" +msgid "Maximum width of a segmented region" +msgstr "" + +msgid "Maximum width of a segmented region. Zero disables this feature." +msgstr "" + +msgid "Interlocking depth of a segmented region" +msgstr "" + +msgid "Interlocking depth of a segmented region. Zero disables this feature." +msgstr "" + msgid "Ironing Type" msgstr "熨燙類型" @@ -9718,6 +9940,22 @@ msgstr "" "回抽完成之後,噴嘴輕微抬升,和列印物件之間產生一定間隙。這能夠避免空駛時噴嘴" "和列印物件剮蹭和碰撞。使用螺旋線抬升z能夠減少拉絲。" +msgid "Z hop lower boundary" +msgstr "" + +msgid "" +"Z hop will only come into effect when Z is above this value and is below the " +"parameter: \"Z hop upper boundary\"" +msgstr "" + +msgid "Z hop upper boundary" +msgstr "" + +msgid "" +"If this value is positive, Z hop will only come into effect when Z is above " +"the parameter: \"Z hop lower boundary\" and is below this value" +msgstr "" + msgid "Z hop type" msgstr "抬Z類型" @@ -10133,6 +10371,12 @@ msgid "" "filament for support and current filament is used" msgstr "列印支撐主體和筏層的線材。\"預設\"代表不指定特定的線材,並使用目前線材" +msgid "No interface filament for body" +msgstr "" + +msgid "Don't use support interface filament to print support body" +msgstr "" + msgid "" "Line width of support. If expressed as a %, it will be computed over the " "nozzle diameter." @@ -10163,6 +10407,12 @@ msgstr "頂部接觸面層數" msgid "Bottom interface layers" msgstr "底部接觸面層數" +msgid "Number of bottom interface layers" +msgstr "" + +msgid "Same as top" +msgstr "" + msgid "Top interface spacing" msgstr "頂部接觸面線距" @@ -10822,82 +11072,12 @@ msgstr "線寬過大" msgid " not in range " msgstr " 不在合理的區間" -#, fuzzy -msgid "Export 3MF" -msgstr "匯出 3MF" - -#, fuzzy -msgid "Export project as 3MF." -msgstr "匯出項目為 3MF。" - -#, fuzzy -msgid "Export slicing data" -msgstr "匯出切片資料" - -#, fuzzy -msgid "Export slicing data to a folder." -msgstr "匯出切片資料到資料夾" - -#, fuzzy -msgid "Load slicing data" -msgstr "匯入切片資料" - -#, fuzzy -msgid "Load cached slicing data from directory" -msgstr "從目錄匯入快取的切片資料" - -#, fuzzy -msgid "Export STL" -msgstr "匯出 STL 檔案" - -#, fuzzy -msgid "Export the objects as multiple STL." -msgstr "將物件匯出為多個 STL 檔案" - -msgid "Slice" -msgstr "切片" - -msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" -msgstr "切片平台:0-所有平台,i-第i個平台,其他-無效" - -msgid "Show command help." -msgstr "顯示命令行幫助。" - -msgid "UpToDate" -msgstr "" - -#, fuzzy -msgid "Update the configs values of 3mf to latest." -msgstr "將 3mf 的設定值更新為最新值。" - -#, fuzzy -msgid "Load default filaments" -msgstr "載入預設列印線材" - -#, fuzzy -msgid "Load first filament as default for those not loaded" -msgstr "載入第一個列印線材為預設線材" - msgid "Minimum save" msgstr "" msgid "export 3mf with minimum size." msgstr "匯出最小尺寸的 3mf。" -msgid "mtcpp" -msgstr "" - -#, fuzzy -msgid "max triangle count per plate for slicing." -msgstr "切片時每個列印板的最大三角形數。" - -msgid "mstpp" -msgstr "" - -#, fuzzy -msgid "max slicing time per plate in seconds." -msgstr "每個列印板的最大切片時間(秒)。" - msgid "No check" msgstr "不檢查" @@ -10905,44 +11085,6 @@ msgstr "不檢查" msgid "Do not run any validity checks, such as gcode path conflicts check." msgstr "不要執行任何有效性檢查,如 G-code 路徑衝突檢查。" -msgid "Normative check" -msgstr "規範性檢查" - -msgid "Check the normative items." -msgstr "檢查規範性項目。" - -msgid "Output Model Info" -msgstr "輸出模型資訊" - -msgid "Output the model's information." -msgstr "輸出模型的資訊。" - -#, fuzzy -msgid "Export Settings" -msgstr "匯出設定" - -#, fuzzy -msgid "Export settings to a file." -msgstr "匯出設定檔到檔案。" - -msgid "Send progress to pipe" -msgstr "將進度傳送到管道" - -msgid "Send progress to pipe." -msgstr "將進度傳送到管道。" - -msgid "Arrange Options" -msgstr "擺放選項" - -msgid "Arrange options: 0-disable, 1-enable, others-auto" -msgstr "擺放選項:0-關閉,1-開啟,其他-自動" - -msgid "Repetions count" -msgstr "重複次數" - -msgid "Repetions count of the whole model" -msgstr "整個模型的重複次數" - msgid "Ensure on bed" msgstr "確認在列印板上" @@ -10950,12 +11092,6 @@ msgid "" "Lift the object above the bed when it is partially below. Disabled by default" msgstr "當物件部分位於列印板的下方時,將其提升到列印板的上方。預設情況下禁用" -msgid "Convert Unit" -msgstr "轉換單位" - -msgid "Convert the units of model" -msgstr "轉換模型的單位" - msgid "Orient Options" msgstr "" @@ -10965,53 +11101,12 @@ msgstr "" msgid "Rotation angle around the Z axis in degrees." msgstr "繞 Z 軸的旋轉角度(以度為單位)。" -msgid "Rotate around X" -msgstr "繞 X 旋轉" - -msgid "Rotation angle around the X axis in degrees." -msgstr "繞 X 軸的旋轉角度(以度為單位)。" - msgid "Rotate around Y" msgstr "繞 Y 旋轉" msgid "Rotation angle around the Y axis in degrees." msgstr "繞 Y 軸的旋轉角度(以度為單位)" -msgid "Scale the model by a float factor" -msgstr "根據因子縮放模型" - -#, fuzzy -msgid "Load General Settings" -msgstr "載入一般設定" - -#, fuzzy -msgid "Load process/machine settings from the specified file" -msgstr "從指定檔案載入列印參數/設備設定" - -#, fuzzy -msgid "Load Filament Settings" -msgstr "載入線材設定" - -#, fuzzy -msgid "Load filament settings from the specified file list" -msgstr "從指定檔案清單載入線材設定" - -msgid "Skip Objects" -msgstr "零件跳過" - -msgid "Skip some objects in this print" -msgstr "列印過程中跳過一些零件" - -#, fuzzy -msgid "load uptodate process/machine settings when using uptodate" -msgstr "使用最新設定時載入最新的列印參數/設備設定" - -#, fuzzy -msgid "" -"load uptodate process/machine settings from the specified file when using " -"uptodate" -msgstr "使用最新設定時,從指定的檔案清單中載入最新的列印參數/設備設定。" - #, fuzzy msgid "Data directory" msgstr "檔案路徑" @@ -11025,23 +11120,6 @@ msgstr "" "指定目錄用以載入或儲存設定檔。 這對於維護不同的設定檔或包含來自網路儲存的設定" "檔非常有用。" -msgid "Output directory" -msgstr "輸出路徑" - -msgid "Output directory for the exported files." -msgstr "匯出檔案的輸出路徑。" - -msgid "Debug level" -msgstr "除錯等級" - -#, fuzzy -msgid "" -"Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" -msgstr "" -"設定除錯日誌等級。0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" -"trace\n" - msgid "Load custom gcode" msgstr "載入自訂 G-code" @@ -11209,9 +11287,6 @@ msgstr "校準" msgid "Finish" msgstr "完成" -msgid "Wiki" -msgstr "Wiki" - msgid "How to use calibration result?" msgstr "如何使用校準結果?" @@ -11230,6 +11305,12 @@ msgstr "" msgid "Calibration not supported" msgstr "不支援校準" +msgid "Error desc" +msgstr "錯誤描述" + +msgid "Extra info" +msgstr "額外資訊" + msgid "Flow Dynamics" msgstr "動態流量" @@ -11263,9 +11344,9 @@ msgstr "" msgid "The name cannot be empty." msgstr "名稱不能為空。" -#, fuzzy, boost-format -msgid "The selected preset: %1% is not found." -msgstr "未找到選定的預設值:%1%。" +#, c-format, boost-format +msgid "The selected preset: %s is not found." +msgstr "" #, fuzzy msgid "The name cannot be the same as the system preset name." @@ -11611,12 +11692,6 @@ msgstr "" "-可以共享相同熱床溫度的線材\n" "-不同的線材品牌和系列(Brand = Bambu, Family = Basic, Matte)" -msgid "Error desc" -msgstr "錯誤描述" - -msgid "Extra info" -msgstr "額外資訊" - msgid "Pattern" msgstr "" @@ -11707,105 +11782,6 @@ msgid "" "Please select one that should be used." msgstr "" -#, fuzzy -msgid "Unable to perform boolean operation on selected parts" -msgstr "無法對所選零件執行布林運算" - -#, fuzzy -msgid "Mesh Boolean" -msgstr "布林運算" - -msgid "Union" -msgstr "併集" - -msgid "Difference" -msgstr "差集" - -msgid "Intersection" -msgstr "交集" - -msgid "Source Volume" -msgstr "" - -msgid "Tool Volume" -msgstr "" - -msgid "Subtract from" -msgstr "從中減去" - -msgid "Subtract with" -msgstr "與之相減" - -msgid "selected" -msgstr "已選取" - -msgid "Part 1" -msgstr "零件 1" - -msgid "Part 2" -msgstr "零件 2" - -msgid "Delete input" -msgstr "刪除輸入" - -#, fuzzy -msgid "Send G-Code to printer host" -msgstr "傳送 G-code 到列印設備" - -msgid "Upload to Printer Host with the following filename:" -msgstr "使用下列檔案名上傳到列印設備:" - -msgid "Use forward slashes ( / ) as a directory separator if needed." -msgstr "如有需要,請使用正斜槓( / )作為目錄分隔符號。" - -msgid "Upload to storage" -msgstr "上傳到儲存單位" - -#, fuzzy, c-format, boost-format -msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" -msgstr "上傳的檔名不以 \"%s\" 結尾。確定要繼續嗎?" - -msgid "Upload" -msgstr "上傳" - -msgid "Print host upload queue" -msgstr "列印主機上傳隊列" - -msgid "ID" -msgstr "" - -msgid "Progress" -msgstr "" - -msgid "Host" -msgstr "主機" - -msgctxt "OfFile" -msgid "Size" -msgstr "尺寸" - -msgid "Filename" -msgstr "檔案名" - -msgid "Cancel selected" -msgstr "取消選取" - -msgid "Show error message" -msgstr "顯示錯誤資訊" - -msgid "Enqueued" -msgstr "已加入隊列" - -msgid "Uploading" -msgstr "正在上傳" - -msgid "Cancelling" -msgstr "取消中" - -#, fuzzy -msgid "Error uploading to print host" -msgstr "上傳到列印設備時發生錯誤" - msgid "PA Calibration" msgstr "PA校準" @@ -11950,74 +11926,110 @@ msgid "mm/mm" msgstr "" #, fuzzy -msgid "Physical Printer" -msgstr "實體列印設備" +msgid "Send G-Code to printer host" +msgstr "傳送 G-code 到列印設備" -msgid "Print Host upload" -msgstr "" +msgid "Upload to Printer Host with the following filename:" +msgstr "使用下列檔案名上傳到列印設備:" -msgid "Test" -msgstr "測試" +msgid "Use forward slashes ( / ) as a directory separator if needed." +msgstr "如有需要,請使用正斜槓( / )作為目錄分隔符號。" + +msgid "Upload to storage" +msgstr "上傳到儲存單位" + +#, fuzzy, c-format, boost-format +msgid "Upload filename doesn't end with \"%s\". Do you wish to continue?" +msgstr "上傳的檔名不以 \"%s\" 結尾。確定要繼續嗎?" -msgid "Could not get a valid Printer Host reference" +msgid "Upload" +msgstr "上傳" + +msgid "Print host upload queue" +msgstr "列印主機上傳隊列" + +msgid "ID" msgstr "" -msgid "Success!" -msgstr "成功!" +msgid "Progress" +msgstr "" + +msgid "Host" +msgstr "主機" + +msgctxt "OfFile" +msgid "Size" +msgstr "尺寸" + +msgid "Filename" +msgstr "檔案名" + +msgid "Cancel selected" +msgstr "取消選取" + +msgid "Show error message" +msgstr "顯示錯誤資訊" + +msgid "Enqueued" +msgstr "已加入隊列" + +msgid "Uploading" +msgstr "正在上傳" + +msgid "Cancelling" +msgstr "取消中" #, fuzzy -msgid "Refresh Printers" -msgstr "重新整理列印設備" +msgid "Error uploading to print host" +msgstr "上傳到列印設備時發生錯誤" #, fuzzy -msgid "" -"HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" -"signed certificate." -msgstr "" -"HTTPS CA 憑證檔案是可選的。 僅當您使用具有自帶簽名憑證的 HTTPS 時才需要它。" +msgid "Unable to perform boolean operation on selected parts" +msgstr "無法對所選零件執行布林運算" #, fuzzy -msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" -msgstr "憑證檔(*.crt, *.pem)|*.crt;*.pem|All files|*.*" +msgid "Mesh Boolean" +msgstr "布林運算" -msgid "Open CA certificate file" -msgstr "開啟 CA憑證檔" +msgid "Union" +msgstr "併集" -#, fuzzy, c-format, boost-format -msgid "" -"On this system, %s uses HTTPS certificates from the system Certificate Store " -"or Keychain." -msgstr "在此系統上,%s 使用系統憑證儲存庫或鑰匙圈中的 HTTPS 憑證。" +msgid "Difference" +msgstr "差集" -msgid "" -"To use a custom CA file, please import your CA file into Certificate Store / " -"Keychain." -msgstr "若要使用自訂 CA 憑證檔,請將您的 CA 憑證檔匯入到憑證儲存庫/鑰匙圈中。" +msgid "Intersection" +msgstr "交集" -msgid "Connection to printers connected via the print host failed." +msgid "Source Volume" msgstr "" -msgid "The start, end or step is not valid value." -msgstr "開始、結束或步距不是有效值。" +msgid "Tool Volume" +msgstr "" -msgid "" -"Unable to calibrate: maybe because the set calibration value range is too " -"large, or the step is too small" -msgstr "無法校準:可能是設定的校準值範圍太大,或步距太小" +msgid "Subtract from" +msgstr "從中減去" -#, fuzzy -msgid "Need select printer" -msgstr "需要選擇列印設備" +msgid "Subtract with" +msgstr "與之相減" -#: resources/data/hints.ini: [hint:3D Scene Operations] -#, fuzzy +msgid "selected" +msgstr "已選取" + +msgid "Part 1" +msgstr "零件 1" + +msgid "Part 2" +msgstr "零件 2" + +msgid "Delete input" +msgstr "刪除輸入" + +#: resources/data/hints.ini: [hint:How to use keyboard shortcuts] msgid "" -"3D Scene Operations\n" -"Did you know how to control view and object/part selection with mouse and " -"touchpanel in the 3D scene?" +"How to use keyboard shortcuts\n" +"Did you know that Orca Slicer offers a wide range of keyboard shortcuts and " +"3D scene operations." msgstr "" -"3D 場景操作\n" -"如何在 3D 場景中使用滑鼠和觸碰面板進行視角控制和物件/零件選擇" #: resources/data/hints.ini: [hint:Cut Tool] msgid "" @@ -12029,14 +12041,11 @@ msgstr "" "您知道嗎?您可以使用切割工具以任何角度和位置切割模型。" #: resources/data/hints.ini: [hint:Fix Model] -#, fuzzy msgid "" "Fix Model\n" "Did you know that you can fix a corrupted 3D model to avoid a lot of slicing " -"problems?" +"problems on the Windows system?" msgstr "" -"修復模型\n" -"您知道嗎?您可以修復一個損壞的 3D 模型以避免諸多切片問題。" #: resources/data/hints.ini: [hint:Timelapse] msgid "" @@ -12088,6 +12097,13 @@ msgstr "" "您知道物件清單嗎?您可以在其中的查看所有物件/零件,並更改每個物件/零件的設" "定。" +#: resources/data/hints.ini: [hint:Search Functionality] +msgid "" +"Search Functionality\n" +"Did you know that you use the Search tool to quickly find a specific Orca " +"Slicer setting?" +msgstr "" + #: resources/data/hints.ini: [hint:Simplify Model] msgid "" "Simplify Model\n" @@ -12271,16 +12287,375 @@ msgstr "" #: resources/data/hints.ini: [hint:When need to print with the printer door #: opened] -#, fuzzy msgid "" "When need to print with the printer door opened\n" -"Opening the printer door can reduce the probability of extruder/hotend " -"clogging when printing lower temperature filament with a higher enclosure " -"temperature. More info about this in the Wiki." +"Did you know that opening the printer door can reduce the probability of " +"extruder/hotend clogging when printing lower temperature filament with a " +"higher enclosure temperature. More info about this in the Wiki." +msgstr "" + +#: resources/data/hints.ini: [hint:Avoid warping] +msgid "" +"Avoid warping\n" +"Did you know that when printing materials that are prone to warping such as " +"ABS, appropriately increasing the heatbed temperature can reduce the " +"probability of warping." msgstr "" -"當需要打開印表機門進行列印時\n" -"當列印較低溫度的耗材時,打開印表機門可以減少擠出機或熱端堵塞的可能性。 有關此" -"內容的更多信息,請參見 Wiki。" + +#~ msgid "Ctrl + Shift + Enter" +#~ msgstr "Ctrl + Shift + Enter" + +#~ msgid "Tool-Lay on Face" +#~ msgstr "工具-選擇底面" + +#~ msgid "Export as STL" +#~ msgstr "匯出為 STL" + +#~ msgid "Check cloud service status" +#~ msgstr "檢查雲端服務狀態" + +#, fuzzy +#~ msgid "Please input a valid value (K in 0~0.5)" +#~ msgstr "請輸入有效的數值(K 值的範圍為 0~0.5)" + +#, fuzzy +#~ msgid "Please input a valid value (K in 0~0.5, N in 0.6~2.0)" +#~ msgstr "請輸入有效的數值(K 值的範圍為 0~0.5, N 值的範圍為 0.6~2.0)" + +#, fuzzy +#~ msgid "Export all objects as STL" +#~ msgstr "匯出所有物件為 STL" + +#~ msgid "Slice ok." +#~ msgstr "切片完成." + +#, fuzzy, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Found following keys " +#~ "unrecognized:" +#~ msgstr "該 3mf 的版本 %s 比 %s 的版本 %s 新,發現以下參數值無法識別:" + +#~ msgid "You'd better upgrade your software.\n" +#~ msgstr "建議升級您的軟體版本。\n" + +#, fuzzy, c-format, boost-format +#~ msgid "" +#~ "The 3mf's version %s is newer than %s's version %s, Suggest to upgrade " +#~ "your software." +#~ msgstr "該 3mf 的版本 %s 比 %s 的版本 %s 要新,建議升級你的軟體。" + +#~ msgid "The 3mf is not compatible, load geometry data only!" +#~ msgstr "該 3mf 檔案與軟體不相容,將只載入幾何數據。" + +#~ msgid "Incompatible 3mf" +#~ msgstr "不相容的 3mf" + +#, fuzzy +#~ msgid "Add/Remove printers" +#~ msgstr "新增/刪除列印設備" + +#, fuzzy +#~ msgid "Bambu Engineering Plate" +#~ msgstr "Bambu 高溫工程列印板" + +#, fuzzy +#~ msgid "Bambu Smooth PEI Plate" +#~ msgstr "Bambu 光滑面列印板" + +#~ msgid "Bambu Textured PEI Plate" +#~ msgstr "Bambu 金屬紋理列印板" + +#, fuzzy +#~ msgid "" +#~ "When print by object, machines with I3 structure will not generate " +#~ "timelapse videos." +#~ msgstr "按物件列印時,龍門結構的設備不會產生縮時攝影影片" + +#, c-format, boost-format +#~ msgid "%s is not supported by AMS." +#~ msgstr "AMS 不支援 %s 。" + +#, fuzzy +#~ msgid "Don't remind me of this version again" +#~ msgstr "不要再提醒我這個版本" + +#~ msgid "Error: IP or Access Code are not correct" +#~ msgstr "錯誤:IP 或訪問碼不正確" + +#~ msgid "" +#~ "Extrude perimeters that have a part over an overhang in the reverse " +#~ "direction on odd layers. This alternating pattern can drastically improve " +#~ "steep overhang." +#~ msgstr "" +#~ "在奇數層上以相反方向列印懸空部位。 這種交替模式的可以大大改善陡峭的懸空列" +#~ "印品質。" + +#~ msgid "Order of inner wall/outer wall/infil" +#~ msgstr "內牆/外牆/填充的順序" + +#~ msgid "Print sequence of inner wall, outer wall and infill. " +#~ msgstr "內圈牆/外圈牆/填充的列印順序" + +#~ msgid "inner/outer/infill" +#~ msgstr "內牆/外牆/填充" + +#~ msgid "outer/inner/infill" +#~ msgstr "外牆/內牆/填充" + +#~ msgid "infill/inner/outer" +#~ msgstr "填充/內牆/外牆" + +#~ msgid "infill/outer/inner" +#~ msgstr "填充/外牆/內牆" + +#~ msgid "inner-outer-inner/infill" +#~ msgstr "內牆/外牆/內牆/填充" + +#, fuzzy +#~ msgid "Export 3MF" +#~ msgstr "匯出 3MF" + +#, fuzzy +#~ msgid "Export project as 3MF." +#~ msgstr "匯出項目為 3MF。" + +#, fuzzy +#~ msgid "Export slicing data" +#~ msgstr "匯出切片資料" + +#, fuzzy +#~ msgid "Export slicing data to a folder." +#~ msgstr "匯出切片資料到資料夾" + +#, fuzzy +#~ msgid "Load slicing data" +#~ msgstr "匯入切片資料" + +#, fuzzy +#~ msgid "Load cached slicing data from directory" +#~ msgstr "從目錄匯入快取的切片資料" + +#, fuzzy +#~ msgid "Export STL" +#~ msgstr "匯出 STL 檔案" + +#, fuzzy +#~ msgid "Export the objects as multiple STL." +#~ msgstr "將物件匯出為多個 STL 檔案" + +#~ msgid "Slice" +#~ msgstr "切片" + +#~ msgid "Slice the plates: 0-all plates, i-plate i, others-invalid" +#~ msgstr "切片平台:0-所有平台,i-第i個平台,其他-無效" + +#~ msgid "Show command help." +#~ msgstr "顯示命令行幫助。" + +#, fuzzy +#~ msgid "Update the configs values of 3mf to latest." +#~ msgstr "將 3mf 的設定值更新為最新值。" + +#, fuzzy +#~ msgid "Load default filaments" +#~ msgstr "載入預設列印線材" + +#, fuzzy +#~ msgid "Load first filament as default for those not loaded" +#~ msgstr "載入第一個列印線材為預設線材" + +#, fuzzy +#~ msgid "max triangle count per plate for slicing." +#~ msgstr "切片時每個列印板的最大三角形數。" + +#, fuzzy +#~ msgid "max slicing time per plate in seconds." +#~ msgstr "每個列印板的最大切片時間(秒)。" + +#~ msgid "Normative check" +#~ msgstr "規範性檢查" + +#~ msgid "Check the normative items." +#~ msgstr "檢查規範性項目。" + +#~ msgid "Output Model Info" +#~ msgstr "輸出模型資訊" + +#~ msgid "Output the model's information." +#~ msgstr "輸出模型的資訊。" + +#, fuzzy +#~ msgid "Export Settings" +#~ msgstr "匯出設定" + +#, fuzzy +#~ msgid "Export settings to a file." +#~ msgstr "匯出設定檔到檔案。" + +#~ msgid "Send progress to pipe" +#~ msgstr "將進度傳送到管道" + +#~ msgid "Send progress to pipe." +#~ msgstr "將進度傳送到管道。" + +#~ msgid "Arrange Options" +#~ msgstr "擺放選項" + +#~ msgid "Arrange options: 0-disable, 1-enable, others-auto" +#~ msgstr "擺放選項:0-關閉,1-開啟,其他-自動" + +#~ msgid "Repetions count" +#~ msgstr "重複次數" + +#~ msgid "Repetions count of the whole model" +#~ msgstr "整個模型的重複次數" + +#~ msgid "Convert Unit" +#~ msgstr "轉換單位" + +#~ msgid "Convert the units of model" +#~ msgstr "轉換模型的單位" + +#~ msgid "Rotate around X" +#~ msgstr "繞 X 旋轉" + +#~ msgid "Rotation angle around the X axis in degrees." +#~ msgstr "繞 X 軸的旋轉角度(以度為單位)。" + +#~ msgid "Scale the model by a float factor" +#~ msgstr "根據因子縮放模型" + +#, fuzzy +#~ msgid "Load General Settings" +#~ msgstr "載入一般設定" + +#, fuzzy +#~ msgid "Load process/machine settings from the specified file" +#~ msgstr "從指定檔案載入列印參數/設備設定" + +#, fuzzy +#~ msgid "Load Filament Settings" +#~ msgstr "載入線材設定" + +#, fuzzy +#~ msgid "Load filament settings from the specified file list" +#~ msgstr "從指定檔案清單載入線材設定" + +#~ msgid "Skip Objects" +#~ msgstr "零件跳過" + +#~ msgid "Skip some objects in this print" +#~ msgstr "列印過程中跳過一些零件" + +#, fuzzy +#~ msgid "load uptodate process/machine settings when using uptodate" +#~ msgstr "使用最新設定時載入最新的列印參數/設備設定" + +#, fuzzy +#~ msgid "" +#~ "load uptodate process/machine settings from the specified file when using " +#~ "uptodate" +#~ msgstr "使用最新設定時,從指定的檔案清單中載入最新的列印參數/設備設定。" + +#~ msgid "Output directory" +#~ msgstr "輸出路徑" + +#~ msgid "Output directory for the exported files." +#~ msgstr "匯出檔案的輸出路徑。" + +#~ msgid "Debug level" +#~ msgstr "除錯等級" + +#, fuzzy +#~ msgid "" +#~ "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:" +#~ "trace\n" +#~ msgstr "" +#~ "設定除錯日誌等級。0:fatal, 1:error, 2:warning, 3:info, 4:debug, " +#~ "5:trace\n" + +#, fuzzy, boost-format +#~ msgid "The selected preset: %1% is not found." +#~ msgstr "未找到選定的預設值:%1%。" + +#, fuzzy +#~ msgid "Physical Printer" +#~ msgstr "實體列印設備" + +#~ msgid "Success!" +#~ msgstr "成功!" + +#, fuzzy +#~ msgid "Refresh Printers" +#~ msgstr "重新整理列印設備" + +#, fuzzy +#~ msgid "" +#~ "HTTPS CA file is optional. It is only needed if you use HTTPS with a self-" +#~ "signed certificate." +#~ msgstr "" +#~ "HTTPS CA 憑證檔案是可選的。 僅當您使用具有自帶簽名憑證的 HTTPS 時才需要" +#~ "它。" + +#, fuzzy +#~ msgid "Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*" +#~ msgstr "憑證檔(*.crt, *.pem)|*.crt;*.pem|All files|*.*" + +#~ msgid "Open CA certificate file" +#~ msgstr "開啟 CA憑證檔" + +#, fuzzy, c-format, boost-format +#~ msgid "" +#~ "On this system, %s uses HTTPS certificates from the system Certificate " +#~ "Store or Keychain." +#~ msgstr "在此系統上,%s 使用系統憑證儲存庫或鑰匙圈中的 HTTPS 憑證。" + +#~ msgid "" +#~ "To use a custom CA file, please import your CA file into Certificate " +#~ "Store / Keychain." +#~ msgstr "" +#~ "若要使用自訂 CA 憑證檔,請將您的 CA 憑證檔匯入到憑證儲存庫/鑰匙圈中。" + +#~ msgid "The start, end or step is not valid value." +#~ msgstr "開始、結束或步距不是有效值。" + +#~ msgid "" +#~ "Unable to calibrate: maybe because the set calibration value range is too " +#~ "large, or the step is too small" +#~ msgstr "無法校準:可能是設定的校準值範圍太大,或步距太小" + +#, fuzzy +#~ msgid "Need select printer" +#~ msgstr "需要選擇列印設備" + +#, fuzzy +#~ msgid "" +#~ "3D Scene Operations\n" +#~ "Did you know how to control view and object/part selection with mouse and " +#~ "touchpanel in the 3D scene?" +#~ msgstr "" +#~ "3D 場景操作\n" +#~ "如何在 3D 場景中使用滑鼠和觸碰面板進行視角控制和物件/零件選擇" + +#, fuzzy +#~ msgid "" +#~ "Fix Model\n" +#~ "Did you know that you can fix a corrupted 3D model to avoid a lot of " +#~ "slicing problems?" +#~ msgstr "" +#~ "修復模型\n" +#~ "您知道嗎?您可以修復一個損壞的 3D 模型以避免諸多切片問題。" + +#, fuzzy +#~ msgid "" +#~ "When need to print with the printer door opened\n" +#~ "Opening the printer door can reduce the probability of extruder/hotend " +#~ "clogging when printing lower temperature filament with a higher enclosure " +#~ "temperature. More info about this in the Wiki." +#~ msgstr "" +#~ "當需要打開印表機門進行列印時\n" +#~ "當列印較低溫度的耗材時,打開印表機門可以減少擠出機或熱端堵塞的可能性。 有" +#~ "關此內容的更多信息,請參見 Wiki。" #~ msgid "Embeded" #~ msgstr "嵌入的" @@ -12404,9 +12779,6 @@ msgstr "" #~ msgid "Score" #~ msgstr "打分" -#~ msgid "Bamabu Engineering Plate" -#~ msgstr "工程列印熱床" - #~ msgid "Bamabu High Temperature Plate" #~ msgstr "高溫列印熱床" diff --git a/resources/config.json b/resources/config.json deleted file mode 100644 index ebd7145769e..00000000000 --- a/resources/config.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "printers": [ - { - "display_name": "Bambu Lab P1P", - "func": { - "FUNC_CHAMBER_TEMP": false, - "FUNC_FIRSTLAYER_INSPECT": false, - "FUNC_AI_MONITORING": true, - "FUNC_LIDAR_CALIBRATION": false, - "FUNC_BUILDPLATE_MARKER_DETECT": false, - "FUNC_FLOW_CALIBRATION": false, - "FUNC_MONITORING": false, - "FUNC_MEDIA_FILE": false, - "FUNC_VIRTUAL_CAMERA": false, - "FUNC_PRINT_WITHOUT_SD": false, - "FUNC_ALTER_RESOLUTION": false, - "FUNC_PRINT_ALL": false, - "FUNC_EXTRUSION_CALI": true, - "FUNC_MOTOR_NOISE_CALI": false, - "FUNC_PROMPT_SOUND": false, - "FUNC_VIRTUAL_TYAY": true - }, - "camera_resolution": [ "720p" ], - "bed_temperature_limit": 100, - "model_id": "C11", - "printer_type": "C11", - "compatible_machine": [ "BL-P001", "BL-P002", "C12", "C13"], - "ftp_folder": "sdcard/", - "printer_thumbnail_image": "printer_thumbnail_p1p" - }, - { - "display_name": "Bambu Lab P1S", - "func": { - "FUNC_CHAMBER_TEMP": false, - "FUNC_FIRSTLAYER_INSPECT": false, - "FUNC_AI_MONITORING": true, - "FUNC_LIDAR_CALIBRATION": false, - "FUNC_BUILDPLATE_MARKER_DETECT": false, - "FUNC_FLOW_CALIBRATION": false, - "FUNC_MONITORING": false, - "FUNC_MEDIA_FILE": false, - "FUNC_VIRTUAL_CAMERA": false, - "FUNC_PRINT_WITHOUT_SD": false, - "FUNC_ALTER_RESOLUTION": false, - "FUNC_PRINT_ALL": false, - "FUNC_MOTOR_NOISE_CALI": false, - "FUNC_PROMPT_SOUND": false, - "FUNC_VIRTUAL_TYAY": true - }, - "camera_resolution": [ "720p" ], - "bed_temperature_limit": 100, - "model_id": "C12", - "compatible_machine":["BL-P001", "BL-P002", "C11", "C13"], - "printer_type": "C12", - "ftp_folder" : "sdcard/", - "printer_thumbnail_image": "printer_thumbnail_p1p" - }, - { - "display_name": "Bambu Lab A1 mini", - "func": { - "FUNC_CHAMBER_TEMP": false, - "FUNC_FIRSTLAYER_INSPECT": false, - "FUNC_AI_MONITORING": false, - "FUNC_BUILDPLATE_MARKER_DETECT": false, - "FUNC_FLOW_CALIBRATION": true, - "FUNC_MONITORING": false, - "FUNC_MEDIA_FILE": false, - "FUNC_VIRTUAL_CAMERA": false, - "FUNC_PRINT_WITHOUT_SD": false, - "FUNC_ALTER_RESOLUTION": true, - "FUNC_CHAMBER_FAN": false, - "FUNC_AUX_FAN": false, - "FUNC_UPDATE_REMAIN": false, - "FUNC_EXTRUSION_CALI": false, - "FUNC_AUTO_LEVELING": true - }, - "printer_arch" : "i3", - "camera_resolution": [ "720p" ], - "bed_temperature_limit": 100, - "model_id": "N1", - "compatible_machine":[], - "printer_type": "N1", - "ftp_folder" : "sdcard/", - "printer_thumbnail_image": "printer_thumbnail_n1" - }, - { - "display_name": "Bambu Lab X1", - "func": { - "FUNC_CHAMBER_TEMP": false, - "FUNC_VIRTUAL_TYAY": true, - "FUNC_EXTRUSION_CALI": false, - "FUNC_MOTOR_NOISE_CALI": false, - "FUNC_PROMPT_SOUND": false - }, - "model_id": "BL-P002", - "compatible_machine": [ "BL-P001", "C11", "C12", "C13"], - "camera_resolution": [ "720p", "1080p" ], - "printer_type": "3DPrinter-X1", - "printer_thumbnail_image": "printer_thumbnail" - }, - { - "display_name": "Bambu Lab X1E", - "func": { - "FUNC_MOTOR_NOISE_CALI": false, - "FUNC_PROMPT_SOUND": false - }, - "camera_resolution": [ "720p", "1080p" ], - "nozzle_max_temperature": 330, - "model_id": "C13", - "compatible_machine": [ "BL-P001", "BL-P002", "C11", "C12"], - "printer_type": "C13", - "printer_thumbnail_image": "printer_thumbnail" - }, - { - "display_name": "Bambu Lab X1 Carbon", - "func": { - "FUNC_CHAMBER_TEMP": false, - "FUNC_VIRTUAL_TYAY": true, - "FUNC_EXTRUSION_CALI": false, - "FUNC_LOCAL_TUNNEL": false, - "FUNC_MOTOR_NOISE_CALI": false, - "FUNC_PROMPT_SOUND": false - }, - "model_id": "BL-P001", - "compatible_machine": [ "BL-P002", "C11", "C12", "C13"], - "camera_resolution": [ "720p", "1080p" ], - "printer_type": "3DPrinter-X1-Carbon", - "printer_thumbnail_image": "printer_thumbnail" - } - ] -} diff --git a/resources/data/hints.ini b/resources/data/hints.ini index 6b1b9da695c..53315be6d01 100644 --- a/resources/data/hints.ini +++ b/resources/data/hints.ini @@ -62,111 +62,101 @@ # Weight must be larger or equal to 1. Default weight is 1. # Weight defines probability as weight : sum_of_all_weights. -[hint:3D Scene Operations] -text = 3D Scene Operations\nDid you know how to control view and object/part selection with mouse and touchpanel in the 3D scene? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/3d-scene-operations +[hint:How to use keyboard shortcuts] +text = How to use keyboard shortcuts\nDid you know that Orca Slicer offers a wide range of keyboard shortcuts and 3D scene operations. [hint:Cut Tool] text = Cut Tool\nDid you know that you can cut a model at any angle and position with the cutting tool? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/cut-tool +image = images/dailytips_CutTool.PNG [hint:Fix Model] -text = Fix Model\nDid you know that you can fix a corrupted 3D model to avoid a lot of slicing problems? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/fix-model +text = Fix Model\nDid you know that you can fix a corrupted 3D model to avoid a lot of slicing problems on the Windows system? [hint:Timelapse] text = Timelapse\nDid you know that you can generate a timelapse video during each print? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/Timelapse [hint:Auto-Arrange] text = Auto-Arrange\nDid you know that you can auto-arrange all objects in your project? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/auto-arranging +image = images/dailytips_AutoArrange.PNG [hint:Auto-Orient] text = Auto-Orient\nDid you know that you can rotate objects to an optimal orientation for printing by a simple click? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/auto-orientation [hint:Lay on Face] text = Lay on Face\nDid you know that you can quickly orient a model so that one of its faces sits on the print bed? Select the \"Place on face\" function or press the F key. -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/lay-on-face +image = images/dailytips_LayOnFace.PNG [hint:Object List] text = Object List\nDid you know that you can view all objects/parts in a list and change settings for each object/part? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/object-list +image = images/dailytips_ObjectList.PNG -#[hint:Search Functionality] -#text = Search Functionality\nDid you know that you use the Search tool to quickly find a specific Orca Slicer setting? Or use the familiar shortcut Ctrl+F. +[hint:Search Functionality] +text = Search Functionality\nDid you know that you use the Search tool to quickly find a specific Orca Slicer setting? [hint:Simplify Model] text = Simplify Model\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in the documentation. -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/simplify-model +image = images/dailytips_SimplifyModel.PNG [hint:Slicing Parameter Table] text = Slicing Parameter Table\nDid you know that you can view all objects/parts on a table and change settings for each object/part? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/parameter-table +image = images/dailytips_SlicingParamTable.PNG [hint:Split to Objects/Parts] text = Split to Objects/Parts\nDid you know that you can split a big object into small ones for easy colorizing or printing? -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/split-to-objects-parts [hint:Subtract a Part] text = Subtract a Part\nDid you know that you can subtract one mesh from another using the Negative part modifier? That way you can, for example, create easily resizable holes directly in Orca Slicer. Read more in the documentation. -documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/subtract-a-part +image = images/dailytips_SubtractPart.png [hint:STEP] text = STEP\nDid you know that you can improve your print quality by slicing a STEP file instead of an STL?\nOrca Slicer supports slicing STEP files, providing smoother results than a lower resolution STL. Give it a try! -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/step [hint:Z seam location] text = Z seam location\nDid you know that you can customize the location of the Z seam, and even paint it on your print, to have it in a less visible location? This improves the overall look of your model. Check it out! -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/Seam +image = images/dailytips_ZSeamLocation.png [hint:Fine-tuning for flow rate] text = Fine-tuning for flow rate\nDid you know that flow rate can be fine-tuned for even better-looking prints? Depending on the material, you can improve the overall finish of the printed model by doing some fine-tuning. -documentation_link= https://wiki.bambulab.com/en/x1/manual/manual-flow-rate-tuning [hint:Split your prints into plates] text = Split your prints into plates\nDid you know that you can split a model that has a lot of parts into individual plates ready to print? This will simplify the process of keeping track of all the parts. -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/plates_management +image = images/dailytips_SplitIntoPlates.png [hint:Speed up your print with Adaptive Layer Height] text = Speed up your print with Adaptive Layer Height\nDid you know that you can print a model even faster, by using the Adaptive Layer Height option? Check it out! -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/adaptive-layer-height [hint:Support painting] text = Support painting\nDid you know that you can paint the location of your supports? This feature makes it easy to place the support material only on the sections of the model that actually need it. -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/support-painting [hint:Different types of supports] text = Different types of supports\nDid you know that you can choose from multiple types of supports? Tree supports work great for organic models, while saving filament and improving print speed. Check them out! -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/support +image = images/dailytips_TypesOfSupports.png [hint:Printing Silk Filament] text = Printing Silk Filament\nDid you know that Silk filament needs special consideration to print it successfully? Higher temperature and lower speed are always recommended for the best results. -documentation_link= https://wiki.bambulab.com/en/x1/manual/printing-with-silk-filaments [hint:Brim for better adhesion] text = Brim for better adhesion\nDid you know that when printing models have a small contact interface with the printing surface, it's recommended to use a brim? -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/auto-brim +image = images/dailytips_Brim.png [hint:Set parameters for multiple objects] text = Set parameters for multiple objects\nDid you know that you can set slicing parameters for all selected objects at one time? -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/set-parameters-for-selected-objects [hint:Stack objects] text = Stack objects\nDid you know that you can stack objects as a whole one? -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/stacking-objects +image = images/dailytips_StackObject.png [hint:Flush into support/objects/infill] text = Flush into support/objects/infill\nDid you know that you can save the wasted filament by flushing them into support/objects/infill during filament change? -documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/reduce-wasting-during-filament-change [hint:Improve strength] text = Improve strength\nDid you know that you can use more wall loops and higher sparse infill density to improve the strength of the model? [hint:When need to print with the printer door opened] -text = When need to print with the printer door opened\nOpening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature. More info about this in the Wiki. -documentation_link= https://wiki.bambulab.com/en/filament-acc/filament/heat-creep +text = When need to print with the printer door opened\nDid you know that opening the printer door can reduce the probability of extruder/hotend clogging when printing lower temperature filament with a higher enclosure temperature. More info about this in the Wiki. + +[hint:Avoid warping] +text = Avoid warping\nDid you know that when printing materials that are prone to warping such as ABS, appropriately increasing the heatbed temperature can reduce the probability of warping. #[hint:] #text = diff --git a/resources/fonts/NotoSansKR-Bold.ttf b/resources/fonts/NotoSansKR-Bold.ttf new file mode 100644 index 00000000000..6cf639eb7d7 Binary files /dev/null and b/resources/fonts/NotoSansKR-Bold.ttf differ diff --git a/resources/fonts/NotoSansKR-Regular.ttf b/resources/fonts/NotoSansKR-Regular.ttf new file mode 100644 index 00000000000..1b14d32473b Binary files /dev/null and b/resources/fonts/NotoSansKR-Regular.ttf differ diff --git a/resources/images/confirm.svg b/resources/images/confirm.svg new file mode 100644 index 00000000000..31a82f6e99f --- /dev/null +++ b/resources/images/confirm.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/confirm_dark.svg b/resources/images/confirm_dark.svg new file mode 100644 index 00000000000..31a82f6e99f --- /dev/null +++ b/resources/images/confirm_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/create_success.svg b/resources/images/create_success.svg new file mode 100644 index 00000000000..242dc573278 --- /dev/null +++ b/resources/images/create_success.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/dailytips_AutoArrange.PNG b/resources/images/dailytips_AutoArrange.PNG new file mode 100644 index 00000000000..a8a33f19323 Binary files /dev/null and b/resources/images/dailytips_AutoArrange.PNG differ diff --git a/resources/images/dailytips_Brim.png b/resources/images/dailytips_Brim.png new file mode 100644 index 00000000000..547364087cc Binary files /dev/null and b/resources/images/dailytips_Brim.png differ diff --git a/resources/images/dailytips_CutTool.PNG b/resources/images/dailytips_CutTool.PNG new file mode 100644 index 00000000000..2f42286ba53 Binary files /dev/null and b/resources/images/dailytips_CutTool.PNG differ diff --git a/resources/images/dailytips_LayOnFace.PNG b/resources/images/dailytips_LayOnFace.PNG new file mode 100644 index 00000000000..bb270db60c3 Binary files /dev/null and b/resources/images/dailytips_LayOnFace.PNG differ diff --git a/resources/images/dailytips_ObjectList.PNG b/resources/images/dailytips_ObjectList.PNG new file mode 100644 index 00000000000..7946006036a Binary files /dev/null and b/resources/images/dailytips_ObjectList.PNG differ diff --git a/resources/images/dailytips_SimplifyModel.PNG b/resources/images/dailytips_SimplifyModel.PNG new file mode 100644 index 00000000000..8a1330d3814 Binary files /dev/null and b/resources/images/dailytips_SimplifyModel.PNG differ diff --git a/resources/images/dailytips_SlicingParamTable.PNG b/resources/images/dailytips_SlicingParamTable.PNG new file mode 100644 index 00000000000..511395f820c Binary files /dev/null and b/resources/images/dailytips_SlicingParamTable.PNG differ diff --git a/resources/images/dailytips_SplitIntoPlates.png b/resources/images/dailytips_SplitIntoPlates.png new file mode 100644 index 00000000000..7ee6eb62b8b Binary files /dev/null and b/resources/images/dailytips_SplitIntoPlates.png differ diff --git a/resources/images/dailytips_StackObject.png b/resources/images/dailytips_StackObject.png new file mode 100644 index 00000000000..9570f7c0f17 Binary files /dev/null and b/resources/images/dailytips_StackObject.png differ diff --git a/resources/images/dailytips_SubtractPart.png b/resources/images/dailytips_SubtractPart.png new file mode 100644 index 00000000000..8f8366bde24 Binary files /dev/null and b/resources/images/dailytips_SubtractPart.png differ diff --git a/resources/images/dailytips_TypesOfSupports.png b/resources/images/dailytips_TypesOfSupports.png new file mode 100644 index 00000000000..a615ceafcc3 Binary files /dev/null and b/resources/images/dailytips_TypesOfSupports.png differ diff --git a/resources/images/dailytips_ZSeamLocation.png b/resources/images/dailytips_ZSeamLocation.png new file mode 100644 index 00000000000..239cfa479a5 Binary files /dev/null and b/resources/images/dailytips_ZSeamLocation.png differ diff --git a/resources/images/dailytips_placeholder.png b/resources/images/dailytips_placeholder.png new file mode 100644 index 00000000000..ef9bf6fe7fd Binary files /dev/null and b/resources/images/dailytips_placeholder.png differ diff --git a/resources/images/extra_ams_tray_left_selected.svg b/resources/images/extra_ams_tray_left_selected.svg index b63329c06c1..f2d168da35c 100644 --- a/resources/images/extra_ams_tray_left_selected.svg +++ b/resources/images/extra_ams_tray_left_selected.svg @@ -1,8 +1,8 @@ - - - - + + + + diff --git a/resources/images/extra_ams_tray_right_selected.svg b/resources/images/extra_ams_tray_right_selected.svg index 3fbb312a792..21c6d2702a5 100644 --- a/resources/images/extra_ams_tray_right_selected.svg +++ b/resources/images/extra_ams_tray_right_selected.svg @@ -1,8 +1,8 @@ - - - + + + diff --git a/resources/images/extra_icon.svg b/resources/images/extra_icon.svg new file mode 100644 index 00000000000..eec95433fff --- /dev/null +++ b/resources/images/extra_icon.svg @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/extra_icon_dark.svg b/resources/images/extra_icon_dark.svg new file mode 100644 index 00000000000..2fa3a59e7ab --- /dev/null +++ b/resources/images/extra_icon_dark.svg @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/fd_calibration_manual.png b/resources/images/fd_calibration_manual.png index e27ac564716..e1cd9f310b0 100644 Binary files a/resources/images/fd_calibration_manual.png and b/resources/images/fd_calibration_manual.png differ diff --git a/resources/images/fd_calibration_manual_result.png b/resources/images/fd_calibration_manual_result.png index efdaff12de9..7c0d568fb18 100644 Binary files a/resources/images/fd_calibration_manual_result.png and b/resources/images/fd_calibration_manual_result.png differ diff --git a/resources/images/fd_calibration_manual_result_CN.png b/resources/images/fd_calibration_manual_result_CN.png index 43fb54678d0..aa6b5b6f73d 100644 Binary files a/resources/images/fd_calibration_manual_result_CN.png and b/resources/images/fd_calibration_manual_result_CN.png differ diff --git a/resources/images/input_access_code_cn.png b/resources/images/input_access_code_cn.png deleted file mode 100644 index f9259b4bfca..00000000000 Binary files a/resources/images/input_access_code_cn.png and /dev/null differ diff --git a/resources/images/input_access_code_en.png b/resources/images/input_access_code_en.png deleted file mode 100644 index 6b72c5d8bd9..00000000000 Binary files a/resources/images/input_access_code_en.png and /dev/null differ diff --git a/resources/images/input_access_code_n1_cn.png b/resources/images/input_access_code_n1_cn.png index 773dc0314b8..1408be84ad6 100644 Binary files a/resources/images/input_access_code_n1_cn.png and b/resources/images/input_access_code_n1_cn.png differ diff --git a/resources/images/input_access_code_n1_en.png b/resources/images/input_access_code_n1_en.png index 0ebdf87fc2b..45ea35153d9 100644 Binary files a/resources/images/input_access_code_n1_en.png and b/resources/images/input_access_code_n1_en.png differ diff --git a/resources/images/input_access_code_p1p_cn.png b/resources/images/input_access_code_p1p_cn.png new file mode 100644 index 00000000000..2ecc6f5691b Binary files /dev/null and b/resources/images/input_access_code_p1p_cn.png differ diff --git a/resources/images/input_access_code_p1p_en.png b/resources/images/input_access_code_p1p_en.png new file mode 100644 index 00000000000..2ecc6f5691b Binary files /dev/null and b/resources/images/input_access_code_p1p_en.png differ diff --git a/resources/images/input_access_code_x1_cn.png b/resources/images/input_access_code_x1_cn.png new file mode 100644 index 00000000000..05354c4a6e7 Binary files /dev/null and b/resources/images/input_access_code_x1_cn.png differ diff --git a/resources/images/input_access_code_x1_en.png b/resources/images/input_access_code_x1_en.png new file mode 100644 index 00000000000..c81f16b1b9f Binary files /dev/null and b/resources/images/input_access_code_x1_en.png differ diff --git a/resources/images/input_accesscode_help1.png b/resources/images/input_accesscode_help1.png deleted file mode 100644 index b23f40a951e..00000000000 Binary files a/resources/images/input_accesscode_help1.png and /dev/null differ diff --git a/resources/images/input_accesscode_help2.png b/resources/images/input_accesscode_help2.png deleted file mode 100644 index 0bff847ce3e..00000000000 Binary files a/resources/images/input_accesscode_help2.png and /dev/null differ diff --git a/resources/images/monitor_frame_temp_active.svg b/resources/images/monitor_frame_temp_active.svg new file mode 100644 index 00000000000..920345fc83b --- /dev/null +++ b/resources/images/monitor_frame_temp_active.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/notification_arrow_left.svg b/resources/images/notification_arrow_left.svg new file mode 100644 index 00000000000..f4b4616c18d --- /dev/null +++ b/resources/images/notification_arrow_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/notification_arrow_open.svg b/resources/images/notification_arrow_open.svg new file mode 100644 index 00000000000..7ae92e27ba2 --- /dev/null +++ b/resources/images/notification_arrow_open.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/notification_arrow_right.svg b/resources/images/notification_arrow_right.svg new file mode 100644 index 00000000000..c6784277e39 --- /dev/null +++ b/resources/images/notification_arrow_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/notification_collapse.svg b/resources/images/notification_collapse.svg new file mode 100644 index 00000000000..9f569d093f3 --- /dev/null +++ b/resources/images/notification_collapse.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/notification_expand.svg b/resources/images/notification_expand.svg new file mode 100644 index 00000000000..91ac2a55bdc --- /dev/null +++ b/resources/images/notification_expand.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/notification_slicing_complete.svg b/resources/images/notification_slicing_complete.svg new file mode 100644 index 00000000000..82bc8ea17f3 --- /dev/null +++ b/resources/images/notification_slicing_complete.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/printer_status_lock.svg b/resources/images/printer_status_lock.svg index 858f4ae2e01..af840d2f7c4 100644 --- a/resources/images/printer_status_lock.svg +++ b/resources/images/printer_status_lock.svg @@ -1,4 +1,4 @@ - - + + diff --git a/resources/images/printer_status_offline.svg b/resources/images/printer_status_offline.svg index e97c5ebdea7..eeb09a4d117 100644 --- a/resources/images/printer_status_offline.svg +++ b/resources/images/printer_status_offline.svg @@ -1,4 +1,4 @@ - - + + diff --git a/resources/images/printer_thumbnail_n1_dark.svg b/resources/images/printer_thumbnail_n1_dark.svg index 87022438d7f..8bffb461145 100644 --- a/resources/images/printer_thumbnail_n1_dark.svg +++ b/resources/images/printer_thumbnail_n1_dark.svg @@ -1,1295 +1,1295 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/printer_thumbnail_p1s.svg b/resources/images/printer_thumbnail_p1s.svg new file mode 100644 index 00000000000..deb1120f5c7 --- /dev/null +++ b/resources/images/printer_thumbnail_p1s.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/printer_thumbnail_p1s_dark.svg b/resources/images/printer_thumbnail_p1s_dark.svg new file mode 100644 index 00000000000..ec725a1d9ec --- /dev/null +++ b/resources/images/printer_thumbnail_p1s_dark.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/step_1.svg b/resources/images/step_1.svg new file mode 100644 index 00000000000..27385f06b15 --- /dev/null +++ b/resources/images/step_1.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/step_2.svg b/resources/images/step_2.svg new file mode 100644 index 00000000000..7ea460c47de --- /dev/null +++ b/resources/images/step_2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/step_2_ready.svg b/resources/images/step_2_ready.svg new file mode 100644 index 00000000000..8e53610c3a5 --- /dev/null +++ b/resources/images/step_2_ready.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/step_is_ok.svg b/resources/images/step_is_ok.svg new file mode 100644 index 00000000000..04ee5c02ae1 --- /dev/null +++ b/resources/images/step_is_ok.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/thumbnail_grid.svg b/resources/images/thumbnail_grid.svg new file mode 100644 index 00000000000..e2e44fdefd2 --- /dev/null +++ b/resources/images/thumbnail_grid.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/printers/C11.json b/resources/printers/C11.json new file mode 100644 index 00000000000..d008dde8f05 --- /dev/null +++ b/resources/printers/C11.json @@ -0,0 +1,87 @@ +{ + "00.00.00.00": { + "display_name": "Bambu Lab P1P", + "print": { + "ipcam": { + "resolution_supported": [ "720p" ], + "liveview": { + "local": "local" + } + }, + "support_motor_noise_cali":false, + "support_tunnel_mqtt":false, + "support_mqtt_alive":false, + "support_command_ams_switch":false, + "support_cloud_print_only":true, + "support_1080dpi":false, + "support_prompt_sound":false, + "support_ams_humidity":true, + "support_auto_recovery_step_loss":true, + "support_auto_leveling":true, + "support_update_remain":true, + "support_timelapse":true, + "support_filament_backup":true, + "support_chamber_fan":true, + "support_aux_fan":true, + "support_send_to_sd":false, + "support_print_all":false, + "support_print_without_sd":false, + "support_flow_calibration":false, + "support_build_plate_marker_detect":false, + "support_lidar_calibration":false, + "support_ai_monitoring":false, + "support_first_layer_inspect":false, + "support_chamber_temp_edit":false, + "support_extrusion_cali":true, + "support_user_preset":false, + "bed_temperature_limit": 100 + }, + "model_id": "C11", + "compatible_machine":["BL-P001", "BL-P002", "C12", "C13"], + "printer_type": "C11", + "ftp_folder" : "sdcard/", + "printer_thumbnail_image": "printer_thumbnail_p1p", + "printer_connect_help_image": "input_access_code_p1p", + "printer_use_ams_image":"ams_icon", + "use_ams_type":"generic", + "printer_arch" : "core_xy", + "printer_series":"series_p1p", + "has_cali_line":false, + "printer_is_enclosed":false + }, + "01.02.00.00": { + "print": { + "support_send_to_sd":true + } + }, + "01.02.99.00": { + "print": { + "ipcam": { + "liveview": { + "remote": "enabled" + } + } + } + }, + "01.02.99.10" : { + "print": { + "support_command_ams_switch":true + } + }, + "01.03.50.01" : { + "engineer":"00.06.03.51", + "print": { + "support_mqtt_alive":true, + "support_tunnel_mqtt":true + } + }, + "01.04.50.01": { + "print": { + "ipcam": { + "file": { + "remote": "enabled" + } + } + } + } +} diff --git a/resources/printers/C12.json b/resources/printers/C12.json new file mode 100644 index 00000000000..06d50b94762 --- /dev/null +++ b/resources/printers/C12.json @@ -0,0 +1,79 @@ +{ + "00.00.00.00": { + "display_name": "Bambu Lab P1S", + "print": { + "ipcam": { + "resolution_supported": [ "720p" ], + "liveview": { + "local": "local" + } + }, + "support_motor_noise_cali":false, + "support_tunnel_mqtt":false, + "support_mqtt_alive":false, + "support_command_ams_switch":false, + "support_cloud_print_only":true, + "support_1080dpi":false, + "support_prompt_sound":false, + "support_ams_humidity":true, + "support_auto_recovery_step_loss":true, + "support_auto_leveling":true, + "support_update_remain":true, + "support_timelapse":true, + "support_filament_backup":true, + "support_chamber_fan":true, + "support_aux_fan":true, + "support_send_to_sd":true, + "support_print_all":false, + "support_print_without_sd":false, + "support_flow_calibration":false, + "support_build_plate_marker_detect":false, + "support_lidar_calibration":false, + "support_ai_monitoring":false, + "support_first_layer_inspect":false, + "support_chamber_temp_edit":false, + "support_extrusion_cali":true, + "support_user_preset":false, + "bed_temperature_limit": 100 + }, + "model_id": "C12", + "compatible_machine":["BL-P001", "BL-P002", "C11", "C13"], + "printer_type": "C12", + "ftp_folder" : "sdcard/", + "printer_thumbnail_image": "printer_thumbnail_p1s", + "printer_connect_help_image": "input_access_code_p1p", + "printer_use_ams_image":"ams_icon", + "use_ams_type":"generic", + "printer_arch" : "core_xy", + "printer_series":"series_p1p", + "has_cali_line":false, + "printer_is_enclosed":true + }, + "01.02.99.10" : { + "print": { + "support_command_ams_switch":true + } + }, + "01.03.50.01": { + "engineer":"00.06.03.51", + "resolution_supported": [ "720p" ], + "print": { + "ipcam": { + "liveview": { + "remote": "enabled" + } + }, + "support_mqtt_alive":true, + "support_tunnel_mqtt":true + } + }, + "01.04.50.01": { + "print": { + "ipcam": { + "file": { + "remote": "enabled" + } + } + } + } +} diff --git a/resources/printers/N1.json b/resources/printers/N1.json new file mode 100644 index 00000000000..2c6131b6781 --- /dev/null +++ b/resources/printers/N1.json @@ -0,0 +1,62 @@ +{ + "00.00.00.00": { + "display_name": "Bambu Lab A1 mini", + "print": { + "ipcam": { + "resolution_supported": [ "720p" ], + "liveview": { + "local": "local", + "remote": "enabled" + } + }, + "support_motor_noise_cali":true, + "support_tunnel_mqtt":true, + "support_mqtt_alive":true, + "support_command_ams_switch":true, + "support_cloud_print_only":true, + "support_1080dpi":true, + "support_prompt_sound":true, + "support_ams_humidity":false, + "support_auto_recovery_step_loss":true, + "support_auto_leveling":true, + "support_update_remain":false, + "support_timelapse":true, + "support_filament_backup":true, + "support_chamber_fan":false, + "support_aux_fan":false, + "support_send_to_sd":true, + "support_print_all":false, + "support_print_without_sd":false, + "support_flow_calibration":true, + "support_build_plate_marker_detect":false, + "support_lidar_calibration":false, + "support_ai_monitoring":false, + "support_first_layer_inspect":false, + "support_chamber_temp_edit":false, + "support_extrusion_cali":true, + "support_user_preset":false, + "bed_temperature_limit": 100 + }, + "model_id": "N1", + "compatible_machine":[], + "printer_type": "N1", + "ftp_folder" : "sdcard/", + "printer_thumbnail_image": "printer_thumbnail_n1", + "printer_connect_help_image": "input_access_code_n1", + "printer_use_ams_image":"extra_icon", + "use_ams_type":"f1", + "printer_arch" : "i3", + "printer_series":"series_p1p", + "has_cali_line":false, + "printer_is_enclosed":false + }, + "01.01.50.01": { + "print": { + "ipcam": { + "file": { + "remote": "enabled" + } + } + } + } +} \ No newline at end of file diff --git a/resources/printers/version.txt b/resources/printers/version.txt new file mode 100644 index 00000000000..8e3f706a564 --- /dev/null +++ b/resources/printers/version.txt @@ -0,0 +1 @@ +01.08.00.02 \ No newline at end of file diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index 2caae25cd11..49a94c4e86c 100644 --- a/resources/profiles/BBL.json +++ b/resources/profiles/BBL.json @@ -1,7 +1,7 @@ { "name": "Bambulab", "url": "http://www.bambulab.com/Parameters/vendor/BBL.json", - "version": "01.07.00.30", + "version": "01.08.00.06", "force_update": "0", "description": "the initial version of BBL configurations", "machine_model_list": [ @@ -175,6 +175,10 @@ "name": "0.30mm Strength @BBL A1M 0.6 nozzle", "sub_path": "process/0.30mm Strength @BBL A1M 0.6 nozzle.json" }, + { + "name": "0.30mm Strength @BBL P1P 0.6 nozzle", + "sub_path": "process/0.30mm Strength @BBL P1P 0.6 nozzle.json" + }, { "name": "0.12mm Fine @BBL X1C", "sub_path": "process/0.12mm Fine @BBL X1C.json" @@ -247,6 +251,10 @@ "name": "0.06mm Fine @BBL A1M 0.2 nozzle", "sub_path": "process/0.06mm Fine @BBL A1M 0.2 nozzle.json" }, + { + "name": "0.06mm Fine @BBL P1P 0.2 nozzle", + "sub_path": "process/0.06mm Fine @BBL P1P 0.2 nozzle.json" + }, { "name": "0.08mm Standard @BBL X1C 0.2 nozzle", "sub_path": "process/0.08mm Standard @BBL X1C 0.2 nozzle.json" @@ -255,6 +263,10 @@ "name": "0.08mm Optimal @BBL A1M 0.2 nozzle", "sub_path": "process/0.08mm Optimal @BBL A1M 0.2 nozzle.json" }, + { + "name": "0.08mm Optimal @BBL P1P 0.2 nozzle", + "sub_path": "process/0.08mm Optimal @BBL P1P 0.2 nozzle.json" + }, { "name": "0.12mm Standard @BBL X1C 0.2 nozzle", "sub_path": "process/0.12mm Standard @BBL X1C 0.2 nozzle.json" @@ -263,6 +275,10 @@ "name": "0.12mm Draft @BBL A1M 0.2 nozzle", "sub_path": "process/0.12mm Draft @BBL A1M 0.2 nozzle.json" }, + { + "name": "0.12mm Draft @BBL P1P 0.2 nozzle", + "sub_path": "process/0.12mm Draft @BBL P1P 0.2 nozzle.json" + }, { "name": "0.14mm Standard @BBL X1C 0.2 nozzle", "sub_path": "process/0.14mm Standard @BBL X1C 0.2 nozzle.json" @@ -271,6 +287,10 @@ "name": "0.14mm Extra Draft @BBL A1M 0.2 nozzle", "sub_path": "process/0.14mm Extra Draft @BBL A1M 0.2 nozzle.json" }, + { + "name": "0.14mm Extra Draft @BBL P1P 0.2 nozzle", + "sub_path": "process/0.14mm Extra Draft @BBL P1P 0.2 nozzle.json" + }, { "name": "0.18mm Standard @BBL X1C 0.6 nozzle", "sub_path": "process/0.18mm Standard @BBL X1C 0.6 nozzle.json" @@ -279,6 +299,10 @@ "name": "0.18mm Fine @BBL A1M 0.6 nozzle", "sub_path": "process/0.18mm Fine @BBL A1M 0.6 nozzle.json" }, + { + "name": "0.18mm Fine @BBL P1P 0.6 nozzle", + "sub_path": "process/0.18mm Fine @BBL P1P 0.6 nozzle.json" + }, { "name": "0.24mm Standard @BBL X1C 0.6 nozzle", "sub_path": "process/0.24mm Standard @BBL X1C 0.6 nozzle.json" @@ -287,6 +311,10 @@ "name": "0.24mm Optimal @BBL A1M 0.6 nozzle", "sub_path": "process/0.24mm Optimal @BBL A1M 0.6 nozzle.json" }, + { + "name": "0.24mm Optimal @BBL P1P 0.6 nozzle", + "sub_path": "process/0.24mm Optimal @BBL P1P 0.6 nozzle.json" + }, { "name": "0.36mm Standard @BBL X1C 0.6 nozzle", "sub_path": "process/0.36mm Standard @BBL X1C 0.6 nozzle.json" @@ -295,6 +323,10 @@ "name": "0.36mm Draft @BBL A1M 0.6 nozzle", "sub_path": "process/0.36mm Draft @BBL A1M 0.6 nozzle.json" }, + { + "name": "0.36mm Draft @BBL P1P 0.6 nozzle", + "sub_path": "process/0.36mm Draft @BBL P1P 0.6 nozzle.json" + }, { "name": "0.42mm Standard @BBL X1C 0.6 nozzle", "sub_path": "process/0.42mm Standard @BBL X1C 0.6 nozzle.json" @@ -303,6 +335,10 @@ "name": "0.42mm Extra Draft @BBL A1M 0.6 nozzle", "sub_path": "process/0.42mm Extra Draft @BBL A1M 0.6 nozzle.json" }, + { + "name": "0.42mm Extra Draft @BBL P1P 0.6 nozzle", + "sub_path": "process/0.42mm Extra Draft @BBL P1P 0.6 nozzle.json" + }, { "name": "0.24mm Standard @BBL X1C 0.8 nozzle", "sub_path": "process/0.24mm Standard @BBL X1C 0.8 nozzle.json" @@ -311,6 +347,10 @@ "name": "0.24mm Fine @BBL A1M 0.8 nozzle", "sub_path": "process/0.24mm Fine @BBL A1M 0.8 nozzle.json" }, + { + "name": "0.24mm Fine @BBL P1P 0.8 nozzle", + "sub_path": "process/0.24mm Fine @BBL P1P 0.8 nozzle.json" + }, { "name": "0.32mm Standard @BBL X1C 0.8 nozzle", "sub_path": "process/0.32mm Standard @BBL X1C 0.8 nozzle.json" @@ -319,6 +359,10 @@ "name": "0.32mm Optimal @BBL A1M 0.8 nozzle", "sub_path": "process/0.32mm Optimal @BBL A1M 0.8 nozzle.json" }, + { + "name": "0.32mm Optimal @BBL P1P 0.8 nozzle", + "sub_path": "process/0.32mm Optimal @BBL P1P 0.8 nozzle.json" + }, { "name": "0.48mm Standard @BBL X1C 0.8 nozzle", "sub_path": "process/0.48mm Standard @BBL X1C 0.8 nozzle.json" @@ -327,6 +371,10 @@ "name": "0.48mm Draft @BBL A1M 0.8 nozzle", "sub_path": "process/0.48mm Draft @BBL A1M 0.8 nozzle.json" }, + { + "name": "0.48mm Draft @BBL P1P 0.8 nozzle", + "sub_path": "process/0.48mm Draft @BBL P1P 0.8 nozzle.json" + }, { "name": "0.56mm Standard @BBL X1C 0.8 nozzle", "sub_path": "process/0.56mm Standard @BBL X1C 0.8 nozzle.json" @@ -335,6 +383,10 @@ "name": "0.56mm Extra Draft @BBL A1M 0.8 nozzle", "sub_path": "process/0.56mm Extra Draft @BBL A1M 0.8 nozzle.json" }, + { + "name": "0.56mm Extra Draft @BBL P1P 0.8 nozzle", + "sub_path": "process/0.56mm Extra Draft @BBL P1P 0.8 nozzle.json" + }, { "name": "0.10mm Standard @BBL A1M 0.2 nozzle", "sub_path": "process/0.10mm Standard @BBL A1M 0.2 nozzle.json" @@ -489,6 +541,10 @@ "name": "Generic PLA High Speed @base", "sub_path": "filament/Generic PLA High Speed @base.json" }, + { + "name": "Bambu PLA Glow @base", + "sub_path": "filament/Bambu PLA Glow @base.json" + }, { "name": "Bambu TPU 95A @base", "sub_path": "filament/Bambu TPU 95A @base.json" @@ -501,6 +557,10 @@ "name": "Generic TPU @BBL P1P", "sub_path": "filament/P1P/Generic TPU @BBL P1P.json" }, + { + "name": "Bambu TPU 95A HF @base", + "sub_path": "filament/Bambu TPU 95A HF @base.json" + }, { "name": "Bambu PETG Basic @base", "sub_path": "filament/Bambu PETG Basic @base.json" @@ -1049,6 +1109,22 @@ "name": "Generic PLA High Speed @BBL A1M", "sub_path": "filament/Generic PLA High Speed @BBL A1M.json" }, + { + "name": "Bambu PLA Glow @BBL X1C", + "sub_path": "filament/Bambu PLA Glow @BBL X1C.json" + }, + { + "name": "Bambu PLA Glow @BBL P1P", + "sub_path": "filament/Bambu PLA Glow @BBL P1P.json" + }, + { + "name": "Bambu PLA Glow @BBL X1E", + "sub_path": "filament/Bambu PLA Glow @BBL X1E.json" + }, + { + "name": "Bambu PLA Glow @BBL X1", + "sub_path": "filament/Bambu PLA Glow @BBL X1.json" + }, { "name": "Bambu TPU 95A @BBL X1C", "sub_path": "filament/Bambu TPU 95A @BBL X1C.json" @@ -1069,6 +1145,30 @@ "name": "Generic TPU @BBL A1M", "sub_path": "filament/Generic TPU @BBL A1M.json" }, + { + "name": "Bambu TPU 95A HF @BBL X1C", + "sub_path": "filament/Bambu TPU 95A HF @BBL X1C.json" + }, + { + "name": "Bambu TPU 95A HF @BBL X1", + "sub_path": "filament/Bambu TPU 95A HF @BBL X1.json" + }, + { + "name": "Bambu TPU 95A HF @BBL P1P", + "sub_path": "filament/Bambu TPU 95A HF @BBL P1P.json" + }, + { + "name": "Bambu TPU 95A HF @BBL P1S", + "sub_path": "filament/Bambu TPU 95A HF @BBL P1S.json" + }, + { + "name": "Bambu TPU 95A HF @BBL X1E", + "sub_path": "filament/Bambu TPU 95A HF @BBL X1E.json" + }, + { + "name": "Bambu TPU 95A HF @BBL A1M", + "sub_path": "filament/Bambu TPU 95A HF @BBL A1M.json" + }, { "name": "Bambu PETG Basic @BBL X1C", "sub_path": "filament/Bambu PETG Basic @BBL X1C.json" @@ -1441,6 +1541,22 @@ "name": "Generic PLA High Speed @BBL A1M 0.2 nozzle", "sub_path": "filament/Generic PLA High Speed @BBL A1M 0.2 nozzle.json" }, + { + "name": "Bambu PLA Glow @BBL X1C 0.2 nozzle", + "sub_path": "filament/Bambu PLA Glow @BBL X1C 0.2 nozzle.json" + }, + { + "name": "Bambu PLA Glow @BBL P1P 0.2 nozzle", + "sub_path": "filament/Bambu PLA Glow @BBL P1P 0.2 nozzle.json" + }, + { + "name": "Bambu PLA Glow @BBL X1E 0.2 nozzle", + "sub_path": "filament/Bambu PLA Glow @BBL X1E 0.2 nozzle.json" + }, + { + "name": "Bambu PLA Glow @BBL X1 0.2 nozzle", + "sub_path": "filament/Bambu PLA Glow @BBL X1 0.2 nozzle.json" + }, { "name": "Bambu PETG Basic @BBL A1M 0.4 nozzle", "sub_path": "filament/Bambu PETG Basic @BBL A1M 0.4 nozzle.json" @@ -1712,4 +1828,4 @@ "sub_path": "machine/Bambu Lab X1E 0.8 nozzle.json" } ] -} +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu ABS @BBL X1C 0.8 nozzle.json b/resources/profiles/BBL/filament/Bambu ABS @BBL X1C 0.8 nozzle.json index 70613a34f23..10bfd2565a6 100644 --- a/resources/profiles/BBL/filament/Bambu ABS @BBL X1C 0.8 nozzle.json +++ b/resources/profiles/BBL/filament/Bambu ABS @BBL X1C 0.8 nozzle.json @@ -6,7 +6,7 @@ "setting_id": "GFSB00_01", "instantiation": "true", "filament_max_volumetric_speed": [ - "22" + "18" ], "nozzle_temperature": [ "260" diff --git a/resources/profiles/BBL/filament/Bambu ABS @BBL X1C.json b/resources/profiles/BBL/filament/Bambu ABS @BBL X1C.json index 3fb2c7f6215..80f4f7c9200 100644 --- a/resources/profiles/BBL/filament/Bambu ABS @BBL X1C.json +++ b/resources/profiles/BBL/filament/Bambu ABS @BBL X1C.json @@ -6,7 +6,7 @@ "setting_id": "GFSB00", "instantiation": "true", "filament_max_volumetric_speed": [ - "22" + "16" ], "compatible_printers": [ "Bambu Lab X1 Carbon 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PA6-CF @base.json b/resources/profiles/BBL/filament/Bambu PA6-CF @base.json index 697101fff83..190e61093e9 100644 --- a/resources/profiles/BBL/filament/Bambu PA6-CF @base.json +++ b/resources/profiles/BBL/filament/Bambu PA6-CF @base.json @@ -14,6 +14,9 @@ "fan_min_speed": [ "10" ], + "filament_cost": [ + "79.99" + ], "filament_density": [ "1.10" ], diff --git a/resources/profiles/BBL/filament/Bambu PETG-CF @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PETG-CF @BBL A1M.json index a630c42d3ce..6c7b97ce7b6 100644 --- a/resources/profiles/BBL/filament/Bambu PETG-CF @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PETG-CF @BBL A1M.json @@ -8,6 +8,9 @@ "filament_max_volumetric_speed": [ "9" ], + "textured_plate_temp_initial_layer": [ + "65" + ], "compatible_printers": [ "Bambu Lab A1 mini 0.6 nozzle", "Bambu Lab A1 mini 0.8 nozzle" diff --git a/resources/profiles/BBL/filament/Bambu PLA Aero @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PLA Aero @BBL A1M.json index 6483f04f4c5..7d6397aa15f 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Aero @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PLA Aero @BBL A1M.json @@ -27,10 +27,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PLA Basic @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA Basic @BBL A1M 0.2 nozzle.json index c1a12b1c4ae..49b44fa936f 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Basic @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/Bambu PLA Basic @BBL A1M 0.2 nozzle.json @@ -27,10 +27,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" diff --git a/resources/profiles/BBL/filament/Bambu PLA Basic @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PLA Basic @BBL A1M.json index 85c54ef7d6d..17858789174 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Basic @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PLA Basic @BBL A1M.json @@ -24,10 +24,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL P1P 0.2 nozzle.json new file mode 100644 index 00000000000..02c4e904e11 --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL P1P 0.2 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @BBL P1P 0.2 nozzle", + "inherits": "Bambu PLA Glow @BBL P1P", + "from": "system", + "setting_id": "GFSA12_03", + "instantiation": "true", + "filament_max_volumetric_speed": [ + "1" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @BBL P1P.json b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL P1P.json new file mode 100644 index 00000000000..e162316fd30 --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL P1P.json @@ -0,0 +1,34 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @BBL P1P", + "inherits": "Bambu PLA Glow @base", + "from": "system", + "setting_id": "GFSA12_02", + "instantiation": "true", + "fan_cooling_layer_time": [ + "80" + ], + "fan_min_speed": [ + "50" + ], + "hot_plate_temp": [ + "65" + ], + "hot_plate_temp_initial_layer": [ + "65" + ], + "slow_down_layer_time": [ + "8" + ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1 0.2 nozzle.json new file mode 100644 index 00000000000..5ae194b74c7 --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1 0.2 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @BBL X1 0.2 nozzle", + "inherits": "Bambu PLA Glow @BBL X1", + "from": "system", + "setting_id": "GFSA12_09", + "instantiation": "true", + "filament_max_volumetric_speed": [ + "1" + ], + "compatible_printers": [ + "Bambu Lab X1 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1.json b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1.json new file mode 100644 index 00000000000..6f91b4f7faa --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1.json @@ -0,0 +1,16 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @BBL X1", + "inherits": "Bambu PLA Glow @base", + "from": "system", + "setting_id": "GFSA12_08", + "instantiation": "true", + "slow_down_layer_time": [ + "8" + ], + "compatible_printers": [ + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1C 0.2 nozzle.json new file mode 100644 index 00000000000..48cf37ec67e --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1C 0.2 nozzle.json @@ -0,0 +1,15 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @BBL X1C 0.2 nozzle", + "inherits": "Bambu PLA Glow @BBL X1C", + "from": "system", + "setting_id": "GFSA12_01", + "instantiation": "true", + "filament_max_volumetric_speed": [ + "1" + ], + "compatible_printers": [ + "Bambu Lab X1 Carbon 0.2 nozzle", + "Bambu Lab P1S 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1C.json b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1C.json new file mode 100644 index 00000000000..115adb144a1 --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1C.json @@ -0,0 +1,16 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @BBL X1C", + "inherits": "Bambu PLA Glow @base", + "from": "system", + "setting_id": "GFSA12_00", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab X1 Carbon 0.4 nozzle", + "Bambu Lab X1 Carbon 0.6 nozzle", + "Bambu Lab X1 Carbon 0.8 nozzle", + "Bambu Lab P1S 0.8 nozzle", + "Bambu Lab P1S 0.6 nozzle", + "Bambu Lab P1S 0.4 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1E 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1E 0.2 nozzle.json new file mode 100644 index 00000000000..6bea42ba190 --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1E 0.2 nozzle.json @@ -0,0 +1,14 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @BBL X1E 0.2 nozzle", + "inherits": "Bambu PLA Glow @BBL X1E", + "from": "system", + "setting_id": "GFSA12_05", + "instantiation": "true", + "filament_max_volumetric_speed": [ + "1" + ], + "compatible_printers": [ + "Bambu Lab X1E 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1E.json b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1E.json new file mode 100644 index 00000000000..51137bdeecf --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @BBL X1E.json @@ -0,0 +1,13 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @BBL X1E", + "inherits": "Bambu PLA Glow @base", + "from": "system", + "setting_id": "GFSA12_04", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab X1E 0.4 nozzle", + "Bambu Lab X1E 0.6 nozzle", + "Bambu Lab X1E 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Glow @base.json b/resources/profiles/BBL/filament/Bambu PLA Glow @base.json new file mode 100644 index 00000000000..c06cc7a28aa --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu PLA Glow @base.json @@ -0,0 +1,29 @@ +{ + "type": "filament", + "name": "Bambu PLA Glow @base", + "inherits": "fdm_filament_pla", + "from": "system", + "filament_id": "GFA12", + "instantiation": "false", + "filament_cost": [ + "29.99" + ], + "filament_density": [ + "1.26" + ], + "filament_flow_ratio": [ + "0.98" + ], + "filament_max_volumetric_speed": [ + "18" + ], + "filament_vendor": [ + "Bambu Lab" + ], + "temperature_vitrification": [ + "45" + ], + "filament_start_gcode": [ + "; filament start gcode\n{if (bed_temperature[current_extruder] >55)||(bed_temperature_initial_layer[current_extruder] >55)}M106 P3 S200\n{elsif(bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_extruder] >50)}M106 P3 S150\n{elsif(bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}M106 P3 S50\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu PLA Marble @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PLA Marble @BBL A1M.json index 92dfae7b7ed..ebb955bdf04 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Marble @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PLA Marble @BBL A1M.json @@ -24,10 +24,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PLA Matte @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA Matte @BBL A1M 0.2 nozzle.json index d637a5e2709..eb0f819f533 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Matte @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/Bambu PLA Matte @BBL A1M 0.2 nozzle.json @@ -27,10 +27,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" diff --git a/resources/profiles/BBL/filament/Bambu PLA Matte @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PLA Matte @BBL A1M.json index c08d84529df..65403831cbd 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Matte @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PLA Matte @BBL A1M.json @@ -27,10 +27,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PLA Metal @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA Metal @BBL A1M 0.2 nozzle.json index b486490b0da..f3f5d36e409 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Metal @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/Bambu PLA Metal @BBL A1M 0.2 nozzle.json @@ -27,10 +27,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" diff --git a/resources/profiles/BBL/filament/Bambu PLA Metal @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PLA Metal @BBL A1M.json index 9b58508d544..fce4ffa8172 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Metal @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PLA Metal @BBL A1M.json @@ -27,10 +27,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL A1M.json index d5855426979..e961b1fcd69 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL A1M.json @@ -24,10 +24,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PLA Tough @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA Tough @BBL A1M 0.2 nozzle.json index 4f10cb0ed52..68423c503a3 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Tough @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/Bambu PLA Tough @BBL A1M 0.2 nozzle.json @@ -27,10 +27,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" diff --git a/resources/profiles/BBL/filament/Bambu PLA Tough @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PLA Tough @BBL A1M.json index 40b03fb52bd..5ef9ff13fe6 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Tough @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PLA Tough @BBL A1M.json @@ -27,10 +27,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PLA-CF @BBL A1M 0.8 nozzle.json b/resources/profiles/BBL/filament/Bambu PLA-CF @BBL A1M 0.8 nozzle.json index 9e6df67b923..d22d4de449b 100644 --- a/resources/profiles/BBL/filament/Bambu PLA-CF @BBL A1M 0.8 nozzle.json +++ b/resources/profiles/BBL/filament/Bambu PLA-CF @BBL A1M 0.8 nozzle.json @@ -33,10 +33,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.6 nozzle", diff --git a/resources/profiles/BBL/filament/Bambu PLA-CF @BBL A1M.json b/resources/profiles/BBL/filament/Bambu PLA-CF @BBL A1M.json index 8994c7d43c4..b976f74eb7d 100644 --- a/resources/profiles/BBL/filament/Bambu PLA-CF @BBL A1M.json +++ b/resources/profiles/BBL/filament/Bambu PLA-CF @BBL A1M.json @@ -33,10 +33,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle" diff --git a/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL A1M.json b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL A1M.json new file mode 100644 index 00000000000..4fdeddc655c --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL A1M.json @@ -0,0 +1,25 @@ +{ + "type": "filament", + "name": "Bambu TPU 95A HF @BBL A1M", + "inherits": "Bambu TPU 95A HF @base", + "from": "system", + "setting_id": "GFSU00_05", + "instantiation": "true", + "hot_plate_temp": [ + "30" + ], + "hot_plate_temp_initial_layer": [ + "30" + ], + "textured_plate_temp": [ + "30" + ], + "textured_plate_temp_initial_layer": [ + "30" + ], + "compatible_printers": [ + "Bambu Lab A1 mini 0.4 nozzle", + "Bambu Lab A1 mini 0.6 nozzle", + "Bambu Lab A1 mini 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL P1P.json b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL P1P.json new file mode 100644 index 00000000000..4271b71a248 --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL P1P.json @@ -0,0 +1,25 @@ +{ + "type": "filament", + "name": "Bambu TPU 95A HF @BBL P1P", + "inherits": "Bambu TPU 95A HF @base", + "from": "system", + "setting_id": "GFSU00_02", + "instantiation": "true", + "hot_plate_temp": [ + "45" + ], + "hot_plate_temp_initial_layer": [ + "45" + ], + "textured_plate_temp": [ + "45" + ], + "textured_plate_temp_initial_layer": [ + "45" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL P1S.json b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL P1S.json new file mode 100644 index 00000000000..3dc7b2b702e --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL P1S.json @@ -0,0 +1,13 @@ +{ + "type": "filament", + "name": "Bambu TPU 95A HF @BBL P1S", + "inherits": "Bambu TPU 95A HF @base", + "from": "system", + "setting_id": "GFSU00_03", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1S 0.4 nozzle", + "Bambu Lab P1S 0.6 nozzle", + "Bambu Lab P1S 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1.json b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1.json new file mode 100644 index 00000000000..1cb82d7da1b --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1.json @@ -0,0 +1,13 @@ +{ + "type": "filament", + "name": "Bambu TPU 95A HF @BBL X1", + "inherits": "Bambu TPU 95A HF @base", + "from": "system", + "setting_id": "GFSU00_01", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1C.json b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1C.json new file mode 100644 index 00000000000..5d2ef43e072 --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1C.json @@ -0,0 +1,13 @@ +{ + "type": "filament", + "name": "Bambu TPU 95A HF @BBL X1C", + "inherits": "Bambu TPU 95A HF @base", + "from": "system", + "setting_id": "GFSU00_00", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab X1 Carbon 0.6 nozzle", + "Bambu Lab X1 Carbon 0.4 nozzle", + "Bambu Lab X1 Carbon 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1E.json b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1E.json new file mode 100644 index 00000000000..6e8b82def5b --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL X1E.json @@ -0,0 +1,13 @@ +{ + "type": "filament", + "name": "Bambu TPU 95A HF @BBL X1E", + "inherits": "Bambu TPU 95A HF @base", + "from": "system", + "setting_id": "GFSU00_04", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab X1E 0.4 nozzle", + "Bambu Lab X1E 0.6 nozzle", + "Bambu Lab X1E 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu TPU 95A HF @base.json b/resources/profiles/BBL/filament/Bambu TPU 95A HF @base.json new file mode 100644 index 00000000000..8e012b89dc6 --- /dev/null +++ b/resources/profiles/BBL/filament/Bambu TPU 95A HF @base.json @@ -0,0 +1,26 @@ +{ + "type": "filament", + "name": "Bambu TPU 95A HF @base", + "inherits": "fdm_filament_tpu", + "from": "system", + "filament_id": "GFU00", + "instantiation": "false", + "filament_cost": [ + "41.99" + ], + "filament_density": [ + "1.22" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_vendor": [ + "Bambu Lab" + ], + "nozzle_temperature": [ + "230" + ], + "nozzle_temperature_initial_layer": [ + "230" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Generic ABS.json b/resources/profiles/BBL/filament/Generic ABS.json index bd7c0959c66..95aebb50197 100644 --- a/resources/profiles/BBL/filament/Generic ABS.json +++ b/resources/profiles/BBL/filament/Generic ABS.json @@ -5,6 +5,9 @@ "from": "system", "setting_id": "GFSB99", "instantiation": "true", + "filament_max_volumetric_speed": [ + "15" + ], "compatible_printers": [ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Generic PA.json b/resources/profiles/BBL/filament/Generic PA.json index ac30ee54092..6a4f7bf4e2a 100644 --- a/resources/profiles/BBL/filament/Generic PA.json +++ b/resources/profiles/BBL/filament/Generic PA.json @@ -9,18 +9,45 @@ "chamber_temperatures": [ "60" ], + "fan_cooling_layer_time": [ + "65" + ], + "fan_max_speed": [ + "85" + ], + "fan_min_speed": [ + "40" + ], "filament_max_volumetric_speed": [ - "16" + "12" ], "nozzle_temperature": [ - "280" + "260" ], "nozzle_temperature_initial_layer": [ + "260" + ], + "nozzle_temperature_range_high": [ "280" ], + "nozzle_temperature_range_low": [ + "240" + ], + "overhang_fan_speed": [ + "95" + ], + "overhang_fan_threshold": [ + "10%" + ], "required_nozzle_HRC": [ "3" ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "10" + ], "compatible_printers": [ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1 Carbon 0.6 nozzle", diff --git a/resources/profiles/BBL/filament/Generic PLA @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/Generic PLA @BBL A1M 0.2 nozzle.json index 79d1f2150bc..16f0ee48606 100644 --- a/resources/profiles/BBL/filament/Generic PLA @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/Generic PLA @BBL A1M 0.2 nozzle.json @@ -24,10 +24,10 @@ "60" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" diff --git a/resources/profiles/BBL/filament/Generic PLA @BBL A1M.json b/resources/profiles/BBL/filament/Generic PLA @BBL A1M.json index 84bbaa9e132..783863506cb 100644 --- a/resources/profiles/BBL/filament/Generic PLA @BBL A1M.json +++ b/resources/profiles/BBL/filament/Generic PLA @BBL A1M.json @@ -21,10 +21,10 @@ "60" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Generic PLA High Speed @BBL A1M.json b/resources/profiles/BBL/filament/Generic PLA High Speed @BBL A1M.json index 0697473589f..a052820c450 100644 --- a/resources/profiles/BBL/filament/Generic PLA High Speed @BBL A1M.json +++ b/resources/profiles/BBL/filament/Generic PLA High Speed @BBL A1M.json @@ -24,10 +24,10 @@ "6" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.6 nozzle", diff --git a/resources/profiles/BBL/filament/Generic PLA-CF @BBL A1M.json b/resources/profiles/BBL/filament/Generic PLA-CF @BBL A1M.json index b8438ffee51..b5b005424cb 100644 --- a/resources/profiles/BBL/filament/Generic PLA-CF @BBL A1M.json +++ b/resources/profiles/BBL/filament/Generic PLA-CF @BBL A1M.json @@ -24,10 +24,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Overture Matte PLA @BBL A1M.json b/resources/profiles/BBL/filament/Overture Matte PLA @BBL A1M.json index 0e6e727a3f9..e76b7f24ce7 100644 --- a/resources/profiles/BBL/filament/Overture Matte PLA @BBL A1M.json +++ b/resources/profiles/BBL/filament/Overture Matte PLA @BBL A1M.json @@ -24,10 +24,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/Overture PLA @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/Overture PLA @BBL A1M 0.2 nozzle.json index 5a705c4a012..cfc3357e355 100644 --- a/resources/profiles/BBL/filament/Overture PLA @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/Overture PLA @BBL A1M 0.2 nozzle.json @@ -8,6 +8,12 @@ "filament_max_volumetric_speed": [ "1" ], + "textured_plate_temp": [ + "65" + ], + "textured_plate_temp_initial_layer": [ + "65" + ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" ] diff --git a/resources/profiles/BBL/filament/Overture PLA @BBL A1M.json b/resources/profiles/BBL/filament/Overture PLA @BBL A1M.json index 851864ce0e5..a542675287f 100644 --- a/resources/profiles/BBL/filament/Overture PLA @BBL A1M.json +++ b/resources/profiles/BBL/filament/Overture PLA @BBL A1M.json @@ -24,10 +24,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/P1P/Bambu ABS @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Bambu ABS @BBL P1P.json index 40a0a0a2608..b1206b169d6 100644 --- a/resources/profiles/BBL/filament/P1P/Bambu ABS @BBL P1P.json +++ b/resources/profiles/BBL/filament/P1P/Bambu ABS @BBL P1P.json @@ -9,7 +9,7 @@ "20" ], "filament_max_volumetric_speed": [ - "22" + "16" ], "hot_plate_temp": [ "100" diff --git a/resources/profiles/BBL/filament/P1P/Bambu TPU 95A @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Bambu TPU 95A @BBL P1P.json index 5c980a1e6b9..02c7a6f8e82 100644 --- a/resources/profiles/BBL/filament/P1P/Bambu TPU 95A @BBL P1P.json +++ b/resources/profiles/BBL/filament/P1P/Bambu TPU 95A @BBL P1P.json @@ -23,9 +23,6 @@ "compatible_printers": [ "Bambu Lab P1P 0.4 nozzle", "Bambu Lab P1P 0.6 nozzle", - "Bambu Lab P1P 0.8 nozzle", - "Bambu Lab A1 mini 0.4 nozzle", - "Bambu Lab A1 mini 0.6 nozzle", - "Bambu Lab A1 mini 0.8 nozzle" + "Bambu Lab P1P 0.8 nozzle" ] } \ No newline at end of file diff --git a/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P.json index 3b46c650d1f..90fa0dcb239 100644 --- a/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P.json +++ b/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P.json @@ -8,6 +8,9 @@ "fan_max_speed": [ "20" ], + "filament_max_volumetric_speed": [ + "15" + ], "hot_plate_temp": [ "100" ], diff --git a/resources/profiles/BBL/filament/PolyLite ABS @base.json b/resources/profiles/BBL/filament/PolyLite ABS @base.json index e722c94f041..29db7f92f29 100644 --- a/resources/profiles/BBL/filament/PolyLite ABS @base.json +++ b/resources/profiles/BBL/filament/PolyLite ABS @base.json @@ -15,7 +15,7 @@ "0.95" ], "filament_max_volumetric_speed": [ - "18" + "15" ], "filament_vendor": [ "Polymaker" diff --git a/resources/profiles/BBL/filament/PolyLite PLA @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/PolyLite PLA @BBL A1M 0.2 nozzle.json index ff991970c23..b3d0a8bb8a7 100644 --- a/resources/profiles/BBL/filament/PolyLite PLA @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/PolyLite PLA @BBL A1M 0.2 nozzle.json @@ -27,10 +27,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" diff --git a/resources/profiles/BBL/filament/PolyLite PLA @BBL A1M.json b/resources/profiles/BBL/filament/PolyLite PLA @BBL A1M.json index a07bb0110d3..8394e1c7a09 100644 --- a/resources/profiles/BBL/filament/PolyLite PLA @BBL A1M.json +++ b/resources/profiles/BBL/filament/PolyLite PLA @BBL A1M.json @@ -27,10 +27,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/PolyTerra PLA @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/PolyTerra PLA @BBL A1M 0.2 nozzle.json index 73d3ce1a89d..f37463b1a5f 100644 --- a/resources/profiles/BBL/filament/PolyTerra PLA @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/PolyTerra PLA @BBL A1M 0.2 nozzle.json @@ -27,10 +27,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" diff --git a/resources/profiles/BBL/filament/PolyTerra PLA @BBL A1M.json b/resources/profiles/BBL/filament/PolyTerra PLA @BBL A1M.json index 288e5e938b1..7a9187dd37c 100644 --- a/resources/profiles/BBL/filament/PolyTerra PLA @BBL A1M.json +++ b/resources/profiles/BBL/filament/PolyTerra PLA @BBL A1M.json @@ -27,10 +27,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/filament/eSUN PLA+ @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/filament/eSUN PLA+ @BBL A1M 0.2 nozzle.json index 96573934d67..ee4e65d4241 100644 --- a/resources/profiles/BBL/filament/eSUN PLA+ @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/eSUN PLA+ @BBL A1M 0.2 nozzle.json @@ -27,10 +27,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.2 nozzle" diff --git a/resources/profiles/BBL/filament/eSUN PLA+ @BBL A1M.json b/resources/profiles/BBL/filament/eSUN PLA+ @BBL A1M.json index 92a72de8f09..9b71d17e271 100644 --- a/resources/profiles/BBL/filament/eSUN PLA+ @BBL A1M.json +++ b/resources/profiles/BBL/filament/eSUN PLA+ @BBL A1M.json @@ -24,10 +24,10 @@ "8" ], "textured_plate_temp": [ - "60" + "65" ], "textured_plate_temp_initial_layer": [ - "60" + "65" ], "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle", diff --git a/resources/profiles/BBL/machine/Bambu Lab A1 mini 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab A1 mini 0.4 nozzle.json index fe6a5d32877..15ffd096df8 100644 --- a/resources/profiles/BBL/machine/Bambu Lab A1 mini 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab A1 mini 0.4 nozzle.json @@ -59,9 +59,9 @@ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1E 0.4 nozzle" ], - "machine_start_gcode": ";===== machine: A1 mini =========================\n;===== date: 20231010 =====================\n\n;===== start to heat heatbead&hotend==========\nM1002 gcode_claim_action : 2\nM1002 set_filament_type:{filament_type[initial_no_support_extruder]}\nM104 S150\nM140 S[bed_temperature_initial_layer_single]\nG392 S0 ;turn off clog detect\n;=====start printer sound ===================\nM17\nM400 S1\nM1006 S1\nM1006 A0 B0 L100 C37 D10 M100 E37 F10 N100\nM1006 A0 B0 L100 C41 D10 M100 E41 F10 N100\nM1006 A0 B0 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A43 B10 L100 C39 D10 M100 E46 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B0 L100 C39 D10 M100 E43 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B0 L100 C41 D10 M100 E41 F10 N100\nM1006 A0 B0 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B0 L100 C49 D10 M100 E49 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A44 B10 L100 C39 D10 M100 E48 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B0 L100 C39 D10 M100 E44 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A43 B10 L100 C39 D10 M100 E46 F10 N100\nM1006 W\nM18\n;=====avoid end stop =================\nG91\nG380 S2 Z30 F1200\nG380 S2 Z-20 F1200\nG1 Z5 F1200\nG90\n\n;===== reset machine status =================\nM290 X39 Y39 Z8\nM204 S6000\n\nM630 S0 P0\nG91\nM17 Z0.3 ; lower the z-motor current\n\nG90\nM17 X0.7 Y0.9 Z0.5 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\n;====== cog noise reduction=================\nM982.2 S1 ; turn on cog noise reduction\n\n;===== prepare print temperature and material ==========\nM1002 gcode_claim_action : 1\nM400\nM18\nM109 S100 H150\nM104 S150\nM400\nM17\nM400\nG28 X\n\nM211 X0 Y0 Z0 ;turn off soft endstop ; turn off soft endstop to prevent protential logic problem\n\nM975 S1 ; turn on\n\nG1 X0.0 F30000\nG1 X-13.5 F3000\n\nM620 M ;enable remap\nM620 S[initial_no_support_extruder]A ; switch material if AMS exist\n G392 S1 ;turn on clog detect\n M1002 gcode_claim_action : 4\n M400\n M1002 set_filament_type:UNKNOWN\n M109 S[nozzle_temperature_initial_layer]\n M104 S250\n M400\n T[initial_no_support_extruder]\n G1 X-13.5 F3000\n M400\n M620.1 E F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_no_support_extruder]}\n M109 S250 ;set nozzle to common flush temp\n M106 P1 S0\n G92 E0\n G1 E50 F200\n M400\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M104 S{nozzle_temperature_range_high[initial_no_support_extruder]}\n G92 E0\n G1 E50 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n M400\n M106 P1 S178\n G92 E0\n G1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n M109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20} ; drop nozzle temp, make filament shink a bit\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-40}\n G92 E0\n G1 E-0.5 F300\n\n G1 X0 F30000\n G1 X-13.5 F3000\n G1 X0 F30000 ;wipe and shake\n G1 X-13.5 F3000\n G1 X0 F12000 ;wipe and shake\n G1 X0 F30000\n G1 X-13.5 F3000\n M109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-40}\n G392 S0 ;turn off clog detect\nM621 S[initial_no_support_extruder]A\n\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== mech mode fast check============================\nM1002 gcode_claim_action : 3\nG0 X50 Y175 F20000 ; find a soft place to home\nM104 S0\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nM104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-65}\n\nG1 X90 Y-1 Z5 F30000\nM400 P200\nM970.3 Q1 A7 K0 O2\nM974 Q1 S2 P0\n\nG1 X90 Y0 Z5 F30000\nM400 P200\nM970 Q0 A5 B50 C90 H15 K0 M20 O3\n;M970.3 Q0 A7 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X-1 Y10\nG28 X ; re-home XY\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\n;M106 S255\nG29.2 S0 ; turn off ABL\nG0 X50 Y175 F20000 ; find a soft place to home\nG28 Z P0 T300; home z with low precision, permit 300deg temperature\n\nM104 S150 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\nM211 S; push soft endstop status\nM211 Z0 ;turn off Z axis endstop\n\nG0 X85 Y185 F10000 ;move to exposed steel surface and stop the nozzle\nG0 Z-1.01 F10000\nG91\n\nG2 I1 J0 X2 Y0 F2000.1\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\n\nG90\nG1 Z5 F30000\nG1 X25 Y175 F30000.1 ;Brush material\nG1 Z0.6 F30000.1\nG1 Y185\nG91\nG1 X-30 F30000\nG1 Y-2\nG1 X27\nG1 Y1.5\nG1 X-28\nG1 Y-2\nG1 X30\nG1 Y1.5\nG1 X-30\n\nG90\nM83\n\nG1 Z10\nG1 X85 Y185\nG1 Z-1.01\nG1 X95\nG1 X90\n\n\nM211 R; pop softend status\n\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== wait heatbed ====================\nM1002 gcode_claim_action : 2\nM104 S0\nM190 S[bed_temperature_initial_layer_single];set bed temp\nM109 S150\n\nG1 Z5 F3000\nG29.2 S1\nG1 X10 Y10 F20000\n\n;===== bed leveling ==================================\n;M1002 set_flag g29_before_print_flag=1\nM1002 judge_flag g29_before_print_flag\nM622 J1\n M1002 gcode_claim_action : 1\n G29 A T155 ;set high than the wipe temperature\n M400\n M500 ; save cali data\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28 T155\n\nM623\n\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\n\nG1 X-13.5 Y0 Z10 F10000\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{nozzle_temperature[initial_extruder]}\nM400\n\nM412 S1 ; ===turn on filament runout detection===\nM400 P10\n\nG392 S1 ;turn on clog detect\n\nM620.3 W1; === turn on filament tangle detection===\nM400 S2\n\nM1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n;M1002 set_flag extrude_cali_flag=1\nM1002 judge_flag extrude_cali_flag\nM622 J1\n M1002 gcode_claim_action : 8\n \n M400\n M900 K0.0 L1000.0 M1.0\n G90\n M83\n G0 X68 Y-4 F30000\n G0 Z0.2 F18000 ;Move to start position\n G0 X88 E10 F{outer_wall_volumetric_speed/(24/20) * 60}\n G0 X93 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n G0 X98 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X103 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n G0 X108 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X113 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n G0 Y0 Z0 F20000\n M400\n \n G1 X-13.5 Y0 Z10 F10000\n M400\n \n G1 E10 F{outer_wall_volumetric_speed/2.4*60}\n M983 F{outer_wall_volumetric_speed/2.4} A0.3 ; cali dynamic extrusion compensation\n M106 P1 S178\n M400 S7\n G1 X0 F18000\n G1 X-13.5 F3000\n G1 X0 F18000 ;wipe and shake\n G1 X-13.5 F3000\n G1 X0 F12000 ;wipe and shake\n G1 X-13.5 F3000\n M400\n M106 P1 S0\n\n M1002 judge_last_extrude_cali_success\n M622 J0\n M983 F{outer_wall_volumetric_speed/2.4} A0.3 ; cali dynamic extrusion compensation\n M106 P1 S178\n M400 S7\n G1 X0 F18000\n G1 X-13.5 F3000\n G1 X0 F18000 ;wipe and shake\n G1 X-13.5 F3000\n G1 X0 F12000 ;wipe and shake\n M400\n M106 P1 S0\n M623\nM623 ; end of \"draw extrinsic para cali paint\"\n\n;===== extrude cali test ===============================\nG90\nM83\nG0 X68 Y-2.5 F30000\nG0 Z0.2 F18000 ;Move to start position\nG0 X88 E10 F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X93 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X98 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 X103 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X108 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 X113 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X115 Z0 F20000\nG0 Z5\nM400\n\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\n\nM400 ; wait all motion done before implement the emprical L parameters\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.02} ; for Textured PEI Plate\n{endif}\n\nM960 S1 P0 ; turn off laser\nM960 S2 P0 ; turn off laser\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\nG90\nM83\nT1000\n\nM211 X0 Y0 Z0 ;turn off soft endstop\n", - "machine_end_gcode": ";===== date: 20230912 =====================\n;turn off nozzle clog detect\nG392 S0\n\n{if timelapse_type == 2}\nM991 S0 P-1 ;end timelapse immediately\n{endif}\nM400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\nG1 E-0.8 F1800 ; retract\nG1 Z{max_layer_z + 0.5} F900 ; lower z a little\nG1 X0 F12000 ; move to safe pos \n{if timelapse_type == 1}\nM991 S0 P-1 ;end timelapse at safe pos\n{endif}\n\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off remote part cooling fan\nM106 P3 S0 ; turn off chamber cooling fan\n\n;G1 X27 F15000 ; wipe\n\n; pull back filament to AMS\nM620 S255\nG1 X181 F12000\nT255\nG1 X0 F18000\nG1 X-13.0 F3000\nG1 X0 F18000 ; wipe\nM621 S255\n\nM104 S0 ; turn off hotend\n\nM400 ; wait all motion done\nM17 S\nM17 Z0.4 ; lower z motor current to reduce impact if there is something in the bottom\n{if (max_layer_z + 100.0) < 180}\n G1 Z{max_layer_z + 100.0} F600\n G1 Z{max_layer_z +98.0}\n{else}\n G1 Z180 F600\n G1 Z180\n{endif}\nM400 P100\nM17 R ; restore z current\n\nG90\nG1 X-13 Y180 F3600\n\nM220 S100 ; Reset feedrate magnitude\nM201.2 K1.0 ; Reset acc magnitude\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 0\n\n;=====printer finish sound=========\nM17\nM400 S1\nM1006 S1\nM1006 A0 B20 L100 C37 D20 M100 E42 F20 N100\nM1006 A0 B10 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B10 L100 C46 D10 M100 E46 F10 N100\nM1006 A44 B20 L100 C39 D20 M100 E48 F20 N100\nM1006 A0 B10 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B10 L100 C39 D10 M100 E39 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B10 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B10 L100 C39 D10 M100 E39 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A44 B10 L100 C0 D10 M100 E48 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A44 B20 L100 C41 D20 M100 E49 F20 N100\nM1006 A0 B20 L100 C0 D20 M100 E0 F20 N100\nM1006 A0 B20 L100 C37 D20 M100 E37 F20 N100\nM1006 W\n;=====printer finish sound=========\nM400 S1\nM18\n", + "machine_start_gcode": ";===== machine: A1 mini =========================\n;===== date: 20231103 =====================\n\n;===== start to heat heatbead&hotend==========\nM1002 gcode_claim_action : 2\nM1002 set_filament_type:{filament_type[initial_no_support_extruder]}\nM104 S170\nM140 S[bed_temperature_initial_layer_single]\nG392 S0 ;turn off clog detect\n;=====start printer sound ===================\nM17\nM400 S1\nM1006 S1\nM1006 A0 B0 L100 C37 D10 M100 E37 F10 N100\nM1006 A0 B0 L100 C41 D10 M100 E41 F10 N100\nM1006 A0 B0 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A43 B10 L100 C39 D10 M100 E46 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B0 L100 C39 D10 M100 E43 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B0 L100 C41 D10 M100 E41 F10 N100\nM1006 A0 B0 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B0 L100 C49 D10 M100 E49 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A44 B10 L100 C39 D10 M100 E48 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B0 L100 C39 D10 M100 E44 F10 N100\nM1006 A0 B0 L100 C0 D10 M100 E0 F10 N100\nM1006 A43 B10 L100 C39 D10 M100 E46 F10 N100\nM1006 W\nM18\n;=====avoid end stop =================\nG91\nG380 S2 Z30 F1200\nG380 S2 Z-20 F1200\nG1 Z5 F1200\nG90\n\n;===== reset machine status =================\nM290 X39 Y39 Z8\nM204 S6000\n\nM630 S0 P0\nG91\nM17 Z0.3 ; lower the z-motor current\n\nG90\nM17 X0.7 Y0.9 Z0.5 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM83\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\n;====== cog noise reduction=================\nM982.2 S1 ; turn on cog noise reduction\n\n;===== prepare print temperature and material ==========\nM400\nM18\nM109 S100 H170\nM104 S170\nM400\nM17\nM400\nG28 X\n\nM211 X0 Y0 Z0 ;turn off soft endstop ; turn off soft endstop to prevent protential logic problem\n\nM975 S1 ; turn on\n\nG1 X0.0 F30000\nG1 X-13.5 F3000\n\nM620 M ;enable remap\nM620 S[initial_no_support_extruder]A ; switch material if AMS exist\n G392 S1 ;turn on clog detect\n M1002 gcode_claim_action : 4\n M400\n M1002 set_filament_type:UNKNOWN\n M109 S[nozzle_temperature_initial_layer]\n M104 S250\n M400\n T[initial_no_support_extruder]\n G1 X-13.5 F3000\n M400\n M620.1 E F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_no_support_extruder]}\n M109 S250 ;set nozzle to common flush temp\n M106 P1 S0\n G92 E0\n G1 E50 F200\n M400\n M1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n M104 S{nozzle_temperature_range_high[initial_no_support_extruder]}\n G92 E0\n G1 E50 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n M400\n M106 P1 S178\n G92 E0\n G1 E5 F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60}\n M109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20} ; drop nozzle temp, make filament shink a bit\n M104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-40}\n G92 E0\n G1 E-0.5 F300\n\n G1 X0 F30000\n G1 X-13.5 F3000\n G1 X0 F30000 ;wipe and shake\n G1 X-13.5 F3000\n G1 X0 F12000 ;wipe and shake\n G1 X0 F30000\n G1 X-13.5 F3000\n M109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-40}\n G392 S0 ;turn off clog detect\nM621 S[initial_no_support_extruder]A\n\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== mech mode fast check============================\nM1002 gcode_claim_action : 3\nG0 X25 Y175 F20000 ; find a soft place to home\n;M104 S0\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nM104 S170\n\nG1 X90 Y-1 Z5 F30000\nM400 P200\nM970.3 Q1 A7 K0 O2\nM974 Q1 S2 P0\n\nG1 X90 Y0 Z5 F30000\nM400 P200\nM970 Q0 A10 B50 C90 H15 K0 M20 O3\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X-1 Y10\nG28 X ; re-home XY\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\n\nM104 S170 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\nM211 S; push soft endstop status\nM211 X0 Y0 Z0 ;turn off Z axis endstop\n\nM83\nG1 E-1 F500\nG90\nM83\n\nM109 S170\nM104 S140\nG0 X90 Y-4 F30000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X91 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X92 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X93 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X94 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X95 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X96 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X97 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X98 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X99 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X99 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X99 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X99 F10000\nG380 S3 Z-5 F1200\nG1 Z2 F1200\nG1 X99 F10000\nG380 S3 Z-5 F1200\n\nG1 Z5 F30000\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\nG1 X25 Y175 F30000.1 ;Brush material\nG1 Z0.2 F30000.1\nG1 Y185\nG91\nG1 X-30 F30000\nG1 Y-2\nG1 X27\nG1 Y1.5\nG1 X-28\nG1 Y-2\nG1 X30\nG1 Y1.5\nG1 X-30\nG90\nM83\n\nG1 Z5 F3000\nG0 X50 Y175 F20000 ; find a soft place to home\nG28 Z P0 T300; home z with low precision, permit 300deg temperature\nG29.2 S0 ; turn off ABL\n\nG0 X85 Y185 F10000 ;move to exposed steel surface and stop the nozzle\nG0 Z-1.01 F10000\nG91\n\nG2 I1 J0 X2 Y0 F2000.1\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\nG2 I1 J0 X2\nG2 I-0.75 J0 X-1.5\n\nG90\nG1 Z5 F30000\nG1 X25 Y175 F30000.1 ;Brush material\nG1 Z0.2 F30000.1\nG1 Y185\nG91\nG1 X-30 F30000\nG1 Y-2\nG1 X27\nG1 Y1.5\nG1 X-28\nG1 Y-2\nG1 X30\nG1 Y1.5\nG1 X-30\nG90\nM83\n\nG1 Z5\nG0 X55 Y175 F20000 ; find a soft place to home\nG28 Z P0 T300; home z with low precision, permit 300deg temperature\nG29.2 S0 ; turn off ABL\n\nG1 Z10\nG1 X85 Y185\nG1 Z-1.01\nG1 X95\nG1 X90\n\nM211 R; pop softend status\n\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== wait heatbed ====================\nM1002 gcode_claim_action : 2\nM104 S0\nM190 S[bed_temperature_initial_layer_single];set bed temp\nM109 S140\n\nG1 Z5 F3000\nG29.2 S1\nG1 X10 Y10 F20000\n\n;===== bed leveling ==================================\n;M1002 set_flag g29_before_print_flag=1\nM1002 judge_flag g29_before_print_flag\nM622 J1\n M1002 gcode_claim_action : 1\n G29 A T145;set high than the wipe temperature\n M400\n M500 ; save cali data\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28 T145\n\nM623\n\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\n\nG1 X-13.5 Y0 Z10 F10000\nG1 E1.2 F500\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{nozzle_temperature[initial_extruder]}\nM400\n\nM412 S1 ; ===turn on filament runout detection===\nM400 P10\n\nG392 S1 ;turn on clog detect\n\nM620.3 W1; === turn on filament tangle detection===\nM400 S2\n\nM1002 set_filament_type:{filament_type[initial_no_support_extruder]}\n;M1002 set_flag extrude_cali_flag=1\nM1002 judge_flag extrude_cali_flag\nM622 J1\n M1002 gcode_claim_action : 8\n \n M400\n M900 K0.0 L1000.0 M1.0\n G90\n M83\n G0 X68 Y-4 F30000\n G0 Z0.2 F18000 ;Move to start position\n M400\n G0 X88 E10 F{outer_wall_volumetric_speed/(24/20) * 60}\n G0 X93 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n G0 X98 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X103 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n G0 X108 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X113 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\n G0 Y0 Z0 F20000\n M400\n \n G1 X-13.5 Y0 Z10 F10000\n M400\n \n G1 E10 F{outer_wall_volumetric_speed/2.4*60}\n M983 F{outer_wall_volumetric_speed/2.4} A0.3 ; cali dynamic extrusion compensation\n M106 P1 S178\n M400 S7\n G1 X0 F18000\n G1 X-13.5 F3000\n G1 X0 F18000 ;wipe and shake\n G1 X-13.5 F3000\n G1 X0 F12000 ;wipe and shake\n G1 X-13.5 F3000\n M400\n M106 P1 S0\n\n M1002 judge_last_extrude_cali_success\n M622 J0\n M983 F{outer_wall_volumetric_speed/2.4} A0.3 ; cali dynamic extrusion compensation\n M106 P1 S178\n M400 S7\n G1 X0 F18000\n G1 X-13.5 F3000\n G1 X0 F18000 ;wipe and shake\n G1 X-13.5 F3000\n G1 X0 F12000 ;wipe and shake\n M400\n M106 P1 S0\n M623\nM623 ; end of \"draw extrinsic para cali paint\"\n\n;===== extrude cali test ===============================\nM104 S{nozzle_temperature_initial_layer[initial_extruder]}\nG90\nM83\nG0 X68 Y-2.5 F30000\nG0 Z0.2 F18000 ;Move to start position\nG0 X88 E10 F{outer_wall_volumetric_speed/(24/20) * 60}\nG0 X93 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X98 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 X103 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X108 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 X113 E.3742 F{outer_wall_volumetric_speed/(0.3*0.5)/4 * 60}\nG0 X115 Z0 F20000\nG0 Z5\nM400\n\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\n\nM400 ; wait all motion done before implement the emprical L parameters\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.02} ; for Textured PEI Plate\n{endif}\n\nM960 S1 P0 ; turn off laser\nM960 S2 P0 ; turn off laser\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\nG90\nM83\nT1000\n\nM211 X0 Y0 Z0 ;turn off soft endstop\n", + "machine_end_gcode": ";===== date: 20230922 =====================\n;turn off nozzle clog detect\nG392 S0\n\nM400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\nG1 E-0.8 F1800 ; retract\nG1 Z{max_layer_z + 0.5} F900 ; lower z a little\nG1 X0 Y{first_layer_center_no_wipe_tower[1]} F18000 ; move to safe pos\nG1 X-13.0 F3000 ; move to safe pos\n{if !spiral_mode && print_sequence != \"by object\"}\nM1002 judge_flag timelapse_record_flag\nM622 J1\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM400 P100\nM971 S11 C11 O0\nM991 S0 P-1 ;end timelapse at safe pos\nM623\n{endif}\n\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off remote part cooling fan\nM106 P3 S0 ; turn off chamber cooling fan\n\n;G1 X27 F15000 ; wipe\n\n; pull back filament to AMS\nM620 S255\nG1 X181 F12000\nT255\nG1 X0 F18000\nG1 X-13.0 F3000\nG1 X0 F18000 ; wipe\nM621 S255\n\nM104 S0 ; turn off hotend\n\nM400 ; wait all motion done\nM17 S\nM17 Z0.4 ; lower z motor current to reduce impact if there is something in the bottom\n{if (max_layer_z + 100.0) < 180}\n G1 Z{max_layer_z + 100.0} F600\n G1 Z{max_layer_z +98.0}\n{else}\n G1 Z180 F600\n G1 Z180\n{endif}\nM400 P100\nM17 R ; restore z current\n\nG90\nG1 X-13 Y180 F3600\n\nM220 S100 ; Reset feedrate magnitude\nM201.2 K1.0 ; Reset acc magnitude\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 0\n\n;=====printer finish sound=========\nM17\nM400 S1\nM1006 S1\nM1006 A0 B20 L100 C37 D20 M100 E42 F20 N100\nM1006 A0 B10 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B10 L100 C46 D10 M100 E46 F10 N100\nM1006 A44 B20 L100 C39 D20 M100 E48 F20 N100\nM1006 A0 B10 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B10 L100 C39 D10 M100 E39 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B10 L100 C44 D10 M100 E44 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A0 B10 L100 C39 D10 M100 E39 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A44 B10 L100 C0 D10 M100 E48 F10 N100\nM1006 A0 B10 L100 C0 D10 M100 E0 F10 N100\nM1006 A44 B20 L100 C41 D20 M100 E49 F20 N100\nM1006 A0 B20 L100 C0 D20 M100 E0 F20 N100\nM1006 A0 B20 L100 C37 D20 M100 E37 F20 N100\nM1006 W\n;=====printer finish sound=========\nM400 S1\nM18\n", "layer_change_gcode": "; layer num/total_layer_count: {layer_num+1}/[total_layer_count]\n; update layer progress\nM73 L{layer_num+1}\nM991 S0 P{layer_num} ;notify layer change\n", - "time_lapse_gcode": "{if !spiral_mode && print_sequence != \"by object\"}\n;===================== date: 20230922 =====================\n; timelapse gcode\n; don't support timelapse gcode in spiral_mode and by object sequence for I3 structure printer\nM622.1 S1 ; for prev firware, default turned on\nM1002 judge_flag timelapse_record_flag\nM622 J1\nG92 E0\nG17\nG2 Z{layer_z + 0.4} I0.86 J0.86 P1 F20000 ; spiral lift a little\nG1 Z{max_layer_z + 0.4}\nG1 X0 Y{first_layer_center_no_wipe_tower[1]} F18000 ; move to safe pos\nG1 X-13.0 F3000 ; move to safe pos\nM400 P300\nM971 S11 C11 O0\nG92 E0\nG1 X0 F18000\nM623\n\n{if layer_num == 2}\n M400\n G90\n M83\n M204 S5000\n G0 Z2 F4000\n G0 X-6 Y170 F20000\n M400 P200\n G39 S1\n G0 Z2 F4000\n G0 X90 Y90 F30000\n{endif}\n\n{endif}\n", + "time_lapse_gcode": ";===================== date: 20230922 =====================\n{if !spiral_mode && print_sequence != \"by object\"}\n; don't support timelapse gcode in spiral_mode and by object sequence for I3 structure printer\nM622.1 S1 ; for prev firware, default turned on\nM1002 judge_flag timelapse_record_flag\nM622 J1\nG92 E0\nG17\nG2 Z{layer_z + 0.4} I0.86 J0.86 P1 F20000 ; spiral lift a little\nG1 Z{max_layer_z + 0.4}\nG1 X0 Y{first_layer_center_no_wipe_tower[1]} F18000 ; move to safe pos\nG1 X-13.0 F3000 ; move to safe pos\nM400 P300\nM971 S11 C11 O0\nG92 E0\nG1 X0 F18000\nM623\n\n; enable nozzle clog detect at 3rd layer\n{if layer_num == 2}\n M400\n G90\n M83\n M204 S5000\n G0 Z2 F4000\n G0 X-6 Y170 F20000\n M400 P200\n G39 S1\n G0 Z2 F4000\n G0 X90 Y90 F30000\n{endif}\n{endif}\n", "change_filament_gcode": ";===== machine: A1 mini =========================\n;===== date: 20231012 =======================\nG392 S0\nM620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1}\nG17\nG2 Z{max_layer_z + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\nG1 Z{max_layer_z + 3.0} F1200\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if old_filament_temp > 142 && next_extruder < 255}\nM104 S[old_filament_temp]\n{endif}\n\nG1 X180 F18000\n;{if toolchange_count == 2}\n; get travel path for change filament\n;M620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\n;M620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\n;M620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n;{endif}\nM620.1 E F[old_filament_e_feedrate] T{nozzle_temperature_range_high[previous_extruder]}\nT[next_extruder]\nM620.1 E F[new_filament_e_feedrate] T{nozzle_temperature_range_high[next_extruder]}\n\nG1 Y90 F9000\n\n{if next_extruder < 255}\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S[nozzle_temperature_range_high]\nM106 P1 S60\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate} ; do not need pulsatile flushing for start part\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\n; FLUSH_END\nG1 E-[old_retract_length_toolchange] F1800\nG1 E[old_retract_length_toolchange] F300\nM400\nM1002 set_filament_type:{filament_type[next_extruder]}\n{endif}\n\n{if flush_length_1 > 45 && flush_length_2 > 1}\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n{endif}\n\n{if flush_length_2 > 1}\nM106 P1 S60\n; FLUSH_START\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_2 > 45 && flush_length_3 > 1}\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n{endif}\n\n{if flush_length_3 > 1}\nM106 P1 S60\n; FLUSH_START\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_3 > 45 && flush_length_4 > 1}\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n{endif}\n\n{if flush_length_4 > 1}\nM106 P1 S60\n; FLUSH_START\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\n; FLUSH_END\n{endif}\n\nM400\nM106 P1 S60\nM109 S[new_filament_temp]\nG1 E5 F{new_filament_e_feedrate} ;Compensate for filament spillage during waiting temperature\nM400\nG92 E0\nG1 E-[new_retract_length_toolchange] F1800\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nM400\nG1 Z{max_layer_z + 3.0} F3000\nM106 P1 S0\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[default_acceleration]\n{endif}\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\nM621 S[next_extruder]A\nG392 S1\n" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab A1 mini.json b/resources/profiles/BBL/machine/Bambu Lab A1 mini.json index c32ab2c90ee..fc0d7a5be5f 100644 --- a/resources/profiles/BBL/machine/Bambu Lab A1 mini.json +++ b/resources/profiles/BBL/machine/Bambu Lab A1 mini.json @@ -2,11 +2,11 @@ "type": "machine_model", "name": "Bambu Lab A1 mini", "nozzle_diameter": "0.4;0.2;0.6;0.8", - "model_id": "N1", - "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", - "machine_tech": "FFF", - "family": "BBL-3DP", "bed_model": "bbl-3dp-A1M.stl", "bed_texture": "bbl-3dp-logo.svg", - "default_materials": "Generic PLA @BBL A1M;Generic PLA Silk @BBL A1M;Bambu PLA Matte @BBL A1M;Bambu PLA Basic @BBL A1M;Bambu ABS @BBL P1P;Bambu PC @BBL P1P;Bambu Support W @BBL A1M;Bambu TPU 95A @BBL P1P;PolyTerra PLA @BBL A1M;PolyLite PLA @BBL A1M;" + "family": "BBL-3DP", + "machine_tech": "FFF", + "model_id": "N1", + "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", + "default_materials": "Bambu PLA Matte @BBL A1M;Bambu PLA Basic @BBL A1M;Bambu PLA Silk @BBL A1M;Bambu Support For PLA @BBL A1M;Bambu PETG Basic @BBL A1M 0.4 nozzle;Bambu TPU 95A @BBL A1M;Generic PLA @BBL A1M;Generic PLA High Speed @BBL A1M;Bambu PLA Metal @BBL A1M;Generic PETG @BBL A1M;Bambu PLA Marble @BBL A1M;Bambu PLA-CF @BBL A1M;Bambu PETG-CF @BBL A1M" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json index 097eb084e10..4bcd6302937 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json @@ -35,5 +35,6 @@ "Bambu Lab X1E 0.4 nozzle" ], "machine_start_gcode": ";===== machine: P1P ========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression", - "layer_change_gcode": "; layer num/total_layer_count: {layer_num+1}/[total_layer_count]\nM622.1 S1 ; for prev firware, default turned on\nM1002 judge_flag timelapse_record_flag\nM622 J1\n{if timelapse_type == 0} ; timelapse without wipe tower\nM971 S11 C10 O0\n{elsif timelapse_type == 1} ; timelapse with wipe tower\nG92 E0\nG1 E-[retraction_length] F1800\nG17\nG2 Z{layer_z + 0.4} I0.86 J0.86 P1 F20000 ; spiral lift a little\nG1 X65 Y245 F20000 ; move to safe pos\nG17\nG2 Z{layer_z} I0.86 J0.86 P1 F20000\nG1 Y265 F3000\nM400 P300\nM971 S11 C11 O0\nG92 E0\nG1 E[retraction_length] F300\nG1 X100 F5000\nG1 Y255 F20000\n{endif}\nM623\n; update layer progress\nM73 L{layer_num+1}\nM991 S0 P{layer_num} ;notify layer change" + "layer_change_gcode": "; layer num/total_layer_count: {layer_num+1}/[total_layer_count]\nM622.1 S1 ; for prev firware, default turned on\nM1002 judge_flag timelapse_record_flag\nM622 J1\n{if timelapse_type == 0} ; timelapse without wipe tower\nM971 S11 C10 O0\n{elsif timelapse_type == 1} ; timelapse with wipe tower\nG92 E0\nG1 E-[retraction_length] F1800\nG17\nG2 Z{layer_z + 0.4} I0.86 J0.86 P1 F20000 ; spiral lift a little\nG1 X65 Y245 F20000 ; move to safe pos\nG17\nG2 Z{layer_z} I0.86 J0.86 P1 F20000\nG1 Y265 F3000\nM400 P300\nM971 S11 C11 O0\nG92 E0\nG1 E[retraction_length] F300\nG1 X100 F5000\nG1 Y255 F20000\n{endif}\nM623\n; update layer progress\nM73 L{layer_num+1}\nM991 S0 P{layer_num} ;notify layer change", + "change_filament_gcode": "M620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1 && (z_hop_types[current_extruder] == 0 || z_hop_types[current_extruder] == 3)}\nG17\nG2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\nG1 Z{max_layer_z + 3.0} F1200\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n{if old_filament_temp > 142 && next_extruder < 255}\nM104 S[old_filament_temp]\n{endif}\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\n\nG1 X20 Y50 F21000\nG1 Y-3\n{if toolchange_count == 2}\n; get travel path for change filament\nM620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\nM620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\nM620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n{endif}\nM620.1 E F[old_filament_e_feedrate] T{nozzle_temperature_range_high[previous_extruder]}\nT[next_extruder]\nM620.1 E F[new_filament_e_feedrate] T{nozzle_temperature_range_high[next_extruder]}\n\n{if next_extruder < 255}\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\n; always use highest temperature to flush\nM400\n{if filament_type[next_extruder] == \"PETG\"}\nM109 S220\n{else}\nM109 S[nozzle_temperature_range_high]\n{endif}\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate} ; do not need pulsatile flushing for start part\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\n; FLUSH_END\nG1 E-[old_retract_length_toolchange] F1800\n{if (flush_length_2 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[old_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\n{if (flush_length_3 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\n{if (flush_length_4 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\n; FLUSH_END\n{endif}\n; FLUSH_START\nM400\nM109 S[new_filament_temp]\nG1 E2 F{new_filament_e_feedrate} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\nM400\nG92 E0\nG1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\nG1 Z{max_layer_z + 3.0} F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[default_acceleration]\n{endif}\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\nM621 S[next_extruder]A\n" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab P1P.json b/resources/profiles/BBL/machine/Bambu Lab P1P.json index ee2f9ec05a0..222634a7c3a 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P1P.json +++ b/resources/profiles/BBL/machine/Bambu Lab P1P.json @@ -2,11 +2,11 @@ "type": "machine_model", "name": "Bambu Lab P1P", "nozzle_diameter": "0.4;0.2;0.6;0.8", - "model_id": "C11", - "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", - "machine_tech": "FFF", - "family": "BBL-3DP", "bed_model": "bbl-3dp-X1.stl", "bed_texture": "bbl-3dp-logo.svg", - "default_materials": "Generic PLA @BBL P1P;Generic PLA Silk @BBL P1P;Bambu PLA Matte @BBL P1P;Bambu PLA Basic @BBL P1P;Bambu ABS @BBL P1P;Bambu PC @BBL P1P;Bambu Support W @BBL P1P;Bambu TPU 95A @BBL P1P;PolyTerra PLA @BBL P1P;PolyLite PLA @BBL P1P;" + "family": "BBL-3DP", + "machine_tech": "FFF", + "model_id": "C11", + "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", + "default_materials": "Bambu PLA Matte @BBL P1P;Bambu PLA Basic @BBL P1P;Bambu PLA-CF @BBL P1P;Bambu PETG Basic @BBL X1C;Bambu PETG-CF @BBL P1P;Bambu ABS @BBL P1P;Bambu PLA Silk @BBL P1P;Bambu PAHT-CF @BBL P1P;Bambu Support For PA/PET @BBL P1P;Bambu Support For PLA @BBL P1P;Generic PLA @BBL P1P;Generic PLA High Speed @BBL P1P;Generic PETG @BBL P1P" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab P1S 0.2 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1S 0.2 nozzle.json index bbb6bcc4758..99b02b8691f 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P1S 0.2 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab P1S 0.2 nozzle.json @@ -29,5 +29,5 @@ "Bambu Lab X1 Carbon 0.2 nozzle", "Bambu Lab X1E 0.2 nozzle" ], - "machine_start_gcode": ";===== machine: P1S ========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z-0.04 ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression" + "machine_start_gcode": ";===== machine: P1S ========================\n;===== date: 20231107 =====================\n;===== turn on the HB fan & MC board fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\nM710 A1 S255 ;turn on MC fan by default(P1S)\n;===== reset machine status =================\nM290 X40 Y40 Z2.6666666\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z-0.04 ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\n" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab P1S 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1S 0.4 nozzle.json index a148d661f07..78a4b625054 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P1S 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab P1S 0.4 nozzle.json @@ -33,6 +33,7 @@ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1E 0.4 nozzle" ], - "machine_start_gcode": ";===== machine: P1S ========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression", - "layer_change_gcode": "; layer num/total_layer_count: {layer_num+1}/[total_layer_count]\nM622.1 S1 ; for prev firware, default turned on\nM1002 judge_flag timelapse_record_flag\nM622 J1\n{if timelapse_type == 0} ; timelapse without wipe tower\nM971 S11 C10 O0\n{elsif timelapse_type == 1} ; timelapse with wipe tower\nG92 E0\nG1 E-[retraction_length] F1800\nG17\nG2 Z{layer_z + 0.4} I0.86 J0.86 P1 F20000 ; spiral lift a little\nG1 X65 Y245 F20000 ; move to safe pos\nG17\nG2 Z{layer_z} I0.86 J0.86 P1 F20000\nG1 Y265 F3000\nM400 P300\nM971 S11 C11 O0\nG92 E0\nG1 E[retraction_length] F300\nG1 X100 F5000\nG1 Y255 F20000\n{endif}\nM623\n; update layer progress\nM73 L{layer_num+1}\nM991 S0 P{layer_num} ;notify layer change" + "machine_start_gcode": ";===== machine: P1S ========================\n;===== date: 20231107 =====================\n;===== turn on the HB fan & MC board fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\nM710 A1 S255 ;turn on MC fan by default(P1S)\n;===== reset machine status =================\nM290 X40 Y40 Z2.6666666\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\n", + "layer_change_gcode": "; layer num/total_layer_count: {layer_num+1}/[total_layer_count]\nM622.1 S1 ; for prev firware, default turned on\nM1002 judge_flag timelapse_record_flag\nM622 J1\n{if timelapse_type == 0} ; timelapse without wipe tower\nM971 S11 C10 O0\n{elsif timelapse_type == 1} ; timelapse with wipe tower\nG92 E0\nG1 E-[retraction_length] F1800\nG17\nG2 Z{layer_z + 0.4} I0.86 J0.86 P1 F20000 ; spiral lift a little\nG1 X65 Y245 F20000 ; move to safe pos\nG17\nG2 Z{layer_z} I0.86 J0.86 P1 F20000\nG1 Y265 F3000\nM400 P300\nM971 S11 C11 O0\nG92 E0\nG1 E[retraction_length] F300\nG1 X100 F5000\nG1 Y255 F20000\n{endif}\nM623\n; update layer progress\nM73 L{layer_num+1}\nM991 S0 P{layer_num} ;notify layer change", + "change_filament_gcode": "M620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1 && (z_hop_types[current_extruder] == 0 || z_hop_types[current_extruder] == 3)}\nG17\nG2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\nG1 Z{max_layer_z + 3.0} F1200\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n{if old_filament_temp > 142 && next_extruder < 255}\nM104 S[old_filament_temp]\n{endif}\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\n\nG1 X20 Y50 F21000\nG1 Y-3\n{if toolchange_count == 2}\n; get travel path for change filament\nM620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\nM620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\nM620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n{endif}\nM620.1 E F[old_filament_e_feedrate] T{nozzle_temperature_range_high[previous_extruder]}\nT[next_extruder]\nM620.1 E F[new_filament_e_feedrate] T{nozzle_temperature_range_high[next_extruder]}\n\n{if next_extruder < 255}\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\n; always use highest temperature to flush\nM400\n{if filament_type[next_extruder] == \"PETG\"}\nM109 S220\n{else}\nM109 S[nozzle_temperature_range_high]\n{endif}\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate} ; do not need pulsatile flushing for start part\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\n; FLUSH_END\nG1 E-[old_retract_length_toolchange] F1800\n{if (flush_length_2 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[old_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\n{if (flush_length_3 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\n{if (flush_length_4 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\n; FLUSH_END\n{endif}\n; FLUSH_START\nM400\nM109 S[new_filament_temp]\nG1 E2 F{new_filament_e_feedrate} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\nM400\nG92 E0\nG1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\nG1 Z{max_layer_z + 3.0} F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[default_acceleration]\n{endif}\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\nM621 S[next_extruder]A\n" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab P1S 0.6 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1S 0.6 nozzle.json index a7c92573fa0..8b42c7b569b 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P1S 0.6 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab P1S 0.6 nozzle.json @@ -33,5 +33,5 @@ "Bambu Lab X1 Carbon 0.6 nozzle", "Bambu Lab X1E 0.6 nozzle" ], - "machine_start_gcode": ";===== machine: P1S ========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E25 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y15 E1.166 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E1.166\nG0 X18 E25 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression" + "machine_start_gcode": ";===== machine: P1S ========================\n;===== date: 20231107 =====================\n;===== turn on the HB fan & MC board fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\nM710 A1 S255 ;turn on MC fan by default(P1S)\n;===== reset machine status =================\nM290 X40 Y40 Z2.6666666\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E25 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y15 E1.166 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E1.166\nG0 X18 E25 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\n" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab P1S 0.8 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1S 0.8 nozzle.json index f4196bd1688..717857d0224 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P1S 0.8 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab P1S 0.8 nozzle.json @@ -28,10 +28,10 @@ "3" ], "upward_compatible_machine": [ - "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle", "Bambu Lab X1 0.8 nozzle", "Bambu Lab X1 Carbon 0.8 nozzle", "Bambu Lab X1E 0.8 nozzle" ], - "machine_start_gcode": ";===== machine: P1S ========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y0.5 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X129 E15 F{outer_wall_volumetric_speed/(0.3*1.0) * 60}\nG0 X240 E15\nG0 Y15 E1.500 F{outer_wall_volumetric_speed/(0.3*1.0)/ 4 * 60}\nG0 X239.5\nG0 E0.3\nG0 Y1.5 E1.500\nG0 X129 E15 F{outer_wall_volumetric_speed/(0.3*1.0) * 60}\nG0 X18 E15\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression" + "machine_start_gcode": ";===== machine: P1S ========================\n;===== date: 20231107 =====================\n;===== turn on the HB fan & MC board fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\nM710 A1 S255 ; turn on MC fan by default(P1S)\n;===== reset machine status =================\nM290 X40 Y40 Z2.6666666\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_extruder]}\n\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X230 Y15\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_extruder]==\"PLA\"}\n {if (bed_temperature[initial_extruder] >45)||(bed_temperature_initial_layer[initial_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_extruder] >50)||(bed_temperature_initial_layer[initial_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n\nM104 S{nozzle_temperature_initial_layer[initial_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== fmech mode fast check============================\n\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y0.5 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X129 E15 F{outer_wall_volumetric_speed/(0.3*1.0) * 60}\nG0 X240 E15\nG0 Y15 E1.500 F{outer_wall_volumetric_speed/(0.3*1.0)/ 4 * 60}\nG0 X239.5\nG0 E0.3\nG0 Y1.5 E1.500\nG0 X129 E15 F{outer_wall_volumetric_speed/(0.3*1.0) * 60}\nG0 X18 E15\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\n" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab P1S.json b/resources/profiles/BBL/machine/Bambu Lab P1S.json index 407df99c0c8..ea426acd142 100644 --- a/resources/profiles/BBL/machine/Bambu Lab P1S.json +++ b/resources/profiles/BBL/machine/Bambu Lab P1S.json @@ -2,11 +2,11 @@ "type": "machine_model", "name": "Bambu Lab P1S", "nozzle_diameter": "0.4;0.2;0.6;0.8", - "model_id": "C12", - "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", - "machine_tech": "FFF", - "family": "BBL-3DP", "bed_model": "bbl-3dp-X1.stl", "bed_texture": "bbl-3dp-logo.svg", - "default_materials": "Generic PLA Silk;Generic PLA;Bambu PLA Matte @BBL X1;Bambu PLA Basic @BBL X1;Bambu ABS @BBL X1C;Bambu PC @BBL X1C;Bambu Support W @BBL X1;Bambu TPU 95A @BBL X1;PolyTerra PLA @BBL X1;PolyLite PLA @BBL X1;" + "family": "BBL-3DP", + "machine_tech": "FFF", + "model_id": "C12", + "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", + "default_materials": "Bambu PLA Matte @BBL X1C;Bambu PLA Basic @BBL X1C;Bambu PLA-CF @BBL X1C;Bambu PETG Basic @BBL X1C;Bambu PETG-CF @BBL X1C;Bambu ABS @BBL X1C;Bambu PLA Silk @BBL X1C;Bambu PAHT-CF @BBL X1C;Bambu Support For PLA @BBL X1C;Bambu Support For PA/PET @BBL X1C;Generic PLA;Generic PLA High Speed @BBL X1C;Generic PETG" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json index 7bf7fc84025..85da2d84cd6 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 0.4 nozzle.json @@ -34,5 +34,6 @@ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1E 0.4 nozzle" ], - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n{if scan_first_layer}\n;=========register first layer scan=====\nM977 S1 P60\n{endif}\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_no_support_extruder]==\"PLA\"}\n {if (bed_temperature[initial_no_support_extruder] >45)||(bed_temperature_initial_layer[initial_no_support_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_no_support_extruder] >50)||(bed_temperature_initial_layer[initial_no_support_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_no_support_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_no_support_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_no_support_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_no_support_extruder]}\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X128 Y128\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n;===== check scanner clarity ===========================\nG1 X128 Y128 F24000\nG28 Z P0\nM972 S5 P0\nG1 X230 Y15 F24000\n;===== check scanner clarity end =======================\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_no_support_extruder]==\"PLA\"}\n {if (bed_temperature[initial_no_support_extruder] >45)||(bed_temperature_initial_layer[initial_no_support_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_no_support_extruder] >50)||(bed_temperature_initial_layer[initial_no_support_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\nM104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== mech mode fast check============================\n\n{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1\nG90\nG1 X128 Y128 F20000\nM976 S3 P2 ;register void printing detection\n{endif}\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature[initial_no_support_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X231 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n\n;===== draw extrinsic para cali paint =================\nM1002 judge_flag extrude_cali_flag\nM622 J1\n\n M1002 gcode_claim_action : 8\n\n T1000\n\n G0 F1200.0 X231 Y15 Z0.2 E0.741\n G0 F1200.0 X226 Y15 Z0.2 E0.275\n G0 F1200.0 X226 Y8 Z0.2 E0.384\n G0 F1200.0 X216 Y8 Z0.2 E0.549\n G0 F1200.0 X216 Y1.5 Z0.2 E0.357\n\n G0 X48.0 E12.0 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X48.0 Y14 E0.92 F1200.0\n G0 X35.0 Y6.0 E1.03 F1200.0\n\n ;=========== extruder cali extrusion ==================\n T1000\n M83\n {if default_acceleration > 0}\n {if outer_wall_acceleration > 0}\n M204 S[outer_wall_acceleration]\n {else}\n M204 S[default_acceleration]\n {endif}\n {endif}\n G0 X35.000 Y6.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800\n M106 S0 ; turn off fan\n G0 X185.000 E9.35441 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X187 Z0\n G1 F1500.000 E-0.800\n G0 Z1\n G0 X180 Z0.3 F18000\n\n M900 L1000.0 M1.0\n M900 K0.040\n G0 X45.000 F30000\n G0 Y8.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n M400\n\n G0 X45.000 F30000\n M900 K0.020\n G0 X45.000 F30000\n G0 Y10.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n M400\n\n G0 X45.000 F30000\n M900 K0.000\n G0 X45.000 F30000\n G0 Y12.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n\n G0 X45.000 F30000 ; move to start point\n\nM623 ; end of \"draw extrinsic para cali paint\"\n\n\nM1002 judge_flag extrude_cali_flag\nM622 J0\n G0 X231 Y1.5 F30000\n G0 X18 E14.3 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM623\n\nM104 S140\n\n\n;=========== laser and rgb calibration ===========\nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X235.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\nM400 P100\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y6.0 Z0.3 F18000.0;Move to vertical extrude line pos\nM960 S2 P1\nM400 P100\nM973 S6 P1; use auto exposure for vertical laser by xcam\nM960 S0 P0\n\n;=========== handeye calibration ======================\nM1002 judge_flag extrude_cali_flag\nM622 J1\n\n M973 S3 P1 ; camera start stream\n M400 P500\n M973 S1\n G0 F6000 X228.500 Y4.500 Z0.000\n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P0\n M400 P500\n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P200\n M971 S5 P1\n M973 S2 P1\n M400 P500\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P3\n G0 Z0.500 F12000\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P4\n M973 S2 P0\n M400 P500\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P500\n M971 S5 P2\n M963 S1\n M400 P1500\n M964\n T1100\n G0 F6000 X228.500 Y4.500 Z0.000\n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P0\n M400 P500\n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P200\n M971 S5 P1\n M973 S2 P1\n M400 P500\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P3\n G0 Z0.500 F12000\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P4\n M973 S2 P0\n M400 P500\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P500\n M971 S5 P2\n M963 S1\n M400 P1500\n M964\n T1100\n G1 Z3 F3000\n\n M400\n M500 ; save cali data\n\n M104 S{nozzle_temperature[initial_no_support_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100\n M400 P400\n M960 S0 P0\n G0 F30000.000 Y10.000 X65.000 Z0.000\n M400 P400\n M960 S1 P1\n M400 P50\n\n M969 S1 N3 A2000\n G0 F360.000 X181.000 Z0.000\n M980.3 A70.000 B{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*60/4} C5.000 D{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*60} E5.000 F175.000 H1.000 I0.000 J0.020 K0.040\n M400 P100\n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y4.000 F30000 ; move to test line pos\n M969 S0 ; turn off scanning\n M960 S0 P0\n\n\n G1 Z2 F20000\n T1000\n G0 X45.000 Y4.000 F30000 E0\n M109 S{nozzle_temperature[initial_no_support_extruder]}\n G0 Z0.3\n G1 F1500.000 E3.600\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n\n ; see if extrude cali success, if not ,use default value\n M1002 judge_last_extrude_cali_success\n M622 J0\n M400\n M900 K0.02 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.02}\n M623\n\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X185.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X190.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X195.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X200.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X205.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X210.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X215.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X220.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X225.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n M973 S4\n\nM623\n\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM973 S4 ; turn off scanner\nM400 ; wait all motion done before implement the emprical L parameters\n;M900 L500.0 ; Empirical parameters\nM109 S[nozzle_temperature_initial_layer]\nM960 S1 P0 ; turn off laser\nM960 S2 P0 ; turn off laser\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\nG90\nM83\nT1000\nG1 E{-retraction_length[initial_no_support_extruder]} F1800\nG1 X128.0 Y253.0 Z0.2 F24000.0;Move to start position\nG1 E{retraction_length[initial_no_support_extruder]} F1800\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]}\nG0 X253 E6.4 F{outer_wall_volumetric_speed/(0.3*0.6) * 60}\nG0 Y128 E6.4\nG0 X252.5\nG0 Y252.5 E6.4\nG0 X128 E6.4" + "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n{if scan_first_layer}\n;=========register first layer scan=====\nM977 S1 P60\n{endif}\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_no_support_extruder]==\"PLA\"}\n {if (bed_temperature[initial_no_support_extruder] >45)||(bed_temperature_initial_layer[initial_no_support_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_no_support_extruder] >50)||(bed_temperature_initial_layer[initial_no_support_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_no_support_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_no_support_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_no_support_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_no_support_extruder]}\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X128 Y128\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n;===== check scanner clarity ===========================\nG1 X128 Y128 F24000\nG28 Z P0\nM972 S5 P0\nG1 X230 Y15 F24000\n;===== check scanner clarity end =======================\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_no_support_extruder]==\"PLA\"}\n {if (bed_temperature[initial_no_support_extruder] >45)||(bed_temperature_initial_layer[initial_no_support_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_no_support_extruder] >50)||(bed_temperature_initial_layer[initial_no_support_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\nM104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== mech mode fast check============================\n\n{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1\nG90\nG1 X128 Y128 F20000\nM976 S3 P2 ;register void printing detection\n{endif}\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature[initial_no_support_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X231 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n\n;===== draw extrinsic para cali paint =================\nM1002 judge_flag extrude_cali_flag\nM622 J1\n\n M1002 gcode_claim_action : 8\n\n T1000\n\n G0 F1200.0 X231 Y15 Z0.2 E0.741\n G0 F1200.0 X226 Y15 Z0.2 E0.275\n G0 F1200.0 X226 Y8 Z0.2 E0.384\n G0 F1200.0 X216 Y8 Z0.2 E0.549\n G0 F1200.0 X216 Y1.5 Z0.2 E0.357\n\n G0 X48.0 E12.0 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X48.0 Y14 E0.92 F1200.0\n G0 X35.0 Y6.0 E1.03 F1200.0\n\n ;=========== extruder cali extrusion ==================\n T1000\n M83\n {if default_acceleration > 0}\n {if outer_wall_acceleration > 0}\n M204 S[outer_wall_acceleration]\n {else}\n M204 S[default_acceleration]\n {endif}\n {endif}\n G0 X35.000 Y6.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800\n M106 S0 ; turn off fan\n G0 X185.000 E9.35441 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X187 Z0\n G1 F1500.000 E-0.800\n G0 Z1\n G0 X180 Z0.3 F18000\n\n M900 L1000.0 M1.0\n M900 K0.040\n G0 X45.000 F30000\n G0 Y8.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n M400\n\n G0 X45.000 F30000\n M900 K0.020\n G0 X45.000 F30000\n G0 Y10.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n M400\n\n G0 X45.000 F30000\n M900 K0.000\n G0 X45.000 F30000\n G0 Y12.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n\n G0 X45.000 F30000 ; move to start point\n\nM623 ; end of \"draw extrinsic para cali paint\"\n\n\nM1002 judge_flag extrude_cali_flag\nM622 J0\n G0 X231 Y1.5 F30000\n G0 X18 E14.3 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM623\n\nM104 S140\n\n\n;=========== laser and rgb calibration ===========\nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X235.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\nM400 P100\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y6.0 Z0.3 F18000.0;Move to vertical extrude line pos\nM960 S2 P1\nM400 P100\nM973 S6 P1; use auto exposure for vertical laser by xcam\nM960 S0 P0\n\n;=========== handeye calibration ======================\nM1002 judge_flag extrude_cali_flag\nM622 J1\n\n M973 S3 P1 ; camera start stream\n M400 P500\n M973 S1\n G0 F6000 X228.500 Y4.500 Z0.000\n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P0\n M400 P500\n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P200\n M971 S5 P1\n M973 S2 P1\n M400 P500\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P3\n G0 Z0.500 F12000\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P4\n M973 S2 P0\n M400 P500\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P500\n M971 S5 P2\n M963 S1\n M400 P1500\n M964\n T1100\n G0 F6000 X228.500 Y4.500 Z0.000\n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P0\n M400 P500\n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P200\n M971 S5 P1\n M973 S2 P1\n M400 P500\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P3\n G0 Z0.500 F12000\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P4\n M973 S2 P0\n M400 P500\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P500\n M971 S5 P2\n M963 S1\n M400 P1500\n M964\n T1100\n G1 Z3 F3000\n\n M400\n M500 ; save cali data\n\n M104 S{nozzle_temperature[initial_no_support_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100\n M400 P400\n M960 S0 P0\n G0 F30000.000 Y10.000 X65.000 Z0.000\n M400 P400\n M960 S1 P1\n M400 P50\n\n M969 S1 N3 A2000\n G0 F360.000 X181.000 Z0.000\n M980.3 A70.000 B{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*60/4} C5.000 D{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*60} E5.000 F175.000 H1.000 I0.000 J0.020 K0.040\n M400 P100\n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y4.000 F30000 ; move to test line pos\n M969 S0 ; turn off scanning\n M960 S0 P0\n\n\n G1 Z2 F20000\n T1000\n G0 X45.000 Y4.000 F30000 E0\n M109 S{nozzle_temperature[initial_no_support_extruder]}\n G0 Z0.3\n G1 F1500.000 E3.600\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n\n ; see if extrude cali success, if not ,use default value\n M1002 judge_last_extrude_cali_success\n M622 J0\n M400\n M900 K0.02 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.02}\n M623\n\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X185.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X190.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X195.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X200.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X205.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X210.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X215.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X220.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X225.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n M973 S4\n\nM623\n\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM973 S4 ; turn off scanner\nM400 ; wait all motion done before implement the emprical L parameters\n;M900 L500.0 ; Empirical parameters\nM109 S[nozzle_temperature_initial_layer]\nM960 S1 P0 ; turn off laser\nM960 S2 P0 ; turn off laser\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\nG90\nM83\nT1000\nG1 E{-retraction_length[initial_no_support_extruder]} F1800\nG1 X128.0 Y253.0 Z0.2 F24000.0;Move to start position\nG1 E{retraction_length[initial_no_support_extruder]} F1800\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]}\nG0 X253 E6.4 F{outer_wall_volumetric_speed/(0.3*0.6) * 60}\nG0 Y128 E6.4\nG0 X252.5\nG0 Y252.5 E6.4\nG0 X128 E6.4", + "change_filament_gcode": "M620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1 && (z_hop_types[current_extruder] == 0 || z_hop_types[current_extruder] == 3)}\nG17\nG2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\nG1 Z{max_layer_z + 3.0} F1200\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n{if old_filament_temp > 142 && next_extruder < 255}\nM104 S[old_filament_temp]\n{endif}\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\n\nG1 X20 Y50 F21000\nG1 Y-3\n{if toolchange_count == 2}\n; get travel path for change filament\nM620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\nM620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\nM620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n{endif}\nM620.1 E F[old_filament_e_feedrate] T{nozzle_temperature_range_high[previous_extruder]}\nT[next_extruder]\nM620.1 E F[new_filament_e_feedrate] T{nozzle_temperature_range_high[next_extruder]}\n\n{if next_extruder < 255}\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\n; always use highest temperature to flush\nM400\n{if filament_type[next_extruder] == \"PETG\"}\nM109 S220\n{else}\nM109 S[nozzle_temperature_range_high]\n{endif}\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate} ; do not need pulsatile flushing for start part\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\n; FLUSH_END\nG1 E-[old_retract_length_toolchange] F1800\n{if (flush_length_2 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[old_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\n{if (flush_length_3 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\n{if (flush_length_4 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\n; FLUSH_END\n{endif}\n; FLUSH_START\nM400\nM109 S[new_filament_temp]\nG1 E2 F{new_filament_e_feedrate} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\nM400\nG92 E0\nG1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\nG1 Z{max_layer_z + 3.0} F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[default_acceleration]\n{endif}\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\nM621 S[next_extruder]A\n" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.4 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.4 nozzle.json index 3d46a130dd3..275a8ed234c 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.4 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.4 nozzle.json @@ -32,5 +32,6 @@ "Bambu Lab X1 0.4 nozzle", "Bambu Lab X1E 0.4 nozzle" ], - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n{if scan_first_layer}\n;=========register first layer scan=====\nM977 S1 P60\n{endif}\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_no_support_extruder]==\"PLA\"}\n {if (bed_temperature[initial_no_support_extruder] >45)||(bed_temperature_initial_layer[initial_no_support_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_no_support_extruder] >50)||(bed_temperature_initial_layer[initial_no_support_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_no_support_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_no_support_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_no_support_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_no_support_extruder]}\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X128 Y128\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n;===== check scanner clarity ===========================\nG1 X128 Y128 F24000\nG28 Z P0\nM972 S5 P0\nG1 X230 Y15 F24000\n;===== check scanner clarity end =======================\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_no_support_extruder]==\"PLA\"}\n {if (bed_temperature[initial_no_support_extruder] >45)||(bed_temperature_initial_layer[initial_no_support_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_no_support_extruder] >50)||(bed_temperature_initial_layer[initial_no_support_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\nM104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== mech mode fast check============================\n\n{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1\nG90\nG1 X128 Y128 F20000\nM976 S3 P2 ;register void printing detection\n{endif}\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature[initial_no_support_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X231 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n\n;===== draw extrinsic para cali paint =================\nM1002 judge_flag extrude_cali_flag\nM622 J1\n\n M1002 gcode_claim_action : 8\n\n T1000\n\n G0 F1200.0 X231 Y15 Z0.2 E0.741\n G0 F1200.0 X226 Y15 Z0.2 E0.275\n G0 F1200.0 X226 Y8 Z0.2 E0.384\n G0 F1200.0 X216 Y8 Z0.2 E0.549\n G0 F1200.0 X216 Y1.5 Z0.2 E0.357\n\n G0 X48.0 E12.0 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X48.0 Y14 E0.92 F1200.0\n G0 X35.0 Y6.0 E1.03 F1200.0\n\n ;=========== extruder cali extrusion ==================\n T1000\n M83\n {if default_acceleration > 0}\n {if outer_wall_acceleration > 0}\n M204 S[outer_wall_acceleration]\n {else}\n M204 S[default_acceleration]\n {endif}\n {endif}\n G0 X35.000 Y6.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800\n M106 S0 ; turn off fan\n G0 X185.000 E9.35441 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X187 Z0\n G1 F1500.000 E-0.800\n G0 Z1\n G0 X180 Z0.3 F18000\n\n M900 L1000.0 M1.0\n M900 K0.040\n G0 X45.000 F30000\n G0 Y8.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n M400\n\n G0 X45.000 F30000\n M900 K0.020\n G0 X45.000 F30000\n G0 Y10.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n M400\n\n G0 X45.000 F30000\n M900 K0.000\n G0 X45.000 F30000\n G0 Y12.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n\n G0 X45.000 F30000 ; move to start point\n\nM623 ; end of \"draw extrinsic para cali paint\"\n\n\nM1002 judge_flag extrude_cali_flag\nM622 J0\n G0 X231 Y1.5 F30000\n G0 X18 E14.3 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM623\n\nM104 S140\n\n\n;=========== laser and rgb calibration ===========\nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X235.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\nM400 P100\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y6.0 Z0.3 F18000.0;Move to vertical extrude line pos\nM960 S2 P1\nM400 P100\nM973 S6 P1; use auto exposure for vertical laser by xcam\nM960 S0 P0\n\n;=========== handeye calibration ======================\nM1002 judge_flag extrude_cali_flag\nM622 J1\n\n M973 S3 P1 ; camera start stream\n M400 P500\n M973 S1\n G0 F6000 X228.500 Y4.500 Z0.000\n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P0\n M400 P500\n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P200\n M971 S5 P1\n M973 S2 P1\n M400 P500\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P3\n G0 Z0.500 F12000\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P4\n M973 S2 P0\n M400 P500\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P500\n M971 S5 P2\n M963 S1\n M400 P1500\n M964\n T1100\n G0 F6000 X228.500 Y4.500 Z0.000\n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P0\n M400 P500\n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P200\n M971 S5 P1\n M973 S2 P1\n M400 P500\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P3\n G0 Z0.500 F12000\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P4\n M973 S2 P0\n M400 P500\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P500\n M971 S5 P2\n M963 S1\n M400 P1500\n M964\n T1100\n G1 Z3 F3000\n\n M400\n M500 ; save cali data\n\n M104 S{nozzle_temperature[initial_no_support_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100\n M400 P400\n M960 S0 P0\n G0 F30000.000 Y10.000 X65.000 Z0.000\n M400 P400\n M960 S1 P1\n M400 P50\n\n M969 S1 N3 A2000\n G0 F360.000 X181.000 Z0.000\n M980.3 A70.000 B{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*60/4} C5.000 D{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*60} E5.000 F175.000 H1.000 I0.000 J0.020 K0.040\n M400 P100\n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y4.000 F30000 ; move to test line pos\n M969 S0 ; turn off scanning\n M960 S0 P0\n\n\n G1 Z2 F20000\n T1000\n G0 X45.000 Y4.000 F30000 E0\n M109 S{nozzle_temperature[initial_no_support_extruder]}\n G0 Z0.3\n G1 F1500.000 E3.600\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n\n ; see if extrude cali success, if not ,use default value\n M1002 judge_last_extrude_cali_success\n M622 J0\n M400\n M900 K0.02 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.02}\n M623\n\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X185.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X190.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X195.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X200.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X205.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X210.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X215.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X220.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X225.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n M973 S4\n\nM623\n\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM973 S4 ; turn off scanner\nM400 ; wait all motion done before implement the emprical L parameters\n;M900 L500.0 ; Empirical parameters\nM109 S[nozzle_temperature_initial_layer]\nM960 S1 P0 ; turn off laser\nM960 S2 P0 ; turn off laser\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\nG90\nM83\nT1000\nG1 E{-retraction_length[initial_no_support_extruder]} F1800\nG1 X128.0 Y253.0 Z0.2 F24000.0;Move to start position\nG1 E{retraction_length[initial_no_support_extruder]} F1800\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]}\nG0 X253 E6.4 F{outer_wall_volumetric_speed/(0.3*0.6) * 60}\nG0 Y128 E6.4\nG0 X252.5\nG0 Y252.5 E6.4\nG0 X128 E6.4" + "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 20230707 =====================\n;===== turn on the HB fan =================\nM104 S75 ;set extruder temp to turn on the HB fan and prevent filament oozing from nozzle\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG380 S2 Z30 F300 ; G380 is same as G38; lower the hotbed , to prevent the nozzle is below the hotbed\nG380 S2 Z-25 F300 ;\nG1 Z5 F300;\nG90\nM17 X1.2 Y1.2 Z0.75 ; reset motor current to default\nM960 S5 P1 ; turn on logo lamp\nG90\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 5\nM221 X0 Y0 Z0 ; turn off soft endstop to prevent protential logic problem\nG29.1 Z{+0.0} ; clear z-trim value first\nM204 S10000 ; init ACC set to 10m/s^2\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n\n{if scan_first_layer}\n;=========register first layer scan=====\nM977 S1 P60\n{endif}\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_no_support_extruder]==\"PLA\"}\n {if (bed_temperature[initial_no_support_extruder] >45)||(bed_temperature_initial_layer[initial_no_support_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_no_support_extruder] >50)||(bed_temperature_initial_layer[initial_no_support_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\n;===== prepare print temperature and material ==========\nM104 S[nozzle_temperature_initial_layer] ;set extruder temp\nG91\nG0 Z10 F1200\nG90\nG28 X\nM975 S1 ; turn on\nG1 X60 F12000\nG1 Y245\nG1 Y265 F3000\nM620 M\nM620 S[initial_no_support_extruder]A ; switch material if AMS exist\n M109 S[nozzle_temperature_initial_layer]\n G1 X120 F12000\n\n G1 X20 Y50 F12000\n G1 Y-3\n T[initial_no_support_extruder]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_no_support_extruder]A\nM620.1 E F{filament_max_volumetric_speed[initial_no_support_extruder]/2.4053*60} T{nozzle_temperature_range_high[initial_no_support_extruder]}\n\nM412 S1 ; ===turn on filament runout detection===\n\nM109 S250 ;set nozzle to common flush temp\nM106 P1 S0\nG92 E0\nG1 E50 F200\nM400\nM104 S[nozzle_temperature_initial_layer]\nG92 E0\nG1 E50 F200\nM400\nM106 P1 S255\nG92 E0\nG1 E5 F300\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20} ; drop nozzle temp, make filament shink a bit\nG92 E0\nG1 E-0.5 F300\n\nG1 X70 F9000\nG1 X76 F15000\nG1 X65 F15000\nG1 X76 F15000\nG1 X65 F15000; shake to put down garbage\nG1 X80 F6000\nG1 X95 F15000\nG1 X80 F15000\nG1 X165 F15000; wipe and shake\nM400\nM106 P1 S0\n;===== prepare print temperature and material end =====\n\n\n;===== wipe nozzle ===============================\nM1002 gcode_claim_action : 14\nM975 S1\nM106 S255\nG1 X65 Y230 F18000\nG1 Y264 F6000\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]-20}\nG1 X100 F18000 ; first wipe mouth\n\nG0 X135 Y253 F20000 ; move to exposed steel surface edge\nG28 Z P0 T300; home z with low precision,permit 300deg temperature\nG29.2 S0 ; turn off ABL\nG0 Z5 F20000\n\nG1 X60 Y265\nG92 E0\nG1 E-0.5 F300 ; retrack more\nG1 X100 F5000; second wipe mouth\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X100 F5000\nG1 X70 F15000\nG1 X90 F5000\nG0 X128 Y261 Z-1.5 F20000 ; move to exposed steel surface and stop the nozzle\nM104 S140 ; set temp down to heatbed acceptable\nM106 S255 ; turn on fan (G28 has turn off fan)\n\nM221 S; push soft endstop status\nM221 Z0 ;turn off Z axis endstop\nG0 Z0.5 F20000\nG0 X125 Y259.5 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y262.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y260.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.5\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 Z0.5 F20000\nG0 X125 Y261.0\nG0 Z-1.01\nG0 X131 F211\nG0 X124\nG0 X128\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\nG2 I0.5 J0 F300\n\nM109 S140 ; wait nozzle temp down to heatbed acceptable\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\nG2 I0.5 J0 F3000\n\nM221 R; pop softend status\nG1 Z10 F1200\nM400\nG1 Z10\nG1 F30000\nG1 X128 Y128\nG29.2 S1 ; turn on ABL\n;G28 ; home again after hard wipe mouth\nM106 S0 ; turn off fan , too noisy\n;===== wipe nozzle end ================================\n\n;===== check scanner clarity ===========================\nG1 X128 Y128 F24000\nG28 Z P0\nM972 S5 P0\nG1 X230 Y15 F24000\n;===== check scanner clarity end =======================\n\n;===== bed leveling ==================================\nM1002 judge_flag g29_before_print_flag\nM622 J1\n\n M1002 gcode_claim_action : 1\n G29 A X{first_layer_print_min[0]} Y{first_layer_print_min[1]} I{first_layer_print_size[0]} J{first_layer_print_size[1]}\n M400\n M500 ; save cali data\n\nM623\n;===== bed leveling end ================================\n\n;===== home after wipe mouth============================\nM1002 judge_flag g29_before_print_flag\nM622 J0\n\n M1002 gcode_claim_action : 13\n G28\n\nM623\n;===== home after wipe mouth end =======================\n\nM975 S1 ; turn on vibration supression\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_no_support_extruder]==\"PLA\"}\n {if (bed_temperature[initial_no_support_extruder] >45)||(bed_temperature_initial_layer[initial_no_support_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[initial_no_support_extruder] >50)||(bed_temperature_initial_layer[initial_no_support_extruder] >50)}\n M106 P3 S255\n {endif};Prevent PLA from jamming\n{endif}\nM106 P2 S100 ; turn on big fan ,to cool down toolhead\n\nM104 S{nozzle_temperature_initial_layer[initial_no_support_extruder]} ; set extrude temp earlier, to reduce wait time\n\n;===== mech mode fast check============================\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q1 A7 B30 C80 H15 K0\nM974 Q1 S2 P0\n\nG1 X128 Y128 Z10 F20000\nM400 P200\nM970.3 Q0 A7 B30 C90 Q0 H15 K0\nM974 Q0 S2 P0\n\nM975 S1\nG1 F30000\nG1 X230 Y15\nG28 X ; re-home XY\n;===== mech mode fast check============================\n\n{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1\nG90\nG1 X128 Y128 F20000\nM976 S3 P2 ;register void printing detection\n{endif}\n\n;===== noozle load line ===============================\nM975 S1\nG90\nM83\nT1000\nG1 X18.0 Y1.0 Z0.8 F18000;Move to start position\nM109 S{nozzle_temperature[initial_no_support_extruder]}\nG1 Z0.2\nG0 E2 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nG0 Y11 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E0.2\nG0 Y1.5 E0.700\nG0 X231 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM400\n\n;===== for Textured PEI Plate , lower the nozzle as the nozzle was touching topmost of the texture when homing ==\n;curr_bed_type={curr_bed_type}\n{if curr_bed_type==\"Textured PEI Plate\"}\nG29.1 Z{-0.04} ; for Textured PEI Plate\n{endif}\n\n;===== draw extrinsic para cali paint =================\nM1002 judge_flag extrude_cali_flag\nM622 J1\n\n M1002 gcode_claim_action : 8\n\n T1000\n\n G0 F1200.0 X231 Y15 Z0.2 E0.741\n G0 F1200.0 X226 Y15 Z0.2 E0.275\n G0 F1200.0 X226 Y8 Z0.2 E0.384\n G0 F1200.0 X216 Y8 Z0.2 E0.549\n G0 F1200.0 X216 Y1.5 Z0.2 E0.357\n\n G0 X48.0 E12.0 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X48.0 Y14 E0.92 F1200.0\n G0 X35.0 Y6.0 E1.03 F1200.0\n\n ;=========== extruder cali extrusion ==================\n T1000\n M83\n {if default_acceleration > 0}\n {if outer_wall_acceleration > 0}\n M204 S[outer_wall_acceleration]\n {else}\n M204 S[default_acceleration]\n {endif}\n {endif}\n G0 X35.000 Y6.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800\n M106 S0 ; turn off fan\n G0 X185.000 E9.35441 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G0 X187 Z0\n G1 F1500.000 E-0.800\n G0 Z1\n G0 X180 Z0.3 F18000\n\n M900 L1000.0 M1.0\n M900 K0.040\n G0 X45.000 F30000\n G0 Y8.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n M400\n\n G0 X45.000 F30000\n M900 K0.020\n G0 X45.000 F30000\n G0 Y10.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n M400\n\n G0 X45.000 F30000\n M900 K0.000\n G0 X45.000 F30000\n G0 Y12.000 F30000\n G1 F1500.000 E0.800\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y6.000 F30000 ; move y to clear pos\n G1 Z0.3\n\n G0 X45.000 F30000 ; move to start point\n\nM623 ; end of \"draw extrinsic para cali paint\"\n\n\nM1002 judge_flag extrude_cali_flag\nM622 J0\n G0 X231 Y1.5 F30000\n G0 X18 E14.3 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\nM623\n\nM104 S140\n\n\n;=========== laser and rgb calibration ===========\nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X235.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\nM400 P100\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y6.0 Z0.3 F18000.0;Move to vertical extrude line pos\nM960 S2 P1\nM400 P100\nM973 S6 P1; use auto exposure for vertical laser by xcam\nM960 S0 P0\n\n;=========== handeye calibration ======================\nM1002 judge_flag extrude_cali_flag\nM622 J1\n\n M973 S3 P1 ; camera start stream\n M400 P500\n M973 S1\n G0 F6000 X228.500 Y4.500 Z0.000\n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P0\n M400 P500\n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P200\n M971 S5 P1\n M973 S2 P1\n M400 P500\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P3\n G0 Z0.500 F12000\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P4\n M973 S2 P0\n M400 P500\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P500\n M971 S5 P2\n M963 S1\n M400 P1500\n M964\n T1100\n G0 F6000 X228.500 Y4.500 Z0.000\n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P0\n M400 P500\n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P200\n M971 S5 P1\n M973 S2 P1\n M400 P500\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P3\n G0 Z0.500 F12000\n M960 S0 P0\n M960 S2 P1\n G0 X228.5 Y11.0\n M400 P200\n M971 S5 P4\n M973 S2 P0\n M400 P500\n M960 S0 P0\n M960 S1 P1\n G0 X221.00 Y4.50\n M400 P500\n M971 S5 P2\n M963 S1\n M400 P1500\n M964\n T1100\n G1 Z3 F3000\n\n M400\n M500 ; save cali data\n\n M104 S{nozzle_temperature[initial_no_support_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100\n M400 P400\n M960 S0 P0\n G0 F30000.000 Y10.000 X65.000 Z0.000\n M400 P400\n M960 S1 P1\n M400 P50\n\n M969 S1 N3 A2000\n G0 F360.000 X181.000 Z0.000\n M980.3 A70.000 B{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*60/4} C5.000 D{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*60} E5.000 F175.000 H1.000 I0.000 J0.020 K0.040\n M400 P100\n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y4.000 F30000 ; move to test line pos\n M969 S0 ; turn off scanning\n M960 S0 P0\n\n\n G1 Z2 F20000\n T1000\n G0 X45.000 Y4.000 F30000 E0\n M109 S{nozzle_temperature[initial_no_support_extruder]}\n G0 Z0.3\n G1 F1500.000 E3.600\n G1 X65.000 E1.24726 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X75.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X80.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X85.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X90.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X95.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X100.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X105.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X110.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X115.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X120.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X125.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X130.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X135.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n\n ; see if extrude cali success, if not ,use default value\n M1002 judge_last_extrude_cali_success\n M622 J0\n M400\n M900 K0.02 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.02}\n M623\n\n G1 X140.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X145.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X150.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X155.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X160.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X165.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X170.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X175.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X180.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X185.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X190.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X195.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X200.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X205.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X210.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X215.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n G1 X220.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X225.000 E0.31181 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n M973 S4\n\nM623\n\n;========turn off light and wait extrude temperature =============\nM1002 gcode_claim_action : 0\nM973 S4 ; turn off scanner\nM400 ; wait all motion done before implement the emprical L parameters\n;M900 L500.0 ; Empirical parameters\nM109 S[nozzle_temperature_initial_layer]\nM960 S1 P0 ; turn off laser\nM960 S2 P0 ; turn off laser\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off big fan\nM106 P3 S0 ; turn off chamber fan\n\nM975 S1 ; turn on mech mode supression\nG90\nM83\nT1000\nG1 E{-retraction_length[initial_no_support_extruder]} F1800\nG1 X128.0 Y253.0 Z0.2 F24000.0;Move to start position\nG1 E{retraction_length[initial_no_support_extruder]} F1800\nM109 S{nozzle_temperature_initial_layer[initial_no_support_extruder]}\nG0 X253 E6.4 F{outer_wall_volumetric_speed/(0.3*0.6) * 60}\nG0 Y128 E6.4\nG0 X252.5\nG0 Y252.5 E6.4\nG0 X128 E6.4", + "change_filament_gcode": "M620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1 && (z_hop_types[current_extruder] == 0 || z_hop_types[current_extruder] == 3)}\nG17\nG2 Z{z_after_toolchange + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\nG1 Z{max_layer_z + 3.0} F1200\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n{if old_filament_temp > 142 && next_extruder < 255}\nM104 S[old_filament_temp]\n{endif}\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\n\nG1 X20 Y50 F21000\nG1 Y-3\n{if toolchange_count == 2}\n; get travel path for change filament\nM620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\nM620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\nM620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n{endif}\nM620.1 E F[old_filament_e_feedrate] T{nozzle_temperature_range_high[previous_extruder]}\nT[next_extruder]\nM620.1 E F[new_filament_e_feedrate] T{nozzle_temperature_range_high[next_extruder]}\n\n{if next_extruder < 255}\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\n; always use highest temperature to flush\nM400\n{if filament_type[next_extruder] == \"PETG\"}\nM109 S220\n{else}\nM109 S[nozzle_temperature_range_high]\n{endif}\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate} ; do not need pulsatile flushing for start part\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\n; FLUSH_END\nG1 E-[old_retract_length_toolchange] F1800\n{if (flush_length_2 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[old_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\n{if (flush_length_3 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\n{if (flush_length_4 > 1) && (filament_type[next_extruder]==\"PLA-CF\" || filament_type[next_extruder]==\"PETG\")}\nM106 P1 S255\nM400 S3\nM106 P1 S0\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y245 F21000\nG1 X65 \nG1 Y265 F3000\n{endif}\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\n; FLUSH_END\n{endif}\n; FLUSH_START\nM400\nM109 S[new_filament_temp]\nG1 E2 F{new_filament_e_feedrate} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\nM400\nG92 E0\nG1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\nG1 Z{max_layer_z + 3.0} F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[default_acceleration]\n{endif}\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\nM621 S[next_extruder]A\n" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon.json b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon.json index fea08f27e8a..f7b35d35918 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon.json @@ -2,11 +2,11 @@ "type": "machine_model", "name": "Bambu Lab X1 Carbon", "nozzle_diameter": "0.4;0.2;0.6;0.8", - "model_id": "BL-P001", - "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1 Carbon.json", - "machine_tech": "FFF", - "family": "BBL-3DP", "bed_model": "bbl-3dp-X1.stl", "bed_texture": "bbl-3dp-logo.svg", - "default_materials": "Generic PLA Silk;Generic PLA;Bambu PLA Matte @BBL X1C;Bambu PLA Basic @BBL X1C;Bambu ABS @BBL X1C;Bambu PC @BBL X1C;Bambu Support W @BBL X1C;Bambu TPU 95A @BBL X1C;PolyTerra PLA @BBL X1C;PolyLite PLA @BBL X1C;" + "family": "BBL-3DP", + "machine_tech": "FFF", + "model_id": "BL-P001", + "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1 Carbon.json", + "default_materials": "Bambu PLA Matte @BBL X1C;Bambu PLA Basic @BBL X1C;Bambu PLA-CF @BBL X1C;Bambu PETG Basic @BBL X1C;Bambu PETG-CF @BBL X1C;Bambu ABS @BBL X1C;Bambu PC @BBL X1C;Bambu TPU 95A @BBL X1C;Bambu PAHT-CF @BBL X1C;Bambu Support For PLA @BBL X1C;Bambu Support For PA/PET @BBL X1C;Generic PLA;Generic PLA High Speed @BBL X1C" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab X1.json b/resources/profiles/BBL/machine/Bambu Lab X1.json index 22e29b15b24..b71f60dc3f5 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1.json @@ -2,11 +2,11 @@ "type": "machine_model", "name": "Bambu Lab X1", "nozzle_diameter": "0.4;0.2;0.6;0.8", - "model_id": "BL-P002", - "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", - "machine_tech": "FFF", - "family": "BBL-3DP", "bed_model": "bbl-3dp-X1.stl", "bed_texture": "bbl-3dp-logo.svg", - "default_materials": "Generic PLA Silk;Generic PLA;Bambu PLA Matte @BBL X1;Bambu PLA Basic @BBL X1;Bambu ABS @BBL X1C;Bambu PC @BBL X1C;Bambu Support W @BBL X1;Bambu TPU 95A @BBL X1;PolyTerra PLA @BBL X1;PolyLite PLA @BBL X1;" + "family": "BBL-3DP", + "machine_tech": "FFF", + "model_id": "BL-P002", + "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", + "default_materials": "Bambu PLA Matte @BBL X1;Bambu PLA Basic @BBL X1;Bambu PLA-CF @BBL X1C;Bambu PETG Basic @BBL X1C;Bambu PETG-CF @BBL X1C;Bambu ABS @BBL X1C;Bambu PLA Silk @BBL X1;Bambu PAHT-CF @BBL X1C;Bambu Support For PLA @BBL X1C;Bambu Support For PA/PET @BBL X1C;Generic PLA;Generic PLA High Speed @BBL X1C;Generic PETG" } \ No newline at end of file diff --git a/resources/profiles/BBL/machine/Bambu Lab X1E.json b/resources/profiles/BBL/machine/Bambu Lab X1E.json index 0c7396a5c11..e5cbb8f47c0 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1E.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1E.json @@ -8,5 +8,5 @@ "machine_tech": "FFF", "model_id": "C13", "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1 Carbon.json", - "default_materials": "Bambu ABS @BBL X1E;Bambu PC @BBL X1E;Generic PLA Silk @BBL X1C;Generic PLA @BBL X1C;Bambu PLA Matte @BBL X1C;Bambu PLA Basic @BBL X1C;Bambu Support W @BBL X1C;Bambu TPU 95A @BBL X1C;PolyLite PLA @BBL X1C;PolyTerra PLA @BBL X1C" + "default_materials": "Bambu PLA Matte @BBL X1C;Bambu PLA Basic @BBL X1C;Bambu PLA-CF @BBL X1C;Bambu PETG Basic @BBL X1C;Bambu PETG-CF @BBL X1C;Bambu ABS @BBL X1E;Bambu ASA @BBL X1E;Bambu PC @BBL X1E;Bambu PAHT-CF @BBL X1C;Bambu Support For PLA @BBL X1C;Bambu Support For PA/PET @BBL X1C;Generic PPA-CF @BBL X1E;Generic PPS @BBL X1E;Generic PPS-CF @BBL X1E" } \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.06mm Fine @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm Fine @BBL P1P 0.2 nozzle.json new file mode 100644 index 00000000000..f75adbb2e6d --- /dev/null +++ b/resources/profiles/BBL/process/0.06mm Fine @BBL P1P 0.2 nozzle.json @@ -0,0 +1,13 @@ +{ + "type": "process", + "name": "0.06mm Fine @BBL P1P 0.2 nozzle", + "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "from": "system", + "setting_id": "GP063", + "instantiation": "true", + "default_acceleration": "5000", + "outer_wall_acceleration": "2500", + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1M.json b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1M.json index e9698adc27c..0a87af8bb3f 100644 --- a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1M.json +++ b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1M.json @@ -6,6 +6,7 @@ "setting_id": "GP049", "instantiation": "true", "default_acceleration": "6000", + "elefant_foot_compensation": "0", "travel_speed": "700", "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle" diff --git a/resources/profiles/BBL/process/0.08mm Optimal @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm Optimal @BBL P1P 0.2 nozzle.json new file mode 100644 index 00000000000..5f0b6f6484a --- /dev/null +++ b/resources/profiles/BBL/process/0.08mm Optimal @BBL P1P 0.2 nozzle.json @@ -0,0 +1,13 @@ +{ + "type": "process", + "name": "0.08mm Optimal @BBL P1P 0.2 nozzle", + "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "from": "system", + "setting_id": "GP064", + "instantiation": "true", + "default_acceleration": "5000", + "outer_wall_acceleration": "2500", + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.12mm Draft @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.12mm Draft @BBL P1P 0.2 nozzle.json new file mode 100644 index 00000000000..700cd50c0db --- /dev/null +++ b/resources/profiles/BBL/process/0.12mm Draft @BBL P1P 0.2 nozzle.json @@ -0,0 +1,13 @@ +{ + "type": "process", + "name": "0.12mm Draft @BBL P1P 0.2 nozzle", + "inherits": "fdm_process_bbl_0.12_nozzle_0.2", + "from": "system", + "setting_id": "GP065", + "instantiation": "true", + "default_acceleration": "5000", + "outer_wall_acceleration": "2500", + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.12mm Fine @BBL A1M.json b/resources/profiles/BBL/process/0.12mm Fine @BBL A1M.json index 13f587e1bfb..3fb96a90781 100644 --- a/resources/profiles/BBL/process/0.12mm Fine @BBL A1M.json +++ b/resources/profiles/BBL/process/0.12mm Fine @BBL A1M.json @@ -6,6 +6,7 @@ "setting_id": "GP044", "instantiation": "true", "default_acceleration": "6000", + "elefant_foot_compensation": "0", "travel_speed": "700", "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle" diff --git a/resources/profiles/BBL/process/0.14mm Extra Draft @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.14mm Extra Draft @BBL P1P 0.2 nozzle.json new file mode 100644 index 00000000000..d5ad5bd49ff --- /dev/null +++ b/resources/profiles/BBL/process/0.14mm Extra Draft @BBL P1P 0.2 nozzle.json @@ -0,0 +1,13 @@ +{ + "type": "process", + "name": "0.14mm Extra Draft @BBL P1P 0.2 nozzle", + "inherits": "fdm_process_bbl_0.14_nozzle_0.2", + "from": "system", + "setting_id": "GP066", + "instantiation": "true", + "default_acceleration": "5000", + "outer_wall_acceleration": "2500", + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.16mm Optimal @BBL A1M.json b/resources/profiles/BBL/process/0.16mm Optimal @BBL A1M.json index 7e7d9ca25b9..88ef46e4824 100644 --- a/resources/profiles/BBL/process/0.16mm Optimal @BBL A1M.json +++ b/resources/profiles/BBL/process/0.16mm Optimal @BBL A1M.json @@ -6,6 +6,7 @@ "setting_id": "GP045", "instantiation": "true", "default_acceleration": "6000", + "elefant_foot_compensation": "0", "travel_speed": "700", "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle" diff --git a/resources/profiles/BBL/process/0.18mm Fine @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.18mm Fine @BBL P1P 0.6 nozzle.json new file mode 100644 index 00000000000..f4a3ee93ea0 --- /dev/null +++ b/resources/profiles/BBL/process/0.18mm Fine @BBL P1P 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.18mm Fine @BBL P1P 0.6 nozzle", + "inherits": "fdm_process_bbl_0.18_nozzle_0.6", + "from": "system", + "setting_id": "GP072", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1P 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.20mm Standard @BBL A1M.json b/resources/profiles/BBL/process/0.20mm Standard @BBL A1M.json index c168acda498..33edabab4d5 100644 --- a/resources/profiles/BBL/process/0.20mm Standard @BBL A1M.json +++ b/resources/profiles/BBL/process/0.20mm Standard @BBL A1M.json @@ -6,6 +6,7 @@ "setting_id": "GP000", "instantiation": "true", "default_acceleration": "6000", + "elefant_foot_compensation": "0", "travel_speed": "700", "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle" diff --git a/resources/profiles/BBL/process/0.20mm Strength @BBL A1M.json b/resources/profiles/BBL/process/0.20mm Strength @BBL A1M.json index 839948ef6fb..2c2595cc9a2 100644 --- a/resources/profiles/BBL/process/0.20mm Strength @BBL A1M.json +++ b/resources/profiles/BBL/process/0.20mm Strength @BBL A1M.json @@ -6,6 +6,7 @@ "setting_id": "GP046", "instantiation": "true", "default_acceleration": "6000", + "elefant_foot_compensation": "0", "travel_speed": "700", "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle" diff --git a/resources/profiles/BBL/process/0.24mm Draft @BBL A1M.json b/resources/profiles/BBL/process/0.24mm Draft @BBL A1M.json index 1b8d37324f7..3915f80f486 100644 --- a/resources/profiles/BBL/process/0.24mm Draft @BBL A1M.json +++ b/resources/profiles/BBL/process/0.24mm Draft @BBL A1M.json @@ -6,6 +6,7 @@ "setting_id": "GP047", "instantiation": "true", "default_acceleration": "6000", + "elefant_foot_compensation": "0", "travel_speed": "700", "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle" diff --git a/resources/profiles/BBL/process/0.24mm Fine @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.24mm Fine @BBL P1P 0.8 nozzle.json new file mode 100644 index 00000000000..6ee5ebfe85a --- /dev/null +++ b/resources/profiles/BBL/process/0.24mm Fine @BBL P1P 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.24mm Fine @BBL P1P 0.8 nozzle", + "inherits": "fdm_process_bbl_0.24_nozzle_0.8", + "from": "system", + "setting_id": "GP068", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1P 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.24mm Optimal @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.24mm Optimal @BBL P1P 0.6 nozzle.json new file mode 100644 index 00000000000..1da10212951 --- /dev/null +++ b/resources/profiles/BBL/process/0.24mm Optimal @BBL P1P 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.24mm Optimal @BBL P1P 0.6 nozzle", + "inherits": "fdm_process_bbl_0.24_nozzle_0.6", + "from": "system", + "setting_id": "GP069", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1P 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1M.json b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1M.json index 4c19dcd43fa..f2ea4704d82 100644 --- a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1M.json +++ b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1M.json @@ -6,6 +6,7 @@ "setting_id": "GP048", "instantiation": "true", "default_acceleration": "6000", + "elefant_foot_compensation": "0", "travel_speed": "700", "compatible_printers": [ "Bambu Lab A1 mini 0.4 nozzle" diff --git a/resources/profiles/BBL/process/0.30mm Strength @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Strength @BBL P1P 0.6 nozzle.json new file mode 100644 index 00000000000..fc06431da3a --- /dev/null +++ b/resources/profiles/BBL/process/0.30mm Strength @BBL P1P 0.6 nozzle.json @@ -0,0 +1,13 @@ +{ + "type": "process", + "name": "0.30mm Strength @BBL P1P 0.6 nozzle", + "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "from": "system", + "setting_id": "GP067", + "instantiation": "true", + "wall_loops": "4", + "sparse_infill_density": "25%", + "compatible_printers": [ + "Bambu Lab P1P 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.32mm Optimal @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.32mm Optimal @BBL P1P 0.8 nozzle.json new file mode 100644 index 00000000000..8dd6c892b80 --- /dev/null +++ b/resources/profiles/BBL/process/0.32mm Optimal @BBL P1P 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.32mm Optimal @BBL P1P 0.8 nozzle", + "inherits": "fdm_process_bbl_0.32_nozzle_0.8", + "from": "system", + "setting_id": "GP075", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1P 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.36mm Draft @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.36mm Draft @BBL P1P 0.6 nozzle.json new file mode 100644 index 00000000000..d9fd1794661 --- /dev/null +++ b/resources/profiles/BBL/process/0.36mm Draft @BBL P1P 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.36mm Draft @BBL P1P 0.6 nozzle", + "inherits": "fdm_process_bbl_0.36_nozzle_0.6", + "from": "system", + "setting_id": "GP070", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1P 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.42mm Extra Draft @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.42mm Extra Draft @BBL P1P 0.6 nozzle.json new file mode 100644 index 00000000000..0ee88c27874 --- /dev/null +++ b/resources/profiles/BBL/process/0.42mm Extra Draft @BBL P1P 0.6 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.42mm Extra Draft @BBL P1P 0.6 nozzle", + "inherits": "fdm_process_bbl_0.42_nozzle_0.6", + "from": "system", + "setting_id": "GP073", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1P 0.6 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.48mm Draft @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.48mm Draft @BBL P1P 0.8 nozzle.json new file mode 100644 index 00000000000..3b9d26f9505 --- /dev/null +++ b/resources/profiles/BBL/process/0.48mm Draft @BBL P1P 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.48mm Draft @BBL P1P 0.8 nozzle", + "inherits": "fdm_process_bbl_0.48_nozzle_0.8", + "from": "system", + "setting_id": "GP074", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1P 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/0.56mm Extra Draft @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.56mm Extra Draft @BBL P1P 0.8 nozzle.json new file mode 100644 index 00000000000..3dca29d8ba3 --- /dev/null +++ b/resources/profiles/BBL/process/0.56mm Extra Draft @BBL P1P 0.8 nozzle.json @@ -0,0 +1,11 @@ +{ + "type": "process", + "name": "0.56mm Extra Draft @BBL P1P 0.8 nozzle", + "inherits": "fdm_process_bbl_0.56_nozzle_0.8", + "from": "system", + "setting_id": "GP071", + "instantiation": "true", + "compatible_printers": [ + "Bambu Lab P1P 0.8 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.16.json b/resources/profiles/BBL/process/fdm_process_bbl_0.16.json index 3c435f4225c..ecc31c5421a 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.16.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.16.json @@ -7,8 +7,8 @@ "layer_height": "0.16", "elefant_foot_compensation": "0.15", "bottom_shell_layers": "4", - "top_shell_layers": "4", - "top_shell_thickness": "0.6", + "top_shell_layers": "6", + "top_shell_thickness": "1.0", "bridge_flow": "1", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.20.json b/resources/profiles/BBL/process/fdm_process_bbl_0.20.json index d48f4a29a1d..331f77e4e70 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.20.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.20.json @@ -5,7 +5,7 @@ "from": "system", "instantiation": "false", "elefant_foot_compensation": "0.15", - "top_shell_thickness": "0.6", + "top_shell_thickness": "1.0", "bridge_flow": "1", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", @@ -13,5 +13,6 @@ "inner_wall_speed": "300", "sparse_infill_speed": "270", "internal_solid_infill_speed": "250", - "gap_infill_speed": "250" + "gap_infill_speed": "250", + "top_shell_layers": "5" } \ No newline at end of file diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.24.json b/resources/profiles/BBL/process/fdm_process_bbl_0.24.json index 02e7595c7b1..1a0bd76e40d 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.24.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.24.json @@ -7,7 +7,7 @@ "layer_height": "0.24", "elefant_foot_compensation": "0.15", "top_surface_line_width": "0.45", - "top_shell_thickness": "0.6", + "top_shell_thickness": "1.0", "bridge_flow": "1", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", @@ -16,5 +16,6 @@ "sparse_infill_speed": "230", "internal_solid_infill_speed": "230", "gap_infill_speed": "230", - "support_threshold_angle": "35" + "support_threshold_angle": "35", + "top_shell_layers": "4" } \ No newline at end of file diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.28.json b/resources/profiles/BBL/process/fdm_process_bbl_0.28.json index 1c70a95b9bb..efd2cc4d010 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.28.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.28.json @@ -7,7 +7,7 @@ "layer_height": "0.28", "elefant_foot_compensation": "0.15", "top_surface_line_width": "0.45", - "top_shell_thickness": "0.6", + "top_shell_thickness": "1.0", "bridge_flow": "1", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", @@ -16,5 +16,6 @@ "sparse_infill_speed": "200", "internal_solid_infill_speed": "200", "gap_infill_speed": "200", - "support_threshold_angle": "40" + "support_threshold_angle": "40", + "top_shell_layers": "4" } \ No newline at end of file diff --git a/resources/profiles/BBL/process/fdm_process_bbl_common.json b/resources/profiles/BBL/process/fdm_process_bbl_common.json index 526773face5..1f6191a1a8b 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_common.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_common.json @@ -58,7 +58,7 @@ "support_object_xy_distance": "0.35", "tree_support_branch_diameter": "2", "tree_support_branch_angle": "45", - "tree_support_wall_count": "1", + "tree_support_wall_count": "0", "top_surface_pattern": "monotonicline", "top_surface_acceleration": "2000", "top_surface_speed": "200", diff --git a/resources/profiles/blacklist.json b/resources/profiles/blacklist.json new file mode 100644 index 00000000000..e876cdca8b9 --- /dev/null +++ b/resources/profiles/blacklist.json @@ -0,0 +1,8 @@ +{ + "filament": [ + "GFSA03" + ], + "process": [ + "GP008" + ] +} \ No newline at end of file diff --git a/resources/profiles/check_unused_setting_id.py b/resources/profiles/check_unused_setting_id.py new file mode 100644 index 00000000000..14888a87b44 --- /dev/null +++ b/resources/profiles/check_unused_setting_id.py @@ -0,0 +1,54 @@ +import os +import json + +setting_id_used=set() +setting_id_all=set() +root_dir=os.path.dirname(os.path.abspath(__file__)) + + +def loadBlackList(): + with open(root_dir+'/blacklist.json') as file: + data=json.load(file) + + for key,val in data.items(): + for item in val: + setting_id_used.add(item) + setting_id_all.add(item) + +def traverse_files(path): + for file in os.listdir(path): + file_path = os.path.join(path, file) + if os.path.isdir(file_path): + traverse_files(file_path) # 递归遍历子文件夹 + elif file_path.endswith('.json'): + # 解析 JSON 文件并提取 setting_id 的值 + with open(file_path) as f: + data = json.load(f) + if 'setting_id' in data: + setting_id_all.add(data['setting_id']) + +def getUsedId(brand): + with open(root_dir+'/'+brand+'.json')as file: + data=json.load(file) + + key_list=["machine_model_list","machine_list","filament_list","process_list"] + + for key in key_list: + for elem in data[key]: + path=elem['sub_path'] + with open(root_dir+'/'+brand+'/'+path) as file: + file_data=json.load(file) + if 'setting_id' in file_data: + setting_id_used.add(file_data['setting_id']) + + +def getTotalId(brand): + traverse_files(root_dir+'/'+brand) + + +loadBlackList() +getUsedId('BBL') +getTotalId('BBL') + +print("unused setting_id :") +print(setting_id_all.difference(setting_id_used)) diff --git a/resources/profiles_template/Template.json b/resources/profiles_template/Template.json new file mode 100644 index 00000000000..8f95fee190b --- /dev/null +++ b/resources/profiles_template/Template.json @@ -0,0 +1,58 @@ +{ + "name": "Template", + "version": "01.07.00.02", + "force_update": "0", + "description": "Template configurations", + "machine_model_list": [ + ], + "process_list": [ + { + "name": "process template", + "sub_path": "process/process template.json" + } + ], + "filament_list": [ + { + "name": "filament_abs_template", + "sub_path": "filament/filament_abs_template.json" + }, + { + "name": "filament_asa_template", + "sub_path": "filament/filament_asa_template.json" + }, + { + "name": "filament_hips_template", + "sub_path": "filament/filament_hips_template.json" + }, + { + "name": "filament_pa_template", + "sub_path": "filament/filament_pa_template.json" + }, + { + "name": "filament_pet_template", + "sub_path": "filament/filament_pet_template.json" + }, + { + "name": "filament_pla_template", + "sub_path": "filament/filament_pla_template.json" + }, + { + "name": "filament_ppa_template", + "sub_path": "filament/filament_ppa_template.json" + }, + { + "name": "filament_pps_template", + "sub_path": "filament/filament_pps_template.json" + }, + { + "name": "filament_pva_template", + "sub_path": "filament/filament_pva_template.json" + }, + { + "name": "filament_tpu_template", + "sub_path": "filament/filament_tpu_template.json" + } + ], + "machine_list": [ + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_abs_template.json b/resources/profiles_template/Template/filament/filament_abs_template.json new file mode 100644 index 00000000000..7664477edee --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_abs_template.json @@ -0,0 +1,165 @@ +{ + "type": "filament", + "name": "Generic ABS template", + "instantiation": "false", + "activate_air_filtration": [ + "1" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "90" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "10" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.04" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "28.6" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "ABS" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "90" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "nozzle_temperature": [ + "270" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "3" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp": [ + "90" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; Filament gcode\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_asa_template.json b/resources/profiles_template/Template/filament/filament_asa_template.json new file mode 100644 index 00000000000..c9607076447 --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_asa_template.json @@ -0,0 +1,165 @@ +{ + "type": "filament", + "name": "Generic ASA template", + "instantiation": "false", + "activate_air_filtration": [ + "1" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "90" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "fan_cooling_layer_time": [ + "35" + ], + "fan_max_speed": [ + "80" + ], + "fan_min_speed": [ + "10" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.04" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "28.6" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "ASA" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "90" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "nozzle_temperature": [ + "260" + ], + "nozzle_temperature_initial_layer": [ + "260" + ], + "nozzle_temperature_range_high": [ + "280" + ], + "nozzle_temperature_range_low": [ + "240" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "3" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp": [ + "90" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; Filament gcode\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_hips_template.json b/resources/profiles_template/Template/filament/filament_hips_template.json new file mode 100644 index 00000000000..22c66f09139 --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_hips_template.json @@ -0,0 +1,168 @@ +{ + "type": "filament", + "name": "Generic HIPS template", + "instantiation": "false", + "activate_air_filtration": [ + "0" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "90" + ], + "eng_plate_temp_initial_layer": [ + "90" + ], + "fan_cooling_layer_time": [ + "10" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "0" + ], + "filament_cost": [ + "22.99" + ], + "filament_density": [ + "1.06" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "HIPS" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "90" + ], + "hot_plate_temp_initial_layer": [ + "90" + ], + "nozzle_temperature": [ + "240" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_low": [ + "220" + ], + "nozzle_temperature_range_high": [ + "270" + ], + "overhang_fan_speed": [ + "80" + ], + "overhang_fan_threshold": [ + "25%" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "6" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "100" + ], + "textured_plate_temp": [ + "90" + ], + "textured_plate_temp_initial_layer": [ + "90" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; Filament gcode\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_pa_template.json b/resources/profiles_template/Template/filament/filament_pa_template.json new file mode 100644 index 00000000000..0d91e2a9fd6 --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_pa_template.json @@ -0,0 +1,165 @@ +{ + "type": "filament", + "name": "Generic PA template", + "instantiation": "false", + "activate_air_filtration": [ + "1" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "100" + ], + "eng_plate_temp_initial_layer": [ + "100" + ], + "fan_cooling_layer_time": [ + "4" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "0" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.04" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "PA" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "100" + ], + "hot_plate_temp_initial_layer": [ + "100" + ], + "nozzle_temperature": [ + "290" + ], + "nozzle_temperature_initial_layer": [ + "290" + ], + "nozzle_temperature_range_high": [ + "300" + ], + "nozzle_temperature_range_low": [ + "260" + ], + "overhang_fan_speed": [ + "30" + ], + "overhang_fan_threshold": [ + "95%" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "required_nozzle_HRC": [ + "40" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "2" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "108" + ], + "textured_plate_temp": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "100" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; Filament gcode\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_pc_template.json b/resources/profiles_template/Template/filament/filament_pc_template.json new file mode 100644 index 00000000000..ff50a7b718f --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_pc_template.json @@ -0,0 +1,165 @@ +{ + "type": "filament", + "name": "Generic PC template", + "instantiation": "false", + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "110" + ], + "eng_plate_temp_initial_layer": [ + "110" + ], + "fan_cooling_layer_time": [ + "30" + ], + "fan_max_speed": [ + "60" + ], + "fan_min_speed": [ + "10" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.04" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "23.2" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "PC" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "110" + ], + "hot_plate_temp_initial_layer": [ + "110" + ], + "nozzle_temperature": [ + "280" + ], + "nozzle_temperature_initial_layer": [ + "270" + ], + "nozzle_temperature_range_low": [ + "260" + ], + "nozzle_temperature_range_high": [ + "290" + ], + "overhang_fan_speed": [ + "60" + ], + "overhang_fan_threshold": [ + "25%" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "2" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "120" + ], + "textured_plate_temp": [ + "110" + ], + "textured_plate_temp_initial_layer": [ + "110" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; Filament gcode\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_pet_template.json b/resources/profiles_template/Template/filament/filament_pet_template.json new file mode 100644 index 00000000000..eeb70299099 --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_pet_template.json @@ -0,0 +1,165 @@ +{ + "type": "filament", + "name": "Generic PET template", + "instantiation": "false", + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "60" + ], + "cool_plate_temp_initial_layer": [ + "60" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "fan_cooling_layer_time": [ + "20" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "20" + ], + "filament_cost": [ + "30" + ], + "filament_density": [ + "1.27" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "25" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "PETG" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "80" + ], + "hot_plate_temp_initial_layer": [ + "80" + ], + "nozzle_temperature": [ + "255" + ], + "nozzle_temperature_initial_layer": [ + "255" + ], + "nozzle_temperature_range_high": [ + "260" + ], + "nozzle_temperature_range_low": [ + "220" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "95%" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "10" + ], + "temperature_vitrification": [ + "70" + ], + "textured_plate_temp": [ + "80" + ], + "textured_plate_temp_initial_layer": [ + "80" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; filament start gcode\n{if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}M106 P3 S180\n{elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_extruder] >50)}M106 P3 S255\n{endif};Prevent PLA from jamming\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_pla_template.json b/resources/profiles_template/Template/filament/filament_pla_template.json new file mode 100644 index 00000000000..e76db6615b9 --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_pla_template.json @@ -0,0 +1,168 @@ +{ + "type": "filament", + "name": "Generic PLA template", + "instantiation": "false", + "activate_air_filtration": [ + "0" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "35" + ], + "cool_plate_temp_initial_layer": [ + "35" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.24" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "PLA" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "55" + ], + "hot_plate_temp_initial_layer": [ + "55" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "55" + ], + "textured_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; filament start gcode\n{if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}M106 P3 S255\n{elsif(bed_temperature[current_extruder] >35)||(bed_temperature_initial_layer[current_extruder] >35)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_ppa_template.json b/resources/profiles_template/Template/filament/filament_ppa_template.json new file mode 100644 index 00000000000..f89e5290cd5 --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_ppa_template.json @@ -0,0 +1,165 @@ +{ + "type": "filament", + "name": "Generic PPA template", + "instantiation": "false", + "activate_air_filtration": [ + "1" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "100" + ], + "eng_plate_temp_initial_layer": [ + "100" + ], + "fan_cooling_layer_time": [ + "5" + ], + "fan_max_speed": [ + "30" + ], + "fan_min_speed": [ + "10" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.17" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "PPA-CF" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "100" + ], + "hot_plate_temp_initial_layer": [ + "100" + ], + "nozzle_temperature": [ + "290" + ], + "nozzle_temperature_initial_layer": [ + "290" + ], + "nozzle_temperature_range_high": [ + "320" + ], + "nozzle_temperature_range_low": [ + "280" + ], + "overhang_fan_speed": [ + "40" + ], + "overhang_fan_threshold": [ + "0%" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "required_nozzle_HRC": [ + "40" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "2" + ], + "slow_down_min_speed": [ + "20" + ], + "temperature_vitrification": [ + "210" + ], + "textured_plate_temp": [ + "100" + ], + "textured_plate_temp_initial_layer": [ + "100" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; Filament gcode\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_pps_template.json b/resources/profiles_template/Template/filament/filament_pps_template.json new file mode 100644 index 00000000000..ef107613bf1 --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_pps_template.json @@ -0,0 +1,165 @@ +{ + "type": "filament", + "name": "Generic PPS template", + "instantiation": "false", + "activate_air_filtration": [ + "0" + ], + "chamber_temperatures": [ + "60" + ], + "close_fan_the_first_x_layers": [ + "3" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "0" + ], + "cool_plate_temp_initial_layer": [ + "0" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "110" + ], + "eng_plate_temp_initial_layer": [ + "110" + ], + "fan_cooling_layer_time": [ + "5" + ], + "fan_max_speed": [ + "50" + ], + "fan_min_speed": [ + "0" + ], + "filament_cost": [ + "0" + ], + "filament_density": [ + "1.36" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "0.96" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "4" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "PPS" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "110" + ], + "hot_plate_temp_initial_layer": [ + "110" + ], + "nozzle_temperature": [ + "320" + ], + "nozzle_temperature_initial_layer": [ + "320" + ], + "nozzle_temperature_range_high": [ + "340" + ], + "nozzle_temperature_range_low": [ + "300" + ], + "overhang_fan_speed": [ + "30" + ], + "overhang_fan_threshold": [ + "0%" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "2" + ], + "slow_down_min_speed": [ + "10" + ], + "temperature_vitrification": [ + "125" + ], + "textured_plate_temp": [ + "110" + ], + "textured_plate_temp_initial_layer": [ + "110" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; Filament gcode\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_pva_template.json b/resources/profiles_template/Template/filament/filament_pva_template.json new file mode 100644 index 00000000000..aab27ba0f86 --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_pva_template.json @@ -0,0 +1,168 @@ +{ + "type": "filament", + "name": "Generic PVA template", + "instantiation": "false", + "activate_air_filtration": [ + "0" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "45" + ], + "cool_plate_temp_initial_layer": [ + "45" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "0" + ], + "eng_plate_temp_initial_layer": [ + "0" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.24" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "1" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "nil" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "1" + ], + "filament_type": [ + "PVA" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "55" + ], + "hot_plate_temp_initial_layer": [ + "55" + ], + "nozzle_temperature": [ + "220" + ], + "nozzle_temperature_initial_layer": [ + "220" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "50%" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "4" + ], + "slow_down_min_speed": [ + "50" + ], + "temperature_vitrification": [ + "55" + ], + "textured_plate_temp": [ + "55" + ], + "textured_plate_temp_initial_layer": [ + "55" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; filament start gcode\n{if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}M106 P3 S255\n{elsif(bed_temperature[current_extruder] >35)||(bed_temperature_initial_layer[current_extruder] >35)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/filament/filament_tpu_template.json b/resources/profiles_template/Template/filament/filament_tpu_template.json new file mode 100644 index 00000000000..5aedc3c87aa --- /dev/null +++ b/resources/profiles_template/Template/filament/filament_tpu_template.json @@ -0,0 +1,168 @@ +{ + "type": "filament", + "name": "Generic TPU template", + "instantiation": "false", + "activate_air_filtration": [ + "0" + ], + "additional_cooling_fan_speed": [ + "70" + ], + "chamber_temperatures": [ + "0" + ], + "close_fan_the_first_x_layers": [ + "1" + ], + "complete_print_exhaust_fan_speed": [ + "70" + ], + "cool_plate_temp": [ + "30" + ], + "cool_plate_temp_initial_layer": [ + "30" + ], + "during_print_exhaust_fan_speed": [ + "70" + ], + "eng_plate_temp": [ + "30" + ], + "eng_plate_temp_initial_layer": [ + "30" + ], + "fan_cooling_layer_time": [ + "100" + ], + "fan_max_speed": [ + "100" + ], + "fan_min_speed": [ + "100" + ], + "filament_cost": [ + "20" + ], + "filament_density": [ + "1.24" + ], + "filament_deretraction_speed": [ + "nil" + ], + "filament_diameter": [ + "1.75" + ], + "filament_flow_ratio": [ + "1" + ], + "filament_is_support": [ + "0" + ], + "filament_max_volumetric_speed": [ + "15" + ], + "filament_minimal_purge_on_wipe_tower": [ + "15" + ], + "filament_retract_before_wipe": [ + "nil" + ], + "filament_retract_restart_extra": [ + "nil" + ], + "filament_retract_when_changing_layer": [ + "nil" + ], + "filament_retraction_length": [ + "0.4" + ], + "filament_retraction_minimum_travel": [ + "nil" + ], + "filament_retraction_speed": [ + "nil" + ], + "filament_settings_id": [ + "" + ], + "filament_soluble": [ + "0" + ], + "filament_type": [ + "TPU" + ], + "filament_vendor": [ + "Generic" + ], + "filament_wipe": [ + "nil" + ], + "filament_wipe_distance": [ + "nil" + ], + "filament_z_hop": [ + "nil" + ], + "filament_z_hop_types": [ + "nil" + ], + "full_fan_speed_layer": [ + "0" + ], + "hot_plate_temp": [ + "35" + ], + "hot_plate_temp_initial_layer": [ + "35" + ], + "nozzle_temperature": [ + "240" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature_range_high": [ + "250" + ], + "nozzle_temperature_range_low": [ + "200" + ], + "overhang_fan_speed": [ + "100" + ], + "overhang_fan_threshold": [ + "95%" + ], + "reduce_fan_stop_start_freq": [ + "1" + ], + "required_nozzle_HRC": [ + "3" + ], + "slow_down_for_layer_cooling": [ + "1" + ], + "slow_down_layer_time": [ + "8" + ], + "slow_down_min_speed": [ + "10" + ], + "temperature_vitrification": [ + "35" + ], + "textured_plate_temp": [ + "35" + ], + "textured_plate_temp_initial_layer": [ + "35" + ], + "compatible_printers": [], + "filament_start_gcode": [ + "; filament start gcode\n{if (bed_temperature[current_extruder] >35)||(bed_temperature_initial_layer[current_extruder] >35)}M106 P3 S255\n{elsif(bed_temperature[current_extruder] >30)||(bed_temperature_initial_layer[current_extruder] >30)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}" + ], + "filament_end_gcode": [ + "; filament end gcode \nM106 P3 S0\n" + ] +} \ No newline at end of file diff --git a/resources/profiles_template/Template/process/process template.json b/resources/profiles_template/Template/process/process template.json new file mode 100644 index 00000000000..67eb93909db --- /dev/null +++ b/resources/profiles_template/Template/process/process template.json @@ -0,0 +1,109 @@ +{ + "type": "process", + "name": "process template", + "instantiation": "false", + "adaptive_layer_height": "0", + "bridge_flow": "1", + "bridge_speed": "50", + "brim_width": "5", + "bridge_no_support": "0", + "bottom_surface_pattern": "monotonic", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "brim_object_gap": "0.1", + "compatible_printers_condition": "", + "default_acceleration": "10000", + "detect_overhang_wall": "1", + "detect_thin_wall": "0", + "draft_shield": "disabled", + "elefant_foot_compensation": "0.15", + "enable_support": "0", + "enable_prime_tower": "1", + "enable_arc_fitting": "1", + "filename_format": "{input_filename_base}_{filament_type[0]}_{print_time}.gcode", + "gap_infill_speed": "250", + "infill_direction": "45", + "initial_layer_line_width": "0.5", + "initial_layer_print_height": "0.2", + "initial_layer_speed": "50", + "infill_combination": "0", + "infill_wall_overlap": "15%", + "interface_shells": "0", + "inner_wall_line_width": "0.45", + "inner_wall_speed": "300", + "internal_solid_infill_line_width": "0.42", + "internal_solid_infill_speed": "250", + "internal_bridge_support_thickness": "0.8", + "initial_layer_acceleration": "500", + "ironing_flow": "10%", + "ironing_spacing": "0.15", + "ironing_speed": "30", + "ironing_type": "no ironing", + "initial_layer_infill_speed": "105", + "line_width": "0.42", + "layer_height": "0.2", + "minimum_sparse_infill_area": "15", + "max_travel_detour_distance": "0", + "outer_wall_line_width": "0.42", + "outer_wall_speed": "200", + "outer_wall_acceleration": "5000", + "overhang_1_4_speed": "0", + "overhang_2_4_speed": "50", + "overhang_3_4_speed": "30", + "overhang_4_4_speed": "10", + "only_one_wall_top": "1", + "print_sequence": "by layer", + "print_settings_id": "", + "prime_tower_width": "35", + "reduce_crossing_wall": "0", + "reduce_infill_retraction": "1", + "raft_layers": "0", + "resolution": "0.012", + "sparse_infill_density": "15%", + "sparse_infill_pattern": "grid", + "sparse_infill_line_width": "0.45", + "sparse_infill_speed": "270", + "seam_position": "aligned", + "skirt_distance": "2", + "skirt_height": "1", + "spiral_mode": "0", + "standby_temperature_delta": "-5", + "support_filament": "0", + "support_line_width": "0.42", + "support_interface_filament": "0", + "support_on_build_plate_only": "0", + "support_top_z_distance": "0.2", + "support_interface_loop_pattern": "0", + "support_interface_top_layers": "2", + "support_interface_spacing": "0.5", + "support_interface_speed": "80", + "support_interface_pattern": "auto", + "support_base_pattern": "default", + "support_base_pattern_spacing": "2.5", + "support_speed": "150", + "support_threshold_angle": "30", + "support_object_xy_distance": "0.35", + "skirt_loops": "0", + "support_type": "normal(auto)", + "support_style": "default", + "support_bottom_z_distance": "0.2", + "support_interface_bottom_layers": "2", + "support_expansion": "0", + "top_surface_line_width": "0.42", + "top_surface_speed": "200", + "travel_speed": "500", + "tree_support_branch_diameter": "2", + "tree_support_branch_angle": "45", + "tree_support_wall_count": "0", + "top_surface_pattern": "monotonicline", + "top_surface_acceleration": "2000", + "top_shell_layers": "3", + "top_shell_thickness": "0.6", + "wall_loops": "2", + "wall_infill_order": "inner wall/outer wall/infill", + "wipe_tower_no_sparse_layers": "0", + "wall_generator": "classic", + "xy_hole_compensation": "0", + "xy_contour_compensation": "0", + "compatible_printers": [] +} \ No newline at end of file diff --git a/resources/web/guide/23/23.js b/resources/web/guide/23/23.js index 68719a93bde..ba92265a965 100644 --- a/resources/web/guide/23/23.js +++ b/resources/web/guide/23/23.js @@ -7,8 +7,13 @@ var VendorPriority=new Array("bambu lab","bambulab","bbl","kexcelled","polymaker function OnInit() { TranslatePage(); + OnSelectMenu(1); RequestProfile(); + + RequestCustomFilaments(); + //TestCustomFilaments(); + //OnSelectMenu(2); } function RequestProfile() @@ -39,6 +44,10 @@ function HandleStudio(pVal) m_ProfileItem=pVal['response']; SortUI(); } + else if(strCmd=='update_custom_filaments') + { + UpdateCustomFilaments( pVal['data'] ); + } } function GetFilamentShortname( sName ) @@ -554,5 +563,95 @@ function ConfirmSelect() } +function OnSelectMenu( nIndex ) +{ + switch(nIndex) + { + case 1: + $('#SystemFilamentBtn').addClass('TitleSelected'); + $('#SystemFilamentBtn').removeClass('TitleUnselected'); + + $('#CustomFilamentBtn').addClass('TitleUnselected'); + $('#CustomFilamentBtn').removeClass('TitleSelected'); + + $('#SystemFilamentsArea').css('display','flex'); + $('#CustomFilamentsArea').css('display','none'); + break; + case 2: + $('#CustomFilamentBtn').addClass('TitleSelected'); + $('#CustomFilamentBtn').removeClass('TitleUnselected'); + + $('#SystemFilamentBtn').addClass('TitleUnselected'); + $('#SystemFilamentBtn').removeClass('TitleSelected'); + + $('#CustomFilamentsArea').css('display','flex'); + $('#SystemFilamentsArea').css('display','none'); + break; + } +} + +function RequestCustomFilaments() +{ + var tSend={}; + tSend['sequence_id']=Math.round(new Date() / 1000); + tSend['command']="request_custom_filaments"; + + SendWXMessage( JSON.stringify(tSend) ); +} + +function TestCustomFilaments() +{ + let strTest='{"command":"update_custom_filaments","data":[{"id":"P0c71f94","name":"AMOLEN ABS 222"},{"id":"P19cc6c5","name":"PrimaSelect PLA 231654"},{"id":"P93a5c3b","name":"3DJAKE PLA 111"}],"sequence_id":"2000"}'; + let tItem=JSON.parse(strTest); + + HandleStudio(tItem); +} + +function UpdateCustomFilaments( CFList ) +{ + let strHtml=''; + let nTotal=CFList.length; + + for(let n=0;n'+F_name+''+ + ''; + + strHtml+=strAdd; + } + + $('#CFilament_List').html(strHtml); +} + + +function OnClickCustomFilamentAdd() +{ + //alert('Create New Custom Filament'); + + var tSend={}; + tSend['sequence_id']=Math.round(new Date() / 1000); + tSend['command']="create_custom_filament"; + + SendWXMessage( JSON.stringify(tSend) ); +} + +//编辑某一个自定义材料 +function CFEdit( fid ) +{ + //alert(fid); + + var tSend={}; + tSend['sequence_id']=Math.round(new Date() / 1000); + tSend['command']="modify_custom_filament"; + tSend['id']=fid; + + SendWXMessage( JSON.stringify(tSend) ); +} diff --git a/resources/web/guide/css/common.css b/resources/web/guide/css/common.css index a2d0f19ebc3..411b219ee4d 100644 --- a/resources/web/guide/css/common.css +++ b/resources/web/guide/css/common.css @@ -4,6 +4,7 @@ border: 0; margin: 0; font-family: "system-ui", "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-sans; + user-select: none; } html diff --git a/resources/web/guide/css/dark.css b/resources/web/guide/css/dark.css index 5cdb5e61855..ff3a22c342a 100644 --- a/resources/web/guide/css/dark.css +++ b/resources/web/guide/css/dark.css @@ -65,4 +65,10 @@ body { background-color:#009688; color: #fff; -} \ No newline at end of file +} + +/*----Menu----*/ +#Title div.TitleUnselected +{ + color: #BEBEC0; +} diff --git a/resources/web/homepage/css/home.css b/resources/web/homepage/css/home.css index cab114ca626..b4e072f7a24 100644 --- a/resources/web/homepage/css/home.css +++ b/resources/web/homepage/css/home.css @@ -5,6 +5,7 @@ margin: 0px; font-family: "system-ui", "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-sans; border-color: #D7D7D7; + user-select: none; } html, body { @@ -421,6 +422,7 @@ body height: 184px; border-radius: 8px; display: inline-block; + object-fit: cover; } .FileName diff --git a/resources/web/homepage/js/home.js b/resources/web/homepage/js/home.js index ec36e552843..26794db0e2b 100644 --- a/resources/web/homepage/js/home.js +++ b/resources/web/homepage/js/home.js @@ -496,7 +496,7 @@ function ShowStaffPick( ModelList ) strPickHtml+='
'+ '
'+DesignerName+'
'+ '
'+ - '
'+ModelName+'
'+ + '
'+ModelName+'
'+ '
'; } diff --git a/resources/web/image/edit.svg b/resources/web/image/edit.svg new file mode 100644 index 00000000000..9806417cc3c --- /dev/null +++ b/resources/web/image/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/web/model/index.html b/resources/web/model/index.html index 717c18bbae9..739f6d4451e 100644 --- a/resources/web/model/index.html +++ b/resources/web/model/index.html @@ -44,7 +44,7 @@ -
+
 
diff --git a/resources/web/model/model.css b/resources/web/model/model.css index 069af8296fd..25aba5201eb 100644 --- a/resources/web/model/model.css +++ b/resources/web/model/model.css @@ -4,6 +4,7 @@ padding: 0px; border: 0px; font-family: "system-ui", "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-sans; + user-select: none; } html @@ -265,6 +266,16 @@ body } /*---Document---*/ +#LeftEmptyBlock +{ + +} + +#Model_Desc img +{ + max-width:100%; +} + #Model_Accessories { } diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 7271af2d973..66b02add2f7 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -38,6 +38,7 @@ using namespace nlohmann; #include #include #include +#include #include #include #include @@ -63,8 +64,10 @@ using namespace nlohmann; #include "libslic3r/Time.hpp" #include "libslic3r/Thread.hpp" #include "libslic3r/BlacklistedLibraryCheck.hpp" +#include "libslic3r/FlushVolCalc.hpp" #include "libslic3r/Orient.hpp" +#include "libslic3r/PNGReadWrite.hpp" #include "OrcaSlicer.hpp" //BBS: add exception handler for win32 @@ -94,34 +97,71 @@ using namespace Slic3r; std::string message; }error_message;*/ +#define MAX_CLONEABLE_SIZE 512 std::map cli_errors = { - {CLI_SUCCESS, "Success"}, - {CLI_ENVIRONMENT_ERROR, "Environment setup failed"}, - {CLI_INVALID_PARAMS, "Input param invalid"}, - {CLI_FILE_NOTFOUND, "Input file not found"}, - {CLI_FILELIST_INVALID_ORDER, "File list order invalid(please make sure 3mf in the first place)"}, - {CLI_CONFIG_FILE_ERROR, "Invalid config file, could not be parsed"}, - {CLI_DATA_FILE_ERROR, "Invalid model file, could not be loaded"}, - {CLI_INVALID_PRINTER_TECH, "Invalid printer technoledge"}, - {CLI_UNSUPPORTED_OPERATION, "Unsupported operation"}, - {CLI_COPY_OBJECTS_ERROR, "Copy objects error"}, - {CLI_SCALE_TO_FIT_ERROR, "Scale to fit error"}, - {CLI_EXPORT_STL_ERROR, "Export stl error"}, - {CLI_EXPORT_OBJ_ERROR, "Export obj error"}, - {CLI_EXPORT_3MF_ERROR, "Export 3mf error"}, - {CLI_OUT_OF_MEMORY, "Out of memory"}, - {CLI_NO_SUITABLE_OBJECTS, "Found no objects in print volume to slice"}, - {CLI_VALIDATE_ERROR, "Validate print error"}, - {CLI_OBJECTS_PARTLY_INSIDE, "Objects partly inside"}, - {CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED, "Objects partly inside"}, - {CLI_EXPORT_CACHE_WRITE_FAILED, "export cached slicedata failed"}, - {CLI_IMPORT_CACHE_NOT_FOUND, "cached slicedata can not be found"}, - {CLI_IMPORT_CACHE_DATA_CAN_NOT_USE, "cached slicedata can not be used"}, - {CLI_IMPORT_CACHE_LOAD_FAILED, "load cached slicedata failed"}, - {CLI_SLICING_ERROR, "Slice error"} + {CLI_SUCCESS, "Success."}, + {CLI_ENVIRONMENT_ERROR, "Failed setting up server environment."}, + {CLI_INVALID_PARAMS, "Invalid parameters to the slicer."}, + {CLI_FILE_NOTFOUND, "The input files to the slicer are not found."}, + {CLI_FILELIST_INVALID_ORDER, "File list order to the slicer is invalid. Please make sure the 3mf in the first place."}, + {CLI_CONFIG_FILE_ERROR, "The input preset file is invalid and can not be parsed."}, + {CLI_DATA_FILE_ERROR, "The input model file to the slicer can not be parsed."}, + {CLI_INVALID_PRINTER_TECH, "Unsupported printer technology (not FDM)."}, + {CLI_UNSUPPORTED_OPERATION, "Unsupported CLI instruction."}, + {CLI_COPY_OBJECTS_ERROR, "Failed copying objects."}, + {CLI_SCALE_TO_FIT_ERROR, "Failed scaling an object to fit the plate."}, + {CLI_EXPORT_STL_ERROR, "Failed exporting STL files."}, + {CLI_EXPORT_OBJ_ERROR, "Failed exporting OBJ files."}, + {CLI_EXPORT_3MF_ERROR, "Failed exporting 3mf files."}, + {CLI_OUT_OF_MEMORY, "Out of memory during slicing. Please upload a model with lower geometry resolution and try again."}, + {CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE, "The selected printer is not supported."}, + {CLI_3MF_NEW_MACHINE_NOT_SUPPORTED, "The selected printer is not compatible with the 3mf."}, + {CLI_PROCESS_NOT_COMPATIBLE, "The selected printer is not compatible with the process preset in the 3mf."}, + {CLI_INVALID_VALUES_IN_3MF, "Invalid parameter value(s) included in the 3mf file."}, + {CLI_POSTPROCESS_NOT_SUPPORTED, "post_process is not supported under CLI."}, + {CLI_PRINTABLE_SIZE_REDUCED, "The selected printer's bed size is smaller than the bed size used in the print profile."}, + {CLI_OBJECT_ARRANGE_FAILED, "An error occurred when auto-arranging object(s)."}, + {CLI_OBJECT_ORIENT_FAILED, "An error occurred when auto-orienting object(s)."}, + {CLI_MODIFIED_PARAMS_TO_PRINTER, "Found modified parameter in printer preset in the 3mf file, which should not be changed."}, + {CLI_NO_SUITABLE_OBJECTS, "One of the plate is empty or has no object fully inside it. Please check that the 3mf contains no empty plate in Orca Slicer before uploading."}, + {CLI_VALIDATE_ERROR, "There are some incorrect slicing parameters in the 3mf. Please verify the slicing of all plates in Orca Slicer before uploading."}, + {CLI_OBJECTS_PARTLY_INSIDE, "Some objects are located over the boundary of the heated bed."}, + {CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED, "Failed creating directory when exporting cache data."}, + {CLI_EXPORT_CACHE_WRITE_FAILED, "Failed exporting cache data."}, + {CLI_IMPORT_CACHE_NOT_FOUND, "Cache data not found."}, + {CLI_IMPORT_CACHE_DATA_CAN_NOT_USE, "Cache data can not be parsed."}, + {CLI_IMPORT_CACHE_LOAD_FAILED, "Failed importing cache data."}, + {CLI_SLICING_TIME_EXCEEDS_LIMIT, "Slicing time of a certain plate exceeds the limit. Please simplify the model or use a larger slicing layer height."}, + {CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT, "Triangle count of single plate exceeds the limit. Please simplify the model and try to upload again."}, + {CLI_NO_SUITABLE_OBJECTS_AFTER_SKIP, "No printable objects to slice after skipping."}, + {CLI_FILAMENT_NOT_MATCH_BED_TYPE, "Filaments are not compatible with the plate type. Please verify the slicing of all plates in Orca Slicer before uploading."}, + {CLI_FILAMENTS_DIFFERENT_TEMP, "The temperature difference of the filaments used is too large. Please verify the slicing of all plates in Orca Slicer before uploading."}, + {CLI_OBJECT_COLLISION_IN_SEQ_PRINT, "Object conflicts were detected when using print-by-object mode. Please verify the slicing of all plates in Orca Slicer before uploading."}, + {CLI_OBJECT_COLLISION_IN_LAYER_PRINT, "Object conflicts were detected. Please verify the slicing of all plates in Orca Slicer before uploading."}, + {CLI_SPIRAL_MODE_INVALID_PARAMS, "Some slicing parameters cannot work with Spiral Vase mode. Please solve the issue in Orca Slicer before uploading."}, + {CLI_SLICING_ERROR, "Failed slicing the model. Please verify the slicing of all plates on Orca Slicer before uploading."}, + {CLI_GCODE_PATH_CONFLICTS, " G-code conflicts detected after slicing. Please make sure the 3mf file can be successfully sliced in the latest Orca Slicer."} }; +typedef struct _sliced_plate_info{ + int plate_id{0}; + size_t sliced_time {0}; + size_t sliced_time_with_cache {0}; + size_t triangle_count{0}; + std::string warning_message; +}sliced_plate_info_t; + +typedef struct _sliced_info { + int plate_count {0}; + int plate_to_slice {0}; + + std::vector sliced_plates; + size_t prepare_time; + size_t export_time; +}sliced_info_t; +std::vector g_slicing_warnings; + #if defined(__linux__) || defined(__LINUX__) #define PIPE_BUFFER_SIZE 512 @@ -183,7 +223,7 @@ typedef struct _cli_callback_mgr { //notify_message = "Plate "+ std::to_string(m_plate_index) + "/" +std::to_string(m_plate_count)+ ": Percent " + std::to_string(m_progress) + ": "+m_message; char pipe_message[PIPE_BUFFER_SIZE] = {0}; - sprintf(pipe_message, "%s\n", notify_message.c_str()); + snprintf(pipe_message, PIPE_BUFFER_SIZE, "%s\n", notify_message.c_str()); int ret = write(m_pipe_fd, pipe_message, strlen(pipe_message)); BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": write returns "<= 50) { + BOOST_LOG_TRIVIAL(warning) << boost::format("reach max retry_count, failed to open pipe"); + return false; + } + boost::this_thread::sleep(boost::posix_time::milliseconds(20)); + m_pipe_fd = open(pipe_name.c_str(),O_WRONLY|O_NONBLOCK); } std::unique_lock lck(m_mutex); m_thread = create_thread([this]{ this->thread_proc(); }); + m_condition.wait(lck, [this](){ return m_started; }); lck.unlock(); + m_condition.notify_one(); BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::start successfully."; return true; } @@ -294,14 +345,29 @@ typedef struct _cli_callback_mgr { }cli_callback_mgr_t; cli_callback_mgr_t g_cli_callback_mgr; - void cli_status_callback(const PrintBase::SlicingStatus& slicing_status) { + if (slicing_status.warning_step != -1) { + g_slicing_warnings.push_back(slicing_status); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": percent=%1%, warning_step=%2%, message=%3%, message_type=%4%, flag=%5%") + %slicing_status.percent %slicing_status.warning_step %slicing_status.text %(int)(slicing_status.message_type) %slicing_status.flags; + } g_cli_callback_mgr.update(slicing_status.percent, slicing_status.text, slicing_status.warning_step); return; } #endif +void default_status_callback(const PrintBase::SlicingStatus& slicing_status) +{ + if (slicing_status.warning_step != -1) { + g_slicing_warnings.push_back(slicing_status); + } + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": percent=%1%, warning_step=%2%, message=%3%, message_type=%4%")%slicing_status.percent %slicing_status.warning_step %slicing_status.text %(int)(slicing_status.message_type); + + return; +} + + static PrinterTechnology get_printer_technology(const DynamicConfig &config) { const ConfigOptionEnum *opt = config.option>("printer_technology"); @@ -328,6 +394,81 @@ static PrinterTechnology get_printer_technology(const DynamicConfig &config) return(ret);} #endif +void record_exit_reson(std::string outputdir, int code, int plate_id, std::string error_message, sliced_info_t& sliced_info, std::map key_values = std::map()) +{ +#if defined(__linux__) || defined(__LINUX__) + std::string result_file; + + if (!outputdir.empty()) + result_file = outputdir + "/result.json"; + else + result_file = "result.json"; + + try { + json j; + //record the headers + j["plate_index"] = plate_id; + j["return_code"] = code; + j["error_string"] = error_message; + j["prepare_time"] = sliced_info.prepare_time; + j["export_time"] = sliced_info.export_time; + for (size_t index = 0; index < sliced_info.sliced_plates.size(); index++) + { + json plate_json; + plate_json["id"] = sliced_info.sliced_plates[index].plate_id; + plate_json["sliced_time"] = sliced_info.sliced_plates[index].sliced_time; + plate_json["sliced_time_with_cache"] = sliced_info.sliced_plates[index].sliced_time_with_cache; + plate_json["triangle_count"] = sliced_info.sliced_plates[index].triangle_count; + plate_json["warning_message"] = sliced_info.sliced_plates[index].warning_message; + j["sliced_plates"].push_back(plate_json); + } + for (auto& iter: key_values) + j[iter.first] = iter.second; + + boost::nowide::ofstream c; + c.open(result_file, std::ios::out | std::ios::trunc); + c << std::setw(4) << j << std::endl; + c.close(); + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", saved config to %1%\n")%result_file; + } + catch (...) {} +#endif +} + +static int decode_png_to_thumbnail(std::string png_file, ThumbnailData& thumbnail_data) +{ + if (!boost::filesystem::exists(png_file)) + { + BOOST_LOG_TRIVIAL(error) << boost::format("can not find file %1%")%png_file; + return -1; + } + + const std::size_t &size = boost::filesystem::file_size(png_file); + std::string png_buffer(size, '\0'); + png_buffer.reserve(size); + + boost::filesystem::ifstream ifs(png_file, std::ios::binary); + ifs.read(png_buffer.data(), png_buffer.size()); + ifs.close(); + + Slic3r::png::ImageColorscale img; + Slic3r::png::ReadBuf rb{png_buffer.data(), png_buffer.size()}; + BOOST_LOG_TRIVIAL(info) << boost::format("read png file %1%, size %2%")%png_file %size; + + if ( !Slic3r::png::decode_colored_png(rb, img)) + { + BOOST_LOG_TRIVIAL(error) << boost::format("decode png file %1% failed")%png_file; + return -2; + } + + thumbnail_data.width = img.cols; + thumbnail_data.height = img.rows; + thumbnail_data.pixels = std::move(img.buf); + + return 0; +} + static void glfw_callback(int error_code, const char* description) { BOOST_LOG_TRIVIAL(error) << "error_code " <& key_values) +{ + json j; + CNumericLocalesSetter locales_setter; + + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< ": begin to parse "<> j; + ifs.close(); + + //parse the json elements + for (auto it = j.begin(); it != j.end(); it++) { + if (boost::iequals(it.key(),BBL_JSON_KEY_MODEL_ID)) { + key_values.emplace(BBL_JSON_KEY_MODEL_ID, it.value()); + } + else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) { + key_values.emplace(BBL_JSON_KEY_NAME, it.value()); + } + } + } + catch (const std::ifstream::failure &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "< gcodes_key_set = {"filament_end_gcode", "filament_start_gcode", "change_filament_gcode", "layer_change_gcode", "machine_end_gcode", "machine_pause_gcode", "machine_start_gcode", + "template_custom_gcode", "printing_by_object_gcode", "before_layer_change_gcode", "time_lapse_gcode"}; + +static void load_default_gcodes_to_config(DynamicPrintConfig& config, Preset::Type type) +{ + if (config.size() == 0) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ", empty config, return directly"; + return; + } + //add those empty gcodes by default + if (type == Preset::TYPE_PRINTER) + { + std::string change_filament_gcode = config.option("change_filament_gcode", true)->value; + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", change_filament_gcode: "<< change_filament_gcode; + + ConfigOptionString* layer_change_gcode_opt = config.option("layer_change_gcode", true); + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", layer_change_gcode: "<value; + + ConfigOptionString* machine_end_gcode_opt = config.option("machine_end_gcode", true); + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", machine_end_gcode: "<value; + + ConfigOptionString* machine_pause_gcode_opt = config.option("machine_pause_gcode", true); + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", machine_pause_gcode: "<value; + + ConfigOptionString* machine_start_gcode_opt = config.option("machine_start_gcode", true); + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", machine_start_gcode: "<value; + + ConfigOptionString* template_custom_gcode_opt = config.option("template_custom_gcode", true); + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", template_custom_gcode: "<value; + + ConfigOptionString* printing_by_object_gcode_opt = config.option("printing_by_object_gcode", true); + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", printing_by_object_gcode: "<value; + + ConfigOptionString* before_layer_change_gcode_opt = config.option("before_layer_change_gcode", true); + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", before_layer_change_gcode: "<value; + + ConfigOptionString* timeplase_gcode_opt = config.option("time_lapse_gcode", true); + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", time_lapse_gcode: "<value; + } + else if (type == Preset::TYPE_FILAMENT) + { + std::vector& filament_start_gcodes = config.option("filament_start_gcode", true)->values; + if (filament_start_gcodes.empty()) { + filament_start_gcodes.resize(1, std::string()); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ", set filament_start_gcodes to empty"; + } + else { + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", filament_start_gcodes: "<& filament_end_gcodes = config.option("filament_end_gcode", true)->values; + if (filament_end_gcodes.empty()) { + filament_end_gcodes.resize(1, std::string()); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ", set filament_end_gcode to empty"; + } + else { + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__<< ", filament_end_gcode: "< &assemble_plate_info_list) +{ + int ret = 0; + boost::filesystem::path directory_path(config_file); + + BOOST_LOG_TRIVIAL(info) << boost::format("%1% enter, file %2%")%__FUNCTION__ % config_file; + if (!fs::exists(directory_path)) { + BOOST_LOG_TRIVIAL(error) << boost::format("directory %1% not exist.")%config_file; + return CLI_FILE_NOTFOUND; + } + + try { + json root_json; + boost::nowide::ifstream ifs(config_file); + ifs >> root_json; + ifs.close(); + + int plate_count = root_json[JSON_ASSEMPLE_PLATES].size(); + if ((plate_count <= 0) || (plate_count > MAX_PLATE_COUNT)) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< boost::format(": invalid plate count %1%")%plate_count; + return CLI_CONFIG_FILE_ERROR; + } + assemble_plate_info_list.resize(plate_count); + + for (int plate_index = 0; plate_index < plate_count; plate_index++) + { + assemble_plate_info_t &assemble_plate = assemble_plate_info_list[plate_index]; + const json& plate_json = root_json[JSON_ASSEMPLE_PLATES][plate_index]; + assemble_plate.plate_name = plate_json[JSON_ASSEMPLE_PLATE_NAME]; + assemble_plate.need_arrange = plate_json[JSON_ASSEMPLE_PLATE_NEED_ARRANGE]; + + if (plate_json.contains(JSON_ASSEMPLE_PLATE_PARAMS)) { + assemble_plate.plate_params = plate_json[JSON_ASSEMPLE_PLATE_PARAMS].get>(); + BOOST_LOG_TRIVIAL(debug) << boost::format("Plate %1%, has %2% plate params") % (plate_index + 1) % assemble_plate.plate_params.size(); + } + + int object_count = plate_json[JSON_ASSEMPLE_OBJECTS].size(); + if (object_count <= 0) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< boost::format(": invalid object count %1% in plate %2%")%object_count %(plate_index+1); + return CLI_CONFIG_FILE_ERROR; + } + + assemble_plate.assemble_obj_list.resize(object_count); + for (int object_index = 0; object_index < object_count; object_index++) + { + assemble_object_info_t& assemble_object = assemble_plate.assemble_obj_list[object_index]; + const json& object_json = plate_json[JSON_ASSEMPLE_OBJECTS][object_index]; + + assemble_object.path = object_json[JSON_ASSEMPLE_OBJECT_PATH]; + assemble_object.count = object_json[JSON_ASSEMPLE_OBJECT_COUNT]; + + if (assemble_object.count <= 0) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": invalid object clone count %1% in plate %2% Object %3%") % assemble_object.count % (plate_index + 1) % assemble_object.path; + return CLI_CONFIG_FILE_ERROR; + } + + assemble_object.filaments = object_json.at(JSON_ASSEMPLE_OBJECT_FILAMENTS).get>(); + if ((assemble_object.filaments.size() > 0) && (assemble_object.filaments.size() != assemble_object.count) && (assemble_object.filaments.size() != 1)) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": object %1%'s filaments count %2% not equal to clone count %3%, also not equal to 1") % assemble_object.path % assemble_object.filaments.size() % assemble_object.count; + return CLI_CONFIG_FILE_ERROR; + } + + if (object_json.contains(JSON_ASSEMPLE_OBJECT_ASSEMBLE_INDEX)) { + assemble_object.assemble_index = object_json[JSON_ASSEMPLE_OBJECT_ASSEMBLE_INDEX].get>(); + if ((assemble_object.assemble_index.size() > 0) && (assemble_object.assemble_index.size() != assemble_object.count) && (assemble_object.assemble_index.size() != 1)) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": object %1%'s assemble_index count %2% not equal to clone count %3%, also not equal to 1") % assemble_object.path % assemble_object.assemble_index.size() % assemble_object.count; + return CLI_CONFIG_FILE_ERROR; + } + } + + if (object_json.contains(JSON_ASSEMPLE_OBJECT_POS_X)) { + assemble_object.pos_x = object_json[JSON_ASSEMPLE_OBJECT_POS_X].get>(); + if ((assemble_object.pos_x.size() > 0) && (assemble_object.pos_x.size() != assemble_object.count) && (assemble_object.pos_x.size() != 1)) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": object %1%'s pos_x count %2% not equal to clone count %3%, also not equal to 1") % assemble_object.path % assemble_object.pos_x.size() % assemble_object.count; + return CLI_CONFIG_FILE_ERROR; + } + } + if (object_json.contains(JSON_ASSEMPLE_OBJECT_POS_Y)) { + assemble_object.pos_y = object_json[JSON_ASSEMPLE_OBJECT_POS_Y].get>(); + if ((assemble_object.pos_y.size() > 0) && (assemble_object.pos_y.size() != assemble_object.count) && (assemble_object.pos_y.size() != 1)) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": object %1%'s pos_y count %2% not equal to clone count %3%, also not equal to 1") % assemble_object.path % assemble_object.pos_y.size() % assemble_object.count; + return CLI_CONFIG_FILE_ERROR; + } + } + if (object_json.contains(JSON_ASSEMPLE_OBJECT_POS_Z)) { + assemble_object.pos_z = object_json[JSON_ASSEMPLE_OBJECT_POS_Z].get>(); + if ((assemble_object.pos_z.size() > 0) && (assemble_object.pos_z.size() != assemble_object.count) && (assemble_object.pos_z.size() != 1)) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": object %1%'s pos_z count %2% not equal to clone count %3%, also not equal to 1") % assemble_object.path % assemble_object.pos_z.size() % assemble_object.count; + return CLI_CONFIG_FILE_ERROR; + } + } + if (object_json.contains(JSON_ASSEMPLE_OBJECT_PRINT_PARAMS)) { + assemble_object.print_params = object_json[JSON_ASSEMPLE_OBJECT_PRINT_PARAMS].get>(); + BOOST_LOG_TRIVIAL(debug) << boost::format("Plate %1%, object %2% has %3% print params") % (plate_index + 1) %assemble_object.path % assemble_object.print_params.size(); + } + } + } + } + catch(std::exception &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse file "<config.assign_config(ori_object->config.get()); + } + else + new_object = iter->second; + + for (auto volume : ori_object->volumes) { + ModelVolume* new_volume = new_object->add_volume(*volume); + // set extruder id + new_volume->config.set_key_value("extruder", new ConfigOptionInt(ori_object->config.extruder())); + } + BOOST_LOG_TRIVIAL(debug) << boost::format("assemble_index %1%, name %2%, merged to new model %3%") % assemble_index % ori_object->name % new_object->name; + } + else { + ModelObject* new_object = model.add_object(*ori_object); + assemble_plate_info.loaded_obj_list.emplace_back(new_object); + BOOST_LOG_TRIVIAL(debug) << boost::format("assemble_index %1%, name %2%, no need to merge, copy to new model") % assemble_index % ori_object->name; + } +} + +#ifdef _WIN32 +#define DIR_SEPARATOR '\\' +#else +#define DIR_SEPARATOR '/' +#endif +static int construct_assemble_list(std::vector &assemble_plate_info_list, Model &model, PlateDataPtrs &plate_list) +{ + int ret = 0; + int plate_count = assemble_plate_info_list.size(); + ConfigSubstitutionContext config_substitutions(ForwardCompatibilitySubstitutionRule::Enable); + Model temp_model; + + plate_list.resize(plate_count); + for (int index = 0; index < plate_count; index++) + { + //each plate has its dependent assemble list + std::map merged_objects; + std::set used_filaments; + //std::map to_merge_objects; + + assemble_plate_info_t& assemble_plate_info = assemble_plate_info_list[index]; + + int object_count = assemble_plate_info.assemble_obj_list.size(); + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": Plate %1%, name %2%, obj count %3%, plate params count %4%") % (index + 1) %assemble_plate_info.plate_name %object_count %assemble_plate_info.plate_params.size(); + PlateData* plate_data = new PlateData(); + plate_list[index] = plate_data; + plate_data->plate_name = assemble_plate_info.plate_name; + plate_data->plate_index = index; + + if (!assemble_plate_info.plate_params.empty()) + { + for (auto plate_iter = assemble_plate_info.plate_params.begin(); plate_iter != assemble_plate_info.plate_params.end(); plate_iter++) + { + plate_data->config.set_deserialize(plate_iter->first, plate_iter->second, config_substitutions); + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": Plate %1%, key %2%, value %3%") % (index + 1) % plate_iter->first % plate_iter->second; + } + } + + //construct the object list + for (size_t obj_index = 0; obj_index < object_count; obj_index++) + { + assemble_object_info_t& assemble_object = assemble_plate_info.assemble_obj_list[obj_index]; + std::string object_name; + TriangleMesh mesh; + + boost::filesystem::path object_path(assemble_object.path); + if (!fs::exists(object_path)) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": directory %1% not exist in plate %2%") % assemble_object.path % (index + 1); + return CLI_FILE_NOTFOUND; + } + + const char* path_str = assemble_object.path.c_str(); + const char* last_slash = strrchr(path_str, DIR_SEPARATOR); + object_name.assign((last_slash == nullptr) ? path_str : last_slash + 1); + + if (boost::algorithm::iends_with(assemble_object.path, ".stl")) + { + if (!mesh.ReadSTLFile(path_str, true, nullptr)) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": failed to read stl file from %1%, plate index %2%, object index %3%") % assemble_object.path % (index+1) % (obj_index+1); + return CLI_DATA_FILE_ERROR; + } + if (mesh.empty()) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": found no mesh data from stl file %1%, plate index %2%, object index %3%") % assemble_object.path % (index + 1) % (obj_index + 1); + return CLI_DATA_FILE_ERROR; + } + object_name.erase(object_name.end() - 3, object_name.end()); + } + else if (boost::algorithm::iends_with(assemble_object.path, ".obj")) + { + std::string message; + bool result = load_obj(path_str, &mesh, message); + if (!result) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": failed to read a valid mesh from obj file %1%, plate index %2%, object index %3%, error %4%") % assemble_object.path % (index + 1) % (obj_index + 1) % message; + return CLI_DATA_FILE_ERROR; + } + object_name.erase(object_name.end() - 3, object_name.end()); + } + else { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": unsupported file %1%, plate index %2%, object index %3%") % assemble_object.path % (index + 1) % (obj_index + 1); + return CLI_INVALID_PARAMS; + } + + std::string object_1_name = object_name + "_1"; + ModelObject* object = temp_model.add_object(object_1_name.c_str(), path_str, std::move(mesh)); + if (!object) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": add_object %1% failed, plate index %2%, object index %3%") % object_1_name % (index + 1) % (obj_index + 1); + return CLI_DATA_FILE_ERROR; + } + object->config.set_key_value("extruder", new ConfigOptionInt(assemble_object.filaments[0])); + if (!assemble_object.print_params.empty()) + { + for (auto param_iter = assemble_object.print_params.begin(); param_iter != assemble_object.print_params.end(); param_iter++) + { + object->config.set_deserialize(param_iter->first, param_iter->second, config_substitutions); + BOOST_LOG_TRIVIAL(debug) << boost::format("Plate %1%, object %2% key %3%, value %4%") % (index + 1) % object_1_name % param_iter->first % param_iter->second; + } + } + + if (assemble_object.pos_x.empty()) + assemble_object.pos_x.resize(1, 0.f); + if (assemble_object.pos_y.empty()) + assemble_object.pos_y.resize(1, 0.f); + if (assemble_object.pos_z.empty()) + assemble_object.pos_z.resize(1, 0.f); + if (assemble_object.assemble_index.empty()) + assemble_object.assemble_index.resize(1, 0); + + object->translate(assemble_object.pos_x[0], assemble_object.pos_y[0], assemble_object.pos_z[0]); + merge_or_add_object(assemble_plate_info, model, assemble_object.assemble_index[0], merged_objects, object); + used_filaments.emplace(assemble_object.filaments[0]); + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": object %1%, name %2%, pos_x %3% pos_y %4%, pos_z %5%, filament %6%, assemble_index %7%") + %obj_index %object->name %assemble_object.pos_x[0] %assemble_object.pos_y[0] %assemble_object.pos_z[0] %assemble_object.filaments[0] %assemble_object.assemble_index[0]; + + for (size_t copy_index = 1; copy_index < assemble_object.count; copy_index++) + { + int array_index = copy_index; + + ModelObject* copy_obj = temp_model.add_object(*object); + copy_obj->name = object_name + "_" + std::to_string(copy_index + 1); + + if (copy_index >= assemble_object.pos_x.size()) + array_index = 0; + copy_obj->translate(assemble_object.pos_x[array_index], assemble_object.pos_y[array_index], assemble_object.pos_z[array_index]); + + if (copy_index < assemble_object.filaments.size()) + array_index = copy_index; + else + array_index = 0; + copy_obj->config.set_key_value("extruder", new ConfigOptionInt(assemble_object.filaments[array_index])); + used_filaments.emplace(assemble_object.filaments[array_index]); + + if (copy_index < assemble_object.assemble_index.size()) + array_index = copy_index; + else + array_index = 0; + merge_or_add_object(assemble_plate_info, model, assemble_object.assemble_index[array_index], merged_objects, copy_obj); + + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": cloned object %1%, name %2%, pos_x %3% pos_y %4%, pos_z %5%") + %copy_index %object->name %assemble_object.pos_x[array_index] %assemble_object.pos_y[array_index] %assemble_object.pos_z[array_index]; + } + } + + assemble_plate_info.filaments_count = used_filaments.size(); + assemble_plate_info.assemble_obj_list.clear(); + assemble_plate_info.assemble_obj_list.shrink_to_fit(); + assemble_plate_info.plate_params.clear(); + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": Plate %1%, used filaments %2%") % (index + 1) % assemble_plate_info.filaments_count; + } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": has objects need to be merged, total plates %1%, total objects %2%") % plate_count % model.objects.size(); + + temp_model.clear_objects(); + temp_model.clear_materials(); + return ret; +} + int CLI::run(int argc, char **argv) { // Mark the main thread for the debugger and for runtime checks. set_current_thread_name("orcaslicer_main"); // Save the thread ID of the main thread. save_main_thread_id(); + #ifdef __WXGTK__ // On Linux, wxGTK has no support for Wayland, and the app crashes on // startup if gtk3 is used. This env var has to be set explicitly to @@ -370,26 +909,7 @@ int CLI::run(int argc, char **argv) boost::nowide::cerr << text.c_str() << std::endl; return CLI_ENVIRONMENT_ERROR; } - BOOST_LOG_TRIVIAL(info) << "Current OraSlicer Version "<< SoftFever_VERSION << std::endl; - - /*BOOST_LOG_TRIVIAL(info) << "begin to setup params, argc=" << argc << std::endl; - for (int index=0; index < argc; index++) - BOOST_LOG_TRIVIAL(info) << "index="<< index <<", arg is "<< argv[index] <setup(debug_argc, debug_argv))*/ + if (!this->setup(argc, argv)) { boost::nowide::cerr << "setup params error" << std::endl; @@ -415,15 +935,27 @@ int CLI::run(int argc, char **argv) boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), "gcodeviewer"); #endif // _WIN32*/ - bool translate_old = false, regenerate_thumbnails = false; - int current_width, current_depth, current_height; + bool translate_old = false, regenerate_thumbnails = false, shrink_to_new_bed = false, filament_color_changed = false; + int current_printable_width, current_printable_depth, current_printable_height; + int old_printable_height = 0, old_printable_width = 0, old_printable_depth = 0; + Pointfs old_printable_area, old_exclude_area; + float old_max_radius = 0.f, old_height_to_rod = 0.f, old_height_to_lid = 0.f; + std::vector old_max_layer_height, old_min_layer_height; + std::string outfile_dir = m_config.opt_string("outputdir", true); const std::vector &load_configs = m_config.option("load_settings", true)->values; + const std::vector &uptodate_configs = m_config.option("uptodate_settings", true)->values; + const std::vector &uptodate_filaments = m_config.option("uptodate_filaments", true)->values; //BBS: always use ForwardCompatibilitySubstitutionRule::Enable //const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option>("config_compatibility", true)->value; const ForwardCompatibilitySubstitutionRule config_substitution_rule = ForwardCompatibilitySubstitutionRule::Enable; const std::vector &load_filaments = m_config.option("load_filaments", true)->values; + //skip model object logic const std::vector &skip_objects = m_config.option("skip_objects", true)->values; + std::map skip_maps; bool need_skip = (skip_objects.size() > 0)?true:false; + long long global_begin_time = 0, global_current_time; + sliced_info_t sliced_info; + std::map record_key_values; if (start_gui) { BOOST_LOG_TRIVIAL(info) << "no action, start gui directly" << std::endl; @@ -488,20 +1020,23 @@ int CLI::run(int argc, char **argv) } } - BOOST_LOG_TRIVIAL(info) << "start_gui="<< start_gui << std::endl; + global_begin_time = (long long)Slic3r::Utils::get_current_time_utc(); + BOOST_LOG_TRIVIAL(warning) << boost::format("cli mode, Current OrcaSlicer Version %1%")%SLIC3R_VERSION; //BBS: add plate data related logic PlateDataPtrs plate_data_src; int arrange_option; - int plate_to_slice = 0, filament_count = 0; - bool first_file = true, is_bbl_3mf = false, need_arrange = true, has_thumbnails = false, up_config_to_date = false, normative_check = true; + int plate_to_slice = 0, filament_count = 0, duplicate_count = 0, real_duplicate_count = 0; + bool first_file = true, is_bbl_3mf = false, need_arrange = true, has_thumbnails = false, up_config_to_date = false, normative_check = true, duplicate_single_object = false, use_first_fila_as_default = false, minimum_save = false, enable_timelapse = false; + bool allow_rotations = true, skip_modified_gcodes = false, avoid_extrusion_cali_region = false; Semver file_version; std::map orients_requirement; std::vector project_presets; - std::string new_printer_name, current_printer_name, new_process_name, current_process_name, current_printer_system_name, current_process_system_name;//, printer_inherits, print_inherits; + std::string new_printer_name, current_printer_name, new_process_name, current_process_name, current_printer_system_name, current_process_system_name, new_process_system_name, new_printer_system_name, printer_model_id;//, printer_inherits, print_inherits; std::vector upward_compatible_printers, new_print_compatible_printers, current_print_compatible_printers, current_different_settings; std::vector current_filaments_name, current_filaments_system_name, current_inherits_group; DynamicPrintConfig load_process_config, load_machine_config; + bool new_process_config_is_system = true, new_printer_config_is_system = true; std::string pipe_name; // Read input file(s) if any. @@ -518,6 +1053,30 @@ int CLI::run(int argc, char **argv) if (uptodate_option) up_config_to_date = uptodate_option->value; + ConfigOptionBool* load_defaultfila_option = m_config.option("load_defaultfila"); + if (load_defaultfila_option) + use_first_fila_as_default = load_defaultfila_option->value; + + ConfigOptionBool* min_save_option = m_config.option("min_save"); + if (min_save_option) + minimum_save = min_save_option->value; + + ConfigOptionBool* enable_timelapse_option = m_config.option("enable_timelapse"); + if (enable_timelapse_option) + enable_timelapse = enable_timelapse_option->value; + + ConfigOptionBool* allow_rotations_option = m_config.option("allow_rotations"); + if (allow_rotations_option) + allow_rotations = allow_rotations_option->value; + + ConfigOptionBool* skip_modified_gcodes_option = m_config.option("skip_modified_gcodes"); + if (skip_modified_gcodes_option) + skip_modified_gcodes = skip_modified_gcodes_option->value; + + ConfigOptionBool* avoid_extrusion_cali_region_option = m_config.option("avoid_extrusion_cali_region"); + if (avoid_extrusion_cali_region_option) + avoid_extrusion_cali_region = avoid_extrusion_cali_region_option->value; + ConfigOptionString* pipe_option = m_config.option("pipe"); if (pipe_option) { pipe_name = pipe_option->value; @@ -525,21 +1084,90 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << boost::format("Will use pipe %1%")%pipe_name; #if defined(__linux__) || defined(__LINUX__) g_cli_callback_mgr.start(pipe_name); + PrintBase::SlicingStatus slicing_status{1, "Start to load files"}; + cli_status_callback(slicing_status); #endif } } + //skip model object map construct + if (need_skip) { + BOOST_LOG_TRIVIAL(info) << boost::format("need to skip objects, size %1%:")%skip_objects.size(); + for (int index = 0; index < skip_objects.size(); index++) + { + skip_maps[skip_objects[index]] = false; + BOOST_LOG_TRIVIAL(info) << boost::format("object %1%, id %2%")%index %skip_objects[index]; + } + } + + std::string custom_gcode_file; + ConfigOptionString* custom_gcode_option = m_config.option("load_custom_gcodes"); + if (custom_gcode_option) + custom_gcode_file = custom_gcode_option->value; + + std::string load_assemble_list; + std::vector assemble_plate_info_list; + ConfigOptionString* load_assemble_list_option = m_config.option("load_assemble_list"); + if (load_assemble_list_option) + load_assemble_list = load_assemble_list_option->value; + + bool allow_multicolor_oneplate = m_config.option("allow_multicolor_oneplate", true)->value; + const std::vector loaded_filament_ids = m_config.option("load_filament_ids", true)->values; + const std::vector clone_objects = m_config.option("clone_objects", true)->values; + //when load objects from stl/obj, the total used filaments set + std::set used_filament_set; + BOOST_LOG_TRIVIAL(info) << boost::format("allow_multicolor_oneplate %1%, allow_rotations %2% skip_modified_gcodes %3% avoid_extrusion_cali_region %4% loaded_filament_ids size %5%, clone_objects size %6%") + %allow_multicolor_oneplate %allow_rotations %skip_modified_gcodes %avoid_extrusion_cali_region %loaded_filament_ids.size() %clone_objects.size(); + if (clone_objects.size() > 0) + { + if (clone_objects.size() != m_input_files.size()) + { + BOOST_LOG_TRIVIAL(error) << boost::format("clone_objects size %1% should be the same with input files size %2%")%clone_objects.size() %m_input_files.size(); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + else if (load_filaments.size() == 0) + { + BOOST_LOG_TRIVIAL(error) << boost::format("clone_objects should be used with load_filaments together"); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + } + if (loaded_filament_ids.size() > 0) + { + if (loaded_filament_ids.size() != m_input_files.size()) + { + BOOST_LOG_TRIVIAL(error) << boost::format("loaded_filament_ids size %1% should be the same with input files size %2%")%loaded_filament_ids.size() %m_input_files.size(); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + else if (load_filaments.size() == 0) + { + BOOST_LOG_TRIVIAL(error) << boost::format("loaded_filament_ids should be used with load_filaments together"); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + } + /*for (const std::string& file : m_input_files) if (is_gcode_file(file) && boost::filesystem::exists(file)) { start_as_gcodeviewer = true; BOOST_LOG_TRIVIAL(info) << "found a gcode file:" << file << ", will start as gcode viewer\n"; break; }*/ - BOOST_LOG_TRIVIAL(info) << boost::format("plate_to_slice=%1%, normative_check=%2%")%plate_to_slice %normative_check; - //if (!start_as_gcodeviewer) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate_to_slice=%1%, normative_check=%2%, use_first_fila_as_default=%3%")%plate_to_slice %normative_check %use_first_fila_as_default; + unsigned int input_index = 0; + if (!load_assemble_list.empty() && ((m_input_files.size() > 0) || (m_transforms.size() > 0))) + { + BOOST_LOG_TRIVIAL(error) << boost::format("load_assemble_list should not be used with input model files to load and should not be sued with transforms"); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + if (load_assemble_list.empty()) { for (const std::string& file : m_input_files) { if (!boost::filesystem::exists(file)) { boost::nowide::cerr << "No such file: " << file << std::endl; + record_exit_reson(outfile_dir, CLI_FILE_NOTFOUND, 0, cli_errors[CLI_FILE_NOTFOUND], sliced_info); flush_and_exit(CLI_FILE_NOTFOUND); } Model model; @@ -555,11 +1183,18 @@ int CLI::run(int argc, char **argv) is_bbl_3mf = false; LoadStrategy strategy; if (boost::algorithm::iends_with(file, ".3mf") && first_file) { + if ((clone_objects.size() > 0) || (loaded_filament_ids.size() > 0)) + { + BOOST_LOG_TRIVIAL(error) << boost::format("can not load 3mf when set loaded_filament_ids or clone_objects"); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } strategy = LoadStrategy::LoadModel | LoadStrategy::LoadConfig|LoadStrategy::AddDefaultInstances | LoadStrategy::LoadAuxiliary; //load_aux = true; } - else + else { strategy = LoadStrategy::LoadModel | LoadStrategy::AddDefaultInstances; + } // BBS: adjust whebackup //LoadStrategy strategy = LoadStrategy::LoadModel | LoadStrategy::LoadConfig|LoadStrategy::AddDefaultInstances; //if (load_aux) strategy = strategy | LoadStrategy::LoadAuxiliary; @@ -569,15 +1204,16 @@ int CLI::run(int argc, char **argv) if (!first_file) { BOOST_LOG_TRIVIAL(info) << "The BBL 3mf file should be placed at the first position, filename=" << file << "\n"; + record_exit_reson(outfile_dir, CLI_FILELIST_INVALID_ORDER, 0, cli_errors[CLI_FILELIST_INVALID_ORDER], sliced_info); flush_and_exit(CLI_FILELIST_INVALID_ORDER); } - BOOST_LOG_TRIVIAL(info) << "the first file is a 3mf, got plate count:" << plate_data_src.size() << "\n"; + BOOST_LOG_TRIVIAL(info) << boost::format("the first file is a 3mf, version %1%, got plate count %2%") %file_version.to_string() %plate_data_src.size(); need_arrange = false; - for (ModelObject* o : model.objects) + /*for (ModelObject* o : model.objects) { orients_requirement.insert(std::pair(o->id().id, false)); BOOST_LOG_TRIVIAL(info) << "object "<name <<", id :" << o->id().id << ", from bbl 3mf\n"; - } + }*/ Semver old_version(1, 5, 9), old_version2(1, 5, 9); if ((file_version < old_version) && !config.empty()) { @@ -595,6 +1231,7 @@ int CLI::run(int argc, char **argv) std::vector postprocess_values = postprocess_scripts->values; if (postprocess_values.size() > 0) { BOOST_LOG_TRIVIAL(error) << boost::format("normative_check: postprocess not supported, array size %1%")%postprocess_values.size(); + record_exit_reson(outfile_dir, CLI_POSTPROCESS_NOT_SUPPORTED, 0, cli_errors[CLI_POSTPROCESS_NOT_SUPPORTED], sliced_info); flush_and_exit(CLI_POSTPROCESS_NOT_SUPPORTED); } } @@ -609,59 +1246,142 @@ int CLI::run(int argc, char **argv) current_printer_name = config.option("printer_settings_id")->value; current_process_name = config.option("print_settings_id")->value; current_filaments_name = config.option("filament_settings_id")->values; + + BOOST_LOG_TRIVIAL(info) << boost::format("current_printer_name %1%, current_process_name %2%")%current_printer_name %current_process_name; ConfigOptionStrings* option_strings = config.option("inherits_group"); if (option_strings) { current_inherits_group = option_strings->values; size_t size = current_inherits_group.size(); - if (current_inherits_group[size-1].empty()) + if (current_inherits_group[size-1].empty()) { current_printer_system_name = current_printer_name; - else + BOOST_LOG_TRIVIAL(info) << boost::format("inherits of printer is null, should be system preset"); + } + else { current_printer_system_name = current_inherits_group[size-1]; + BOOST_LOG_TRIVIAL(info) << boost::format("inherits of printer valid, current_printer_system_name is %1%") %current_printer_system_name; + } - if (current_inherits_group[0].empty()) + if (current_inherits_group[0].empty()) { current_process_system_name = current_process_name; - else + BOOST_LOG_TRIVIAL(info) << boost::format("inherits of process is null, should be system preset"); + } + else { current_process_system_name = current_inherits_group[0]; + BOOST_LOG_TRIVIAL(info) << boost::format("inherits of process valid, current_process_system_name is %1%") %current_process_system_name; + } current_filaments_system_name.resize(size - 2); for (int index = 1; index < (size - 1); index++) { - if (current_inherits_group[index].empty()) + if (current_inherits_group[index].empty()) { current_filaments_system_name[index-1] = current_filaments_name[index-1]; - else + } + else { current_filaments_system_name[index-1] = current_inherits_group[index]; + } } } else { current_printer_system_name = current_printer_name; current_process_system_name = current_process_name; current_filaments_system_name = current_filaments_name; + BOOST_LOG_TRIVIAL(info) << boost::format("no inherits_group: use system name the same as current name"); } filament_count = current_filaments_name.size(); upward_compatible_printers = config.option("upward_compatible_machine", true)->values; current_print_compatible_printers = config.option("print_compatible_printers", true)->values; current_different_settings = config.option("different_settings_to_system", true)->values; + + //use Pointfs insteadof Points + old_printable_area = config.option("printable_area", true)->values; + old_exclude_area = config.option("bed_exclude_area", true)->values; + if (old_printable_area.size() >= 4) { + old_printable_width = (int)(old_printable_area[2].x() - old_printable_area[0].x()); + old_printable_depth = (int)(old_printable_area[2].y() - old_printable_area[0].y()); + } + old_printable_height = (int)(config.opt_float("printable_height")); + + if (config.option("extruder_clearance_height_to_rod")) + old_height_to_rod = config.opt_float("extruder_clearance_height_to_rod"); + if (config.option("extruder_clearance_height_to_lid")) + old_height_to_lid = config.opt_float("extruder_clearance_height_to_lid"); + if (config.option("extruder_clearance_max_radius")) + old_max_radius = config.opt_float("extruder_clearance_max_radius"); + if (config.option("max_layer_height")) + old_max_layer_height = config.option("max_layer_height")->values; + if (config.option("min_layer_height")) + old_min_layer_height = config.option("min_layer_height")->values; + BOOST_LOG_TRIVIAL(info) << boost::format("old printable size from 3mf: {%1%, %2%, %3%}")%old_printable_width %old_printable_depth %old_printable_height; + BOOST_LOG_TRIVIAL(info) << boost::format("old extruder_clearance_height_to_rod %1%, extruder_clearance_height_to_lid %2%, extruder_clearance_max_radius %3%}")%old_height_to_rod %old_height_to_lid %old_max_radius; } else { need_arrange = true; - for (ModelObject* o : model.objects) - { - orients_requirement.insert(std::pair(o->id().id, true)); - BOOST_LOG_TRIVIAL(info) << "object "<name <<", id :" << o->id().id << ", from stl or other 3mf\n"; - o->ensure_on_bed(); + int object_extruder_id = 0, clone_count = 1; + if (loaded_filament_ids.size() > input_index) { + if (loaded_filament_ids[input_index] > 0) { + if (loaded_filament_ids[input_index] > load_filaments.size()) { + BOOST_LOG_TRIVIAL(error) << boost::format("invalid filament id %1% at index %2%, max %3%")%loaded_filament_ids[input_index] % (input_index + 1) %load_filaments.size(); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + object_extruder_id = loaded_filament_ids[input_index]; + used_filament_set.emplace(object_extruder_id); + } } - } - first_file = false; - PrinterTechnology other_printer_technology = get_printer_technology(config); - if (printer_technology == ptUnknown) { - printer_technology = other_printer_technology; - } - if ((printer_technology != other_printer_technology) && (other_printer_technology != ptUnknown)) { - boost::nowide::cerr << "invalid printer_technology " < input_index) { + if (clone_objects[input_index] > 0) { + if (clone_objects[input_index] > MAX_CLONEABLE_SIZE) { + BOOST_LOG_TRIVIAL(error) << boost::format("invalid clone count %1% at index %2%, max %3%")%clone_objects[input_index] % (input_index + 1) %MAX_CLONEABLE_SIZE; + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + clone_count = clone_objects[input_index]; + } + } + + //clone objects process + if (clone_count > 1) + { + unsigned int object_count = model.objects.size(); + + for (unsigned int obj_index = 0; obj_index < object_count; obj_index++) + { + ModelObject* object = model.objects[obj_index]; + + for (unsigned int clone_index = 1; clone_index < clone_count; clone_index++) + { + ModelObject* newObj = model.add_object(*object); + newObj->name = object->name +"_"+ std::to_string(clone_index+1); + } + object->name = object->name +"_"+ std::to_string(1); + } + } + + for (ModelObject* o : model.objects) + { + if (object_extruder_id != 0) { + o->config.set_key_value("extruder", new ConfigOptionInt(object_extruder_id)); + } + + //default not orient for all, if need to orient use the action + //orients_requirement.insert(std::pair(o->id().id, false)); + BOOST_LOG_TRIVIAL(info) << "object "<name <<", id :" << o->id().id << ", from stl or other 3mf\n"; + o->ensure_on_bed(); + } + } + first_file = false; + + PrinterTechnology other_printer_technology = get_printer_technology(config); + if (printer_technology == ptUnknown) { + printer_technology = other_printer_technology; + } + if ((printer_technology != other_printer_technology) && (other_printer_technology != ptUnknown)) { + boost::nowide::cerr << "invalid printer_technology " <opt_key << "\"\t old_value = \"" << subst.old_value << "\tnew_value = \"" << subst.new_value->serialize() << "\"\n"; @@ -670,9 +1390,11 @@ int CLI::run(int argc, char **argv) // config is applied to m_print_config before the current m_config values. config += std::move(m_print_config); m_print_config = std::move(config); + input_index++; } catch (std::exception& e) { boost::nowide::cerr << file << ": " << e.what() << std::endl; + record_exit_reson(outfile_dir, CLI_DATA_FILE_ERROR, 0, cli_errors[CLI_DATA_FILE_ERROR], sliced_info); flush_and_exit(CLI_DATA_FILE_ERROR); } if (model.objects.empty()) { @@ -681,10 +1403,70 @@ int CLI::run(int argc, char **argv) } m_models.push_back(std::move(model)); } - //} + } + else { + //parse the json and assemble object here + Model model; + + int ret = load_assemble_plate_list(load_assemble_list, assemble_plate_info_list); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); + flush_and_exit(ret); + } + + try { + ret = construct_assemble_list(assemble_plate_info_list, model, plate_data_src); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); + flush_and_exit(ret); + } + } + catch (std::exception& e) { + boost::nowide::cerr << construct_assemble_list << ": " << e.what() << std::endl; + record_exit_reson(outfile_dir, CLI_DATA_FILE_ERROR, 0, cli_errors[CLI_DATA_FILE_ERROR], sliced_info); + flush_and_exit(CLI_DATA_FILE_ERROR); + } + model.add_default_instances(); + m_models.push_back(std::move(model)); + } + + //load custom gcode file + std::map custom_gcodes_map; + if (!custom_gcode_file.empty()) { + // parse the custom gcode json file + std::string file = custom_gcode_file; + if(!boost::filesystem::exists(file)) { + boost::nowide::cerr << __FUNCTION__ << ": can not find custom_gcode file: " << file << std::endl; + record_exit_reson(outfile_dir, CLI_FILE_NOTFOUND, 0, cli_errors[CLI_FILE_NOTFOUND], sliced_info); + flush_and_exit(CLI_FILE_NOTFOUND); + } + try { + nlohmann::json jj; + boost::nowide::ifstream ifs(file); + ifs >> jj; + ifs.close(); + + int plate_id = 0; + if (plate_to_slice == 0) + plate_id = 0; + else + plate_id = plate_to_slice-1; + + CustomGCode::Info info; + info.from_json(jj); + + custom_gcodes_map.emplace(plate_id, info); + BOOST_LOG_TRIVIAL(info) << boost::format("load custom_gcode from file %1% success, store custom gcodes to plate %2%")%file %(plate_id+1); + } + catch (std::exception &ex) { + boost::nowide::cerr << __FUNCTION__<< ":Loading custom-gcode file \"" << file << "\" failed: " << ex.what() << std::endl; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + } - auto load_system_config_file = [config_substitution_rule](const std::string& file, DynamicPrintConfig& config, std::string& config_type, - std::string& config_name, std::string& filament_id) { + auto load_config_file = [config_substitution_rule](const std::string& file, DynamicPrintConfig& config, std::string& config_type, + std::string& config_name, std::string& filament_id, std::string& config_from) { if (! boost::filesystem::exists(file)) { boost::nowide::cerr << __FUNCTION__<< ": can not find setting file: " << file << std::endl; return CLI_FILE_NOTFOUND; @@ -693,7 +1475,7 @@ int CLI::run(int argc, char **argv) try { BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ":load setting file "<< file << ", with rule "<< config_substitution_rule << std::endl; std::map key_values; - std::string reason, config_from; + std::string reason; config_substitutions = config.load_from_json(file, config_substitution_rule, key_values, reason); if (!reason.empty()) { @@ -706,7 +1488,7 @@ int CLI::run(int argc, char **argv) if (from_iter != key_values.end()) { config_from = from_iter->second; } - if (config_from != "system") { + if ((config_from != "system")&&(config_from != "User")&&(config_from != "user")) { boost::nowide::cerr <<__FUNCTION__ << boost::format(":file %1%'s from %2% unsupported") % file % config_from; return CLI_CONFIG_FILE_ERROR; } @@ -756,32 +1538,70 @@ int CLI::run(int argc, char **argv) // load config files supplied via --load for (auto const &file : load_configs) { DynamicPrintConfig config; - std::string config_type, config_name, filament_id; - int ret = load_system_config_file(file, config, config_type, config_name, filament_id); + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from); if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); flush_and_exit(ret); } if (config_type == "machine") { if (!new_printer_name.empty()) { boost::nowide::cerr << "duplicate machine config file: " << file << std::endl; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); flush_and_exit(CLI_CONFIG_FILE_ERROR); } new_printer_name = config_name; + if (config_from == "system") { + new_printer_system_name = new_printer_name; + new_printer_config_is_system = true; + } + else { + new_printer_system_name = config.option("inherits", true)->value; + new_printer_config_is_system = false; + } config.set("printer_settings_id", new_printer_name, true); + + //get printer_model_id + std::string printer_model = config.option("printer_model", true)->value; + if (!printer_model.empty()) { + std::string printer_model_path = resources_dir() + "/profiles/BBL/machine_full/"+printer_model+".json"; + if (boost::filesystem::exists(printer_model_path)) + { + std::map key_values; + + load_key_values_from_json(printer_model_path, key_values); + if (key_values.find("model_id") != key_values.end()) { + printer_model_id = key_values["model_id"]; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, load printer_model_id %2% from current printer model %3%")%__LINE__ %printer_model_id %printer_model; + } + } + } + //printer_inherits = config.option("inherits", true)->value; load_machine_config = std::move(config); + BOOST_LOG_TRIVIAL(info) << boost::format("loaded machine config %1%, type %2%, name %3%, inherits %4%, printer_model_id %5%")%file %config_name %config_from % new_printer_system_name %printer_model_id; } else if (config_type == "process") { if (!new_process_name.empty()) { boost::nowide::cerr << "duplicate process config file: " << file << std::endl; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); flush_and_exit(CLI_CONFIG_FILE_ERROR); } new_process_name = config_name; + if (config_from == "system") { + new_process_system_name = new_process_name; + new_process_config_is_system = true; + } + else { + new_process_system_name = config.option("inherits", true)->value; + new_process_config_is_system = false; + } config.set("print_settings_id", new_process_name, true); //print_inherits = config.option("inherits", true)->value; new_print_compatible_printers = config.option("compatible_printers", true)->values; load_process_config = std::move(config); + BOOST_LOG_TRIVIAL(info) << boost::format("loaded process config %1%, type %2%, name %3%, inherits %4%")%file %config_name %config_from % new_process_system_name; } PrinterTechnology other_printer_technology = get_printer_technology(config); @@ -791,6 +1611,7 @@ int CLI::run(int argc, char **argv) if ((printer_technology != other_printer_technology)&&(other_printer_technology != ptUnknown)){ boost::nowide::cerr << "invalid printer_technology " < load_filaments_index; + std::set load_filaments_set; + bool disable_wipe_tower_after_mapping = false; std::vector load_filaments_config; std::vector load_filaments_id; - std::vector load_filaments_name; + std::vector load_filaments_name, load_filaments_inherit; int current_index = 0; + std::string default_load_fila_name, default_load_fila_id, default_filament_file, default_filament_inherit; + DynamicPrintConfig default_load_fila_config; + if (use_first_fila_as_default) { + //construct default filament + for (int index = 0; index < load_filament_count; index++) { + const std::string& file = load_filaments[index]; + if (default_filament_file.empty() && !file.empty()) { + DynamicPrintConfig config; + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); + flush_and_exit(ret); + } + + if (config_type != "filament") { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % file; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + + if ((config_from == "User")||(config_from == "user")) { + default_filament_inherit = config.option("inherits", true)->value; + } + + default_filament_file = file; + default_load_fila_name = config_name; + default_load_fila_id = filament_id; + default_load_fila_config = std::move(config); + + BOOST_LOG_TRIVIAL(info) << boost::format("loaded default filament config %1%, type %2%, name %3%, inherits %4%")%file %config_from %config_name % default_filament_inherit; + break; + } + } + if ((load_filament_count > 0) && default_filament_file.empty()) + { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": load_filament_count is %1%, but can not load a default filament") % load_filament_count; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + } for (int index = 0; index < load_filament_count; index++) { const std::string& file = load_filaments[index]; current_index++; if (!file.empty()) { DynamicPrintConfig config; - std::string config_type, config_name, filament_id; - int ret = load_system_config_file(file, config, config_type, config_name, filament_id); + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from); if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); flush_and_exit(ret); } if (config_type != "filament") { - boost::nowide::cerr <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % file; + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % file; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); flush_and_exit(CLI_CONFIG_FILE_ERROR); } @@ -823,15 +1689,35 @@ int CLI::run(int argc, char **argv) printer_technology = other_printer_technology; } if ((printer_technology != other_printer_technology) && (other_printer_technology != ptUnknown)) { - boost::nowide::cerr << "invalid printer_technology " <("inherits", true)->value; + } + load_filaments_inherit.push_back(inherits); load_filaments_id.push_back(filament_id); load_filaments_name.push_back(config_name); load_filaments_config.push_back(std::move(config)); load_filaments_index.push_back(current_index); + + load_filaments_set.emplace(config_name); + + BOOST_LOG_TRIVIAL(info) << boost::format("loaded filament %1% from file %2%, type %3%, name %4%, inherits %5%")%(index+1) %file %config_from %config_name % inherits; } else { + if (use_first_fila_as_default) { + BOOST_LOG_TRIVIAL(info)<<__FUNCTION__ << boost::format(": load filament %1% from default, config name %2%, filament_id %3%, current_index %4%") % (index+1) % default_load_fila_name %default_load_fila_id %current_index; + load_filaments_id.push_back(default_load_fila_id); + load_filaments_name.push_back(default_load_fila_name); + load_filaments_config.push_back(default_load_fila_config); + load_filaments_index.push_back(current_index); + load_filaments_inherit.push_back(default_filament_inherit); + + load_filaments_set.emplace(default_load_fila_name); + } continue; } } @@ -839,69 +1725,240 @@ int CLI::run(int argc, char **argv) if (filament_count == 0) filament_count = load_filament_count; + if (is_bbl_3mf && (load_filament_count > 0) && (load_filaments_set.size() == 1)) + { + disable_wipe_tower_after_mapping = true; + BOOST_LOG_TRIVIAL(warning) << boost::format("map all the filaments to the same one, load_filament_count %1%")%load_filament_count; + } + //load system config if needed bool fetch_compatible_values = false, fetch_upward_values = false; if (is_bbl_3mf && up_config_to_date) { - if (new_printer_name.empty() && !current_printer_system_name.empty()) { - //use the original printer name in 3mf - std::string system_printer_path = resources_dir() + "/profiles/BBL/machine_full/"+current_printer_system_name+".json"; - if (! boost::filesystem::exists(system_printer_path)) { - boost::nowide::cerr << __FUNCTION__<< ": can not find system preset file: " << system_printer_path << std::endl; - //use original one - } - else { + if (uptodate_configs.size() > 0) + { + for (auto const &file : uptodate_configs) { DynamicPrintConfig config; - std::string config_type, config_name, filament_id; - int ret = load_system_config_file(system_printer_path, config, config_type, config_name, filament_id); - if (ret) + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); flush_and_exit(ret); - upward_compatible_printers = config.option("upward_compatible_machine", true)->values; - config.set("printer_settings_id", config_name, true); - load_machine_config = std::move(config); + } + + if (config_type == "machine") { + if ( config_name != current_printer_system_name ) { + BOOST_LOG_TRIVIAL(error) << boost::format("wrong machine config file %1% loaded, current machine config name %2% ")%config_name %current_printer_system_name; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + upward_compatible_printers = config.option("upward_compatible_machine", true)->values; + BOOST_LOG_TRIVIAL(info) << boost::format("load a machine config %1% from file %2%, upward_compatible_printers size is %3% ")%config_name %file %upward_compatible_printers.size(); + if (new_printer_name.empty() && !current_printer_system_name.empty()) + { + config.set("printer_settings_id", config_name, true); + + //get printer_model_id + std::string printer_model = config.option("printer_model", true)->value; + if (!printer_model.empty()) { + std::string printer_model_path = resources_dir() + "/profiles/BBL/machine_full/"+printer_model+".json"; + if (boost::filesystem::exists(printer_model_path)) + { + std::map key_values; + + load_key_values_from_json(printer_model_path, key_values); + if (key_values.find("model_id") != key_values.end()) { + printer_model_id = key_values["model_id"]; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, load printer_model_id %2% from current printer model %3%")%__LINE__ %printer_model_id %printer_model; + } + } + } + + int orig_printable_width = 0, orig_printable_depth = 0, orig_printable_height = 0; + Pointfs orig_printable_area; + orig_printable_area = config.option("printable_area", true)->values; + if (orig_printable_area.size() >= 4) { + orig_printable_width = (int)(orig_printable_area[2].x() - orig_printable_area[0].x()); + orig_printable_depth = (int)(orig_printable_area[2].y() - orig_printable_area[0].y()); + } + orig_printable_height = (int)(config.opt_float("printable_height")); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, check printable size: old_printable_width=%2%, orig_printable_width=%3%, old_printable_depth=%4%, orig_printable_depth=%5%, old_printable_height=%6%, orig_printable_height=%7%") + %__LINE__ %old_printable_width %orig_printable_width %old_printable_depth %orig_printable_depth %old_printable_height %orig_printable_height; + if ((orig_printable_width > 0) && (orig_printable_depth > 0) && (orig_printable_height > 0)) + { + if ((old_printable_width > orig_printable_width) || (old_printable_depth > orig_printable_depth) || (old_printable_height > orig_printable_height)) + { + std::string error_str = (boost::format("Printer Settings: the printable size {%1%, %2%, %3%} exceeds the default size.")%old_printable_width %old_printable_depth %old_printable_height).str(); + BOOST_LOG_TRIVIAL(error) << error_str; + record_exit_reson(outfile_dir, CLI_MODIFIED_PARAMS_TO_PRINTER, 0, error_str, sliced_info); + flush_and_exit(CLI_MODIFIED_PARAMS_TO_PRINTER); + } + } + + load_machine_config = std::move(config); + } + } + else if (config_type == "process") { + if ( config_name != current_process_system_name ) { + BOOST_LOG_TRIVIAL(error) << boost::format("wrong process config file %1% loaded, current process config name %2% ")%config_name %current_process_system_name; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + current_print_compatible_printers = config.option("compatible_printers", true)->values; + BOOST_LOG_TRIVIAL(info) << boost::format("load a process config %1% from file %2%, current_print_compatible_printers size is %3% ")%config_name %file %current_print_compatible_printers.size(); + if (new_process_name.empty() && !current_process_system_name.empty()) + { + config.set("print_settings_id", config_name, true); + load_process_config = std::move(config); + } + } + else { + BOOST_LOG_TRIVIAL(error) << boost::format("found invalid config type %1% from config %2% ")%config_type %file; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } } } - else - fetch_upward_values = true; + else { + if (new_printer_name.empty() && !current_printer_system_name.empty()) { + //use the original printer name in 3mf + std::string system_printer_path = resources_dir() + "/profiles/BBL/machine_full/"+current_printer_system_name+".json"; + if (! boost::filesystem::exists(system_printer_path)) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_printer_path; + //use original one + } + else { + DynamicPrintConfig config; + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(system_printer_path, config, config_type, config_name, filament_id, config_from); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); + flush_and_exit(ret); + } - if (new_process_name.empty() && !current_process_system_name.empty()) { - //use the original printer name in 3mf - std::string system_process_path = resources_dir() + "/profiles/BBL/process_full/"+current_process_system_name+".json"; - if (! boost::filesystem::exists(system_process_path)) { - boost::nowide::cerr << __FUNCTION__<< ": can not find system preset file: " << system_process_path << std::endl; - //use original one + upward_compatible_printers = config.option("upward_compatible_machine", true)->values; + config.set("printer_settings_id", config_name, true); + + //get printer_model_id + std::string printer_model = config.option("printer_model", true)->value; + if (!printer_model.empty()) { + std::string printer_model_path = resources_dir() + "/profiles/BBL/machine_full/"+printer_model+".json"; + if (boost::filesystem::exists(printer_model_path)) + { + std::map key_values; + + load_key_values_from_json(printer_model_path, key_values); + if (key_values.find("model_id") != key_values.end()) { + printer_model_id = key_values["model_id"]; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(":%1%, load printer_model_id %2% from current printer model %3%")%__LINE__ %printer_model_id %printer_model; + } + } + } + + load_machine_config = std::move(config); + } } - else { - DynamicPrintConfig config; - std::string config_type, config_name, filament_id; - int ret = load_system_config_file(system_process_path, config, config_type, config_name, filament_id); - if (ret) - flush_and_exit(ret); - current_print_compatible_printers = config.option("compatible_printers", true)->values; - config.set("print_settings_id", config_name, true); - load_process_config = std::move(config); + else + fetch_upward_values = true; + + if (new_process_name.empty() && !current_process_system_name.empty()) { + //use the original printer name in 3mf + std::string system_process_path = resources_dir() + "/profiles/BBL/process_full/"+current_process_system_name+".json"; + if (! boost::filesystem::exists(system_process_path)) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_process_path; + //use original one + } + else { + DynamicPrintConfig config; + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(system_process_path, config, config_type, config_name, filament_id, config_from); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); + flush_and_exit(ret); + } + current_print_compatible_printers = config.option("compatible_printers", true)->values; + config.set("print_settings_id", config_name, true); + load_process_config = std::move(config); + } } + else + fetch_compatible_values = true; } - else - fetch_compatible_values = true; - if (load_filaments_config.empty() && !current_filaments_system_name.empty()) { - for (int index = 0; index < current_filaments_system_name.size(); index++) { - std::string system_filament_path = resources_dir() + "/profiles/BBL/filament_full/"+current_filaments_system_name[index]+".json"; - current_index++; - if (! boost::filesystem::exists(system_filament_path)) { - boost::nowide::cerr << __FUNCTION__<< ": can not find system preset file: " << system_filament_path << std::endl; - continue; + //filament processes + if (load_filament_count == 0) + { + if (uptodate_filaments.size() > 0) + { + if (uptodate_filaments.size() != filament_count) + { + BOOST_LOG_TRIVIAL(error) << boost::format("uptodate_filaments size %1% not equal to filament_count %2% ")%uptodate_filaments.size() %filament_count; + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + for (unsigned int index = 0; index < filament_count; index ++) + { + std::string file = uptodate_filaments[index]; + DynamicPrintConfig config; + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(file, config, config_type, config_name, filament_id, config_from); + if (ret) { + BOOST_LOG_TRIVIAL(error) << boost::format("load uptodate_filaments %1% fail, index %2%!")%file %index; + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); + flush_and_exit(ret); + } + + if (config_type != "filament") { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % file; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + + if (config_name != current_filaments_system_name[index]) { + BOOST_LOG_TRIVIAL(error) << boost::format("wrong filament config file %1% loaded, current filament config name %2%, index %3%")%config_name %current_filaments_system_name[index] %index; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + + load_filaments_id.push_back(filament_id); + load_filaments_name.push_back(config_name); + load_filaments_config.push_back(std::move(config)); + load_filaments_index.push_back(index+1); + load_filaments_inherit.push_back(config_name); + BOOST_LOG_TRIVIAL(info) << boost::format("load a filament config %1% from file %2%, using uptodate_filaments index %3%")%config_name %file %index; } - DynamicPrintConfig config; - std::string config_type, config_name, filament_id; - int ret = load_system_config_file(system_filament_path, config, config_type, config_name, filament_id); - if (ret) - flush_and_exit(ret); + } + else + { + current_index = 0; + for (int index = 0; index < current_filaments_system_name.size(); index++) + { + std::string system_filament_path = resources_dir() + "/profiles/BBL/filament_full/"+current_filaments_system_name[index]+".json"; + current_index++; + if (! boost::filesystem::exists(system_filament_path)) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_filament_path; + continue; + } + DynamicPrintConfig config; + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(system_filament_path, config, config_type, config_name, filament_id, config_from); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); + flush_and_exit(ret); + } - load_filaments_id.push_back(filament_id); - load_filaments_name.push_back(config_name); - load_filaments_config.push_back(std::move(config)); - load_filaments_index.push_back(current_index); + if (config_type != "filament") { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-filaments") % config_type % system_filament_path; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + + load_filaments_id.push_back(filament_id); + load_filaments_name.push_back(config_name); + load_filaments_config.push_back(std::move(config)); + load_filaments_index.push_back(current_index); + load_filaments_inherit.push_back(config_name); + BOOST_LOG_TRIVIAL(info) << boost::format("LINE %4%: load a filament config %1% from file %2%, index %3%")%config_name %system_filament_path %index %__LINE__; + } } } } @@ -916,15 +1973,17 @@ int CLI::run(int argc, char **argv) //use the original printer name in 3mf std::string system_printer_path = resources_dir() + "/profiles/BBL/machine_full/"+current_printer_system_name+".json"; if (! boost::filesystem::exists(system_printer_path)) { - boost::nowide::cerr << __FUNCTION__<< ": can not find system preset file: " << system_printer_path << std::endl; + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_printer_path; //skip } else { DynamicPrintConfig config; - std::string config_type, config_name, filament_id; - int ret = load_system_config_file(system_printer_path, config, config_type, config_name, filament_id); - if (ret) + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(system_printer_path, config, config_type, config_name, filament_id, config_from); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); flush_and_exit(ret); + } upward_compatible_printers = config.option("upward_compatible_machine", true)->values; } } @@ -936,81 +1995,116 @@ int CLI::run(int argc, char **argv) //use the original printer name in 3mf std::string system_process_path = resources_dir() + "/profiles/BBL/process_full/"+current_process_system_name+".json"; if (! boost::filesystem::exists(system_process_path)) { - boost::nowide::cerr << __FUNCTION__<< ": can not find system preset file: " << system_process_path << std::endl; + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(":%1%, can not find system preset file: %2% ")%__LINE__ %system_process_path; //use original one } else { DynamicPrintConfig config; - std::string config_type, config_name, filament_id; - int ret = load_system_config_file(system_process_path, config, config_type, config_name, filament_id); - if (ret) + std::string config_type, config_name, filament_id, config_from; + int ret = load_config_file(system_process_path, config, config_type, config_name, filament_id, config_from); + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); flush_and_exit(ret); + } current_print_compatible_printers = config.option("compatible_printers", true)->values; } } } //upwards check - bool process_compatible = true, machine_upwards = false; + bool process_compatible = false, machine_upwards = false; + BOOST_LOG_TRIVIAL(info) << boost::format("current printer %1%, new printer %2%, current process %3%, new process %4%")%current_printer_name %new_printer_name %current_process_name %new_process_name; + BOOST_LOG_TRIVIAL(info) << boost::format("current printer inherits %1%, new printer inherits %2%, current process inherits %3%, new process inherits %4%") + %current_printer_system_name %new_printer_system_name %current_process_system_name %new_process_system_name; + for (int index = 0; index < current_print_compatible_printers.size(); index++) { + BOOST_LOG_TRIVIAL(info) << boost::format("index %1%, current print compatible printer %2%")%index %current_print_compatible_printers[index]; + } + for (int index = 0; index < new_print_compatible_printers.size(); index++) { + BOOST_LOG_TRIVIAL(info) << boost::format("index %1%, new print compatible printer %2%")%index %new_print_compatible_printers[index]; + } + for (int index = 0; index < upward_compatible_printers.size(); index++) { + BOOST_LOG_TRIVIAL(info) << boost::format("index %1%, upward_compatible_printers %2%")%index %upward_compatible_printers[index]; + } if (!new_printer_name.empty()) { - process_compatible = false; if (!new_process_name.empty()) { for (int index = 0; index < new_print_compatible_printers.size(); index++) { - if (new_print_compatible_printers[index] == new_printer_name) { + if (new_print_compatible_printers[index] == new_printer_system_name) { process_compatible = true; break; } } - BOOST_LOG_TRIVIAL(info) << boost::format("new printer %1%, new process %2%, compatible %3%")%new_printer_name %new_process_name %process_compatible; + BOOST_LOG_TRIVIAL(info) << boost::format("new printer %1%, inherited from %2%, new process %3%, inherited from %4% ,compatible %5%") + %new_printer_name %new_printer_system_name %new_process_name %new_process_system_name %process_compatible; } else { for (int index = 0; index < current_print_compatible_printers.size(); index++) { - if (current_print_compatible_printers[index] == new_printer_name) { + if (current_print_compatible_printers[index] == new_printer_system_name) { process_compatible = true; break; } } - BOOST_LOG_TRIVIAL(info) << boost::format("new printer %1%, old process %2%, compatible %3%")%new_printer_name %current_process_name %process_compatible; + BOOST_LOG_TRIVIAL(info) << boost::format("new printer %1%, inherited from %2%, old process %3%, inherited from %4% ,compatible %5%") + %new_printer_name %new_printer_system_name %current_process_name %current_process_system_name %process_compatible; } } else if (!new_process_name.empty()) { - process_compatible = false; for (int index = 0; index < new_print_compatible_printers.size(); index++) { - if (new_print_compatible_printers[index] == current_printer_name) { + if (new_print_compatible_printers[index] == current_printer_system_name) { + process_compatible = true; + break; + } + } + BOOST_LOG_TRIVIAL(info) << boost::format("old printer %1%, inherited from %2%, new process %3%, inherited from %4% ,compatible %5%") + %current_printer_name %current_printer_system_name %new_process_name %new_process_system_name %process_compatible; + } + else { + //check the compatible of old printer&&process + for (int index = 0; index < current_print_compatible_printers.size(); index++) { + if (current_print_compatible_printers[index] == current_printer_system_name) { process_compatible = true; break; } } - BOOST_LOG_TRIVIAL(info) << boost::format("old printer %1%, new process %2%, compatible %3%")%current_printer_name %new_process_name %process_compatible; + if (!process_compatible && current_print_compatible_printers.empty()) + { + BOOST_LOG_TRIVIAL(info) << boost::format("old 3mf, no compatible printers, set to compatible"); + process_compatible = true; + } + BOOST_LOG_TRIVIAL(info) << boost::format("old printer %1%, inherited from %2%, old process %3%, inherited from %4% ,compatible %5%") + %current_printer_name %current_printer_system_name %current_process_name %current_process_system_name %process_compatible; } if (!process_compatible && !new_printer_name.empty() && !current_printer_name.empty() && (new_printer_name != current_printer_name)) { if (upward_compatible_printers.size() > 0) { for (int index = 0; index < upward_compatible_printers.size(); index++) { - if (upward_compatible_printers[index] == new_printer_name) { + if (upward_compatible_printers[index] == new_printer_system_name) { process_compatible = true; machine_upwards = true; break; } } if (!process_compatible) { - boost::nowide::cout <<__FUNCTION__ << boost::format(": current 3mf file not support the new printer %1%")%new_printer_name; + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(" %1% : current 3mf file not support the new printer %2%, new_printer_system_name %3%")%__LINE__%new_printer_name %new_printer_system_name; + record_exit_reson(outfile_dir, CLI_3MF_NEW_MACHINE_NOT_SUPPORTED, 0, cli_errors[CLI_3MF_NEW_MACHINE_NOT_SUPPORTED], sliced_info); flush_and_exit(CLI_3MF_NEW_MACHINE_NOT_SUPPORTED); } } else { - boost::nowide::cout <<__FUNCTION__ << boost::format(": current 3mf file not support upward_compatible_printers, can not change machine preset."); + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(" %1%: current 3mf file not support upward_compatible_printers, can not change machine preset.")%__LINE__; + record_exit_reson(outfile_dir, CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE, 0, cli_errors[CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE], sliced_info); flush_and_exit(CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE); } } if (!process_compatible) { - boost::nowide::cout <<__FUNCTION__ << boost::format(": process not compatible with printer."); + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__ << boost::format(" %1%: process not compatible with printer.")%__LINE__; + record_exit_reson(outfile_dir, CLI_PROCESS_NOT_COMPATIBLE, 0, cli_errors[CLI_PROCESS_NOT_COMPATIBLE], sliced_info); flush_and_exit(CLI_PROCESS_NOT_COMPATIBLE); } //create project embedded preset if needed Preset *new_preset = NULL; if (is_bbl_3mf && machine_upwards) { + //we need to update the compatible printer and create a new process here, or if we load the 3mf in studio, the process preset can not be loaded as not compatible Preset *current_preset = NULL; size_t project_presets_count = project_presets.size(); for (int index = 0; index < project_presets_count; index++) @@ -1026,13 +2120,13 @@ int CLI::run(int argc, char **argv) std::vector& compatible_printers = new_preset->config.option("compatible_printers", true)->values; bool need_insert = true; for (int index = 0; index < compatible_printers.size(); index++) { - if (compatible_printers[index] == new_printer_name) { + if (compatible_printers[index] == new_printer_system_name) { need_insert = false; break; } } if (need_insert) - compatible_printers.push_back(new_printer_name); + compatible_printers.push_back(new_printer_system_name); } else { //store a project-embedded preset @@ -1040,7 +2134,7 @@ int CLI::run(int argc, char **argv) new_preset->config.apply_only(m_print_config, process_keys); std::vector& compatible_printers = new_preset->config.option("compatible_printers", true)->values; compatible_printers = current_print_compatible_printers; - compatible_printers.push_back(new_printer_name); + compatible_printers.push_back(new_printer_system_name); if (current_process_system_name != current_process_name) { std::string& inherits = new_preset->config.option("inherits", true)->value; inherits = current_process_system_name; @@ -1056,12 +2150,24 @@ int CLI::run(int argc, char **argv) } //update seperate configs into full config - auto update_full_config = [](DynamicPrintConfig& full_config, const DynamicPrintConfig& config, std::set& diff_key_sets) { - for (const t_config_option_key &opt_key : config.keys()) { - if (!diff_key_sets.empty() && (diff_key_sets.find(opt_key) != diff_key_sets.end())) { - //uptodate, diff keys, continue - BOOST_LOG_TRIVIAL(info) << boost::format("keep key %1%")%opt_key; - continue; + auto update_full_config = [](DynamicPrintConfig& full_config, const DynamicPrintConfig& config, std::set& diff_key_sets, bool update_all = false, bool skip_gcodes = false) { + const t_config_option_keys& config_keys = config.keys(); + BOOST_LOG_TRIVIAL(info) << boost::format("update_full_config: config keys count %1%")%config_keys.size(); + for (const t_config_option_key &opt_key : config_keys) { + if (!update_all && !diff_key_sets.empty()) { + std::set::iterator iter = diff_key_sets.find(opt_key); + if ( iter != diff_key_sets.end()) { + if (skip_gcodes && (gcodes_key_set.find(opt_key) != gcodes_key_set.end())) + { + diff_key_sets.erase(iter); + BOOST_LOG_TRIVIAL(info) << boost::format("%1%, gcodes %2% modified, reset to default.")%__LINE__ %opt_key; + } + else { + //uptodate, diff keys, continue + BOOST_LOG_TRIVIAL(info) << boost::format("%1%, keep key %2%")%__LINE__ %opt_key; + continue; + } + } } const ConfigOption *source_opt = config.option(opt_key); if (source_opt == nullptr) { @@ -1069,7 +2175,8 @@ int CLI::run(int argc, char **argv) boost::nowide::cerr << __FUNCTION__<<": can not found option " < different_keys_set(different_keys.begin(), different_keys.end()); - BOOST_LOG_TRIVIAL(info) << boost::format("update printer config to newest, different size %1%")%different_keys_set.size(); - int ret = update_full_config(m_print_config, load_machine_config, different_keys_set); - if (ret) + BOOST_LOG_TRIVIAL(info) << boost::format("update printer config to newest, different size %1%, different_settings: %2%")%different_keys_set.size() %different_settings[filament_count+1]; + + int ret; + + load_default_gcodes_to_config(load_machine_config, Preset::TYPE_PRINTER); + if (new_printer_name.empty()) { + int diff_keys_size = different_keys_set.size(); + ret = update_full_config(m_print_config, load_machine_config, different_keys_set, false, skip_modified_gcodes); + if (diff_keys_size != different_keys_set.size()) { + //changed + BOOST_LOG_TRIVIAL(info) << boost::format("new different key size %1%")%different_keys_set.size(); + different_keys.clear(); + + for (std::set::iterator iter=different_keys_set.begin(); iter !=different_keys_set.end(); ++iter) + different_keys.emplace_back(*iter); + different_settings[filament_count+1] = Slic3r::escape_strings_cstyle(different_keys); + } + BOOST_LOG_TRIVIAL(info) << boost::format("no new printer, only update the different key, new different_settings: %1%")%different_settings[filament_count+1]; + } + else { + ret = update_full_config(m_print_config, load_machine_config, different_keys_set, true); + BOOST_LOG_TRIVIAL(info) << boost::format("load a new printer, update all the keys, different_settings: %1%")%different_settings[filament_count+1]; + } + + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); flush_and_exit(ret); + } } //set the process settings into print config @@ -1137,20 +2272,48 @@ int CLI::run(int argc, char **argv) print_compatible_printers = std::move(current_print_compatible_printers); } else { + //todo: support system process preset different_settings[0] = ""; - inherits_group[0] = ""; + if (new_process_config_is_system) + inherits_group[0] = ""; + else + inherits_group[0] = new_process_system_name; print_compatible_printers = std::move(new_print_compatible_printers); } std::set different_keys_set(different_keys.begin(), different_keys.end()); - BOOST_LOG_TRIVIAL(info) << boost::format("update process config to newest, different size %1%")%different_keys_set.size(); - int ret = update_full_config(m_print_config, load_machine_config, different_keys_set); - if (ret) + BOOST_LOG_TRIVIAL(info) << boost::format("update process config to newest, different size %1%, different_settings: %2%")%different_keys_set.size() %different_settings[0]; + + int ret; + + load_default_gcodes_to_config(load_machine_config, Preset::TYPE_PRINT); + if (new_process_name.empty()) { + int diff_keys_size = different_keys_set.size(); + ret = update_full_config(m_print_config, load_process_config, different_keys_set, false, skip_modified_gcodes); + if (diff_keys_size != different_keys_set.size()) { + //changed + BOOST_LOG_TRIVIAL(info) << boost::format("new different key size %1%")%different_keys_set.size(); + different_keys.clear(); + + for (std::set::iterator iter=different_keys_set.begin(); iter !=different_keys_set.end(); ++iter) + different_keys.emplace_back(*iter); + different_settings[0] = Slic3r::escape_strings_cstyle(different_keys); + } + BOOST_LOG_TRIVIAL(info) << boost::format("no new process, only update the different key, new different_settings: %1%")%different_settings[0]; + } + else { + ret = update_full_config(m_print_config, load_process_config, different_keys_set, true); + BOOST_LOG_TRIVIAL(info) << boost::format("load a new process, update all the keys, different_settings: %1%")%different_settings[0]; + } + + if (ret) { + record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info); flush_and_exit(ret); + } } if (machine_upwards) { - print_compatible_printers.push_back(new_printer_name); + print_compatible_printers.push_back(new_printer_system_name); std::string old_setting = different_settings[0]; if (old_setting.empty()) @@ -1178,6 +2341,8 @@ int CLI::run(int argc, char **argv) int filament_index = load_filaments_index[index]; std::vector different_keys; + load_default_gcodes_to_config(config, Preset::TYPE_FILAMENT); + if (load_filament_count > 0) { ConfigOptionStrings *opt_filament_settings = static_cast (m_print_config.option("filament_settings_id", true)); std::string& filament_name = load_filaments_name[index]; @@ -1194,8 +2359,9 @@ int CLI::run(int argc, char **argv) opt_filament_ids->resize(filament_count, filament_id_setting); opt_filament_ids->set_at(filament_id_setting, filament_index-1, 0); + //todo: update different settings of filaments different_settings[filament_index] = ""; - inherits_group[filament_index] = ""; + inherits_group[filament_index] = load_filaments_inherit[index]; } else { std::string diff_settings; @@ -1209,12 +2375,25 @@ int CLI::run(int argc, char **argv) //parse the filament value to index th //loop through options and apply them std::set different_keys_set(different_keys.begin(), different_keys.end()); - BOOST_LOG_TRIVIAL(info) << boost::format("update filament %1%'s config to newest, different size %2%")%filament_index%different_keys_set.size(); + int diff_keys_size = different_keys_set.size(); + BOOST_LOG_TRIVIAL(info) << boost::format("update filament %1%'s config to newest, different size %2%, name %3%, different_settings %4%") + %filament_index%different_keys_set.size()%load_filaments_name[index] % different_settings[filament_index]; for (const t_config_option_key &opt_key : config.keys()) { - if (!different_keys_set.empty() && (different_keys_set.find(opt_key) != different_keys_set.end())) { - //uptodate, diff keys, continue - BOOST_LOG_TRIVIAL(info) << boost::format("keep key %1%")%opt_key; - continue; + if ((load_filament_count == 0) && !different_keys_set.empty()) + { + std::set::iterator iter = different_keys_set.find(opt_key); + if ( iter != different_keys_set.end()) { + if (skip_modified_gcodes && (gcodes_key_set.find(opt_key) != gcodes_key_set.end())) + { + different_keys_set.erase(iter); + BOOST_LOG_TRIVIAL(info) << boost::format("%1%, filament %2%'s gcodes %3% modified, reset to default.")%__LINE__ %filament_index %opt_key; + } + else { + //uptodate, diff keys, continue + BOOST_LOG_TRIVIAL(info) << boost::format("%1%, keep key %2%")%__LINE__ %opt_key; + continue; + } + } } // Create a new option with default value for the key. // If the key is not in the parameter definition, or this ConfigBase is a static type and it does not support the parameter, @@ -1224,6 +2403,7 @@ int CLI::run(int argc, char **argv) if (source_opt == nullptr) { // The key was not found in the source config, therefore it will not be initialized! BOOST_LOG_TRIVIAL(error) << boost::format("can not find %1% from filament %2%: %3%")%opt_key%filament_index%load_filaments_name[index]; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); flush_and_exit(CLI_CONFIG_FILE_ERROR); } if (source_opt->is_scalar()) { @@ -1256,6 +2436,7 @@ int CLI::run(int argc, char **argv) // opt_key does not exist in this ConfigBase and it cannot be created, because it is not defined by this->def(). // This is only possible if other is of DynamicConfig type. BOOST_LOG_TRIVIAL(error) << boost::format("can not create option %1% to config, from filament %2%: %3%")%opt_key%filament_index%load_filaments_name[index]; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); flush_and_exit(CLI_CONFIG_FILE_ERROR); } ConfigOptionVectorBase* opt_vec_dst = static_cast(opt); @@ -1263,33 +2444,191 @@ int CLI::run(int argc, char **argv) opt_vec_dst->set_at(opt_vec_src, filament_index-1, 0); } } + + if (diff_keys_size != different_keys_set.size()) { + //changed + different_keys.clear(); + + for (std::set::iterator iter=different_keys_set.begin(); iter !=different_keys_set.end(); ++iter) + different_keys.emplace_back(*iter); + different_settings[filament_index] = Slic3r::escape_strings_cstyle(different_keys); + BOOST_LOG_TRIVIAL(info) << boost::format("filament %1% new different key size %2%, different_settings %3%")%filament_index %different_keys_set.size() %different_settings[filament_index]; + } } } - //BBS: set default to ptFFF - if (printer_technology == ptUnknown) - printer_technology = ptFFF; - - //BBS: merge these models into one - BOOST_LOG_TRIVIAL(info) << "total " << m_models.size() << " models, "< 1) + //compute the flush volume + ConfigOptionStrings *selected_filament_colors_option = m_extra_config.option("filament_colour"); + ConfigOptionStrings *project_filament_colors_option = m_print_config.option("filament_colour"); + if ((!project_filament_colors_option || (project_filament_colors_option->values.size() == 0)) && selected_filament_colors_option) { - BOOST_LOG_TRIVIAL(info) << "merge all the models into one\n"; - Model m; - m.set_backup_path(m_models[0].get_backup_path()); - for (auto& model : m_models) - for (ModelObject* o : model.objects) + BOOST_LOG_TRIVIAL(info) << boost::format("initial project_filament_colors is null, create it due to filament_colour set in cli"); + project_filament_colors_option = m_print_config.option("filament_colour", true); + std::vector& project_filament_colors = project_filament_colors_option->values; + project_filament_colors.resize(filament_count, "#FFFFFF"); + } + if (project_filament_colors_option && (selected_filament_colors_option || !m_print_config.option("flush_volumes_matrix"))) + { + std::vector selected_filament_colors; + if (selected_filament_colors_option) { + selected_filament_colors = selected_filament_colors_option->values; + //erase here + m_extra_config.erase("filament_colour"); + } + + std::vector &project_filament_colors = project_filament_colors_option->values; + size_t project_filament_count = project_filament_colors.size(); + BOOST_LOG_TRIVIAL(info) << boost::format("select filament color from cli, size %1%")%selected_filament_colors.size(); + BOOST_LOG_TRIVIAL(info) << boost::format("project filament colors size %1%")%project_filament_colors.size(); + if (project_filament_count > 0) + { + for ( size_t index = 0; index < project_filament_count; index++ ) + { + BOOST_LOG_TRIVIAL(info) << boost::format("project filament %1% original color %2%")%index %project_filament_colors[index]; + if (selected_filament_colors.size() > index) + { + if (!selected_filament_colors[index].empty()) + { + BOOST_LOG_TRIVIAL(info) << boost::format("changed to new color %1%")%selected_filament_colors[index]; + unsigned char ori_rgb_color[4] = {}, new_rgb_color[4] = {}; + Slic3r::GUI::BitmapCache::parse_color4(project_filament_colors[index], ori_rgb_color); + Slic3r::GUI::BitmapCache::parse_color4(selected_filament_colors[index], new_rgb_color); + if ((ori_rgb_color[0] != new_rgb_color[0]) || (ori_rgb_color[1] != new_rgb_color[1]) || (ori_rgb_color[2] != new_rgb_color[2]) || (ori_rgb_color[3] != new_rgb_color[3])) + { + BOOST_LOG_TRIVIAL(info) << boost::format("found color changes, need to regenerate thumbnail"); + filament_color_changed = true; + } + project_filament_colors[index] = selected_filament_colors[index]; + } + } + } + + //computing + ConfigOptionBools* filament_is_support = m_print_config.option("filament_is_support", true); + std::vector& flush_vol_matrix = m_print_config.option("flush_volumes_matrix", true)->values; + //std::vector& flush_vol_vector = m_print_config.option("flush_volumes_vector", true)->values; + flush_vol_matrix.resize(project_filament_count*project_filament_count, 0.f); + //flush_vol_vector.resize(project_filament_count); + //set multiplier to 1? + m_print_config.option("flush_multiplier", true)->set(new ConfigOptionFloat(1.f)); + ConfigOption* extra_flush_volume_opt = m_print_config.option("nozzle_volume"); + int extra_flush_volume = extra_flush_volume_opt ? (int)extra_flush_volume_opt->getFloat() : 0; + + if (filament_is_support->size() != project_filament_count) + { + BOOST_LOG_TRIVIAL(error) << boost::format("filament_is_support's count %1% not equal to filament_colour's size %2%")%filament_is_support->size() %project_filament_count; + record_exit_reson(outfile_dir, CLI_CONFIG_FILE_ERROR, 0, cli_errors[CLI_CONFIG_FILE_ERROR], sliced_info); + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + + BOOST_LOG_TRIVIAL(info) << boost::format("extra_flush_volume: %1%")%extra_flush_volume; + BOOST_LOG_TRIVIAL(info) << boost::format("filament_is_support: %1%")%filament_is_support->serialize(); + BOOST_LOG_TRIVIAL(info) << boost::format("flush_volumes_matrix before computing: %1%")%m_print_config.option("flush_volumes_matrix")->serialize(); + for (int from_idx = 0; from_idx < project_filament_count; from_idx++) { + const std::string& from_color = project_filament_colors[from_idx]; + unsigned char from_rgb[4] = {}; + Slic3r::GUI::BitmapCache::parse_color4(from_color, from_rgb); + bool is_from_support = filament_is_support->get_at(from_idx); + for (int to_idx = 0; to_idx < project_filament_count; to_idx++) { + bool is_to_support = filament_is_support->get_at(to_idx); + if (from_idx == to_idx) { + flush_vol_matrix[project_filament_count*from_idx + to_idx] = 0.f; + } + else { + int flushing_volume = 0; + if (is_to_support) { + flushing_volume = Slic3r::g_flush_volume_to_support; + } + else { + const std::string& to_color = project_filament_colors[to_idx]; + unsigned char to_rgb[4] = {}; + Slic3r::GUI::BitmapCache::parse_color4(to_color, to_rgb); + //BOOST_LOG_TRIVIAL(info) << boost::format("src_idx %1%, src color %2%, dst idex %3%, dst color %4%")%from_idx %from_color %to_idx %to_color; + //BOOST_LOG_TRIVIAL(info) << boost::format("src_rgba {%1%,%2%,%3%,%4%} dst_rgba {%5%,%6%,%7%,%8%}")%(unsigned int)(from_rgb[0]) %(unsigned int)(from_rgb[1]) %(unsigned int)(from_rgb[2]) %(unsigned int)(from_rgb[3]) + // %(unsigned int)(to_rgb[0]) %(unsigned int)(to_rgb[1]) %(unsigned int)(to_rgb[2]) %(unsigned int)(to_rgb[3]); + + Slic3r::FlushVolCalculator calculator(extra_flush_volume, Slic3r::g_max_flush_volume); + + flushing_volume = calculator.calc_flush_vol(from_rgb[3], from_rgb[0], from_rgb[1], from_rgb[2], to_rgb[3], to_rgb[0], to_rgb[1], to_rgb[2]); + if (is_from_support) { + flushing_volume = std::max(Slic3r::g_min_flush_volume_from_support, flushing_volume); + } + } + + flush_vol_matrix[project_filament_count * from_idx + to_idx] = flushing_volume; + //flushing_volume = int(flushing_volume * get_flush_multiplier()); + } + } + } + BOOST_LOG_TRIVIAL(info) << boost::format("flush_volumes_matrix after computed: %1%")%m_print_config.option("flush_volumes_matrix")->serialize(); + } + else + { + BOOST_LOG_TRIVIAL(warning) << boost::format("filament colors count is 0 in projects"); + } + } + else + { + BOOST_LOG_TRIVIAL(warning) << boost::format("no filament colors found in projects"); + } + + //BBS: set default to ptFFF + if (printer_technology == ptUnknown) + printer_technology = ptFFF; + + //BBS: merge these models into one + BOOST_LOG_TRIVIAL(info) << "total " << m_models.size() << " models, "< 1) + { + BOOST_LOG_TRIVIAL(info) << "merge all the models into one\n"; + Model m; + m.set_backup_path(m_models[0].get_backup_path()); + for (auto& model : m_models) + for (ModelObject* o : model.objects) { ModelObject* new_object = m.add_object(*o); //BOOST_LOG_TRIVIAL(info) << "object "<name <<", id :" << o->id().id << "\n"; - orients_requirement.emplace(new_object->id().id, orients_requirement[o->id().id]); - orients_requirement.erase(o->id().id); + //orients_requirement.emplace(new_object->id().id, orients_requirement[o->id().id]); + //orients_requirement.erase(o->id().id); } m.add_default_instances(); m_models.clear(); m_models.emplace_back(std::move(m)); } + //load custom gcodes into model if needed + if ((custom_gcodes_map.size() > 0)&&(m_models.size() > 0)) + { + m_models[0].plates_custom_gcodes = custom_gcodes_map; + /*m_models[0].plates_custom_gcodes.clear(); + + for (auto& custom_gcode: custom_gcodes_map) + { + BOOST_LOG_TRIVIAL(info) << boost::format("insert custom_gocde %1% into plate %2%")%plate_id; + m_models[0].plates_custom_gcodes.emplace(custom_gcode.first, custom_gcode.second); + }*/ + } + + if (skip_modified_gcodes) + { + std::map::iterator gcodes_iter; + for (gcodes_iter = m_models[0].plates_custom_gcodes.begin(); gcodes_iter != m_models[0].plates_custom_gcodes.end(); gcodes_iter++) + { + CustomGCode::Info &gcode_info = gcodes_iter->second; + std::vector::iterator item_iter = gcode_info.gcodes.begin(); + + while ( item_iter != gcode_info.gcodes.end() ) + { + if (item_iter->type == CustomGCode::Custom) { + BOOST_LOG_TRIVIAL(warning) << boost::format("skip_modified_gcodes: remove custom gcodes %1% in plate %2%") %item_iter->extra %gcodes_iter->first; + item_iter = gcode_info.gcodes.erase(item_iter); + } + else + item_iter++; + } + } + } + // Apply command line options to a more specific DynamicPrintConfig which provides normalize() // (command line options override --load files) m_print_config.apply(m_extra_config, true); @@ -1308,6 +2647,7 @@ int CLI::run(int argc, char **argv) m_print_config.apply(fff_print_config, true); } else { boost::nowide::cerr << "invalid printer_technology " << std::endl; + record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH], sliced_info); flush_and_exit(CLI_INVALID_PRINTER_TECH); /*assert(printer_technology == ptSLA); sla_print_config.filename_format.value = "[input_filename_base].sl1"; @@ -1327,54 +2667,128 @@ int CLI::run(int argc, char **argv) boost::nowide::cerr << "Param values in 3mf/config error: "<< std::endl; for (std::map::iterator it=validity.begin(); it!=validity.end(); ++it) boost::nowide::cerr << it->first <<": "<< it->second << std::endl; + record_exit_reson(outfile_dir, CLI_INVALID_VALUES_IN_3MF, 0, cli_errors[CLI_INVALID_VALUES_IN_3MF], sliced_info); flush_and_exit(CLI_INVALID_VALUES_IN_3MF); } //BBS: partplate list Slic3r::GUI::PartPlateList partplate_list(NULL, m_models.data(), printer_technology); //use Pointfs insteadof Points - Pointfs bedfs = m_print_config.opt("printable_area")->values; - Pointfs excluse_areas = m_print_config.opt("bed_exclude_area")->values; + Pointfs current_printable_area = m_print_config.opt("printable_area")->values; + Pointfs current_exclude_area = m_print_config.opt("bed_exclude_area")->values; //update part plate's size double print_height = m_print_config.opt_float("printable_height"); double height_to_lid = m_print_config.opt_float("extruder_clearance_height_to_lid"); double height_to_rod = m_print_config.opt_float("extruder_clearance_height_to_rod"); - double plate_stride; + double cleareance_radius = m_print_config.opt_float("extruder_clearance_max_radius"); + //double plate_stride; std::string bed_texture; + + current_printable_width = current_printable_area[2].x() - current_printable_area[0].x(); + current_printable_depth = current_printable_area[2].y() - current_printable_area[0].y(); + current_printable_height = print_height; + if (old_printable_width == 0) + old_printable_width = current_printable_width; + if (old_printable_depth == 0) + old_printable_depth = current_printable_depth; + if (old_printable_height == 0) + old_printable_height = current_printable_height; + if ((old_printable_width > 0)&&(old_printable_depth > 0)&&(old_printable_height > 0)) + { + //check the printable size logic + if ((old_printable_width > current_printable_width) || (old_printable_depth > current_printable_depth) || (old_printable_height > current_printable_height)) + { + BOOST_LOG_TRIVIAL(error) << boost::format("old printable size {%1%, %2%, %3%} is larger than new printable size {%4%, %5%, %6%}, can not print") + %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; + record_exit_reson(outfile_dir, CLI_PRINTABLE_SIZE_REDUCED, 0, cli_errors[CLI_PRINTABLE_SIZE_REDUCED], sliced_info); + flush_and_exit(CLI_PRINTABLE_SIZE_REDUCED); + } + else if ((old_printable_width < current_printable_width) || (old_printable_depth < current_printable_depth)) + { + BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%} is smaller than new printable size {%4%, %5%, %6%}, need to center the model") + %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; + shrink_to_new_bed = true; + } + else { + BOOST_LOG_TRIVIAL(info) << boost::format("old printable size {%1%, %2%, %3%}, new printable size {%4%, %5%, %6%}") + %old_printable_width %old_printable_depth %old_printable_height %current_printable_width %current_printable_depth %current_printable_height; + } + } + if (m_models.size() > 0) { + BOOST_LOG_TRIVIAL(info) << boost::format("translate_old %1%, shrink_to_new_bed %2%, old bed size {%3%, %4%, %5%}")%translate_old%shrink_to_new_bed %old_printable_width %old_printable_depth %old_printable_height; if (translate_old) { - current_width = bedfs[2].x() - bedfs[0].x(); - current_depth = bedfs[2].y() - bedfs[0].y(); - current_height = print_height; - BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch to old bed size,{%1%, %2%, %3%}")%(current_width + bed3d_ax3s_default_tip_radius)%(current_depth+bed3d_ax3s_default_tip_radius) %current_height; - partplate_list.reset_size(current_width + bed3d_ax3s_default_tip_radius, current_depth + bed3d_ax3s_default_tip_radius, current_height, false); + BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch to older bed size,{%1%, %2%, %3%}")%(old_printable_width + bed3d_ax3s_default_tip_radius)%(old_printable_depth+bed3d_ax3s_default_tip_radius) %old_printable_height; + partplate_list.reset_size(old_printable_width + bed3d_ax3s_default_tip_radius, old_printable_depth + bed3d_ax3s_default_tip_radius, old_printable_height, false); } else { - partplate_list.reset_size(bedfs[2].x() - bedfs[0].x(), bedfs[2].y() - bedfs[0].y(), print_height, false); + partplate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, false); } - partplate_list.set_shapes(bedfs, excluse_areas, bed_texture, height_to_lid, height_to_rod); - plate_stride = partplate_list.plate_stride_x(); - BOOST_LOG_TRIVIAL(info) << "bed size, x="< 0) - { - partplate_list.load_from_3mf_structure(plate_data_src); + + auto translate_models = [translate_old, shrink_to_new_bed, old_printable_width, old_printable_depth, old_printable_height, current_printable_width, current_printable_depth, current_printable_height] (Slic3r::GUI::PartPlateList& plate_list, DynamicPrintConfig& print_config) { //BBS: translate old 3mf to correct positions if (translate_old) { //translate the objects - int plate_count = partplate_list.get_plate_count(); + int plate_count = plate_list.get_plate_count(); for (int index = 1; index < plate_count; index ++) { - Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(index); + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index); Vec3d cur_origin = cur_plate->get_origin(); - Vec3d new_origin = partplate_list.compute_origin_using_new_size(index, current_width, current_depth); + Vec3d new_origin = plate_list.compute_origin_using_new_size(index, old_printable_width, old_printable_depth); cur_plate->translate_all_instance(new_origin - cur_origin); } - BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch back to current bed size,{%1%, %2%, %3%}")%current_width %current_depth %current_height; - partplate_list.reset_size(current_width, current_depth, current_height, true, true); + BOOST_LOG_TRIVIAL(info) << boost::format("translate old 3mf, switch back to current bed size,{%1%, %2%, %3%}")%old_printable_width %old_printable_depth %old_printable_height; + plate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, true, true); + } + + if (shrink_to_new_bed) + { + int plate_count = plate_list.get_plate_count(); + ConfigOptionFloats *wipe_x_option = nullptr, *wipe_y_option = nullptr; + Vec3d wipe_offset; + if (print_config.has("wipe_tower_x")) { + wipe_x_option = dynamic_cast(print_config.option("wipe_tower_x")); + wipe_y_option = dynamic_cast(print_config.option("wipe_tower_y")); + } + for (int index = 0; index < plate_count; index ++) { + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)plate_list.get_plate(index); + + Vec3d cur_origin = cur_plate->get_origin(); + Vec3d new_origin = plate_list.compute_origin_using_new_size(index, current_printable_width, current_printable_depth); + Vec3d cur_center_offset { ((double)old_printable_width)/2, ((double)old_printable_depth)/2, 0}, new_center_offset { ((double)current_printable_width)/2, ((double)current_printable_depth)/2, 0}; + Vec3d cur_center = cur_origin + cur_center_offset; + Vec3d new_center = new_origin + new_center_offset; + Vec3d offset = new_center - cur_center; + + cur_plate->translate_all_instance(offset); + if (index == 0) + wipe_offset = offset; + if (wipe_x_option) { + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, plate %1%: wipe tower src: {%2%, %3%}")%(index+1) %wipe_x_option->get_at(index) %wipe_y_option->get_at(index); + ConfigOptionFloat wipe_tower_x(wipe_x_option->get_at(index) + wipe_offset(0)); + ConfigOptionFloat wipe_tower_y(wipe_y_option->get_at(index) + wipe_offset(1)); + + wipe_x_option->set_at(&wipe_tower_x, index, 0); + wipe_y_option->set_at(&wipe_tower_y, index, 0); + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, plate %1% wipe tower changes to: {%2%, %3%}")%(index+1) %wipe_x_option->get_at(index) %wipe_y_option->get_at(index); + } + + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, plate %1% translate offset: {%2%, %3%, %4%}")%(index+1) %offset[0] %offset[1] %offset[2]; + } + BOOST_LOG_TRIVIAL(info) << boost::format("shrink_to_new_bed, shrink all the models to current bed size,{%1%, %2%, %3%}")%current_printable_width %current_printable_depth %current_printable_height; + plate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true); } + }; + if (plate_data_src.size() > 0) + { + partplate_list.load_from_3mf_structure(plate_data_src); + + translate_models(partplate_list, m_print_config); } /*for (ModelObject *model_object : m_models[0].objects) @@ -1384,38 +2798,100 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << boost::format("instance %1% transform {%2%,%3%,%4%} at %5%:%6%")% model_object->name % instance_offset.x() % instance_offset.y() %instance_offset.z() % __FUNCTION__ % __LINE__<< std::endl; }*/ + auto timelapse_type_opt = m_print_config.option("timelapse_type"); + bool is_smooth_timelapse = false; + if (enable_timelapse && timelapse_type_opt && (timelapse_type_opt->getInt() == TimelapseType::tlSmooth)) + is_smooth_timelapse = true; + if (disable_wipe_tower_after_mapping) { + if (is_smooth_timelapse) + { + disable_wipe_tower_after_mapping = false; + BOOST_LOG_TRIVIAL(warning) << boost::format("%1%: disable_wipe_tower_after_mapping: set back to false due to smooth timelapse!")%__LINE__; + } + else { + ConfigOptionBool* enable_wipe_op = m_print_config.option("enable_prime_tower", true); + enable_wipe_op->value = false; + BOOST_LOG_TRIVIAL(warning) << boost::format("%1%: disable_wipe_tower_after_mapping: disable prime tower for only one filament!")%__LINE__; + + std::string diff_settings = different_settings[0]; + + if (diff_settings.empty()) + different_settings[0] = "enable_prime_tower"; + else { + std::vector different_keys; + Slic3r::unescape_strings_cstyle(diff_settings, different_keys); + bool need_insert = true; + for (int index = 0; index < different_keys.size(); index++) { + if (different_keys[index] == "enable_prime_tower") { + need_insert = false; + break; + } + } + if (need_insert) + different_settings[0] = diff_settings + ";enable_prime_tower"; + } + } + } + // Loop through transform options. bool user_center_specified = false; Points beds = get_bed_shape(m_print_config); ArrangeParams arrange_cfg; - arrange_cfg.min_obj_distance = scaled(min_object_distance(m_print_config)); BOOST_LOG_TRIVIAL(info) << "will start transforms, commands count " << m_transforms.size() << "\n"; #if defined(__linux__) || defined(__LINUX__) if (g_cli_callback_mgr.is_started()) { - PrintBase::SlicingStatus slicing_status{1, "Loading files finished"}; + PrintBase::SlicingStatus slicing_status{2, "Loading files finished"}; cli_status_callback(slicing_status); } #endif for (auto const &opt_key : m_transforms) { BOOST_LOG_TRIVIAL(info) << "process transform " << opt_key << "\n"; - if (opt_key == "merge") { - //BBS: always merge, do nothing here - /*Model m; - for (auto& model : m_models) - for (ModelObject* o : model.objects) - m.add_object(*o); - // Rearrange instances unless --dont-arrange is supplied - if (!m_config.opt_bool("dont_arrange")) { - m.add_default_instances(); - if (this->has_print_action()) - arrange_objects(m, bed, arrange_cfg); - else - arrange_objects(m, InfiniteBed{}, arrange_cfg); + if (opt_key == "assemble") { + if (clone_objects.size() > 0) { + BOOST_LOG_TRIVIAL(error) << "Invalid params: can not set assemble and clone_objects together." << std::endl; + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); } + Model m; + ModelObject* new_object = m.add_object(); + new_object->name = _u8L("Assembly"); + new_object->add_instance(); + int idx = 0; + for (auto& model : m_models) + for (ModelObject* o : model.objects) { + for (auto volume : o->volumes) { + ModelVolume* new_volume = new_object->add_volume(*volume); + // set extruder id + new_volume->config.set_key_value("extruder", new ConfigOptionInt(o->config.extruder())); + } + } m_models.clear(); - m_models.emplace_back(std::move(m));*/ + m_models.emplace_back(std::move(m)); + } + else if (opt_key == "repetitions") { + int repetitions_count = m_config.option("repetitions")->value; + if (repetitions_count <= 1) + { + BOOST_LOG_TRIVIAL(info) << "invalid repetitions value " << repetitions_count << ", just skip\n"; + } + else { + if (plate_to_slice == 0) { + BOOST_LOG_TRIVIAL(error) << "Invalid params: can not set repetitions when slice all." << std::endl; + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + else if (plate_to_slice > partplate_list.get_plate_count()) { + BOOST_LOG_TRIVIAL(error) << boost::format("Invalid params:invalid plate %1% to slice, total %2%")%plate_to_slice %partplate_list.get_plate_count(); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + + BOOST_LOG_TRIVIAL(info) << "repetitions value " << repetitions_count << std::endl; + + duplicate_count = repetitions_count - 1; + } } else if (opt_key == "convert_unit") { for (auto& model : m_models) { @@ -1430,18 +2906,35 @@ int CLI::run(int argc, char **argv) } } else if (opt_key == "orient") { - for (auto& model : m_models) - for (ModelObject* o : model.objects) - { - // coconut: always orient instance instead of object - for (ModelInstance* mi : o->instances) + //BBS: orient 0 means disable, 1 means force orient, others means auto + int orient_option = m_config.option("orient")->value; + + if (orient_option == 0) + { + //orients_requirement.clear(); + for (auto& model : m_models) + for (ModelObject* o : model.objects) { - orientation::orient(mi); + orients_requirement.insert(std::pair(o->id().id, false)); + BOOST_LOG_TRIVIAL(info) << "object "<name <<", id :" << o->id().id << ", no need to orient when setting orient to 0\n"; } - BOOST_LOG_TRIVIAL(info) << "orient object, name=" << o->name <<",id="<id().id<id().id] = false; - } + } + else if (orient_option == 1) + { + //force orient + //orients_requirement.clear(); + for (auto& model : m_models) + for (ModelObject* o : model.objects) + { + orients_requirement.insert(std::pair(o->id().id, true)); + BOOST_LOG_TRIVIAL(info) << "object "<name <<", id :" << o->id().id << ", need to orient when setting orient to 1\n"; + } + } + else + { + //auto arrange, keep the original logic + } + BOOST_LOG_TRIVIAL(info) << boost::format("orient_option %1%")%orient_option; } else if (opt_key == "copy") { for (auto &model : m_models) { @@ -1462,6 +2955,7 @@ int CLI::run(int argc, char **argv) } } catch (std::exception &ex) { boost::nowide::cerr << "error: " << ex.what() << std::endl; + record_exit_reson(outfile_dir, CLI_COPY_OBJECTS_ERROR, 0, cli_errors[CLI_COPY_OBJECTS_ERROR], sliced_info); flush_and_exit(CLI_COPY_OBJECTS_ERROR); } } @@ -1531,6 +3025,7 @@ int CLI::run(int argc, char **argv) const Vec3d &opt = m_config.opt(opt_key)->value; if (opt.x() <= 0 || opt.y() <= 0 || opt.z() <= 0) { boost::nowide::cerr << "--scale-to-fit requires a positive volume" << std::endl; + record_exit_reson(outfile_dir, CLI_SCALE_TO_FIT_ERROR, 0, cli_errors[CLI_SCALE_TO_FIT_ERROR], sliced_info); flush_and_exit(CLI_SCALE_TO_FIT_ERROR); } for (auto &model : m_models) @@ -1538,240 +3033,960 @@ int CLI::run(int argc, char **argv) // this affects volumes: o->scale_to_fit(opt); } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") { + boost::nowide::cerr << "Cut operation is not supported yet" << std::endl; + return CLI_INVALID_PARAMS; + + // std::vector new_models; + // for (auto &model : m_models) { + // model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0 + // size_t num_objects = model.objects.size(); + // for (size_t i = 0; i < num_objects; ++ i) { + + // #if 0 + // if (opt_key == "cut_x") { + // o->cut(X, m_config.opt_float("cut_x"), &out); + // } else if (opt_key == "cut_y") { + // o->cut(Y, m_config.opt_float("cut_y"), &out); + // } else if (opt_key == "cut") { + // o->cut(Z, m_config.opt_float("cut"), &out); + // } + // #else + // ModelObject* object = model.objects.front(); + // const BoundingBoxf3& box = object->bounding_box(); + // const float Margin = 20.0; + // const float max_x = box.size()(0) / 2.0 + Margin; + // const float min_x = -max_x; + // const float max_y = box.size()(1) / 2.0 + Margin; + // const float min_y = -max_y; + + // std::array plane_points; + // plane_points[0] = { min_x, min_y, 0 }; + // plane_points[1] = { max_x, min_y, 0 }; + // plane_points[2] = { max_x, max_y, 0 }; + // plane_points[3] = { min_x, max_y, 0 }; + // for (Vec3d& point : plane_points) { + // point += box.center(); + // } + // model.objects.front()->cut(0, plane_points, ModelObjectCutAttribute::KeepUpper | + // ModelObjectCutAttribute::KeepLower); + // #endif + // model.delete_object(size_t(0)); + // } + // } + + // // TODO: copy less stuff around using pointers + // m_models = new_models; + + // if (m_actions.empty()) + // m_actions.push_back("export_stl"); + } +#if 0 + else if (opt_key == "cut_grid") { std::vector new_models; for (auto &model : m_models) { - model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0 + TriangleMesh mesh = model.mesh(); + mesh.repair(); + + std::vector meshes = mesh.cut_by_grid(m_config.option("cut_grid")->value); + size_t i = 0; + for (TriangleMesh* m : meshes) { + Model out; + auto o = out.add_object(); + o->add_volume(*m); + o->input_file += "_" + std::to_string(i++); + delete m; + } + } + + // TODO: copy less stuff around using pointers + m_models = new_models; + + if (m_actions.empty()) + m_actions.push_back("export_stl"); + } +#endif + else if (opt_key == "split") { + for (Model &model : m_models) { size_t num_objects = model.objects.size(); for (size_t i = 0; i < num_objects; ++ i) { + ModelObjectPtrs new_objects; + model.objects.front()->split(&new_objects); + model.delete_object(size_t(0)); + } + } + } else if (opt_key == "repair") { + // Models are repaired by default. + //for (auto &model : m_models) + // model.repair(); + } else { + boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; + record_exit_reson(outfile_dir, CLI_UNSUPPORTED_OPERATION, 0, cli_errors[CLI_UNSUPPORTED_OPERATION], sliced_info); + flush_and_exit(CLI_UNSUPPORTED_OPERATION); + } + } -#if 0 - if (opt_key == "cut_x") { - o->cut(X, m_config.opt_float("cut_x"), &out); - } else if (opt_key == "cut_y") { - o->cut(Y, m_config.opt_float("cut_y"), &out); - } else if (opt_key == "cut") { - o->cut(Z, m_config.opt_float("cut"), &out); + BOOST_LOG_TRIVIAL(info) << "finished model pre-process commands\n"; + bool oriented_or_arranged = false; + //BBS: add orient and arrange logic here + for (auto& model : m_models) + { + for (ModelObject* o : model.objects) + { + if (orients_requirement[o->id().id]) + { + BOOST_LOG_TRIVIAL(info) << "Before process command, Orient object, name=" << o->name <<",id="<id().id<id().id< partplate_list.get_plate_count())) + { + BOOST_LOG_TRIVIAL(error) << boost::format("invalid plate id %1%, total %2%")%plate_to_slice %partplate_list.get_plate_count(); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + else if (plate_to_slice > 0){ + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1); + PrintSequence curr_plate_seq = cur_plate->get_print_seq(); + + if (curr_plate_seq == PrintSequence::ByDefault) { + auto seq_print = m_print_config.option>("print_sequence"); + if (seq_print && (seq_print->value == PrintSequence::ByObject)) { + BOOST_LOG_TRIVIAL(info) << boost::format("Check whether need to arrange by print_sequence: plate %1% print by object, set from global")%plate_to_slice; + is_seq_print_for_curr_plate = true; + } + } + else if (curr_plate_seq == PrintSequence::ByObject) { + BOOST_LOG_TRIVIAL(info) << boost::format("Check whether need to arrange by print_sequence: plate %1% print by object, set from plate self")%plate_to_slice; + is_seq_print_for_curr_plate = true; + } + + if (duplicate_count > 0) { + const ConfigOptionBool* spiral_vase = m_print_config.option("spiral_mode"); + if ((spiral_vase != nullptr) && spiral_vase->value) + { + //spiral mode can only be duplicated with by-object + if (!is_seq_print_for_curr_plate) { + BOOST_LOG_TRIVIAL(warning) << boost::format("Spiral mode can not be duplicated under by-object print, skip duplicate"); + duplicate_count = 0; + } + } + } + + if (duplicate_count > 0) + need_arrange = true; + } + + if ((!need_arrange) && is_bbl_3mf && !shrink_to_new_bed && (plate_to_slice > 0)) + { + if (((old_height_to_rod != 0.f) && (old_height_to_rod != height_to_rod)) + || ((old_height_to_lid != 0.f) && (old_height_to_lid != height_to_lid)) + || ((old_max_radius != 0.f) && (old_max_radius != cleareance_radius))) + { + if (is_seq_print_for_curr_plate) { + need_arrange = true; + BOOST_LOG_TRIVIAL(info) << boost::format("old_height_to_rod %1%, old_height_to_lid %2%, old_max_radius %3%, current height_to_rod %4%, height_to_lid %5%, cleareance_radius %6%, need arrange!") + %old_height_to_rod %old_height_to_lid %old_max_radius %height_to_rod %height_to_lid %cleareance_radius; + } + } + } + + oriented_or_arranged |= need_arrange; + + BOOST_LOG_TRIVIAL(info) << boost::format("before arrange, need_arrange=%1%, duplicate_count %2%, filament_color_changed %3%")%need_arrange %duplicate_count %filament_color_changed; + if (need_arrange || filament_color_changed) + { + for (int index = 0; index < partplate_list.get_plate_count(); index ++) + { + if ((plate_to_slice != 0) && (plate_to_slice != (index + 1))) { + continue; + } + + if (plate_data_src.size() > index) { + if (!plate_data_src[index]->thumbnail_file.empty()) { + BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded thumbnail %2%.")%(index+1)%plate_data_src[index]->thumbnail_file; + plate_data_src[index]->thumbnail_file.clear(); + } + if (!plate_data_src[index]->top_file.empty()) { + BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded top_thumbnail %2%.")%(index+1)%plate_data_src[index]->top_file; + plate_data_src[index]->top_file.clear(); + } + if (!plate_data_src[index]->pick_file.empty()) { + BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: clear loaded pick_thumbnail %2%.")%(index+1)%plate_data_src[index]->pick_file; + plate_data_src[index]->pick_file.clear(); + } + } + } + } + + auto get_print_sequence = [](Slic3r::GUI::PartPlate* plate, DynamicPrintConfig& print_config, bool &is_seq_print) { + PrintSequence curr_plate_seq = plate->get_print_seq(); + if (curr_plate_seq == PrintSequence::ByDefault) { + auto seq_print = print_config.option>("print_sequence"); + if (seq_print && (seq_print->value == PrintSequence::ByObject)) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate print by object, set from global"); + is_seq_print = true; + } + } + else if (curr_plate_seq == PrintSequence::ByObject) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate print by object, set from plate self"); + is_seq_print = true; + } + }; + + if (!assemble_plate_info_list.empty()) + { + //need to arrange for assemble cases + int plate_count = assemble_plate_info_list.size(); + if (plate_count != partplate_list.get_plate_count()) + { + BOOST_LOG_TRIVIAL(error) << boost::format("mismatch plate count, to_assemble %1%, generated %2%") % plate_count % partplate_list.get_plate_count(); + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + + for (size_t i = 0; i < plate_count; i++) + { + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate*)partplate_list.get_plate(i); + //lock those plates no need to arrange + if (!assemble_plate_info_list[i].need_arrange) + cur_plate->lock(true); + } + + for (size_t i = 0; i < plate_count; i++) + { + assemble_plate_info_t& assemble_plate = assemble_plate_info_list[i]; + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate*)partplate_list.get_plate(i); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%, need arrange %2%, filaments_count %3%") % (i+1) % assemble_plate.need_arrange % assemble_plate.filaments_count; + if (assemble_plate.need_arrange) + { + //do arrange for plate + ArrangePolygons selected, unselected; + Model& model = m_models[0]; + arrange_cfg = ArrangeParams(); // reset all params + get_print_sequence(cur_plate, m_print_config, arrange_cfg.is_seq_print); + + //Step-1: prepare the arranged data + partplate_list.lock_plate(i, false); + partplate_list.select_plate(i); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% set to selected") % i; + size_t plate_obj_count = assemble_plate.loaded_obj_list.size(); + for (size_t oidx = 0; oidx < plate_obj_count; ++oidx) + { + ModelObject* mo = assemble_plate.loaded_obj_list[oidx]; + + for (size_t inst_idx = 0; inst_idx < mo->instances.size(); ++inst_idx) + { + ModelInstance* minst = mo->instances[inst_idx]; + ArrangePolygon ap = get_instance_arrange_poly(minst, m_print_config); + ap.itemid = selected.size(); + selected.emplace_back(std::move(ap)); + BOOST_LOG_TRIVIAL(debug) << boost::format("plate %1%: add object %2% object index %3%, into selected") % (i+1) % ap.name %(oidx+1); + } + } + + if (!arrange_cfg.is_seq_print && assemble_plate.filaments_count > 1) + { + //prepare the wipe tower + int plate_count = partplate_list.get_plate_count(); + + auto printer_structure_opt = m_print_config.option>("printer_structure"); + // set the default position, the same with print config(left top) + float x = WIPE_TOWER_DEFAULT_X_POS; + float y = WIPE_TOWER_DEFAULT_Y_POS; + if (printer_structure_opt && printer_structure_opt->value == PrinterStructure::psI3) { + x = I3_WIPE_TOWER_DEFAULT_X_POS; + y = I3_WIPE_TOWER_DEFAULT_Y_POS; + } + ConfigOptionFloat wt_x_opt(x); + ConfigOptionFloat wt_y_opt(y); + + //create the options using default if neccessary + ConfigOptionFloats* wipe_x_option = m_print_config.option("wipe_tower_x", true); + ConfigOptionFloats* wipe_y_option = m_print_config.option("wipe_tower_y", true); + ConfigOptionFloat* width_option = m_print_config.option("prime_tower_width", true); + ConfigOptionFloat* rotation_angle_option = m_print_config.option("wipe_tower_rotation_angle", true); + ConfigOptionFloat* volume_option = m_print_config.option("prime_volume", true); + + BOOST_LOG_TRIVIAL(info) << boost::format("prime_tower_width %1% wipe_tower_rotation_angle %2% prime_volume %3%") % width_option->value % rotation_angle_option->value % volume_option->value; + + wipe_x_option->set_at(&wt_x_opt, i, 0); + wipe_y_option->set_at(&wt_y_opt, i, 0); + + + ArrangePolygon wipe_tower_ap = cur_plate->estimate_wipe_tower_polygon(m_print_config, i, assemble_plate.filaments_count, true); + + wipe_tower_ap.bed_idx = i; + unselected.emplace_back(wipe_tower_ap); + } + + // add the virtual object into unselect list if has + partplate_list.preprocess_exclude_areas(unselected, i + 1); + if (avoid_extrusion_cali_region) + partplate_list.preprocess_nonprefered_areas(unselected, i + 1); + + //Step-2:prepare the arrange params + arrange_cfg.allow_rotations = allow_rotations; + arrange_cfg.allow_multi_materials_on_same_plate = allow_multicolor_oneplate; + arrange_cfg.avoid_extrusion_cali_region = avoid_extrusion_cali_region; + arrange_cfg.clearance_height_to_rod = height_to_rod; + arrange_cfg.clearance_height_to_lid = height_to_lid; + arrange_cfg.cleareance_radius = cleareance_radius; + arrange_cfg.printable_height = print_height; + arrange_cfg.min_obj_distance = 0; + if (arrange_cfg.is_seq_print) { + arrange_cfg.bed_shrink_x = BED_SHRINK_SEQ_PRINT; + arrange_cfg.bed_shrink_y = BED_SHRINK_SEQ_PRINT; + } + if (auto printer_structure_opt = m_print_config.option>("printer_structure")) { + arrange_cfg.align_to_y_axis = (printer_structure_opt->value == PrinterStructure::psI3); + } + + arrangement::update_arrange_params(arrange_cfg, &m_print_config, selected); + arrangement::update_selected_items_inflation(selected, &m_print_config, arrange_cfg); + arrangement::update_unselected_items_inflation(unselected, &m_print_config, arrange_cfg); + arrangement::update_selected_items_axis_align(selected, &m_print_config, arrange_cfg); + + beds = get_shrink_bedpts(&m_print_config, arrange_cfg); + + partplate_list.preprocess_exclude_areas(arrange_cfg.excluded_regions, 1, scale_(1)); + + { + BOOST_LOG_TRIVIAL(debug) << "arrange bedpts:" << beds[0].transpose() << ", " << beds[1].transpose() << ", " << beds[2].transpose() << ", " << beds[3].transpose(); + BOOST_LOG_TRIVIAL(info) << "Arrange full params: " << arrange_cfg.to_json(); + BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%") % selected.size(); + for (auto item : selected) + BOOST_LOG_TRIVIAL(trace) << item.name << ", extruder: " << item.extrude_ids.back() << ", bed: " << item.bed_idx + << ", trans: " << item.translation.transpose(); + BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size(); + for (auto item : unselected) + BOOST_LOG_TRIVIAL(trace) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); + } + arrange_cfg.progressind = [](unsigned st, std::string str = "") { + //boost::nowide::cout << "st=" << st << ", " << str << std::endl; + }; + + //Step-3:do the arrange + BOOST_LOG_TRIVIAL(info) << boost::format("start plate %1%'s arranging...") % (i + 1); + arrangement::arrange(selected, unselected, beds, arrange_cfg); + //arrangement::arrange(unprintable, {}, beds, arrange_cfg); + BOOST_LOG_TRIVIAL(info) << boost::format("finished plate %1%'s arranging") % (i + 1); + + //step-4: postprocess the bed index and result + partplate_list.clear(false, false, true, i); + + for (ArrangePolygon& ap : selected) { + partplate_list.postprocess_bed_index_for_current_plate(ap); + if (ap.bed_idx != i) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":arrange failed: ap.name %1% ap.bed_idx %2%, plate index %3%") % ap.name % ap.bed_idx % i; + record_exit_reson(outfile_dir, CLI_OBJECT_ARRANGE_FAILED, 0, cli_errors[CLI_OBJECT_ARRANGE_FAILED], sliced_info); + flush_and_exit(CLI_OBJECT_ARRANGE_FAILED); + } + } + + // Apply the arrange result to all selected objects + for (ArrangePolygon& ap : selected) { + //BBS: partplate postprocess + partplate_list.postprocess_arrange_polygon(ap, true); + + ap.apply(); + } + partplate_list.rebuild_plates_after_arrangement(false, true, i); + } + else { + size_t plate_obj_count = assemble_plate.loaded_obj_list.size(); + Vec3d plate_origin = cur_plate->get_origin(); + + for (size_t oidx = 0; oidx < plate_obj_count; ++oidx) + { + ModelObject* mo = assemble_plate.loaded_obj_list[oidx]; + + mo->translate_instances(plate_origin); + + BOOST_LOG_TRIVIAL(debug) << boost::format("plate %1%: no arrange, directly translate object %2% by {%3%, %4%}") % (i+1) % mo->name %plate_origin(0) %plate_origin(1); + } + } + } + + for (size_t i = 0; i < plate_count; i++) + { + //unlock all the plates + Slic3r::GUI::PartPlate* cur_plate = (Slic3r::GUI::PartPlate*)partplate_list.get_plate(i); + cur_plate->lock(false); + } + } + else if (need_arrange) + { + ArrangePolygons selected, unselected, unprintable, locked_aps; + + //for (Model &model : m_models) + if (m_models.size() > 0) + { + Model &model = m_models[0]; + Model original_model; + std::set> backup_set; + bool finished_arrange = false, first_run = true; + Slic3r::GUI::PartPlate* cur_plate = nullptr; + int low_duplicate_count = 0, up_duplicate_count = duplicate_count, arrange_count = 0; + + if (duplicate_count > 0) { + original_model = model; + } + + while(!finished_arrange) + { + arrange_cfg = ArrangeParams(); // reset all params + arrange_count++; + //step-0: duplicate model + if (duplicate_count > 0) + { + //copy model objects and instances on plate + if (!first_run) { + BOOST_LOG_TRIVIAL(info) << boost::format("restore model object and plate, new duplicate_count %1%, arrange_count=%2%")%duplicate_count%arrange_count; + beds = get_bed_shape(m_print_config); + model.clear_objects(); + model.clear_materials(); + model = original_model; + partplate_list.load_from_3mf_structure(plate_data_src); + + selected.clear(); + unselected.clear(); + unprintable.clear(); + locked_aps.clear(); + } + else + first_run = false; + + cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1); + cur_plate->duplicate_all_instance(duplicate_count, need_skip, skip_maps); + } + else if (plate_to_slice > 0) + { + cur_plate = (Slic3r::GUI::PartPlate *)partplate_list.get_plate(plate_to_slice-1); + } + + if (cur_plate) { + get_print_sequence(cur_plate, m_print_config, arrange_cfg.is_seq_print); + } + + //Step-1: prepare arrange polygons + if ((duplicate_count == 0) && (plate_to_slice == 0)) + { + //global arrange + for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) + { + ModelObject* mo = model.objects[oidx]; + for (size_t inst_idx = 0; inst_idx < mo->instances.size(); ++inst_idx) + { + ModelInstance* minst = mo->instances[inst_idx]; + ArrangePolygon ap = get_instance_arrange_poly(minst, m_print_config); + + //preprocess by partplate list + //remove the locked plate's instances, neither in selected, nor in un-selected + bool locked = partplate_list.preprocess_arrange_polygon(oidx, inst_idx, ap, true); + if (!locked) + { + ap.itemid = selected.size(); + if (minst->printable) + selected.emplace_back(ap); + else + unprintable.emplace_back(ap); + } + else + { + //skip this object due to be locked in plate + ap.itemid = locked_aps.size(); + locked_aps.emplace_back(ap); + boost::nowide::cout <<__FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, instance_id %2%") % oidx % inst_idx; + } + } + } + + if (m_print_config.has("print_sequence")) { + PrintSequence seq = m_print_config.option>("print_sequence")->value; + arrange_cfg.is_seq_print = (seq == PrintSequence::ByObject); + } + + //add the virtual object into unselect list if has + partplate_list.preprocess_exclude_areas(unselected); + + if (used_filament_set.size() > 0) + { + //prepare the wipe tower + int plate_count = partplate_list.get_plate_count(); + int extruder_size = used_filament_set.size(); + + auto printer_structure_opt = m_print_config.option>("printer_structure"); + // set the default position, the same with print config(left top) + float x = WIPE_TOWER_DEFAULT_X_POS; + float y = WIPE_TOWER_DEFAULT_Y_POS; + if (printer_structure_opt && printer_structure_opt->value == PrinterStructure::psI3) { + x = I3_WIPE_TOWER_DEFAULT_X_POS; + y = I3_WIPE_TOWER_DEFAULT_Y_POS; + } + ConfigOptionFloat wt_x_opt(x); + ConfigOptionFloat wt_y_opt(y); + + //create the options using default if neccessary + ConfigOptionFloats* wipe_x_option = m_print_config.option("wipe_tower_x", true); + ConfigOptionFloats* wipe_y_option = m_print_config.option("wipe_tower_y", true); + ConfigOptionFloat* width_option = m_print_config.option("prime_tower_width", true); + ConfigOptionFloat* rotation_angle_option = m_print_config.option("wipe_tower_rotation_angle", true); + ConfigOptionFloat* volume_option = m_print_config.option("prime_volume", true); + + BOOST_LOG_TRIVIAL(info) << boost::format("prime_tower_width %1% wipe_tower_rotation_angle %2% prime_volume %3%")%width_option->value %rotation_angle_option->value %volume_option->value ; + + + for (int bedid = 0; bedid < MAX_PLATE_COUNT; bedid++) { + int plate_index_valid = std::min(bedid, plate_count - 1); + if (bedid < plate_count) { + wipe_x_option->set_at(&wt_x_opt, plate_index_valid, 0); + wipe_y_option->set_at(&wt_y_opt, plate_index_valid, 0); + } + + + ArrangePolygon wipe_tower_ap = partplate_list.get_plate(plate_index_valid)->estimate_wipe_tower_polygon(m_print_config, plate_index_valid, extruder_size, true); + + wipe_tower_ap.bed_idx = bedid; + unselected.emplace_back(wipe_tower_ap); + } + } + } + else { + //only arrange current plate + partplate_list.lock_plate(plate_to_slice - 1, false); + partplate_list.select_plate(plate_to_slice-1); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% set to selected")%plate_to_slice; + + for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) + { + ModelObject* mo = model.objects[oidx]; + + for (size_t inst_idx = 0; inst_idx < mo->instances.size(); ++inst_idx) + { + ModelInstance* minst = mo->instances[inst_idx]; + bool in_plate = cur_plate->contain_instance(oidx, inst_idx) || cur_plate->intersect_instance(oidx, inst_idx); + ArrangePolygon ap = get_instance_arrange_poly(minst, m_print_config); + + ArrangePolygons& cont = mo->instances[inst_idx]->printable ? + (in_plate ? selected : unselected) : + unprintable; + bool locked = partplate_list.preprocess_arrange_polygon_other_locked(oidx, inst_idx, ap, in_plate); + BOOST_LOG_TRIVIAL(info) << boost::format("name %4% in_plate %1% printable %2%, locked %3%")%in_plate %mo->instances[inst_idx]->printable %locked % ap.name ; + if (!locked) + { + ap.itemid = cont.size(); + cont.emplace_back(std::move(ap)); + } + else + { + //skip this object due to be not in current plate, treated as locked + ap.itemid = locked_aps.size(); + locked_aps.emplace_back(std::move(ap)); + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format("arrange: skip locked instance, obj_id %1%, name %2%") % oidx % mo->name; + } + } + } + if ((duplicate_count > 0)&&(selected.size() == (duplicate_count + 1))) + { + duplicate_single_object = true; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": found single object mode"); + } + + if (m_print_config.has("wipe_tower_x") && (is_smooth_timelapse || !arrange_cfg.is_seq_print || (selected.size() <= 1))) { + float x = dynamic_cast(m_print_config.option("wipe_tower_x"))->get_at(plate_to_slice-1); + float y = dynamic_cast(m_print_config.option("wipe_tower_y"))->get_at(plate_to_slice-1); + float w = dynamic_cast(m_print_config.option("prime_tower_width"))->value; + float a = dynamic_cast(m_print_config.option("wipe_tower_rotation_angle"))->value; + float v = dynamic_cast(m_print_config.option("prime_volume"))->value; + unsigned int filaments_cnt = plate_data_src[plate_to_slice-1]->slice_filaments_info.size(); + if ((filaments_cnt == 0) || need_skip) + { + // slice filaments info invalid + std::vector extruders = cur_plate->get_extruders_under_cli(true, m_print_config); + filaments_cnt = extruders.size(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange: slice filaments info invalid or need_skip, get from partplate: filament_count %1%")%filaments_cnt; + } + + if ((filaments_cnt <= 1) && !is_smooth_timelapse) + { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("arrange: not a multi-color object anymore, drop the wipe tower before arrange."); + } + else + { + float layer_height = 0.2; + ConfigOption* layer_height_opt = m_print_config.option("layer_height"); + if (layer_height_opt) + layer_height = layer_height_opt->getFloat(); + + //float depth = v * (filaments_cnt - 1) / (layer_height * w); + + Vec3d wipe_tower_size = cur_plate->estimate_wipe_tower_size(m_print_config, w, v, filaments_cnt); + Vec3d plate_origin = cur_plate->get_origin(); + int plate_width, plate_depth, plate_height; + partplate_list.get_plate_size(plate_width, plate_depth, plate_height); + float depth = wipe_tower_size(1); + float margin = 15.f, wp_brim_width = 0.f; + ConfigOption *wipe_tower_brim_width_opt = m_print_config.option("prime_tower_brim_width"); + if (wipe_tower_brim_width_opt ) { + wp_brim_width = wipe_tower_brim_width_opt->getFloat(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: wp_brim_width %1%")%wp_brim_width; + } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: x=%1%, y=%2%, width=%3%, depth=%4%, angle=%5%, prime_volume=%6%, filaments_cnt=%7%, layer_height=%8%, plate_width=%9%, plate_depth=%10%") + %x %y %w %depth %a %v %filaments_cnt %layer_height %plate_width %plate_depth; + if ((y + depth + margin + wp_brim_width) > (float)plate_depth) { + y = (float)plate_depth - depth - margin - wp_brim_width; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: exceeds the border, change y to %1%, plate_depth=%2%")%y %plate_depth; + } + + if ((x + w + margin + wp_brim_width) > (float)plate_width) { + x = (float)plate_width - w - margin - wp_brim_width; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: exceeds the border, change x to %1%, plate_width=%2%")%y %plate_width; + } + + ArrangePolygon wipe_tower_ap; + + Polygon ap({ + {scaled(x - wp_brim_width), scaled(y - wp_brim_width)}, + {scaled(x + w + wp_brim_width), scaled(y - wp_brim_width)}, + {scaled(x + w + wp_brim_width), scaled(y + depth + wp_brim_width)}, + {scaled(x - wp_brim_width), scaled(y + depth + wp_brim_width)} + }); + wipe_tower_ap.bed_idx = 0; + wipe_tower_ap.setter = NULL; // do not move wipe tower + + wipe_tower_ap.poly.contour = std::move(ap); + wipe_tower_ap.translation = {scaled(0.f), scaled(0.f)}; + wipe_tower_ap.rotation = a; + wipe_tower_ap.name = "WipeTower"; + wipe_tower_ap.is_virt_object = true; + wipe_tower_ap.is_wipe_tower = true; + ++wipe_tower_ap.priority; + unselected.emplace_back(std::move(wipe_tower_ap)); + } + } + + // add the virtual object into unselect list if has + partplate_list.preprocess_exclude_areas(unselected, plate_to_slice); + } + + + //Step-2:prepare the arrange params + arrange_cfg.allow_rotations = allow_rotations; + arrange_cfg.allow_multi_materials_on_same_plate = allow_multicolor_oneplate; + arrange_cfg.avoid_extrusion_cali_region = avoid_extrusion_cali_region; + arrange_cfg.clearance_height_to_rod = height_to_rod; + arrange_cfg.clearance_height_to_lid = height_to_lid; + arrange_cfg.cleareance_radius = cleareance_radius; + arrange_cfg.printable_height = print_height; + arrange_cfg.min_obj_distance = 0; + if (arrange_cfg.is_seq_print) { + arrange_cfg.bed_shrink_x = BED_SHRINK_SEQ_PRINT; + arrange_cfg.bed_shrink_y = BED_SHRINK_SEQ_PRINT; + } + if (auto printer_structure_opt = m_print_config.option>("printer_structure")) { + arrange_cfg.align_to_y_axis = (printer_structure_opt->value == PrinterStructure::psI3); + } + + arrangement::update_arrange_params(arrange_cfg, &m_print_config, selected); + arrangement::update_selected_items_inflation(selected, &m_print_config, arrange_cfg); + arrangement::update_unselected_items_inflation(unselected, &m_print_config, arrange_cfg); + arrangement::update_selected_items_axis_align(selected, &m_print_config, arrange_cfg); + + beds=get_shrink_bedpts(&m_print_config, arrange_cfg); + + partplate_list.preprocess_exclude_areas(arrange_cfg.excluded_regions, 1, scale_(1)); + + { + BOOST_LOG_TRIVIAL(debug) << "arrange bedpts:" << beds[0].transpose() << ", " << beds[1].transpose() << ", " << beds[2].transpose() << ", " << beds[3].transpose(); + BOOST_LOG_TRIVIAL(info)<< "Arrange full params: "<< arrange_cfg.to_json(); + BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%")%selected.size(); + for (auto item : selected) + BOOST_LOG_TRIVIAL(trace) << item.name << ", extruder: " << item.extrude_ids.back() << ", bed: " << item.bed_idx + << ", trans: " << item.translation.transpose(); + BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items unselected before arranging: %1%") % unselected.size(); + for (auto item : unselected) + BOOST_LOG_TRIVIAL(trace) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); + } + arrange_cfg.progressind= [](unsigned st, std::string str = "") { + //boost::nowide::cout << "st=" << st << ", " << str << std::endl; + }; + + //Step-3:do the arrange + BOOST_LOG_TRIVIAL(info) << boost::format("start %1% th arranging...")%arrange_count; + arrangement::arrange(selected, unselected, beds, arrange_cfg); + arrangement::arrange(unprintable, {}, beds, arrange_cfg); + BOOST_LOG_TRIVIAL(info) << boost::format("finished %1% th arranging...")%arrange_count; + + //Step-4:postprocess by partplate list&&apply the result + int bed_idx_max = 0; + if (duplicate_count == 0) + { + if (plate_to_slice > 0) + { + //only for partplate case + partplate_list.clear(false, false, true, plate_to_slice-1); + + for (ArrangePolygon& ap : selected) { + partplate_list.postprocess_bed_index_for_current_plate(ap); + if (ap.bed_idx != (plate_to_slice-1)) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":arrange failed: ap.name %1% ap.bed_idx %2%, plate index %3%")% ap.name % ap.bed_idx % (plate_to_slice-1); + record_exit_reson(outfile_dir, CLI_OBJECT_ARRANGE_FAILED, 0, cli_errors[CLI_OBJECT_ARRANGE_FAILED], sliced_info); + flush_and_exit(CLI_OBJECT_ARRANGE_FAILED); + } + bed_idx_max = std::max(ap.bed_idx, bed_idx_max); + } + } + else + { + //clear all the relations before apply the arrangement results + partplate_list.clear(); + + // Apply the arrange result to all selected objects + for (ArrangePolygon &ap : selected) { + //BBS: partplate postprocess + partplate_list.postprocess_bed_index_for_selected(ap); + + bed_idx_max = std::max(ap.bed_idx, bed_idx_max); + BOOST_LOG_TRIVIAL(trace)<< "after arrange: name=" << ap.name << boost::format(",bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) << "\n"; + } + } + for (ArrangePolygon &ap : locked_aps) { + bed_idx_max = std::max(ap.bed_idx, bed_idx_max); + + partplate_list.postprocess_arrange_polygon(ap, false); + + ap.apply(); + } + + // Apply the arrange result to all selected objects + for (ArrangePolygon &ap : selected) { + //BBS: partplate postprocess + partplate_list.postprocess_arrange_polygon(ap, true); + + ap.apply(); } -#else - Cut cut(model.objects.front(), 0, Geometry::translation_transform(m_config.opt_float("cut") * Vec3d::UnitZ()), - ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::PlaceOnCutUpper); - auto cut_objects = cut.perform_with_plane(); - for (ModelObject* obj : cut_objects) - model.add_object(*obj); -#endif - model.delete_object(size_t(0)); - } - } - // TODO: copy less stuff around using pointers - m_models = new_models; + // Apply the arrange result to unselected objects(due to the sukodu-style column changes, the position of unselected may also be modified) + for (ArrangePolygon& ap : unselected) + { + if (ap.is_virt_object) + continue; - if (m_actions.empty()) - m_actions.push_back("export_stl"); - } -#if 0 - else if (opt_key == "cut_grid") { - std::vector new_models; - for (auto &model : m_models) { - TriangleMesh mesh = model.mesh(); - mesh.repair(); + //BBS: partplate postprocess + partplate_list.postprocess_arrange_polygon(ap, false); - std::vector meshes = mesh.cut_by_grid(m_config.option("cut_grid")->value); - size_t i = 0; - for (TriangleMesh* m : meshes) { - Model out; - auto o = out.add_object(); - o->add_volume(*m); - o->input_file += "_" + std::to_string(i++); - delete m; - } - } + ap.apply(); + } - // TODO: copy less stuff around using pointers - m_models = new_models; + // Move the unprintable items to the last virtual bed. + // Note ap.apply() moves relatively according to bed_idx, so we need to subtract the orignal bed_idx + for (ArrangePolygon& ap : unprintable) + { + ap.bed_idx = bed_idx_max + 1; + partplate_list.postprocess_arrange_polygon(ap, true); - if (m_actions.empty()) - m_actions.push_back("export_stl"); - } -#endif - else if (opt_key == "split") { - for (Model &model : m_models) { - size_t num_objects = model.objects.size(); - for (size_t i = 0; i < num_objects; ++ i) { - ModelObjectPtrs new_objects; - model.objects.front()->split(&new_objects); - model.delete_object(size_t(0)); + ap.apply(); + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":arrange m_unprintable: name: %4%, bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) % ap.name; + } + + //BBS: reload all objects due to arrange + if (plate_to_slice > 0) + partplate_list.rebuild_plates_after_arrangement(false, true, plate_to_slice-1); + else + partplate_list.rebuild_plates_after_arrangement(); } - } - } else if (opt_key == "repair") { - // Models are repaired by default. - //for (auto &model : m_models) - // model.repair(); - } else { - boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; - flush_and_exit(CLI_UNSUPPORTED_OPERATION); - } - } + else { + //only for partplate case + partplate_list.clear(false, false, true, plate_to_slice-1); + + //BBS: adjust the bed_index, create new plates, get the max bed_index + bool failed_this_time = false; + for (ArrangePolygon& ap : selected) { + partplate_list.postprocess_bed_index_for_current_plate(ap); + if (ap.bed_idx != (plate_to_slice-1)) + { + // + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":arrange failed: ap.name %1% ap.bed_idx %2%, plate index %3%")% ap.name % ap.bed_idx % (plate_to_slice-1); + if (!duplicate_single_object) + { + BOOST_LOG_TRIVIAL(warning) << boost::format("arrange failed when duplicate multiple objects at count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count; - BOOST_LOG_TRIVIAL(info) << "finished model pre-process commands\n"; - bool oriented_or_arranged = false; - //BBS: add orient and arrange logic here - for (auto& model : m_models) - { - for (ModelObject* o : model.objects) - { - if (orients_requirement[o->id().id]) - { - BOOST_LOG_TRIVIAL(info) << "Before process command, Orient object, name=" << o->name <<",id="<id().id<id().id<(ap.translation(X)) % unscale(ap.translation(Y)) % ap.name; + } - for (Model &model : m_models) - { - //Step-1: prepare arrange polygons - for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) - { - ModelObject* mo = model.objects[oidx]; - for (size_t inst_idx = 0; inst_idx < mo->instances.size(); ++inst_idx) - { - ModelInstance* minst = mo->instances[inst_idx]; - ArrangePolygon ap = get_instance_arrange_poly(minst, m_print_config); + if (failed_this_time) { + if (duplicate_count == 0) + { + //restore to the original + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": restore to the original model and plates"); + finished_arrange = true; + model = original_model; + partplate_list.load_from_3mf_structure(plate_data_src); + partplate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": exit arrange process"); + } + continue; + } - //preprocess by partplate list - //remove the locked plate's instances, neither in selected, nor in un-selected - bool locked = partplate_list.preprocess_arrange_polygon(oidx, inst_idx, ap, true); - if (!locked) + if (duplicate_single_object) { - ap.itemid = selected.size(); - if (minst->printable) - selected.emplace_back(ap); - else - unprintable.emplace_back(ap); + if (real_duplicate_count <= 1) { + BOOST_LOG_TRIVIAL(warning) << "no object can be placed under single object mode, restore to the original model and plates also" << std::endl; + //record_exit_reson(outfile_dir, CLI_OBJECT_ARRANGE_FAILED, 0, cli_errors[CLI_OBJECT_ARRANGE_FAILED], sliced_info); + //flush_and_exit(CLI_OBJECT_ARRANGE_FAILED); + finished_arrange = true; + model = original_model; + partplate_list.load_from_3mf_structure(plate_data_src); + partplate_list.reset_size(current_printable_width, current_printable_depth, current_printable_height, true, true); + duplicate_count = 0; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": exit arrange process"); + continue; + } + duplicate_count = real_duplicate_count - 1; } - else + else { + //multiple objects case + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": multiple objects mode, arrange success on count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count; + if ((duplicate_count == up_duplicate_count) || (duplicate_count == (up_duplicate_count - 1))) + { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": found the max arrangeable count %1%")%duplicate_count; + } + else { + low_duplicate_count = duplicate_count; + duplicate_count = (up_duplicate_count + low_duplicate_count)/2; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": try new count %1%, low_duplicate_count %2%, up_duplicate_count %3%")%duplicate_count %low_duplicate_count %up_duplicate_count; + continue; + } + } + + //BBS: adjust the bed_index, create new plates, get the max bed_index + for (ArrangePolygon& ap : unselected) { - //skip this object due to be locked in plate - ap.itemid = locked_aps.size(); - locked_aps.emplace_back(ap); - boost::nowide::cout <<__FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, instance_id %2%") % oidx % inst_idx; - } - } - } - - //add the virtual object into unselect list if has - partplate_list.preprocess_exclude_areas(unselected); - - //Step-2:prepare the arrange params - arrange_cfg.allow_rotations = true; - arrange_cfg.min_obj_distance = scaled(6.0); - //BBS: add specific params - arrange_cfg.is_seq_print = false; - arrange_cfg.bed_shrink_x = 0; - arrange_cfg.bed_shrink_y = 0; - double skirt_distance = m_print_config.opt_float("skirt_distance"); - double brim_width = m_print_config.opt_float("brim_width"); - arrange_cfg.brim_skirt_distance = skirt_distance + brim_width; - BOOST_LOG_TRIVIAL(info) << boost::format("Arrange Params: brim_skirt_distance=%1%, min_obj_distance=%2%, is_seq_print=%3%\n") % arrange_cfg.brim_skirt_distance % arrange_cfg.min_obj_distance % arrange_cfg.is_seq_print; - - // Note: skirt_distance is now defined between outermost brim and skirt, not the object and skirt. - // So we can't do max but do adding instead. - arrange_cfg.bed_shrink_x += arrange_cfg.brim_skirt_distance; - arrange_cfg.bed_shrink_y += arrange_cfg.brim_skirt_distance; - // shrink bed - beds[0] += Point(scaled(arrange_cfg.bed_shrink_x), scaled(arrange_cfg.bed_shrink_y)); - beds[1] += Point(-scaled(arrange_cfg.bed_shrink_x), scaled(arrange_cfg.bed_shrink_y)); - beds[2] += Point(-scaled(arrange_cfg.bed_shrink_x), -scaled(arrange_cfg.bed_shrink_y)); - beds[3] += Point(scaled(arrange_cfg.bed_shrink_x), -scaled(arrange_cfg.bed_shrink_y)); - - // do not inflate brim_width. Objects are allowed to have overlapped brim. - std::for_each(selected.begin(), selected.end(), [&](auto& ap) {ap.inflation = arrange_cfg.min_obj_distance / 2; }); + if (ap.is_virt_object) + continue; - { - BOOST_LOG_TRIVIAL(info) << "items selected before arranging: "; - for (auto selected : selected) - BOOST_LOG_TRIVIAL(info) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx - << ", trans: " << selected.translation.transpose(); - } - arrange_cfg.progressind= [](unsigned st, std::string str = "") { - boost::nowide::cout << "st=" << st << ", " << str << std::endl; - }; + bed_idx_max = std::max(ap.bed_idx, bed_idx_max); + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":arrange unselected %4%: bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) % ap.name; + } - //Step-3:do the arrange - arrangement::arrange(selected, unselected, beds, arrange_cfg); - arrangement::arrange(unprintable, {}, beds, arrange_cfg); + for (ArrangePolygon& ap : locked_aps) + { + bed_idx_max = std::max(ap.bed_idx, bed_idx_max); - //Step-4:postprocess by partplate list&&apply the result - int bed_idx_max = 0; - //clear all the relations before apply the arrangement results - partplate_list.clear(); + partplate_list.postprocess_arrange_polygon(ap, false); - // Apply the arrange result to all selected objects - for (ArrangePolygon &ap : selected) { - //BBS: partplate postprocess - partplate_list.postprocess_bed_index_for_selected(ap); + ap.apply(); + } - bed_idx_max = std::max(ap.bed_idx, bed_idx_max); - boost::nowide::cout<< "after arrange: name=" << ap.name << boost::format(",bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) << "\n"; - } - for (ArrangePolygon &ap : locked_aps) { - bed_idx_max = std::max(ap.bed_idx, bed_idx_max); + // Apply the arrange result to all selected objects + for (ArrangePolygon& ap : selected) { + //BBS: partplate postprocess + partplate_list.postprocess_arrange_polygon(ap, true); - partplate_list.postprocess_arrange_polygon(ap, false); + ap.apply(); + } - ap.apply(); - } + // Apply the arrange result to unselected objects(due to the sukodu-style column changes, the position of unselected may also be modified) + for (ArrangePolygon& ap : unselected) + { + if (ap.is_virt_object) + continue; - // Apply the arrange result to all selected objects - for (ArrangePolygon &ap : selected) { - //BBS: partplate postprocess - partplate_list.postprocess_arrange_polygon(ap, true); + //BBS: partplate postprocess + partplate_list.postprocess_arrange_polygon(ap, false); - ap.apply(); - } + ap.apply(); + } - // Move the unprintable items to the last virtual bed. - for (ArrangePolygon &ap : unprintable) { - ap.bed_idx += bed_idx_max + 1; - partplate_list.postprocess_arrange_polygon(ap, true); + // Move the unprintable items to the last virtual bed. + // Note ap.apply() moves relatively according to bed_idx, so we need to subtract the orignal bed_idx + for (ArrangePolygon& ap : unprintable) + { + ap.bed_idx = bed_idx_max + 1; + partplate_list.postprocess_arrange_polygon(ap, true); - ap.apply(); - } + ap.apply(); + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":arrange m_unprintable: name: %4%, bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale(ap.translation(X)) % unscale(ap.translation(Y)) % ap.name; + } - //BBS: reload all objects due to arrange - partplate_list.rebuild_plates_after_arrangement(); + partplate_list.rebuild_plates_after_arrangement(false, true, plate_to_slice-1); + } + finished_arrange = true; + } + original_model.clear_objects(); + original_model.clear_materials(); } } // All transforms have been dealt with. Now ensure that the objects are on bed. // (Unless the user said otherwise.) //BBS: current only support models on bed, 0407 sinking supported - //if (m_config.opt_bool("ensure_on_bed")) - // for (auto &model : m_models) - // for (auto &o : model.objects) - // o->ensure_on_bed(); + if (m_config.opt_bool("ensure_on_bed")) + { + BOOST_LOG_TRIVIAL(info) << "ensure_on_bed: need to ensure each object on beds"; + for (auto &model : m_models) + for (auto &o : model.objects) + o->ensure_on_bed(); + } // loop through action options bool export_to_3mf = false, load_slicedata = false, export_slicedata = false, export_slicedata_error = false; bool no_check = false; std::string export_3mf_file, load_slice_data_dir, export_slice_data_dir; - std::string outfile_dir = m_config.opt_string("outputdir"); std::vector calibration_thumbnails; int max_slicing_time_per_plate = 0, max_triangle_count_per_plate = 0; + std::vector plate_has_skips(partplate_list.get_plate_count(), false); + std::vector> plate_skipped_objects(partplate_list.get_plate_count()); + + global_current_time = (long long)Slic3r::Utils::get_current_time_utc(); + sliced_info.prepare_time = (size_t) (global_current_time - global_begin_time); + global_begin_time = global_current_time; + for (auto const &opt_key : m_actions) { if (opt_key == "help") { this->print_help(); @@ -1786,13 +4001,26 @@ int CLI::run(int argc, char **argv) load_slice_data_dir = m_config.opt_string(opt_key); if (export_slicedata) { BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata and export_slicedata together." << std::endl; + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + flush_and_exit(CLI_INVALID_PARAMS); + } + else if (duplicate_count > 0) + { + BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata when set repetitions." << std::endl; + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); flush_and_exit(CLI_INVALID_PARAMS); } + else if (shrink_to_new_bed) + { + BOOST_LOG_TRIVIAL(warning) << "use load_slicedata when shrink_to_new_bed(switch printer from small to bigger." << std::endl; + //record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); + //flush_and_exit(CLI_INVALID_PARAMS); + } } else if (opt_key == "export_settings") { //FIXME check for mixing the FFF / SLA parameters. // or better save fff_print_config vs. sla_print_config //m_print_config.save(m_config.opt_string("save")); - m_print_config.save_to_json(m_config.opt_string(opt_key), std::string("project_settings"), std::string("project"), std::string(SoftFever_VERSION)); + m_print_config.save_to_json(m_config.opt_string(opt_key), std::string("project_settings"), std::string("project"), std::string(SLIC3R_VERSION)); } else if (opt_key == "info") { // --info works on unrepaired model for (Model &model : m_models) { @@ -1801,6 +4029,10 @@ int CLI::run(int argc, char **argv) } } else if (opt_key == "uptodate") { //already processed before + } else if (opt_key == "min_save") { + //already processed before + } else if (opt_key == "load_defaultfila") { + //already processed before } else if (opt_key == "mtcpp") { max_triangle_count_per_plate = m_config.option("mtcpp")->value; } else if (opt_key == "mstpp") { @@ -1808,13 +4040,17 @@ int CLI::run(int argc, char **argv) } else if (opt_key == "export_stl") { for (auto &model : m_models) model.add_default_instances(); - if (! this->export_models(IO::STL)) + if (! this->export_models(IO::STL)) { + record_exit_reson(outfile_dir, CLI_EXPORT_STL_ERROR, 0, cli_errors[CLI_EXPORT_STL_ERROR], sliced_info); flush_and_exit(CLI_EXPORT_STL_ERROR); + } } else if (opt_key == "export_obj") { for (auto &model : m_models) model.add_default_instances(); - if (! this->export_models(IO::OBJ)) + if (! this->export_models(IO::OBJ)) { + record_exit_reson(outfile_dir, CLI_EXPORT_OBJ_ERROR, 0, cli_errors[CLI_EXPORT_OBJ_ERROR], sliced_info); flush_and_exit(CLI_EXPORT_OBJ_ERROR); + } }/* else if (opt_key == "export_amf") { if (! this->export_models(IO::AMF)) return 1; @@ -1831,31 +4067,22 @@ int CLI::run(int argc, char **argv) export_slice_data_dir = m_config.opt_string(opt_key); if (load_slicedata) { BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata and export_slicedata together." << std::endl; + record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info); flush_and_exit(CLI_INVALID_PARAMS); } } else if (opt_key == "slice") { //BBS: slice 0 means all plates, i means plate i; plate_to_slice = m_config.option("slice")->value; bool pre_check = (plate_to_slice == 0)?true:false; - if (partplate_list.get_plate_count() == 1) - pre_check = false; bool finished = false; - //skip model object - std::map skip_maps; - if (need_skip) { - BOOST_LOG_TRIVIAL(info) << boost::format("need to skip objects, size %1%:")%skip_objects.size(); - for (int index = 0; index < skip_objects.size(); index++) - { - skip_maps[skip_objects[index]] = false; - BOOST_LOG_TRIVIAL(info) << boost::format("object %1%, id %2%")%index %skip_objects[index]; - } - } /*if (opt_key == "export_gcode" && printer_technology == ptSLA) { boost::nowide::cerr << "error: cannot export G-code for an FFF configuration" << std::endl; + record_exit_reson(outfile_dir, 1, 0, cli_errors[1], sliced_info); flush_and_exit(1); } else if (opt_key == "export_sla" && printer_technology == ptFFF) { boost::nowide::cerr << "error: cannot export SLA slices for a SLA configuration" << std::endl; + record_exit_reson(outfile_dir, 1, 0, cli_errors[1], sliced_info); flush_and_exit(1); }*/ BOOST_LOG_TRIVIAL(info) << "Need to slice for plate "< plate_triangle_counts(partplate_list.get_plate_count(), 0); while(!finished) { //BBS: slice every partplate one by one PrintBase *print=NULL; + Print *print_fff = NULL; + Slic3r::GUI::GCodeResult *gcode_result = NULL; int print_index; for (int index = 0; index < partplate_list.get_plate_count(); index ++) @@ -1892,12 +4122,18 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << "Skip plate " << index+1 << std::endl; continue; } + sliced_plate_info_t sliced_plate_info; + sliced_plate_info.plate_id = index+1; + + model.curr_plate_index = index; BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: pre_check %2%, start")%(index+1)%pre_check; - long long start_time = 0, end_time = 0; + long long start_time = 0, end_time = 0, temp_time = 0, time_using_cache = 0; start_time = (long long)Slic3r::Utils::get_current_time_utc(); //get the current partplate Slic3r::GUI::PartPlate* part_plate = partplate_list.get_plate(index); part_plate->get_print(&print, &gcode_result, &print_index); + + print_fff = dynamic_cast(print); /*if (outfile_config.empty()) { outfile = "plate_" + std::to_string(index + 1) + ".gcode"; @@ -1922,6 +4158,7 @@ int CLI::run(int argc, char **argv) if (count == 0) { BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume before apply." << std::endl; + record_exit_reson(outfile_dir, CLI_NO_SUITABLE_OBJECTS, index+1, cli_errors[CLI_NO_SUITABLE_OBJECTS], sliced_info); flush_and_exit(CLI_NO_SUITABLE_OBJECTS); } else if ((plate_to_slice != 0) || pre_check) { @@ -1931,11 +4168,14 @@ int CLI::run(int argc, char **argv) for (ModelObject* model_object : model.objects) for (ModelInstance *i : model_object->instances) { + i->use_loaded_id_for_label = true; if (skip_maps.find(i->loaded_id) != skip_maps.end()) { skip_maps[i->loaded_id] = true; i->printable = false; if (i->print_volume_state == ModelInstancePVS_Inside) { skipped_count++; + plate_has_skips[index] = true; + plate_skipped_objects[index].emplace_back(i->loaded_id); BOOST_LOG_TRIVIAL(info) << boost::format("Plate %1%: skip object %2%.")%(index+1)%i->loaded_id; //need to regenerate the thumbnail if (plate_data_src.size() > index) { @@ -1959,9 +4199,10 @@ int CLI::run(int argc, char **argv) if (i->print_volume_state == ModelInstancePVS_Partly_Outside) { BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Found Object " << model_object->name <<" partly inside, can not be sliced." << std::endl; + record_exit_reson(outfile_dir, CLI_OBJECTS_PARTLY_INSIDE, index+1, cli_errors[CLI_OBJECTS_PARTLY_INSIDE], sliced_info); flush_and_exit(CLI_OBJECTS_PARTLY_INSIDE); } - else if ((max_triangle_count_per_plate != 0) && (i->print_volume_state == ModelInstancePVS_Inside)) + else if (i->print_volume_state == ModelInstancePVS_Inside) { for (const ModelVolume* vol : model_object->volumes) { @@ -1969,9 +4210,10 @@ int CLI::run(int argc, char **argv) size_t volume_triangle_count = vol->mesh().facets_count(); triangle_count += volume_triangle_count; BOOST_LOG_TRIVIAL(info) << boost::format("volume triangle count %1%, total %2%")%volume_triangle_count %triangle_count; - if (triangle_count > max_triangle_count_per_plate) + if ((max_triangle_count_per_plate != 0) && (triangle_count > max_triangle_count_per_plate)) { BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": triangle count " << triangle_count <<" exceeds the limit:" << max_triangle_count_per_plate; + record_exit_reson(outfile_dir, CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT, index+1, cli_errors[CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT], sliced_info); flush_and_exit(CLI_TRIANGLE_COUNT_EXCEEDS_LIMIT); } } @@ -1984,8 +4226,12 @@ int CLI::run(int argc, char **argv) if (printable_instances == 0) { BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, after skipping "<{%4%, %5%, %6%}, has %7% printables") % print_volume.min(0) % print_volume.min(1) @@ -2000,21 +4246,49 @@ int CLI::run(int argc, char **argv) StringObjectException warning; auto err = print->validate(&warning); if (!err.string.empty()) { - BOOST_LOG_TRIVIAL(info) << "got error when validate: "<< err.string << std::endl; - boost::nowide::cerr << err.string << std::endl; - //BBS: continue for other plates - //continue; - flush_and_exit(CLI_VALIDATE_ERROR); + if ((STRING_EXCEPT_LAYER_HEIGHT_EXCEEDS_LIMIT == err.type) && no_check) { + BOOST_LOG_TRIVIAL(warning) << "got warnings: "<< err.string << std::endl; + } + else { + BOOST_LOG_TRIVIAL(error) << "got error when validate: "<< err.string << std::endl; + boost::nowide::cerr << err.string << std::endl; + int validate_error; + switch (err.type) + { + case STRING_EXCEPT_FILAMENT_NOT_MATCH_BED_TYPE: + validate_error = CLI_FILAMENT_NOT_MATCH_BED_TYPE; + break; + case STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMP: + validate_error = CLI_FILAMENTS_DIFFERENT_TEMP; + break; + case STRING_EXCEPT_OBJECT_COLLISION_IN_SEQ_PRINT: + validate_error = CLI_OBJECT_COLLISION_IN_SEQ_PRINT; + break; + case STRING_EXCEPT_OBJECT_COLLISION_IN_LAYER_PRINT: + validate_error = CLI_OBJECT_COLLISION_IN_LAYER_PRINT; + break; + default: + validate_error = CLI_VALIDATE_ERROR; + break; + } + if (no_check) + record_exit_reson(outfile_dir, validate_error, index+1, err.string, sliced_info); + else + record_exit_reson(outfile_dir, validate_error, index+1, cli_errors[validate_error], sliced_info); + flush_and_exit(validate_error); + } + } + else if (!warning.string.empty()) { + BOOST_LOG_TRIVIAL(warning) << "got warnings: "<< warning.string << std::endl; } - else if (!warning.string.empty()) - BOOST_LOG_TRIVIAL(info) << "got warnings: "<< warning.string << std::endl; if (print->empty()) { BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": Nothing to be sliced, Either the print is empty or no object is fully inside the print volume after apply." << std::endl; + record_exit_reson(outfile_dir, CLI_NO_SUITABLE_OBJECTS, index+1, cli_errors[CLI_NO_SUITABLE_OBJECTS], sliced_info); flush_and_exit(CLI_NO_SUITABLE_OBJECTS); } else { - if (pre_check) //continue to next plate directly + if (pre_check && (partplate_list.get_plate_count() > 1)) //continue to next plate directly continue; try { std::string outfile_final; @@ -2034,7 +4308,35 @@ int CLI::run(int argc, char **argv) cli_status_callback(slicing_status); } } + else { + BOOST_LOG_TRIVIAL(info) << "set print's callback to default_status_callback."; + print->set_status_callback(default_status_callback); + } +#else + BOOST_LOG_TRIVIAL(info) << "set print's callback to default_status_callback."; + print->set_status_callback(default_status_callback); #endif + //check whether it is bbl printer + std::string& printer_model_string = new_print_config.opt_string("printer_model", true); + bool is_bbl_vendor_preset = false; + + if (!printer_model_string.empty()) { + is_bbl_vendor_preset = (printer_model_string.compare(0, 9, "Bambu Lab") == 0); + BOOST_LOG_TRIVIAL(info) << boost::format("printer_model_string: %1%, is_bbl_vendor_preset %2%")%printer_model_string %is_bbl_vendor_preset; + } + else { + if (!new_printer_name.empty()) + is_bbl_vendor_preset = (new_printer_name.compare(0, 9, "Bambu Lab") == 0); + else if (!current_printer_system_name.empty()) + is_bbl_vendor_preset = (current_printer_system_name.compare(0, 9, "Bambu Lab") == 0); + BOOST_LOG_TRIVIAL(info) << boost::format("new_printer_name: %1%, current_printer_system_name %2%, is_bbl_vendor_preset %3%")%new_printer_name %current_printer_system_name %is_bbl_vendor_preset; + } + (dynamic_cast(print))->is_BBL_printer() = is_bbl_vendor_preset; + + //update information for brim + const PrintConfig& print_config = print_fff->config(); + Model::setExtruderParams(m_print_config, filament_count); + Model::setPrintSpeedTable(m_print_config, print_config); if (load_slicedata) { std::string plate_dir = load_slice_data_dir+"/"+std::to_string(index+1); int ret = print->load_cached_data(plate_dir); @@ -2051,19 +4353,54 @@ int CLI::run(int argc, char **argv) cli_status_callback(slicing_status); } #endif - print->process(); + print->process(nullptr, true); BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": finished print::process."; } } else { - print->process(); + print->process(&time_using_cache); + BOOST_LOG_TRIVIAL(info) << "print::process: first time_using_cache is " << time_using_cache << " secs."; } if (printer_technology == ptFFF) { - std::string conflict_result = dynamic_cast(print)->get_conflict_string(); + std::string conflict_result = print_fff->get_conflict_string(); if (!conflict_result.empty()) { BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": found slicing result conflict!"<< std::endl; + record_exit_reson(outfile_dir, CLI_GCODE_PATH_CONFLICTS, index+1, cli_errors[CLI_GCODE_PATH_CONFLICTS], sliced_info); flush_and_exit(CLI_GCODE_PATH_CONFLICTS); } + + //check the warnings + if (!g_slicing_warnings.empty()) + { + for (unsigned int i = 0; i < g_slicing_warnings.size(); i++) + { + PrintBase::SlicingStatus& status = g_slicing_warnings[i]; + if ((status.warning_step != -1) && (status.message_type != PrintStateBase::SlicingDefaultNotification)) + { + sliced_plate_info.warning_message = status.text; + + if (status.warning_level == PrintStateBase::WarningLevel::NON_CRITICAL) { + BOOST_LOG_TRIVIAL(warning) << "plate "<< index+1<< ": found NON_CRITICAL slicing warnings: "<get_tmp_gcode_path(); if (outfile_dir.empty()) { @@ -2074,7 +4411,11 @@ int CLI::run(int argc, char **argv) part_plate->set_tmp_gcode_path(outfile); } BOOST_LOG_TRIVIAL(info) << "process finished, will export gcode temporily to " << outfile << std::endl; - outfile = (dynamic_cast(print))->export_gcode(outfile, gcode_result, nullptr); + temp_time = (long long)Slic3r::Utils::get_current_time_utc(); + outfile = print_fff->export_gcode(outfile, gcode_result, nullptr); + time_using_cache = time_using_cache + ((long long)Slic3r::Utils::get_current_time_utc() - temp_time); + BOOST_LOG_TRIVIAL(info) << "export_gcode finished: time_using_cache update to " << time_using_cache << " secs."; + //outfile_final = (dynamic_cast(print))->print_statistics().finalize_output_path(outfile); //m_fff_print->export_gcode(m_temp_output_path, m_gcode_result, [this](const ThumbnailsParams& params) { return this->render_thumbnails(params); }); }/* else { @@ -2086,6 +4427,7 @@ int CLI::run(int argc, char **argv) /*if (outfile != outfile_final) { if (Slic3r::rename_file(outfile, outfile_final)) { boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; + record_exit_reson(outfile_dir, 1, index+1, cli_errors[1], sliced_info); flush_and_exit(1); } outfile = outfile_final; @@ -2110,26 +4452,35 @@ int CLI::run(int argc, char **argv) export_slicedata_error = true; if (fs::exists(plate_dir)) fs::remove_all(plate_dir); + record_exit_reson(outfile_dir, ret, index+1, cli_errors[ret], sliced_info); + flush_and_exit(ret); } } + end_time = (long long)Slic3r::Utils::get_current_time_utc(); + sliced_plate_info.sliced_time = end_time - start_time; + sliced_plate_info.sliced_time_with_cache = time_using_cache; + if (max_slicing_time_per_plate != 0) { - end_time = (long long)Slic3r::Utils::get_current_time_utc(); long long time_cost = end_time - start_time; if (time_cost > max_slicing_time_per_plate) { - BOOST_LOG_TRIVIAL(error) << boost::format("plate %1%'s slice time %2% exceeds the limit %3%, return error.") - %(index+1) %time_cost %max_slicing_time_per_plate; + sliced_plate_info.warning_message = (boost::format("plate %1%'s slice time %2% exceeds the limit %3%, return error.")%(index+1) %time_cost %max_slicing_time_per_plate).str(); + BOOST_LOG_TRIVIAL(error) << sliced_plate_info.warning_message; + sliced_info.sliced_plates.push_back(sliced_plate_info); + record_exit_reson(outfile_dir, CLI_SLICING_TIME_EXCEEDS_LIMIT, index+1, cli_errors[CLI_SLICING_TIME_EXCEEDS_LIMIT], sliced_info); flush_and_exit(CLI_SLICING_TIME_EXCEEDS_LIMIT); } } + sliced_info.sliced_plates.push_back(sliced_plate_info); } catch (const std::exception &ex) { BOOST_LOG_TRIVIAL(error) << "found slicing or export error for partplate "< 1)) pre_check = false; else finished = true; @@ -2174,10 +4525,12 @@ int CLI::run(int argc, char **argv) } } else { boost::nowide::cerr << "error: option not supported yet: " << opt_key << std::endl; + record_exit_reson(outfile_dir, CLI_UNSUPPORTED_OPERATION, 0, cli_errors[CLI_UNSUPPORTED_OPERATION], sliced_info); flush_and_exit(CLI_UNSUPPORTED_OPERATION); } } + global_begin_time = (long long)Slic3r::Utils::get_current_time_utc(); if (export_to_3mf) { //BBS: export as bbl 3mf std::vector thumbnails, top_thumbnails, pick_thumbnails; @@ -2204,11 +4557,21 @@ int CLI::run(int argc, char **argv) auto* filament_types = dynamic_cast(m_print_config.option("filament_type")); const ConfigOptionStrings* filament_color = dynamic_cast(m_print_config.option("filament_colour")); //auto* filament_id = dynamic_cast(m_print_config.option("filament_ids")); + const ConfigOptionFloats* nozzle_diameter_option = dynamic_cast(m_print_config.option("nozzle_diameter")); + std::string nozzle_diameter_str; + if (nozzle_diameter_option) + nozzle_diameter_str = nozzle_diameter_option->serialize(); for (int i = 0; i < plate_data_list.size(); i++) { PlateData *plate_data = plate_data_list[i]; bool skip_this_plate = ((plate_to_slice != 0) && (plate_to_slice != (i + 1)))?true:false; + plate_data->skipped_objects = plate_skipped_objects[i]; + if (!printer_model_id.empty()) + plate_data->printer_model_id = printer_model_id; + if (!nozzle_diameter_str.empty()) + plate_data->nozzle_diameters = nozzle_diameter_str; + for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) { //it->filament_id = filament_id?filament_id->get_at(it->id):"unknown"; std::string display_filament_type; @@ -2228,7 +4591,12 @@ int CLI::run(int argc, char **argv) } } else { - BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file exists, no need to regenerate")%(i+1); + if (regenerate_thumbnails) { + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file %2% cleared, need to regenerate")%(i+1) %plate_data->thumbnail_file; + plate_data->thumbnail_file.clear(); + } + else + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file exists, no need to regenerate")%(i+1); } } else { @@ -2254,7 +4622,13 @@ int CLI::run(int argc, char **argv) } } else { - BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s top_thumbnail file exists, no need to regenerate")%(i+1); + if (regenerate_thumbnails) { + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s top_thumbnail file %2% cleared, need to regenerate")%(i+1) %plate_data->top_file; + plate_data->top_file.clear(); + plate_data->pick_file.clear(); + } + else + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s top_thumbnail file exists, no need to regenerate")%(i+1); } } } @@ -2265,14 +4639,14 @@ int CLI::run(int argc, char **argv) colors= filament_color->vserialize(); } else - colors.push_back("#FFFFFF"); + colors.push_back("#FFFFFFFF"); std::vector colors_out(colors.size()); - ColorRGBA rgb_color; + unsigned char rgb_color[4] = {}; for (const std::string& color : colors) { - Slic3r::decode_color(color, rgb_color); + Slic3r::GUI::BitmapCache::parse_color4(color, rgb_color); size_t color_idx = &color - &colors.front(); - colors_out[color_idx] = rgb_color; + colors_out[color_idx] = ColorRGBA(float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, float(rgb_color[3]) / 255.f); } int gl_major, gl_minor, gl_verbos; @@ -2319,7 +4693,7 @@ int CLI::run(int argc, char **argv) //opengl manager related logic { Slic3r::GUI::OpenGLManager opengl_mgr; - bool opengl_valid = opengl_mgr.init_gl(); + bool opengl_valid = opengl_mgr.init_gl(false); if (!opengl_valid) { BOOST_LOG_TRIVIAL(error) << "init opengl failed! skip thumbnail generating" << std::endl; } @@ -2327,30 +4701,43 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << "glewInit Sucess." << std::endl; GLVolumeCollection glvolume_collection; Model &model = m_models[0]; - int extruder_id = 1; + int obj_extruder_id = 1, volume_extruder_id = 1; for (unsigned int obj_idx = 0; obj_idx < (unsigned int)model.objects.size(); ++ obj_idx) { const ModelObject &model_object = *model.objects[obj_idx]; const ConfigOption* option = model_object.config.option("extruder"); if (option) - extruder_id = (dynamic_cast(option))->getInt(); + obj_extruder_id = (dynamic_cast(option))->getInt(); + else + obj_extruder_id = 1; for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) { const ModelVolume &model_volume = *model_object.volumes[volume_idx]; option = model_volume.config.option("extruder"); - if (option) extruder_id = (dynamic_cast(option))->getInt(); + if (option) + volume_extruder_id = (dynamic_cast(option))->getInt(); + else + volume_extruder_id = obj_extruder_id; + + BOOST_LOG_TRIVIAL(debug) << boost::format("volume %1%'s extruder_id %2%")%volume_idx %volume_extruder_id; //if (!model_volume.is_model_part()) // continue; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, false, true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, "volume", true, false, true); //glvolume_collection.volumes.back()->geometry_id = key.geometry_id; - std::string color = filament_color?filament_color->get_at(extruder_id - 1):"#00FF00"; + std::string color = filament_color?filament_color->get_at(volume_extruder_id - 1):"#00FF00FF"; + + BOOST_LOG_TRIVIAL(debug) << boost::format("volume %1%'s color %2%")%volume_idx %color; - ColorRGBA rgb_color; - Slic3r::decode_color(color, rgb_color); - glvolume_collection.volumes.back()->set_render_color(rgb_color); + unsigned char rgb_color[4] = {}; + Slic3r::GUI::BitmapCache::parse_color4(color, rgb_color); ColorRGBA new_color; - new_color = rgb_color; + new_color.r(float(rgb_color[0]) / 255.f); + new_color.g(float(rgb_color[1]) / 255.f); + new_color.b(float(rgb_color[2]) / 255.f); + new_color.a(float(rgb_color[3]) / 255.f); + + glvolume_collection.volumes.back()->set_render_color(new_color); glvolume_collection.volumes.back()->set_color(new_color); glvolume_collection.volumes.back()->printable = model_instance.printable; } @@ -2371,8 +4758,9 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, reset plate %2%'s thumbnail.")%__LINE__%(i+1); plate_data->plate_thumbnail.reset(); } - else + else { BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail, width %2%, height %3%, directly using it")%(i+1) %plate_data->plate_thumbnail.width %plate_data->plate_thumbnail.height; + } } else if (!plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))) { @@ -2380,8 +4768,17 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, clear plate %2%'s thumbnail file path to empty.")%__LINE__%(i+1); plate_data->thumbnail_file.clear(); } - else + else { BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail %2% extracted from 3mf, directly using it")%(i+1) %plate_data->thumbnail_file; + int dec_ret = decode_png_to_thumbnail(plate_data->thumbnail_file, plate_data->plate_thumbnail); + if (!dec_ret) + { + BOOST_LOG_TRIVIAL(info) << boost::format("decode png to mem sucess."); + } + else { + BOOST_LOG_TRIVIAL(warning) << boost::format("decode png to mem failed."); + } + } } else { ThumbnailData* thumbnail_data = &plate_data->plate_thumbnail; @@ -2514,7 +4911,7 @@ int CLI::run(int argc, char **argv) glfwTerminate(); } else { - BOOST_LOG_TRIVIAL(info) << boost::format("use previous thumbnails, no need to regenerate"); + BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: use previous thumbnails, no need to regenerate")%__LINE__; for (int i = 0; i < partplate_list.get_plate_count(); i++) { PlateData *plate_data = plate_data_list[i]; bool skip_this_plate = ((plate_to_slice != 0) && (plate_to_slice != (i + 1)))?true:false; @@ -2529,6 +4926,24 @@ int CLI::run(int argc, char **argv) plate_data->top_file.clear(); plate_data->pick_file.clear(); } + else if (!plate_data->plate_thumbnail.is_valid() && !plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))) + { + BOOST_LOG_TRIVIAL(info) << boost::format("no need to generate: plate %1% has a valid thumbnail %2% extracted from 3mf, convert to data")%(i+1) %plate_data->thumbnail_file; + int dec_ret = decode_png_to_thumbnail(plate_data->thumbnail_file, plate_data->plate_thumbnail); + if (!dec_ret) + { + BOOST_LOG_TRIVIAL(info) << boost::format("decode png to mem sucess."); + need_create_thumbnail_group = true; + } + else { + BOOST_LOG_TRIVIAL(warning) << boost::format("decode png to mem failed."); + } + } + } + + for (int i = 0; i < partplate_list.get_plate_count(); i++) { + PlateData *plate_data = plate_data_list[i]; + Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i); if (need_create_thumbnail_group) { thumbnails.push_back(&plate_data->plate_thumbnail); @@ -2631,8 +5046,6 @@ int CLI::run(int argc, char **argv) BBoxData data; auto bb_scaled = obj->get_first_layer_bbox(data.area, data.layer_height, data.name); auto bb = unscaled(bb_scaled); - bb.min -= orig2d; - bb.max -= orig2d; bbox_all.merge(bb); data.area *= (SCALING_FACTOR * SCALING_FACTOR); // unscale area data.id = obj->id().id; @@ -2676,12 +5089,13 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << "will export 3mf to " << export_3mf_file << std::endl; if (! this->export_project(&m_models[0], export_3mf_file, plate_data_list, project_presets, thumbnails, top_thumbnails, pick_thumbnails, - calibration_thumbnails, plate_bboxes, &m_print_config)) + calibration_thumbnails, plate_bboxes, &m_print_config, minimum_save, plate_to_slice - 1)) { release_PlateData_list(plate_data_list); + record_exit_reson(outfile_dir, CLI_EXPORT_3MF_ERROR, 0, cli_errors[CLI_EXPORT_3MF_ERROR], sliced_info); flush_and_exit(CLI_EXPORT_3MF_ERROR); } - release_PlateData_list(plate_data_list); + for (unsigned int i = 0; i < thumbnails.size(); i++) thumbnails[i]->reset(); for (unsigned int i = 0; i < top_thumbnails.size(); i++) @@ -2689,6 +5103,8 @@ int CLI::run(int argc, char **argv) for (unsigned int i = 0; i < pick_thumbnails.size(); i++) pick_thumbnails[i]->reset(); + release_PlateData_list(plate_data_list); + for (unsigned int i = 0; i < calibration_thumbnails.size(); i++) delete calibration_thumbnails[i]; @@ -2715,6 +5131,19 @@ int CLI::run(int argc, char **argv) } //BBS: flush logs BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl; + global_current_time = (long long)Slic3r::Utils::get_current_time_utc(); + sliced_info.export_time = (size_t) (global_current_time - global_begin_time); + + //record the duplicate here + if (duplicate_count > 0) + { + record_key_values["sliced_count"] = std::to_string(duplicate_count+1); + record_exit_reson(outfile_dir, 0, plate_to_slice, cli_errors[0], sliced_info, record_key_values); + } + else { + record_exit_reson(outfile_dir, 0, plate_to_slice, cli_errors[0], sliced_info); + } + boost::nowide::cout.flush(); boost::nowide::cerr.flush(); @@ -2798,7 +5227,7 @@ bool CLI::setup(int argc, char **argv) for (const t_optiondef_map::value_type &optdef : *options) m_config.option(optdef.first, true); - set_data_dir(m_config.opt_string("datadir")); + //set_data_dir(m_config.opt_string("datadir")); //FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet. if (!validity.empty()) { @@ -2814,7 +5243,7 @@ bool CLI::setup(int argc, char **argv) void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const { boost::nowide::cout - << SLIC3R_APP_KEY <<"-"<< SoftFever_VERSION << ":" + << SLIC3R_APP_KEY <<"-"<< SLIC3R_VERSION << ":" << std::endl << "Usage: orca-slicer [ OPTIONS ] [ file.3mf/file.stl ... ]" << std::endl << std::endl @@ -2845,21 +5274,38 @@ bool CLI::export_models(IO::ExportFormat format) { for (Model &model : m_models) { const std::string path = this->output_filepath(model, format); - bool success = false; + bool success = true; switch (format) { //case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr, false); break; - case IO::OBJ: success = Slic3r::store_obj(path.c_str(), &model); break; - case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break; + case IO::OBJ: + success = Slic3r::store_obj(path.c_str(), &model); + if (success) + BOOST_LOG_TRIVIAL(info) << "Model successfully exported to " << path << std::endl; + else { + boost::nowide::cerr << "Model export to " << path << " failed" << std::endl; + return false; + } + break; + case IO::STL: + { + unsigned int index = 1; + for (ModelObject* model_object : model.objects) + { + const std::string path = this->output_filepath(*model_object, index++, format); + success = Slic3r::store_stl(path.c_str(), model_object, true); + if (success) + BOOST_LOG_TRIVIAL(info) << "Model successfully exported to " << path << std::endl; + else { + boost::nowide::cerr << "Model export to " << path << " failed" << std::endl; + return false; + } + } + break; + } //BBS: use bbs 3mf instead of original //case IO::TMF: success = Slic3r::store_bbs_3mf(path.c_str(), &model, nullptr, false); break; default: assert(false); break; } - if (success) - BOOST_LOG_TRIVIAL(info) << "Model exported to " << path << std::endl; - else { - boost::nowide::cerr << "Model export to " << path << " failed" << std::endl; - return false; - } } return true; } @@ -2867,7 +5313,7 @@ bool CLI::export_models(IO::ExportFormat format) //BBS: add export_project function bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data, std::vector& project_presets, std::vector& thumbnails, std::vector& top_thumbnails, std::vector& pick_thumbnails, - std::vector& calibration_thumbnails, std::vector& plate_bboxes, const DynamicPrintConfig* config) + std::vector& calibration_thumbnails, std::vector& plate_bboxes, const DynamicPrintConfig* config, bool minimum_save, int plate_to_export) { //const std::string path = this->output_filepath(*model, IO::TMF); bool success = false; @@ -2883,7 +5329,10 @@ bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partpla store_params.pick_thumbnail_data = pick_thumbnails; store_params.calibration_thumbnail_data = calibration_thumbnails; store_params.id_bboxes = plate_bboxes; - store_params.strategy = SaveStrategy::Silence|SaveStrategy::WithGcode|SaveStrategy::SplitModel|SaveStrategy::UseLoadedId; + store_params.strategy = SaveStrategy::Silence|SaveStrategy::WithGcode|SaveStrategy::SplitModel|SaveStrategy::UseLoadedId|SaveStrategy::ShareMesh; + store_params.export_plate_idx = plate_to_export; + if (minimum_save) + store_params.strategy = store_params.strategy | SaveStrategy::SkipModel; success = Slic3r::store_bbs_3mf(store_params); @@ -2908,7 +5357,7 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co }; auto proposed_path = boost::filesystem::path(model.propose_export_file_name_and_path(ext)); // use --output when available - std::string cmdline_param = m_config.opt_string("output"); + std::string cmdline_param = m_config.opt_string("outputdir"); if (! cmdline_param.empty()) { // if we were supplied a directory, use it and append our automatically generated filename boost::filesystem::path cmdline_path(cmdline_param); @@ -2920,6 +5369,50 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co return proposed_path.string(); } +std::string CLI::output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format) const +{ + std::string ext, subdir, file_name, output_path; + switch (format) { + case IO::AMF: + ext = ".zip.amf"; + subdir = "amf"; + break; + case IO::OBJ: + ext = ".obj"; + subdir = "obj"; + break; + case IO::STL: + ext = ".stl"; + subdir = "stl"; + break; + case IO::TMF: + ext = ".3mf"; + subdir = "3mf"; + break; + default: assert(false); break; + }; + // use --outputdir when available + file_name = object.name.empty()?object.input_file:object.name; + file_name = "obj_"+std::to_string(index)+"_"+file_name; + size_t pos = file_name.find_last_of(ext), ext_pos = file_name.size() - 1; + if (pos != ext_pos) + file_name += ext; + + BOOST_LOG_TRIVIAL(trace) << __FUNCTION__ << ": file_name="< //#pragma comment(lib, "version.lib") @@ -2993,8 +5486,20 @@ extern "C" { #if BBL_RELEASE_TO_PUBLIC SET_DEFULTER_HANDLER(); #else - AddVectoredExceptionHandler(1, CBaseException::UnhandledExceptionFilter); + //AddVectoredExceptionHandler(1, CBaseException::UnhandledExceptionFilter); + SET_DEFULTER_HANDLER(); #endif + std::set_new_handler([]() { + int smallSize = 10 * 1024 * 1024; + int *test_apply = (int *) malloc(smallSize); + if (test_apply == NULL) { + throw std::bad_alloc(); + } else { + free(test_apply); + int *a = nullptr; + *a = 0; + } + }); // Call the UTF8 main. return CLI().run(argc, argv_ptrs.data()); } diff --git a/src/OrcaSlicer.hpp b/src/OrcaSlicer.hpp index c7fc5ae3e12..6f174f3cef8 100644 --- a/src/OrcaSlicer.hpp +++ b/src/OrcaSlicer.hpp @@ -17,6 +17,44 @@ namespace IO { }; } +#define JSON_ASSEMPLE_PLATES "plates" +#define JSON_ASSEMPLE_PLATE_PARAMS "plate_params" +#define JSON_ASSEMPLE_PLATE_NAME "plate_name" +#define JSON_ASSEMPLE_PLATE_NEED_ARRANGE "need_arrange" +#define JSON_ASSEMPLE_OBJECTS "objects" +#define JSON_ASSEMPLE_OBJECT_PATH "path" +#define JSON_ASSEMPLE_OBJECT_COUNT "count" +#define JSON_ASSEMPLE_OBJECT_FILAMENTS "filaments" +#define JSON_ASSEMPLE_OBJECT_POS_X "pos_x" +#define JSON_ASSEMPLE_OBJECT_POS_Y "pos_y" +#define JSON_ASSEMPLE_OBJECT_POS_Z "pos_z" +#define JSON_ASSEMPLE_OBJECT_ASSEMBLE_INDEX "assemble_index" +#define JSON_ASSEMPLE_OBJECT_PRINT_PARAMS "print_params" + + +typedef struct _assemble_object_info { + std::string path; + int count; + + std::vector filaments; + std::vector assemble_index; + std::vector pos_x; + std::vector pos_y; + std::vector pos_z; + std::map print_params; +}assemble_object_info_t; + +typedef struct _assemble_plate_info { + std::string plate_name; + bool need_arrange {false}; + int filaments_count {0}; + + std::map plate_params; + std::vector assemble_obj_list; + std::vector loaded_obj_list; +}assemble_plate_info_t; + + class CLI { public: int run(int argc, char **argv); @@ -41,11 +79,12 @@ class CLI { bool export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data, std::vector& project_presets, std::vector& thumbnails, std::vector& top_thumbnails, std::vector& pick_thumbnails, std::vector& calibration_thumbnails, - std::vector& plate_bboxes, const DynamicPrintConfig* config); + std::vector& plate_bboxes, const DynamicPrintConfig* config, bool minimum_save, int plate_to_export = -1); bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); } std::string output_filepath(const Model &model, IO::ExportFormat format) const; + std::string output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format) const; }; } diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 65527e6f6b1..2593777969c 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -45,7 +45,7 @@ typedef Eigen::Matrix stl_triangle_vertex_indices static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect"); static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect"); -typedef std::function ImportstlProgressFn; +typedef std::function ImportstlProgressFn; typedef enum { eNormal, // normal face @@ -157,6 +157,7 @@ struct stl_file { return sizeof(*this) + sizeof(stl_facet) * facet_start.size() + sizeof(stl_neighbors) * neighbors_start.size(); } + char mw_data[256]; std::vector facet_start; std::vector neighbors_start; // Statistics @@ -275,7 +276,6 @@ extern void stl_mirror_yz(stl_file *stl); extern void stl_mirror_xz(stl_file *stl); extern float get_area(stl_facet* facet); - extern void stl_get_size(stl_file *stl); // the following function is not used diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index f1be4ac77c7..ec044f87e54 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -44,6 +44,7 @@ extern void stl_internal_reverse_quads(char *buf, size_t cnt); #endif /* BOOST_ENDIAN_BIG_BYTE */ const int LOAD_STL_UNIT_NUM = 5; +static std::string model_id = ""; static FILE* stl_open_count_facets(stl_file *stl, const char *file) { @@ -150,31 +151,66 @@ static FILE* stl_open_count_facets(stl_file *stl, const char *file) time running this for the stl and therefore we should reset our max and min stats. */ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, ImportstlProgressFn stlFn) { - if (stl->stats.type == binary) - fseek(fp, HEADER_SIZE, SEEK_SET); - else - rewind(fp); + if (stl->stats.type == binary) { + fseek(fp, HEADER_SIZE, SEEK_SET); + } + else { + rewind(fp); + try{ + char solid_name[256]; + int res_solid = fscanf(fp, " solid %[^\n]", solid_name); + if (res_solid == 1) { + char* mw_position = strstr(solid_name, "MW"); + if (mw_position != NULL) { + // Extract the value after "MW" + char version_str[16]; + char model_id_str[128]; + int num_values = sscanf(mw_position + 3, "%s %s", version_str, model_id_str); + if (num_values == 2) { + if (strcmp(version_str, "1.0") == 0) { + model_id = model_id_str; + } + } + else { + model_id = ""; + } + } + else { + model_id = ""; // No MW format found + } + } + } + catch (...){ + } + + rewind(fp); + } + char normal_buf[3][32]; uint32_t facets_num = stl->stats.number_of_facets; uint32_t unit = facets_num / LOAD_STL_UNIT_NUM + 1; for (uint32_t i = first_facet; i < facets_num; ++ i) { - if ((i % unit) == 0) { - bool cb_cancel = false; - if (stlFn) { - stlFn(i, facets_num, cb_cancel); - if (cb_cancel) - return false; - } - } + if ((i % unit) == 0) { + bool cb_cancel = false; + if (stlFn) { + stlFn(i, facets_num, cb_cancel, model_id); + if (cb_cancel) + return false; + } + } stl_facet facet; if (stl->stats.type == binary) { + + // Read a single facet from a binary .STL file. We assume little-endian architecture! if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET) return false; + + #if BOOST_ENDIAN_BIG_BYTE // Convert the loaded little endian data to big endian. stl_internal_reverse_quads((char*)&facet, 48); @@ -237,11 +273,21 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first, Impor } #endif - // Write the facet into memory. + // Write the facet into memory if none of facet vertices is NAN. + bool someone_is_nan = false; + for (size_t j = 0; j < 3; ++j) { + if (isnan(facet.vertex[j](0)) || isnan(facet.vertex[j](1)) || isnan(facet.vertex[j](2))) { + someone_is_nan = true; + break; + } + } + if(someone_is_nan) + continue; + stl->facet_start[i] = facet; stl_facet_stats(stl, facet, first); } - + stl->stats.size = stl->stats.max - stl->stats.min; stl->stats.bounding_diameter = stl->stats.size.norm(); return true; diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index 9380ea16498..aa8a061bf86 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -172,6 +172,7 @@ namespace ImGui const wchar_t UnfoldButtonIcon = 0x0815; const wchar_t SphereButtonIcon = 0x0816; const wchar_t GapFillIcon = 0x0817; + const wchar_t ConfirmIcon = 0x0818; const wchar_t MinimalizeDarkButton = 0x081C; const wchar_t MinimalizeHoverDarkButton = 0x081D; @@ -186,6 +187,7 @@ namespace ImGui const wchar_t HeightRangeDarkIcon = 0x0825; const wchar_t SphereButtonDarkIcon = 0x0826; const wchar_t GapFillDarkIcon = 0x0827; + const wchar_t ConfirmDarkIcon = 0x0828; const wchar_t TextSearchIcon = 0x0828; const wchar_t TextSearchCloseIcon = 0x0829; @@ -199,6 +201,15 @@ namespace ImGui const wchar_t BlockNotifErrorIcon = 0x0835; const wchar_t ClipboardBtnDarkIcon = 0x0836; + const wchar_t PrevArrowBtnIcon = 0x0836; + const wchar_t PrevArrowHoverBtnIcon = 0x0837; + const wchar_t NextArrowBtnIcon = 0x0838; + const wchar_t NextArrowHoverBtnIcon = 0x0839; + const wchar_t OpenArrowIcon = 0x0840; + const wchar_t CollapseArrowIcon = 0x0841; + const wchar_t ExpandArrowIcon = 0x0842; + const wchar_t CompleteIcon = 0x0843; + // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/imgui/imgui_widgets.cpp b/src/imgui/imgui_widgets.cpp index 21e7a9142ce..b09b09abca8 100644 --- a/src/imgui/imgui_widgets.cpp +++ b/src/imgui/imgui_widgets.cpp @@ -41,7 +41,7 @@ Index of this file: #include "imgui_internal.h" #include - +#include // System includes #include // toupper #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier @@ -3070,6 +3070,9 @@ bool ImGui::BBLDragFloat(const char *label, float *v, float v_speed, float v_min ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.00f, 0.59f, 0.53f, 0.00f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.00f, 0.59f, 0.53f, 0.00f)); bool bbl_drag_scalar = BBLDragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags); + if (v_max > v_min + 0.001) { + *v = std::clamp(*v, v_min, v_max); + } ImGui::PopStyleColor(3); return bbl_drag_scalar; } diff --git a/src/libslic3r/AStar.hpp b/src/libslic3r/AStar.hpp new file mode 100644 index 00000000000..a7d9e7b8f9b --- /dev/null +++ b/src/libslic3r/AStar.hpp @@ -0,0 +1,157 @@ +#ifndef ASTAR_HPP +#define ASTAR_HPP + +#include // std::isinf() is here +#include + +#include "libslic3r/MutablePriorityQueue.hpp" + +namespace Slic3r { namespace astar { + +// Borrowed from C++20 +template using remove_cvref_t = std::remove_cv_t>; + +// Input interface for the Astar algorithm. Specialize this struct for a +// particular type and implement all the 4 methods and specify the Node type +// to register the new type for the astar implementation. +template struct TracerTraits_ +{ + // The type of a node used by this tracer. Usually a point in space. + using Node = typename T::Node; + + // Call fn for every new node reachable from node 'src'. fn should have the + // candidate node as its only argument. + template static void foreach_reachable(const T &tracer, const Node &src, Fn &&fn) { tracer.foreach_reachable(src, fn); } + + // Get the distance from node 'a' to node 'b'. This is sometimes referred + // to as the g value of a node in AStar context. + static float distance(const T &tracer, const Node &a, const Node &b) { return tracer.distance(a, b); } + + // Get the estimated distance heuristic from node 'n' to the destination. + // This is referred to as the h value in AStar context. + // If node 'n' is the goal, this function should return a negative value. + // Note that this heuristic should be admissible (never bigger than the real + // cost) in order for Astar to work. + static float goal_heuristic(const T &tracer, const Node &n) { return tracer.goal_heuristic(n); } + + // Return a unique identifier (hash) for node 'n'. + static size_t unique_id(const T &tracer, const Node &n) { return tracer.unique_id(n); } +}; + +// Helper definition to get the node type of a tracer +template using TracerNodeT = typename TracerTraits_>::Node; + +constexpr auto Unassigned = std::numeric_limits::max(); + +template struct QNode // Queue node. Keeps track of scores g, and h +{ + TracerNodeT node; // The actual node itself + size_t queue_id; // Position in the open queue or Unassigned if closed + size_t parent; // unique id of the parent or Unassigned + + float g, h; + float f() const { return g + h; } + + QNode(TracerNodeT n = {}, size_t p = Unassigned, float gval = std::numeric_limits::infinity(), float hval = 0.f) + : node{std::move(n)}, parent{p}, queue_id{InvalidQueueID}, g{gval}, h{hval} + {} +}; + +// Run the AStar algorithm on a tracer implementation. +// The 'tracer' argument encapsulates the domain (grid, point cloud, etc...) +// The 'source' argument is the starting node. +// The 'out' argument is the output iterator into which the output nodes are +// written. For performance reasons, the order is reverse, from the destination +// to the source -- (destination included, source is not). +// The 'cached_nodes' argument is an optional associative container to hold a +// QNode entry for each visited node. Any compatible container can be used +// (like std::map or maps with different allocators, even a sufficiently large +// std::vector). +// +// Note that no destination node is given in the signature. The tracer's +// goal_heuristic() method should return a negative value if a node is a +// destination node. +template>> +bool search_route(const Tracer &tracer, const TracerNodeT &source, It out, NodeMap &&cached_nodes = {}) +{ + using Node = TracerNodeT; + using QNode = QNode; + using TracerTraits = TracerTraits_>; + + struct LessPred + { // Comparison functor needed by the priority queue + NodeMap &m; + bool operator()(size_t node_a, size_t node_b) { return m[node_a].f() < m[node_b].f(); } + }; + + auto qopen = make_mutable_priority_queue([&cached_nodes](size_t el, size_t qidx) { cached_nodes[el].queue_id = qidx; }, LessPred{cached_nodes}); + + QNode initial{source, /*parent = */ Unassigned, /*g = */ 0.f}; + size_t source_id = TracerTraits::unique_id(tracer, source); + cached_nodes[source_id] = initial; + qopen.push(source_id); + + size_t goal_id = TracerTraits::goal_heuristic(tracer, source) < 0.f ? source_id : Unassigned; + + while (goal_id == Unassigned && !qopen.empty()) { + size_t q_id = qopen.top(); + qopen.pop(); + QNode &q = cached_nodes[q_id]; + + // This should absolutely be initialized in the cache already + assert(!std::isinf(q.g)); + + TracerTraits::foreach_reachable(tracer, q.node, [&](const Node &succ_nd) { + if (goal_id != Unassigned) return true; + + float h = TracerTraits::goal_heuristic(tracer, succ_nd); + float dst = TracerTraits::distance(tracer, q.node, succ_nd); + size_t succ_id = TracerTraits::unique_id(tracer, succ_nd); + QNode qsucc_nd{succ_nd, q_id, q.g + dst, h}; + + if (h < 0.f) { + goal_id = succ_id; + cached_nodes[succ_id] = qsucc_nd; + } else { + // If succ_id is not in cache, it gets created with g = infinity + QNode &prev_nd = cached_nodes[succ_id]; + + if (qsucc_nd.g < prev_nd.g) { + // new route is better, apply it: + + // Save the old queue id, it would be lost after the next line + size_t queue_id = prev_nd.queue_id; + + // The cache needs to be updated either way + prev_nd = qsucc_nd; + + if (queue_id == InvalidQueueID) + // was in closed or unqueued, rescheduling + qopen.push(succ_id); + else // was in open, updating + qopen.update(queue_id); + } + } + + return goal_id != Unassigned; + }); + } + + // Write the output, do not reverse. Clients can do so if they need to. + if (goal_id != Unassigned) { + const QNode *q = &cached_nodes[goal_id]; + while (q->parent != Unassigned) { + assert(!std::isinf(q->g)); // Uninitialized nodes are NOT allowed + + *out = q->node; + ++out; + q = &cached_nodes[q->parent]; + } + } + + return goal_id != Unassigned; +} + +}} // namespace Slic3r::astar + +#endif // ASTAR_HPP diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 94f1735ce96..665fb077186 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -255,6 +255,10 @@ void AppConfig::set_defaults() if (get("show_daily_tips").empty()) { set_bool("show_daily_tips", true); } + //true is auto calculate + if (get("auto_calculate").empty()) { + set_bool("auto_calculate", true); + } if (get("show_home_page").empty()) { set_bool("show_home_page", true); @@ -998,7 +1002,7 @@ void AppConfig::set_vendors(const AppConfig &from) m_dirty = true; } -void AppConfig::save_printer_cali_infos(const PrinterCaliInfo &cali_info) +void AppConfig::save_printer_cali_infos(const PrinterCaliInfo &cali_info, bool need_change_status) { auto iter = std::find_if(m_printer_cali_infos.begin(), m_printer_cali_infos.end(), [&cali_info](const PrinterCaliInfo &cali_info_item) { return cali_info_item.dev_id == cali_info.dev_id; @@ -1007,7 +1011,9 @@ void AppConfig::save_printer_cali_infos(const PrinterCaliInfo &cali_info) if (iter == m_printer_cali_infos.end()) { m_printer_cali_infos.emplace_back(cali_info); } else { - (*iter).cali_finished = cali_info.cali_finished; + if (need_change_status) { + (*iter).cali_finished = cali_info.cali_finished; + } (*iter).cache_flow_ratio = cali_info.cache_flow_ratio; (*iter).selected_presets = cali_info.selected_presets; } diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp index 42614bd7db5..dfcc246580f 100644 --- a/src/libslic3r/AppConfig.hpp +++ b/src/libslic3r/AppConfig.hpp @@ -209,7 +209,7 @@ class AppConfig } const std::vector &get_printer_cali_infos() const { return m_printer_cali_infos; } - void save_printer_cali_infos(const PrinterCaliInfo& cali_info); + void save_printer_cali_infos(const PrinterCaliInfo& cali_info, bool need_change_status = true); // return recent/last_opened_folder or recent/settings_folder or empty string. std::string get_last_dir() const; diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 612a2b864bd..5b4aee507f1 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -228,16 +228,23 @@ void update_selected_items_axis_align(ArrangePolygons& selected, const DynamicPr double c = m02 / m00 - cy * cy; //if a and c are close, there is no dominant axis, then do not rotate - if (std::abs(a) < 1.5*std::abs(c) && std::abs(c) < 1.5*std::abs(a)) { + // ratio is always no more than 1 + double ratio = std::abs(a) > std::abs(c) ? std::abs(c / a) : + std::abs(c) > 0 ? std::abs(a / c) : 0; + if (ratio>0.66) { validResult = false; } else { angle = std::atan2(2 * b, (a - c)) / 2; + angle = PI / 2 - angle; + // if the angle is close to PI or -PI, it means the object is vertical, then do not rotate + if (std::abs(std::abs(angle) - PI) < 0.01) + angle = 0; validResult = true; } } } - if (validResult) { ap.rotation += (PI / 2 - angle); } + if (validResult) { ap.rotation += angle; } } } @@ -406,6 +413,18 @@ class AutoArranger { return bindist; } + double dist_to_bin(const Box& ibb, const ClipperLib::IntPoint& origin_pack, typename Packer::PlacementConfig::Alignment starting_point_alignment) + { + double bindist = 0; + if (starting_point_alignment == PConfig::Alignment::BOTTOM_LEFT) + bindist = norm(pl::distance(ibb.minCorner(), origin_pack)); + else if (starting_point_alignment == PConfig::Alignment::TOP_RIGHT) + bindist = norm(pl::distance(ibb.maxCorner(), origin_pack)); + else + bindist = norm(pl::distance(ibb.center(), origin_pack)); + return bindist; + } + // This is "the" object function which is evaluated many times for each // vertex (decimated with the accuracy parameter) of each object. // Therefore it is upmost crucial for this function to be as efficient @@ -488,7 +507,7 @@ class AutoArranger { score = 0.2 * dist + 0.8 * bindist; } else { - double bindist = norm(pl::distance(ibb.center(), origin_pack)); + double bindist = dist_to_bin(ibb, origin_pack, m_pconf.starting_point); dist = 0.8 * dist + 0.2 * bindist; @@ -520,11 +539,13 @@ class AutoArranger { auto ascore = 1.0 - (item.area() + parea) / bbarea; if (ascore < alignment_score) alignment_score = ascore; - } } + } density = std::sqrt(norm(fullbb.width()) * norm(fullbb.height())); double R = double(m_remaining.size()) / m_item_count; + // alighment score is more important for rectangle items + double alignment_weight = std::max(0.3, 0.6 * item.area() / ibb.area()); // The final mix of the score is the balance between the // distance from the full pile center, the pack density and @@ -533,8 +554,8 @@ class AutoArranger { score = 0.50 * dist + 0.50 * density; else // Let the density matter more when fewer objects remain - score = 0.50 * dist + (1.0 - R) * 0.20 * density + - 0.30 * alignment_score; + score = (1 - 0.2 - alignment_weight) * dist + (1.0 - R) * 0.20 * density + + alignment_weight * alignment_score; } break; } @@ -814,7 +835,8 @@ class AutoArranger { template<> std::function AutoArranger::get_objfn() { - auto origin_pack = m_pconf.starting_point == PConfig::Alignment::CENTER ? m_bin.center() : m_bin.minCorner(); + auto origin_pack = m_pconf.starting_point == PConfig::Alignment::CENTER ? m_bin.center() : + m_pconf.starting_point == PConfig::Alignment::TOP_RIGHT ? m_bin.maxCorner() : m_bin.minCorner(); return [this, origin_pack](const Item &itm, const ItemGroup&) { auto result = objfunc(itm, origin_pack); diff --git a/src/libslic3r/BuildVolume.cpp b/src/libslic3r/BuildVolume.cpp index 05274c0b61a..f6547e2b3dc 100644 --- a/src/libslic3r/BuildVolume.cpp +++ b/src/libslic3r/BuildVolume.cpp @@ -419,4 +419,15 @@ std::string_view BuildVolume::type_name(BuildVolume_Type type) return {}; } +indexed_triangle_set BuildVolume::bounding_mesh(bool scale) const +{ + auto max_pt3 = m_bboxf.max; + if (scale) { + return its_make_cube(scale_(max_pt3.x()), scale_(max_pt3.y()), scale_(max_pt3.z())); + } + else { + return its_make_cube(max_pt3.x(), max_pt3.y(), max_pt3.z()); + } +} + } // namespace Slic3r diff --git a/src/libslic3r/BuildVolume.hpp b/src/libslic3r/BuildVolume.hpp index 0df41f1be55..f513356002b 100644 --- a/src/libslic3r/BuildVolume.hpp +++ b/src/libslic3r/BuildVolume.hpp @@ -52,6 +52,7 @@ class BuildVolume // Bounding volume of printable_area(), printable_height(), unscaled. const BoundingBoxf3& bounding_volume() const { return m_bboxf; } BoundingBoxf bounding_volume2d() const { return { to_2d(m_bboxf.min), to_2d(m_bboxf.max) }; } + indexed_triangle_set bounding_mesh(bool scale=true) const; // Center of the print bed, unscaled. Vec2d bed_center() const { return to_2d(m_bboxf.center()); } diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 01347071786..d5a020e05cd 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -304,7 +304,7 @@ set(lisbslic3r_sources PrincipalComponents2D.hpp SupportSpotsGenerator.cpp SupportSpotsGenerator.hpp - TreeSupport.hpp + TreeSupport.hpp TreeSupport.cpp MinimumSpanningTree.hpp MinimumSpanningTree.cpp diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 03e7000c85e..567e736e698 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -308,6 +308,7 @@ ConfigOption* ConfigOptionDef::create_default_option() const opt->keys_map = this->enum_keys_map; return opt; } + delete dft; } return this->default_value->clone(); @@ -782,6 +783,8 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex json j; std::list different_settings_append; std::string new_support_style; + std::string is_infill_first; + std::string get_wall_sequence; bool is_project_settings = false; CNumericLocalesSetter locales_setter; @@ -845,6 +848,16 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex different_settings_append.push_back("support_style"); new_support_style = "tree_hybrid"; } + } else if (opt_key == "wall_infill_order") { + //BBS: check wall_infill order to decide if it be different and append to diff_setting_append + if (it.value() == "outer wall/inner wall/infill" || it.value() == "infill/outer wall/inner wall" || it.value() == "inner-outer-inner wall/infill") { + get_wall_sequence = "wall_seq_diff_to_system"; + } + + if (it.value() == "infill/outer wall/inner wall" || it.value() == "infill/inner wall/outer wall") { + different_settings_append.push_back("is_infill_first"); + is_infill_first = "true"; + } } } else if (it.value().is_array()) { @@ -916,6 +929,12 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex ConfigOptionEnum* opt = this->option>("support_style", true); opt->value = smsTreeHybrid; } + + if (!is_infill_first.empty()) { + ConfigOptionBool *opt = this->option("is_infill_first", true); + opt->value = true; + } + if (is_project_settings) { std::vector& different_settings = this->option("different_settings_to_system", true)->values; size_t size = different_settings.size(); @@ -932,6 +951,25 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex is_first[index] = true; } else { + // remove unneeded key + if (get_wall_sequence.empty()) { + std::string wall_sqe_string = "wall_sequence"; + int pos=different_settings[index].find(wall_sqe_string); + + if (pos != different_settings[index].npos) { + int erase_len = wall_sqe_string.size(); + if (pos + erase_len < different_settings[index].size() && different_settings[index][pos + erase_len] == ';') + erase_len++; + different_settings[index].erase(pos, erase_len); + } + + } + + if (different_settings[index].empty()) { + is_first[index] = true; + continue; + } + Slic3r::unescape_strings_cstyle(different_settings[index], original_diffs[index]); } } @@ -945,6 +983,8 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex index = 0; else if (diff_key == "support_style") index = 0; + else if (diff_key == "is_infill_first") + index = 0; //check whether exist firstly if (!original_diffs[index].empty()) { diff --git a/src/libslic3r/CutUtils.cpp b/src/libslic3r/CutUtils.cpp index cdda3097aca..f847c7ad738 100644 --- a/src/libslic3r/CutUtils.cpp +++ b/src/libslic3r/CutUtils.cpp @@ -445,6 +445,11 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector parts, int dowe ModelObject* lower{ nullptr }; if (m_attributes.has(ModelObjectCutAttribute::KeepLower)) cut_mo->clone_for_cut(&lower); + if (upper && lower) { + upper->name = upper->name + "_A"; + lower->name = lower->name + "_B"; + } + const size_t cut_parts_cnt = parts.size(); bool has_modifiers = false; @@ -527,6 +532,10 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran ModelObject* lower{ nullptr }; cut_mo->clone_for_cut(&lower); + if (upper && lower) { + upper->name = upper->name + "_A"; + lower->name = lower->name + "_B"; + } const double groove_half_depth = 0.5 * double(groove.depth); Model tmp_model_for_cut = Model(); diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp index e6ae1edd4d3..9a37ff3ac12 100644 --- a/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/src/libslic3r/ExtrusionEntityCollection.cpp @@ -26,6 +26,7 @@ ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths ExtrusionEntityCollection& ExtrusionEntityCollection::operator=(const ExtrusionEntityCollection &other) { + clear(); this->entities = other.entities; for (size_t i = 0; i < this->entities.size(); ++i) this->entities[i] = this->entities[i]->clone(); diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 4a6d09e0cc0..ea7b24709d9 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -1095,7 +1095,7 @@ void Layer::make_ironing() // Create the filler object. f->spacing = ironing_params.line_spacing; - f->angle = float(ironing_params.angle + 0.25 * M_PI); + f->angle = float(ironing_params.angle); f->link_max_length = (coord_t) scale_(3. * f->spacing); double extrusion_height = ironing_params.height * f->spacing / nozzle_dmr; float extrusion_width = Flow::rounded_rectangle_extrusion_width_from_spacing(float(nozzle_dmr), float(extrusion_height)); diff --git a/src/libslic3r/Format/STL.cpp b/src/libslic3r/Format/STL.cpp index 3ba514dc9ba..133a7a5056e 100644 --- a/src/libslic3r/Format/STL.cpp +++ b/src/libslic3r/Format/STL.cpp @@ -17,6 +17,8 @@ namespace Slic3r { bool load_stl(const char *path, Model *model, const char *object_name_in, ImportstlProgressFn stlFn) { TriangleMesh mesh; + std::string design_id; + if (! mesh.ReadSTLFile(path, true, stlFn)) { // die "Failed to open $file\n" if !-e $path; return false; @@ -59,4 +61,4 @@ bool store_stl(const char *path, Model *model, bool binary) return store_stl(path, &mesh, binary); } -}; // namespace Slic3r +}; // namespace Slic3r \ No newline at end of file diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index c616d0f1b4d..3e35e5e07c4 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -276,6 +276,7 @@ static constexpr const char* LOCK_ATTR = "locked"; static constexpr const char* BED_TYPE_ATTR = "bed_type"; static constexpr const char* PRINT_SEQUENCE_ATTR = "print_sequence"; static constexpr const char* FIRST_LAYER_PRINT_SEQUENCE_ATTR = "first_layer_print_sequence"; +static constexpr const char* SPIRAL_VASE_MODE = "spiral_mode"; static constexpr const char* GCODE_FILE_ATTR = "gcode_file"; static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file"; static constexpr const char* TOP_FILE_ATTR = "top_file"; @@ -288,6 +289,8 @@ static constexpr const char* IDENTIFYID_ATTR = "identify_id"; static constexpr const char* PLATERID_ATTR = "plater_id"; static constexpr const char* PLATER_NAME_ATTR = "plater_name"; static constexpr const char* PLATE_IDX_ATTR = "index"; +static constexpr const char* PRINTER_MODEL_ID_ATTR = "printer_model_id"; +static constexpr const char* NOZZLE_DIAMETERS_ATTR = "nozzle_diameters"; static constexpr const char* SLICE_PREDICTION_ATTR = "prediction"; static constexpr const char* SLICE_WEIGHT_ATTR = "weight"; static constexpr const char* TIMELAPSE_TYPE_ATTR = "timelapse_type"; @@ -1282,9 +1285,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // BBS: load relationships if (!_extract_xml_from_archive(archive, RELATIONSHIPS_FILE, _handle_start_relationships_element, _handle_end_relationships_element)) return false; - if (m_thumbnail_small.empty()) m_thumbnail_small = m_thumbnail_path; - if (!m_thumbnail_small.empty()) { - return _extract_from_archive(archive, m_thumbnail_small, [&data](auto &archive, auto const &stat) -> bool { + if (m_thumbnail_middle.empty()) m_thumbnail_middle = m_thumbnail_path; + if (!m_thumbnail_middle.empty()) { + return _extract_from_archive(archive, m_thumbnail_middle, [&data](auto &archive, auto const &stat) -> bool { data.resize(stat.m_uncomp_size); return mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, data.data(), data.size(), 0); }); @@ -1368,7 +1371,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_thumbnail_small.erase(m_thumbnail_small.begin()); if (!m_thumbnail_middle.empty() && m_thumbnail_middle.front() == '/') m_thumbnail_middle.erase(m_thumbnail_middle.begin()); - m_model->model_info->metadata_items.emplace("Thumbnail", m_thumbnail_small); + m_model->model_info->metadata_items.emplace("Thumbnail", m_thumbnail_middle); m_model->model_info->metadata_items.emplace("Poster", m_thumbnail_middle); // we then loop again the entries to read other files stored in the archive @@ -3900,6 +3903,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) }; m_curr_plater->config.set_key_value("first_layer_print_sequence", new ConfigOptionInts(get_vector_from_string(value))); } + else if (key == SPIRAL_VASE_MODE) { + bool spiral_mode = false; + std::istringstream(value) >> std::boolalpha >> spiral_mode; + m_curr_plater->config.set_key_value("spiral_mode", new ConfigOptionBool(spiral_mode)); + } else if (key == GCODE_FILE_ATTR) { m_curr_plater->gcode_file = value; @@ -5375,7 +5383,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) ~close_lock() { if (filename) { close_zip_writer(&archive); - boost::filesystem::remove(*filename); + boost::system::error_code ec; + boost::filesystem::remove(*filename, ec); } } } lock{archive, &filepath_tmp}; @@ -5439,8 +5448,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::string const * filename; ~close_lock() { close_zip_writer(&archive); - if (filename) - boost::filesystem::remove(*filename); + if (filename) { + boost::system::error_code ec; + boost::filesystem::remove(*filename, ec); + } } } lock{ archive, &filename}; @@ -5588,7 +5599,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { if (!_add_calibration_file_to_archive(archive, *calibration_data[index], index)) { close_zip_writer(&archive); - boost::filesystem::remove(filename); return false; } } @@ -5604,7 +5614,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (id_bboxes[index]->is_valid()) { if (!_add_bbox_file_to_archive(archive, *id_bboxes[index], index)) { close_zip_writer(&archive); - boost::filesystem::remove(filename); return false; } } @@ -5631,7 +5640,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // The index differes from the index of an object ID of an object instance of a 3MF file! if (!_add_layer_height_profile_file_to_archive(archive, model)) { close_zip_writer(&archive); - boost::filesystem::remove(filename); return false; } @@ -5648,7 +5656,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // The index differes from the index of an object ID of an object instance of a 3MF file! if (!_add_layer_config_ranges_file_to_archive(archive, model)) { close_zip_writer(&archive); - boost::filesystem::remove(filename); return false; } @@ -6417,7 +6424,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << COMPONENT_TAG << " objectid=\"" << volume_id; else stream << " <" << COMPONENT_TAG << " p:path=\"" << xml_escape(*ppath) << "\" objectid=\"" << volume_id; // << "\"/>\n"; - stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap{(boost::uint32_t) object_data.backup_id} << COMPONENT_UUID_SUFFIX; + if (m_production_ext) + stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap{(boost::uint32_t) (index + (object_data.backup_id << 16))} << COMPONENT_UUID_SUFFIX; const Transform3d &transf = volume->get_matrix(); stream << "\" " << TRANSFORM_ATTR << "=\""; for (unsigned c = 0; c < 4; ++c) { @@ -6515,7 +6523,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) char buf[256]; unsigned int vertices_count = 0; //unsigned int triangles_count = 0; - for (ModelVolume* volume : object.volumes) { + for (unsigned int index = 0; index < object.volumes.size(); index++) { + ModelVolume *volume = object.volumes[index]; if (volume == nullptr) continue; @@ -6542,7 +6551,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (m_production_ext) { std::stringstream stream; reset_stream(stream); - stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap{(boost::uint32_t) object_data.backup_id} << SUB_OBJECT_UUID_SUFFIX; + stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap{(boost::uint32_t) (index + (object_data.backup_id << 16))} << SUB_OBJECT_UUID_SUFFIX; //output_buffer += "\" "; //output_buffer += PUUID_ATTR; //output_buffer += "=\""; @@ -7218,6 +7227,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << "\"/>\n"; } + ConfigOption* spiral_mode_opt = plate_data->config.option("spiral_mode"); + if (spiral_mode_opt) + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SPIRAL_VASE_MODE << "\" " << VALUE_ATTR << "=\"" << spiral_mode_opt->getBool() << "\"/>\n"; + if (save_gcode) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << GCODE_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << xml_escape(plate_data->gcode_file) << "\"/>\n"; if (!plate_data->gcode_file.empty()) { @@ -7371,6 +7384,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) break; } } + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PRINTER_MODEL_ID_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->printer_model_id << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << NOZZLE_DIAMETERS_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->nozzle_diameters << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TIMELAPSE_TYPE_ATTR << "\" " << VALUE_ATTR << "=\"" << timelapse_type << "\"/>\n"; //stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TIMELAPSE_ERROR_CODE_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->timelapse_warning_code << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_PREDICTION_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_prediction_str() << "\"/>\n"; @@ -7714,10 +7729,12 @@ class _BBS_Backup_Manager void set_interval(long n) { boost::lock_guard lock(m_mutex); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry, and last interval is: " << m_interval; m_next_backup -= boost::posix_time::seconds(m_interval); m_interval = n; m_next_backup += boost::posix_time::seconds(m_interval); m_cond.notify_all(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " exit, and new interval is: " << m_interval; } void put_other_changes() @@ -7795,6 +7812,7 @@ class _BBS_Backup_Manager }; private: _BBS_Backup_Manager() { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " inital and interval = " << m_interval; m_next_backup = boost::get_system_time() + boost::posix_time::seconds(m_interval); boost::unique_lock lock(m_mutex); m_thread = std::move(boost::thread(boost::ref(*this))); @@ -7823,7 +7841,7 @@ class _BBS_Backup_Manager } void process_ui_task(Task& t, bool canceled = false) { - BOOST_LOG_TRIVIAL(info) << "process_ui_task" << t.to_string(); + BOOST_LOG_TRIVIAL(info) << "process_ui_task" << t.to_string() << " and interval = " << m_interval; switch (t.type) { case Backup: { if (canceled) @@ -7867,7 +7885,7 @@ class _BBS_Backup_Manager } void process_task(Task& t) { - BOOST_LOG_TRIVIAL(info) << "process_task" << t.to_string(); + BOOST_LOG_TRIVIAL(info) << "process_task" << t.to_string() << " and interval = " << m_interval; switch (t.type) { case Backup: // do it in response @@ -7882,13 +7900,15 @@ class _BBS_Backup_Manager break; } case RemoveObject: { - boost::filesystem::remove(t.path + "/mesh_" + boost::lexical_cast(t.id) + ".xml"); + boost::system::error_code ec; + boost::filesystem::remove(t.path + "/mesh_" + boost::lexical_cast(t.id) + ".xml", ec); t.type = None; break; } case RemoveBackup: { try { - boost::filesystem::remove(t.path + "/.3mf"); + boost::system::error_code ec; + boost::filesystem::remove(t.path + "/.3mf", ec); // We Saved with SplitModel now, so we can safe delete these sub models. boost::filesystem::remove_all(t.path + "/3D/Objects"); boost::filesystem::create_directory(t.path + "/3D/Objects"); diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index ed7e440c9a0..af6994b77ea 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -69,6 +69,8 @@ struct PlateData int plate_index; std::vector> objects_and_instances; std::map> obj_inst_map; + std::string printer_model_id; + std::string nozzle_diameters; std::string gcode_file; std::string gcode_file_md5; std::string thumbnail_file; @@ -231,7 +233,7 @@ extern bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSub extern std::string bbs_3mf_get_thumbnail(const char * path); -extern bool load_gcode_3mf_from_stream(std::istream & data, DynamicPrintConfig* config, Model* model, PlateDataPtrs* plate_data_list, +extern bool load_gcode_3mf_from_stream(std::istream & data, DynamicPrintConfig* config, Model* model, PlateDataPtrs* plate_data_list, Semver* file_version); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ecb98062758..6b0c6f632db 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1357,7 +1357,22 @@ namespace DoExport { total_weight += weight; total_cost += weight * extruder->filament_cost() * 0.001; } - + + for (auto volume : result.print_statistics.wipe_tower_volumes_per_extruder) { + total_extruded_volume += volume.second; + + size_t extruder_id = volume.first; + auto extruder = std::find_if(extruders.begin(), extruders.end(), [extruder_id](const Extruder& extr) {return extr.id() == extruder_id; }); + if (extruder == extruders.end()) + continue; + + double s = PI * sqr(0.5* extruder->filament_diameter()); + double weight = volume.second * extruder->filament_density() * 0.001; + total_used_filament += volume.second/s; + total_weight += weight; + total_cost += weight * extruder->filament_cost() * 0.001; + } + total_cost += config.time_cost.getFloat() * (normal_print_time/3600.0); print_statistics.total_extruded_volume = total_extruded_volume; @@ -1398,8 +1413,7 @@ namespace DoExport { if (ret.size() < MAX_TAGS_COUNT) check(_(L("Layer change G-code")), config.layer_change_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_(L("Time lapse G-code")), config.time_lapse_gcode.value); if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change filament G-code")), config.change_filament_gcode.value); - //BBS - //if (ret.size() < MAX_TAGS_COUNT) check(_(L("Printing by object G-code")), config.printing_by_object_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_(L("Printing by object G-code")), config.printing_by_object_gcode.value); //if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value); //Orca if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change extrusion role G-code")), config.change_extrusion_role_gcode.value); @@ -1531,6 +1545,27 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu } m_processor.result().timelapse_warning_code = m_timelapse_warning_code; m_processor.result().support_traditional_timelapse = m_support_traditional_timelapse; + + { //BBS:check bed and filament compatible + const ConfigOptionDef *bed_type_def = print_config_def.get("curr_bed_type"); + assert(bed_type_def != nullptr); + const t_config_enum_values *bed_type_keys_map = bed_type_def->enum_keys_map; + const ConfigOptionInts *bed_temp_opt = m_config.option(get_bed_temp_key(m_config.curr_bed_type)); + for(auto extruder_id : m_initial_layer_extruders){ + int cur_bed_temp = bed_temp_opt->get_at(extruder_id); + if (cur_bed_temp == 0 && bed_type_keys_map != nullptr) { + for (auto item : *bed_type_keys_map) { + if (item.second == m_config.curr_bed_type) { + m_processor.result().bed_match_result = BedMatchResult(false, item.first, extruder_id); + break; + } + } + } + if (m_processor.result().bed_match_result.match == false) + break; + } + } + m_processor.finalize(true); // DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics); DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics, print->config()); @@ -1919,6 +1954,24 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato } } + { + std::string filament_density_list = "; filament_density: "; + (filament_density_list+=m_config.filament_density.serialize()) +='\n'; + file.writeln(filament_density_list); + + std::string filament_diameter_list = "; filament_diameter: "; + (filament_diameter_list += m_config.filament_diameter.serialize()) += '\n'; + file.writeln(filament_diameter_list); + + coordf_t max_height_z = -1; + for (const auto& object : print.objects()) + max_height_z = std::max(object->layers().back()->print_z, max_height_z); + + std::ostringstream max_height_z_tip; + max_height_z_tip<<"; max_z_height: " << std::fixed << std::setprecision(2) << max_height_z << '\n'; + file.writeln(max_height_z_tip.str()); + } + file.write_format("; HEADER_BLOCK_END\n\n"); @@ -3545,6 +3598,27 @@ LayerResult GCode::process_layer( Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) : Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done); + // BBS: get next extruder according to flush and soluble + auto get_next_extruder = [&](int current_extruder,const std::vector&extruders) { + std::vector flush_matrix(cast(m_config.flush_volumes_matrix.values)); + const unsigned int number_of_extruders = (unsigned int)(sqrt(flush_matrix.size()) + EPSILON); + // Extract purging volumes for each extruder pair: + std::vector> wipe_volumes; + for (unsigned int i = 0; i < number_of_extruders; ++i) + wipe_volumes.push_back(std::vector(flush_matrix.begin() + i * number_of_extruders, flush_matrix.begin() + (i + 1) * number_of_extruders)); + unsigned int next_extruder = current_extruder; + float min_flush = std::numeric_limits::max(); + for (auto extruder_id : extruders) { + if (print.config().filament_soluble.get_at(extruder_id) || extruder_id == current_extruder) + continue; + if (wipe_volumes[current_extruder][extruder_id] < min_flush) { + next_extruder = extruder_id; + min_flush = wipe_volumes[current_extruder][extruder_id]; + } + } + return next_extruder; + }; + if (m_config.enable_overhang_speed && !m_config.overhang_speed_classic) { for (const auto &layer_to_print : layers) { m_extrusion_quality_estimator.prepare_for_new_layer(layer_to_print.original_object, @@ -3597,12 +3671,21 @@ LayerResult GCode::process_layer( if (print.config().filament_soluble.get_at(extruder_id)) continue; + //BBS: now we don't consider interface filament used in other object if (extruder_id == interface_extruder) continue; dontcare_extruder = extruder_id; break; } + #if 0 + //BBS: not found a suitable extruder in current layer ,dontcare_extruider==first_extruder_id==interface_extruder + if (dontcare_extruder == interface_extruder && (object.config().support_interface_not_for_body && object.config().support_interface_filament.value!=0)) { + // BBS : get a suitable extruder from other layer + auto all_extruders = print.extruders(); + dontcare_extruder = get_next_extruder(dontcare_extruder, all_extruders); + } + #endif if (support_dontcare) support_extruder = dontcare_extruder; @@ -3964,16 +4047,56 @@ LayerResult GCode::process_layer( m_last_obj_copy = this_object_copy; this->set_origin(unscale(offset)); //FIXME the following code prints regions in the order they are defined, the path is not optimized in any way. - bool is_infill_first = print.default_region_config().wall_infill_order == WallInfillOrder::InfillInnerOuter || - print.default_region_config().wall_infill_order == WallInfillOrder::InfillOuterInner; + bool is_infill_first =print.config().is_infill_first; + + auto has_infill = [](const std::vector &by_region) { + for (auto region : by_region) { + if (!region.infills.empty()) + return true; + } + return false; + }; + //BBS: for first layer, we always print wall firstly to get better bed adhesive force //This behaviour is same with cura if (is_infill_first && !first_layer) { - gcode += this->extrude_infill(print, by_region_specific, false); + if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && has_infill(by_region_specific)) { + gcode += this->retract(false, false, LiftType::NormalLift); + + std::string timepals_gcode = insert_timelapse_gcode(); + gcode += timepals_gcode; + m_writer.set_current_position_clear(false); + //BBS: check whether custom gcode changes the z position. Update if changed + double temp_z_after_timepals_gcode; + if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) { + Vec3d pos = m_writer.get_position(); + pos(2) = temp_z_after_timepals_gcode; + m_writer.set_position(pos); + } + + has_insert_timelapse_gcode = true; + } + gcode += this->extrude_infill(print, by_region_specific, false); gcode += this->extrude_perimeters(print, by_region_specific); } else { gcode += this->extrude_perimeters(print, by_region_specific); - gcode += this->extrude_infill(print,by_region_specific, false); + if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && has_infill(by_region_specific)) { + gcode += this->retract(false, false, LiftType::NormalLift); + + std::string timepals_gcode = insert_timelapse_gcode(); + gcode += timepals_gcode; + m_writer.set_current_position_clear(false); + //BBS: check whether custom gcode changes the z position. Update if changed + double temp_z_after_timepals_gcode; + if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) { + Vec3d pos = m_writer.get_position(); + pos(2) = temp_z_after_timepals_gcode; + m_writer.set_position(pos); + } + + has_insert_timelapse_gcode = true; + } + gcode += this->extrude_infill(print,by_region_specific, false); } // ironing gcode += this->extrude_infill(print,by_region_specific, true); @@ -4002,6 +4125,12 @@ LayerResult GCode::process_layer( } } } + if (first_layer) { + for (auto iter = by_extruder.begin(); iter != by_extruder.end(); ++iter) { + if (!iter->second.empty()) + m_initial_layer_extruders.insert(iter->first); + } + } #if 0 // Apply spiral vase post-processing if this layer contains suitable geometry @@ -4197,9 +4326,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou Point last_pos = this->last_pos(); if (!m_config.spiral_mode && description == "perimeter") { assert(m_layer != nullptr); - bool is_outer_wall_first = m_config.wall_infill_order == WallInfillOrder::OuterInnerInfill - || m_config.wall_infill_order == WallInfillOrder::InfillOuterInner - || m_config.wall_infill_order == WallInfillOrder::InnerOuterInnerInfill; + bool is_outer_wall_first = m_config.wall_sequence == WallSequence::OuterInner; m_seam_placer.place_seam(m_layer, loop, is_outer_wall_first, this->last_pos()); } else loop.split_at(last_pos, false); @@ -5207,10 +5334,11 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role, LiftTyp travel_bbox.inflated(1); travel_bbox.defined = true; - const float protect_z_scaled = scale_(0.4); + // do not scale for z + const float protect_z = 0.4; std::pair z_range; z_range.second = m_layer ? m_layer->print_z : 0.f; - z_range.first = std::max(0.f, z_range.second - protect_z_scaled); + z_range.first = std::max(0.f, z_range.second - protect_z); std::vector layers_of_objects; std::vector boundingBox_for_objects; std::vector objects_instances_shift; @@ -5261,7 +5389,7 @@ bool GCode::needs_retraction(const Polyline &travel, ExtrusionRole role, LiftTyp float max_z_hop = 0.f; for (int i = 0; i < m_config.z_hop.size(); i++) max_z_hop = std::max(max_z_hop, (float)m_config.z_hop.get_at(i)); - float travel_len_thresh = max_z_hop / tan(GCodeWriter::slope_threshold); + float travel_len_thresh = scale_(max_z_hop / tan(GCodeWriter::slope_threshold)); float accum_len = 0.f; Polyline clipped_travel; @@ -5337,8 +5465,7 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li gcode += toolchange ? m_writer.retract_for_toolchange() : m_writer.retract(); gcode += m_writer.reset_e(); - - // check if should + can lift (roughly from SuperSlicer) + // Orca: check if should + can lift (roughly from SuperSlicer) RetractLiftEnforceType retract_lift_type = RetractLiftEnforceType(EXTRUDER_CONFIG(retract_lift_enforce)); bool needs_lift = toolchange @@ -5371,7 +5498,7 @@ std::string GCode::retract(bool toolchange, bool is_last_retraction, LiftType li return gcode; } -std::string GCode::set_extruder(unsigned int extruder_id, double print_z) +std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool by_object) { if (!m_writer.need_toolchange(extruder_id)) return ""; @@ -5405,6 +5532,10 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) // Always reset the extrusion path, even if the tool change retract is set to zero. m_wipe.reset_path(); + // BBS: insert skip object label before change filament while by object + if (by_object) + m_writer.add_object_change_labels(gcode); + if (m_writer.extruder() != nullptr) { // Process the custom filament_end_gcode. set_extruder() is only called if there is no wipe tower // so it should not be injected twice. diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 5e8d8d19341..708df1c5f1c 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -216,7 +216,7 @@ class GCode { bool needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type); std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift); std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } - std::string set_extruder(unsigned int extruder_id, double print_z); + std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false); bool is_BBL_Printer(); // SoftFever @@ -549,6 +549,7 @@ class GCode { bool m_need_change_layer_lift_z = false; int m_start_gcode_filament = -1; + std::set m_initial_layer_extruders; // BBS int get_bed_temperature(const int extruder_id, const bool is_first_layer, const BedType bed_type) const; diff --git a/src/libslic3r/GCode/ConflictChecker.cpp b/src/libslic3r/GCode/ConflictChecker.cpp index 645709523e1..99661540946 100644 --- a/src/libslic3r/GCode/ConflictChecker.cpp +++ b/src/libslic3r/GCode/ConflictChecker.cpp @@ -91,34 +91,34 @@ inline Grids line_rasterization(const Line &line, int64_t xdist = RasteXDistance void LinesBucketQueue::emplace_back_bucket(ExtrusionLayers &&els, const void *objPtr, Point offset) { - auto oldSize = _buckets.capacity(); - _buckets.emplace_back(std::move(els), objPtr, offset); - _pq.push(&_buckets.back()); - auto newSize = _buckets.capacity(); + auto oldSize = line_buckets.capacity(); + line_buckets.emplace_back(std::move(els), objPtr, offset); + line_bucket_ptr_queue.push(&line_buckets.back()); + auto newSize = line_buckets.capacity(); if (oldSize != newSize) { // pointers change - decltype(_pq) newQueue; - for (LinesBucket &bucket : _buckets) { newQueue.push(&bucket); } - std::swap(_pq, newQueue); + decltype(line_bucket_ptr_queue) newQueue; + for (LinesBucket &bucket : line_buckets) { newQueue.push(&bucket); } + std::swap(line_bucket_ptr_queue, newQueue); } } // remove lowest and get the current bottom z float LinesBucketQueue::getCurrBottomZ() { - auto lowest = _pq.top(); - _pq.pop(); + auto lowest = line_bucket_ptr_queue.top(); + line_bucket_ptr_queue.pop(); float layerBottomZ = lowest->curBottomZ(); std::vector lowests; lowests.push_back(lowest); - while (_pq.empty() == false && std::abs(_pq.top()->curBottomZ() - lowest->curBottomZ()) < EPSILON) { - lowests.push_back(_pq.top()); - _pq.pop(); + while (line_bucket_ptr_queue.empty() == false && std::abs(line_bucket_ptr_queue.top()->curBottomZ() - lowest->curBottomZ()) < EPSILON) { + lowests.push_back(line_bucket_ptr_queue.top()); + line_bucket_ptr_queue.pop(); } for (LinesBucket *bp : lowests) { bp->raise(); - if (bp->valid()) { _pq.push(bp); } + if (bp->valid()) { line_bucket_ptr_queue.push(bp); } } return layerBottomZ; } @@ -126,7 +126,7 @@ float LinesBucketQueue::getCurrBottomZ() LineWithIDs LinesBucketQueue::getCurLines() const { LineWithIDs lines; - for (const LinesBucket &bucket : _buckets) { + for (const LinesBucket &bucket : line_buckets) { if (bucket.valid()) { LineWithIDs tmpLines = bucket.curLines(); lines.insert(lines.end(), tmpLines.begin(), tmpLines.end()); diff --git a/src/libslic3r/GCode/ConflictChecker.hpp b/src/libslic3r/GCode/ConflictChecker.hpp index 0779ff28ca8..eac10aac419 100644 --- a/src/libslic3r/GCode/ConflictChecker.hpp +++ b/src/libslic3r/GCode/ConflictChecker.hpp @@ -109,12 +109,12 @@ struct LinesBucketPtrComp class LinesBucketQueue { public: - std::vector _buckets; - std::priority_queue, LinesBucketPtrComp> _pq; + std::vector line_buckets; + std::priority_queue, LinesBucketPtrComp> line_bucket_ptr_queue; public: void emplace_back_bucket(ExtrusionLayers &&els, const void *objPtr, Point offset); - bool valid() const { return _pq.empty() == false; } + bool valid() const { return line_bucket_ptr_queue.empty() == false; } float getCurrBottomZ(); LineWithIDs getCurLines() const; }; diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index d4aee4b0edd..88d4fb189e4 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -44,6 +44,7 @@ static const size_t MIN_EXTRUDERS_COUNT = 5; static const float DEFAULT_FILAMENT_DIAMETER = 1.75f; static const int DEFAULT_FILAMENT_HRC = 0; static const float DEFAULT_FILAMENT_DENSITY = 1.245f; +static const float DEFAULT_FILAMENT_COST = 29.99f; static const int DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE = 0; static const Slic3r::Vec3f DEFAULT_EXTRUDER_OFFSET = Slic3r::Vec3f::Zero(); @@ -64,7 +65,9 @@ const std::vector GCodeProcessor::Reserved_Tags = { "_GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER", "_GP_TOTAL_LAYER_NUMBER_PLACEHOLDER", " MANUAL_TOOL_CHANGE ", - "_DURING_PRINT_EXHAUST_FAN" + "_DURING_PRINT_EXHAUST_FAN", + " WIPE_TOWER_START", + " WIPE_TOWER_END" }; const std::vector GCodeProcessor::Reserved_Tags_compatible = { @@ -81,7 +84,10 @@ const std::vector GCodeProcessor::Reserved_Tags_compatible = { "_GP_LAST_LINE_M73_PLACEHOLDER", "_GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER", "_GP_TOTAL_LAYER_NUMBER_PLACEHOLDER", - " MANUAL_TOOL_CHANGE " + " MANUAL_TOOL_CHANGE ", + "_DURING_PRINT_EXHAUST_FAN", + " WIPE_TOWER_START", + " WIPE_TOWER_END" }; @@ -732,22 +738,30 @@ void GCodeProcessor::UsedFilaments::reset() color_change_cache = 0.0f; volumes_per_color_change = std::vector(); - tool_change_cache = 0.0f; + model_extrude_cache = 0.0f; volumes_per_extruder.clear(); flush_per_filament.clear(); role_cache = 0.0f; filaments_per_role.clear(); + + wipe_tower_cache = 0.0f; + wipe_tower_volume_per_extruder.clear(); } -void GCodeProcessor::UsedFilaments::increase_caches(double extruded_volume) +void GCodeProcessor::UsedFilaments::increase_model_caches(double extruded_volume) { color_change_cache += extruded_volume; - tool_change_cache += extruded_volume; + model_extrude_cache += extruded_volume; role_cache += extruded_volume; } +void GCodeProcessor::UsedFilaments::increase_wipe_tower_caches(double extruded_volume) +{ + wipe_tower_cache += extruded_volume; +} + void GCodeProcessor::UsedFilaments::process_color_change_cache() { if (color_change_cache != 0.0f) { @@ -756,15 +770,27 @@ void GCodeProcessor::UsedFilaments::process_color_change_cache() } } -void GCodeProcessor::UsedFilaments::process_extruder_cache(GCodeProcessor* processor) +void GCodeProcessor::UsedFilaments::process_model_cache(GCodeProcessor* processor) { size_t active_extruder_id = processor->m_extruder_id; - if (tool_change_cache != 0.0f) { + if (model_extrude_cache != 0.0f) { if (volumes_per_extruder.find(active_extruder_id) != volumes_per_extruder.end()) - volumes_per_extruder[active_extruder_id] += tool_change_cache; + volumes_per_extruder[active_extruder_id] += model_extrude_cache; else - volumes_per_extruder[active_extruder_id] = tool_change_cache; - tool_change_cache = 0.0f; + volumes_per_extruder[active_extruder_id] = model_extrude_cache; + model_extrude_cache = 0.0f; + } +} + +void GCodeProcessor::UsedFilaments::process_wipe_tower_cache(GCodeProcessor* processor) +{ + size_t active_extruder_id = processor->m_extruder_id; + if (wipe_tower_cache != 0.0f) { + if (wipe_tower_volume_per_extruder.find(active_extruder_id) != wipe_tower_volume_per_extruder.end()) + wipe_tower_volume_per_extruder[active_extruder_id] += wipe_tower_cache; + else + wipe_tower_volume_per_extruder[active_extruder_id] = wipe_tower_cache; + wipe_tower_cache = 0.0f; } } @@ -799,8 +825,9 @@ void GCodeProcessor::UsedFilaments::process_role_cache(GCodeProcessor* processor void GCodeProcessor::UsedFilaments::process_caches(GCodeProcessor* processor) { process_color_change_cache(); - process_extruder_cache(processor); + process_model_cache(processor); process_role_cache(processor); + process_wipe_tower_cache(processor); } #if ENABLE_GCODE_VIEWER_STATISTICS @@ -852,8 +879,10 @@ void GCodeProcessorResult::reset() { filament_diameters = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER); required_nozzle_HRC = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_HRC); filament_densities = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY); + filament_costs = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_COST); custom_gcode_per_print_z = std::vector(); spiral_vase_layers = std::vector>>(); + bed_match_result = BedMatchResult(true); warnings.clear(); //BBS: add mutex for protection of gcode result @@ -962,6 +991,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_result.required_nozzle_HRC.resize(extruders_count); m_result.filament_densities.resize(extruders_count); m_result.filament_vitrification_temperature.resize(extruders_count); + m_result.filament_costs.resize(extruders_count); m_extruder_temps.resize(extruders_count); m_result.nozzle_hrc = static_cast(config.nozzle_hrc.getInt()); m_result.nozzle_type = config.nozzle_type; @@ -972,6 +1002,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_result.required_nozzle_HRC[i] = static_cast(config.required_nozzle_HRC.get_at(i)); m_result.filament_densities[i] = static_cast(config.filament_density.get_at(i)); m_result.filament_vitrification_temperature[i] = static_cast(config.temperature_vitrification.get_at(i)); + m_result.filament_costs[i] = static_cast(config.filament_cost.get_at(i)); } if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfKlipper || m_flavor == gcfRepRapFirmware) { @@ -1027,6 +1058,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) const ConfigOptionFloat* z_offset = config.option("z_offset"); if (z_offset != nullptr) m_z_offset = z_offset->value; + } void GCodeProcessor::apply_config(const DynamicPrintConfig& config) @@ -1114,6 +1146,19 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_result.filament_densities.emplace_back(DEFAULT_FILAMENT_DENSITY); } } + + //BBS + const ConfigOptionFloats* filament_costs = config.option("filament_cost"); + if (filament_costs != nullptr) { + m_result.filament_costs.clear(); + m_result.filament_costs.resize(filament_costs->values.size()); + for (size_t i = 0; i < filament_costs->values.size(); ++i) + m_result.filament_costs[i]=static_cast(filament_costs->values[i]); + } + for (size_t i = m_result.filament_costs.size(); i < m_result.extruders_count; ++i) { + m_result.filament_costs.emplace_back(DEFAULT_FILAMENT_COST); + } + //BBS const ConfigOptionInts* filament_vitrification_temperature = config.option("temperature_vitrification"); if (filament_vitrification_temperature != nullptr) { @@ -1330,6 +1375,7 @@ void GCodeProcessor::reset() m_cached_position.reset(); m_wiping = false; m_flushing = false; + m_wipe_tower = false; m_remaining_volume = 0.f; // BBS: arc move related data m_move_path_type = EMovePathType::Noop_move; @@ -2106,6 +2152,17 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers return; } + if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Tower_Start))) { + m_wipe_tower = true; + return; + } + + if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Tower_End))) { + m_wipe_tower = false; + m_used_filaments.process_wipe_tower_cache(this); + return; + } + //BBS: flush start tag if (boost::starts_with(comment, GCodeProcessor::Flush_Start_Tag)) { m_flushing = true; @@ -2811,10 +2868,13 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) float delta_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); float volume_extruded_filament = area_filament_cross_section * delta_pos[E]; float area_toolpath_cross_section = volume_extruded_filament / delta_xyz; - - // save extruded volume to the cache - m_used_filaments.increase_caches(volume_extruded_filament); - + if (m_wipe_tower) { + m_used_filaments.increase_wipe_tower_caches(volume_extruded_filament); + } + else { + // save extruded volume to the cache + m_used_filaments.increase_model_caches(volume_extruded_filament); + } // volume extruded filament / tool displacement = area toolpath cross section m_mm3_per_mm = area_toolpath_cross_section; #if ENABLE_GCODE_VIEWER_DATA_CHECKING @@ -3268,10 +3328,14 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) if (type == EMoveType::Extrude) { float volume_extruded_filament = area_filament_cross_section * delta_pos[E]; float area_toolpath_cross_section = volume_extruded_filament / delta_xyz; - - //BBS: save extruded volume to the cache - m_used_filaments.increase_caches(volume_extruded_filament); - + if (m_wipe_tower) { + //BBS: save wipe tower volume to the cache + m_used_filaments.increase_wipe_tower_caches(volume_extruded_filament); + } + else { + //BBS: save extruded volume to the cache + m_used_filaments.increase_model_caches(volume_extruded_filament); + } //BBS: volume extruded filament / tool displacement = area toolpath cross section m_mm3_per_mm = area_toolpath_cross_section; #if ENABLE_GCODE_VIEWER_DATA_CHECKING @@ -4320,7 +4384,7 @@ void GCodeProcessor::process_filaments(CustomGCode::Type code) m_used_filaments.process_color_change_cache(); if (code == CustomGCode::ToolChange) { - m_used_filaments.process_extruder_cache(this); + m_used_filaments.process_model_cache(this); //BBS: reset remaining filament m_remaining_volume = m_nozzle_volume; } @@ -4353,6 +4417,7 @@ void GCodeProcessor::update_estimated_times_stats() m_result.print_statistics.volumes_per_color_change = m_used_filaments.volumes_per_color_change; m_result.print_statistics.volumes_per_extruder = m_used_filaments.volumes_per_extruder; + m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volume_per_extruder; m_result.print_statistics.flush_per_filament = m_used_filaments.flush_per_filament; m_result.print_statistics.used_filaments_per_role = m_used_filaments.filaments_per_role; } diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 95f4680fd5e..f831b5c26f3 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -73,6 +73,7 @@ namespace Slic3r { std::vector volumes_per_color_change; std::map volumes_per_extruder; + std::map wipe_tower_volumes_per_extruder; //BBS: the flush amount of every filament std::map flush_per_filament; std::map> used_filaments_per_role; @@ -88,6 +89,7 @@ namespace Slic3r { } volumes_per_color_change.clear(); volumes_per_color_change.shrink_to_fit(); + wipe_tower_volumes_per_extruder.clear(); volumes_per_extruder.clear(); flush_per_filament.clear(); used_filaments_per_role.clear(); @@ -109,11 +111,23 @@ namespace Slic3r { ConflictResult() = default; }; + struct BedMatchResult + { + bool match; + std::string bed_type_name; + int extruder_id; + BedMatchResult():match(true),bed_type_name(""),extruder_id(-1) {} + BedMatchResult(bool _match,const std::string& _bed_type_name="",int _extruder_id=-1) + :match(_match),bed_type_name(_bed_type_name),extruder_id(_extruder_id) + {} + }; + using ConflictResultOpt = std::optional; struct GCodeProcessorResult { ConflictResultOpt conflict_result; + BedMatchResult bed_match_result; struct SettingsIds { @@ -190,6 +204,7 @@ namespace Slic3r { std::vector filament_diameters; std::vector required_nozzle_HRC; std::vector filament_densities; + std::vector filament_costs; std::vector filament_vitrification_temperature; PrintEstimatedStatistics print_statistics; std::vector custom_gcode_per_print_z; @@ -223,11 +238,13 @@ namespace Slic3r { extruder_colors = other.extruder_colors; filament_diameters = other.filament_diameters; filament_densities = other.filament_densities; + filament_costs = other.filament_costs; print_statistics = other.print_statistics; custom_gcode_per_print_z = other.custom_gcode_per_print_z; spiral_vase_layers = other.spiral_vase_layers; warnings = other.warnings; bed_type = other.bed_type; + bed_match_result = other.bed_match_result; #if ENABLE_GCODE_VIEWER_STATISTICS time = other.time; #endif @@ -261,7 +278,9 @@ namespace Slic3r { Estimated_Printing_Time_Placeholder, Total_Layer_Number_Placeholder, Manual_Tool_Change, - During_Print_Exhaust_Fan + During_Print_Exhaust_Fan, + Wipe_Tower_Start, + Wipe_Tower_End, }; static const std::string& reserved_tag(ETags tag) { return s_IsBBLPrinter ? Reserved_Tags[static_cast(tag)] : Reserved_Tags_compatible[static_cast(tag)]; } @@ -474,9 +493,12 @@ namespace Slic3r { double color_change_cache; std::vector volumes_per_color_change; - double tool_change_cache; + double model_extrude_cache; std::map volumes_per_extruder; + double wipe_tower_cache; + std::mapwipe_tower_volume_per_extruder; + //BBS: the flush amount of every filament std::map flush_per_filament; @@ -485,10 +507,12 @@ namespace Slic3r { void reset(); - void increase_caches(double extruded_volume); + void increase_model_caches(double extruded_volume); + void increase_wipe_tower_caches(double extruded_volume); void process_color_change_cache(); - void process_extruder_cache(GCodeProcessor* processor); + void process_model_cache(GCodeProcessor* processor); + void process_wipe_tower_cache(GCodeProcessor* processor); void update_flush_per_filament(size_t extrude_id, float flush_length); void process_role_cache(GCodeProcessor* processor); void process_caches(GCodeProcessor* processor); @@ -637,6 +661,7 @@ namespace Slic3r { CachedPosition m_cached_position; bool m_wiping; bool m_flushing; + bool m_wipe_tower; float m_remaining_volume; bool m_manual_filament_change; diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index cf5b9c5080a..7d8bdf3e80d 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1,7 +1,5 @@ #include "SeamPlacer.hpp" -#include "Polygon.hpp" -#include "PrintConfig.hpp" #include "tbb/parallel_for.h" #include "tbb/blocked_range.h" #include "tbb/parallel_reduce.h" @@ -35,1059 +33,958 @@ namespace Slic3r { namespace SeamPlacerImpl { -template int sgn(T val) { - return int(T(0) < val) - int(val < T(0)); +// ************ FOR BACKPORT COMPATIBILITY ONLY *************** +// Color mapping of a value into RGB false colors. +inline Vec3f value_to_rgbf(float minimum, float maximum, float value) +{ + float ratio = 2.0f * (value - minimum) / (maximum - minimum); + float b = std::max(0.0f, (1.0f - ratio)); + float r = std::max(0.0f, (ratio - 1.0f)); + float g = 1.0f - b - r; + return Vec3f{r, g, b}; } +// Color mapping of a value into RGB false colors. +inline Vec3i value_to_rgbi(float minimum, float maximum, float value) { return (value_to_rgbf(minimum, maximum, value) * 255).cast(); } +// *************************** + +template int sgn(T val) { return int(T(0) < val) - int(val < T(0)); } + // base function: ((e^(((1)/(x^(2)+1)))-1)/(e-1)) // checkout e.g. here: https://www.geogebra.org/calculator -float gauss(float value, float mean_x_coord, float mean_value, float falloff_speed) { - float shifted = value - mean_x_coord; - float denominator = falloff_speed * shifted * shifted + 1.0f; - float exponent = 1.0f / denominator; - return mean_value * (std::exp(exponent) - 1.0f) / (std::exp(1.0f) - 1.0f); +float gauss(float value, float mean_x_coord, float mean_value, float falloff_speed) +{ + float shifted = value - mean_x_coord; + float denominator = falloff_speed * shifted * shifted + 1.0f; + float exponent = 1.0f / denominator; + return mean_value * (std::exp(exponent) - 1.0f) / (std::exp(1.0f) - 1.0f); } -float compute_angle_penalty(float ccw_angle) { - // This function is used: - // ((ℯ^(((1)/(x^(2)*3+1)))-1)/(ℯ-1))*1+((1)/(2+ℯ^(-x))) - // looks scary, but it is gaussian combined with sigmoid, - // so that concave points have much smaller penalty over convex ones - // https://github.com/prusa3d/PrusaSlicer/tree/master/doc/seam_placement/corner_penalty_function.png - return gauss(ccw_angle, 0.0f, 1.0f, 3.0f) + - 1.0f / (2 + std::exp(-ccw_angle)); +float compute_angle_penalty(float ccw_angle) +{ + // This function is used: + // ((ℯ^(((1)/(x^(2)*3+1)))-1)/(ℯ-1))*1+((1)/(2+ℯ^(-x))) + // looks scary, but it is gaussian combined with sigmoid, + // so that concave points have much smaller penalty over convex ones + // https://github.com/prusa3d/PrusaSlicer/tree/master/doc/seam_placement/corner_penalty_function.png + return gauss(ccw_angle, 0.0f, 1.0f, 3.0f) + 1.0f / (2 + std::exp(-ccw_angle)); } /// Coordinate frame -class Frame { +class Frame +{ public: - Frame() { - mX = Vec3f(1, 0, 0); - mY = Vec3f(0, 1, 0); - mZ = Vec3f(0, 0, 1); - } - - Frame(const Vec3f &x, const Vec3f &y, const Vec3f &z) : - mX(x), mY(y), mZ(z) { - } - - void set_from_z(const Vec3f &z) { - mZ = z.normalized(); - Vec3f tmpZ = mZ; - Vec3f tmpX = (std::abs(tmpZ.x()) > 0.99f) ? Vec3f(0, 1, 0) : Vec3f(1, 0, 0); - mY = (tmpZ.cross(tmpX)).normalized(); - mX = mY.cross(tmpZ); - } - - Vec3f to_world(const Vec3f &a) const { - return a.x() * mX + a.y() * mY + a.z() * mZ; - } - - Vec3f to_local(const Vec3f &a) const { - return Vec3f(mX.dot(a), mY.dot(a), mZ.dot(a)); - } - - const Vec3f& binormal() const { - return mX; - } - - const Vec3f& tangent() const { - return mY; - } - - const Vec3f& normal() const { - return mZ; - } + Frame() + { + mX = Vec3f(1, 0, 0); + mY = Vec3f(0, 1, 0); + mZ = Vec3f(0, 0, 1); + } + + Frame(const Vec3f &x, const Vec3f &y, const Vec3f &z) : mX(x), mY(y), mZ(z) {} + + void set_from_z(const Vec3f &z) + { + mZ = z.normalized(); + Vec3f tmpZ = mZ; + Vec3f tmpX = (std::abs(tmpZ.x()) > 0.99f) ? Vec3f(0, 1, 0) : Vec3f(1, 0, 0); + mY = (tmpZ.cross(tmpX)).normalized(); + mX = mY.cross(tmpZ); + } + + Vec3f to_world(const Vec3f &a) const { return a.x() * mX + a.y() * mY + a.z() * mZ; } + + Vec3f to_local(const Vec3f &a) const { return Vec3f(mX.dot(a), mY.dot(a), mZ.dot(a)); } + + const Vec3f &binormal() const { return mX; } + + const Vec3f &tangent() const { return mY; } + + const Vec3f &normal() const { return mZ; } private: - Vec3f mX, mY, mZ; + Vec3f mX, mY, mZ; }; -Vec3f sample_sphere_uniform(const Vec2f &samples) { - float term1 = 2.0f * float(PI) * samples.x(); - float term2 = 2.0f * sqrt(samples.y() - samples.y() * samples.y()); - return {cos(term1) * term2, sin(term1) * term2, - 1.0f - 2.0f * samples.y()}; +Vec3f sample_sphere_uniform(const Vec2f &samples) +{ + float term1 = 2.0f * float(PI) * samples.x(); + float term2 = 2.0f * sqrt(samples.y() - samples.y() * samples.y()); + return {cos(term1) * term2, sin(term1) * term2, 1.0f - 2.0f * samples.y()}; } -Vec3f sample_hemisphere_uniform(const Vec2f &samples) { - float term1 = 2.0f * float(PI) * samples.x(); - float term2 = 2.0f * sqrt(samples.y() - samples.y() * samples.y()); - return {cos(term1) * term2, sin(term1) * term2, - abs(1.0f - 2.0f * samples.y())}; +Vec3f sample_hemisphere_uniform(const Vec2f &samples) +{ + float term1 = 2.0f * float(PI) * samples.x(); + float term2 = 2.0f * sqrt(samples.y() - samples.y() * samples.y()); + return {cos(term1) * term2, sin(term1) * term2, abs(1.0f - 2.0f * samples.y())}; } -Vec3f sample_power_cosine_hemisphere(const Vec2f &samples, float power) { - float term1 = 2.f * float(PI) * samples.x(); - float term2 = pow(samples.y(), 1.f / (power + 1.f)); - float term3 = sqrt(1.f - term2 * term2); +Vec3f sample_power_cosine_hemisphere(const Vec2f &samples, float power) +{ + float term1 = 2.f * float(PI) * samples.x(); + float term2 = pow(samples.y(), 1.f / (power + 1.f)); + float term3 = sqrt(1.f - term2 * term2); - return Vec3f(cos(term1) * term3, sin(term1) * term3, term2); + return Vec3f(cos(term1) * term3, sin(term1) * term3, term2); } std::vector raycast_visibility(const AABBTreeIndirect::Tree<3, float> &raycasting_tree, - const indexed_triangle_set &triangles, - const TriangleSetSamples &samples, - size_t negative_volumes_start_index) { - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: raycast visibility of " << samples.positions.size() << " samples over " << triangles.indices.size() - << " triangles: end"; - - //prepare uniform samples of a hemisphere - float step_size = 1.0f / SeamPlacer::sqr_rays_per_sample_point; - std::vector precomputed_sample_directions( - SeamPlacer::sqr_rays_per_sample_point * SeamPlacer::sqr_rays_per_sample_point); - for (size_t x_idx = 0; x_idx < SeamPlacer::sqr_rays_per_sample_point; ++x_idx) { - float sample_x = x_idx * step_size + step_size / 2.0; - for (size_t y_idx = 0; y_idx < SeamPlacer::sqr_rays_per_sample_point; ++y_idx) { - size_t dir_index = x_idx * SeamPlacer::sqr_rays_per_sample_point + y_idx; - float sample_y = y_idx * step_size + step_size / 2.0; - precomputed_sample_directions[dir_index] = sample_hemisphere_uniform( { sample_x, sample_y }); + const indexed_triangle_set & triangles, + const TriangleSetSamples & samples, + size_t negative_volumes_start_index) +{ + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: raycast visibility of " << samples.positions.size() << " samples over " << triangles.indices.size() << " triangles: end"; + + // prepare uniform samples of a hemisphere + float step_size = 1.0f / SeamPlacer::sqr_rays_per_sample_point; + std::vector precomputed_sample_directions(SeamPlacer::sqr_rays_per_sample_point * SeamPlacer::sqr_rays_per_sample_point); + for (size_t x_idx = 0; x_idx < SeamPlacer::sqr_rays_per_sample_point; ++x_idx) { + float sample_x = x_idx * step_size + step_size / 2.0; + for (size_t y_idx = 0; y_idx < SeamPlacer::sqr_rays_per_sample_point; ++y_idx) { + size_t dir_index = x_idx * SeamPlacer::sqr_rays_per_sample_point + y_idx; + float sample_y = y_idx * step_size + step_size / 2.0; + precomputed_sample_directions[dir_index] = sample_hemisphere_uniform({sample_x, sample_y}); + } } - } - - bool model_contains_negative_parts = negative_volumes_start_index < triangles.indices.size(); - - std::vector result(samples.positions.size()); - tbb::parallel_for(tbb::blocked_range(0, result.size()), - [&triangles, &precomputed_sample_directions, model_contains_negative_parts, negative_volumes_start_index, - &raycasting_tree, &result, &samples](tbb::blocked_range r) { - // Maintaining hits memory outside of the loop, so it does not have to be reallocated for each query. - std::vector hits; - for (size_t s_idx = r.begin(); s_idx < r.end(); ++s_idx) { - result[s_idx] = 1.0f; - constexpr float decrease_step = 1.0f - / (SeamPlacer::sqr_rays_per_sample_point * SeamPlacer::sqr_rays_per_sample_point); - - const Vec3f ¢er = samples.positions[s_idx]; - const Vec3f &normal = samples.normals[s_idx]; - // apply the local direction via Frame struct - the local_dir is with respect to +Z being forward - Frame f; - f.set_from_z(normal); - - for (const auto &dir : precomputed_sample_directions) { - Vec3f final_ray_dir = (f.to_world(dir)); - if (!model_contains_negative_parts) { - igl::Hit hitpoint; - // FIXME: This AABBTTreeIndirect query will not compile for float ray origin and - // direction. - Vec3d final_ray_dir_d = final_ray_dir.cast(); - Vec3d ray_origin_d = (center + normal * 0.01f).cast(); // start above surface. - bool hit = AABBTreeIndirect::intersect_ray_first_hit(triangles.vertices, - triangles.indices, raycasting_tree, ray_origin_d, final_ray_dir_d, hitpoint); - if (hit && its_face_normal(triangles, hitpoint.id).dot(final_ray_dir) <= 0) { - result[s_idx] -= decrease_step; - } - } else { //TODO improve logic for order based boolean operations - consider order of volumes - bool casting_from_negative_volume = samples.triangle_indices[s_idx] - >= negative_volumes_start_index; - - Vec3d ray_origin_d = (center + normal * 0.01f).cast(); // start above surface. - if (casting_from_negative_volume) { // if casting from negative volume face, invert direction, change start pos - final_ray_dir = -1.0 * final_ray_dir; - ray_origin_d = (center - normal * 0.01f).cast(); - } - Vec3d final_ray_dir_d = final_ray_dir.cast(); - bool some_hit = AABBTreeIndirect::intersect_ray_all_hits(triangles.vertices, - triangles.indices, raycasting_tree, - ray_origin_d, final_ray_dir_d, hits); - if (some_hit) { - int counter = 0; - // NOTE: iterating in reverse, from the last hit for one simple reason: We know the state of the ray at that point; - // It cannot be inside model, and it cannot be inside negative volume - for (int hit_index = int(hits.size()) - 1; hit_index >= 0; --hit_index) { - Vec3f face_normal = its_face_normal(triangles, hits[hit_index].id); - if (hits[hit_index].id >= int(negative_volumes_start_index)) { //negative volume hit - counter -= sgn(face_normal.dot(final_ray_dir)); // if volume face aligns with ray dir, we are leaving negative space - // which in reverse hit analysis means, that we are entering negative space :) and vice versa - } else { - counter += sgn(face_normal.dot(final_ray_dir)); - } - } - if (counter == 0) { - result[s_idx] -= decrease_step; - } + + bool model_contains_negative_parts = negative_volumes_start_index < triangles.indices.size(); + + std::vector result(samples.positions.size()); + tbb::parallel_for(tbb::blocked_range(0, result.size()), [&triangles, &precomputed_sample_directions, model_contains_negative_parts, negative_volumes_start_index, + &raycasting_tree, &result, &samples](tbb::blocked_range r) { + // Maintaining hits memory outside of the loop, so it does not have to be reallocated for each query. + std::vector hits; + for (size_t s_idx = r.begin(); s_idx < r.end(); ++s_idx) { + result[s_idx] = 1.0f; + constexpr float decrease_step = 1.0f / (SeamPlacer::sqr_rays_per_sample_point * SeamPlacer::sqr_rays_per_sample_point); + + const Vec3f ¢er = samples.positions[s_idx]; + const Vec3f &normal = samples.normals[s_idx]; + // apply the local direction via Frame struct - the local_dir is with respect to +Z being forward + Frame f; + f.set_from_z(normal); + + for (const auto &dir : precomputed_sample_directions) { + Vec3f final_ray_dir = (f.to_world(dir)); + if (!model_contains_negative_parts) { + igl::Hit hitpoint; + // FIXME: This AABBTTreeIndirect query will not compile for float ray origin and + // direction. + Vec3d final_ray_dir_d = final_ray_dir.cast(); + Vec3d ray_origin_d = (center + normal * 0.01f).cast(); // start above surface. + bool hit = AABBTreeIndirect::intersect_ray_first_hit(triangles.vertices, triangles.indices, raycasting_tree, ray_origin_d, final_ray_dir_d, hitpoint); + if (hit && its_face_normal(triangles, hitpoint.id).dot(final_ray_dir) <= 0) { result[s_idx] -= decrease_step; } + } else { // TODO improve logic for order based boolean operations - consider order of volumes + bool casting_from_negative_volume = samples.triangle_indices[s_idx] >= negative_volumes_start_index; + + Vec3d ray_origin_d = (center + normal * 0.01f).cast(); // start above surface. + if (casting_from_negative_volume) { // if casting from negative volume face, invert direction, change start pos + final_ray_dir = -1.0 * final_ray_dir; + ray_origin_d = (center - normal * 0.01f).cast(); + } + Vec3d final_ray_dir_d = final_ray_dir.cast(); + bool some_hit = AABBTreeIndirect::intersect_ray_all_hits(triangles.vertices, triangles.indices, raycasting_tree, ray_origin_d, final_ray_dir_d, hits); + if (some_hit) { + int counter = 0; + // NOTE: iterating in reverse, from the last hit for one simple reason: We know the state of the ray at that point; + // It cannot be inside model, and it cannot be inside negative volume + for (int hit_index = int(hits.size()) - 1; hit_index >= 0; --hit_index) { + Vec3f face_normal = its_face_normal(triangles, hits[hit_index].id); + if (hits[hit_index].id >= int(negative_volumes_start_index)) { // negative volume hit + counter -= sgn(face_normal.dot(final_ray_dir)); // if volume face aligns with ray dir, we are leaving negative space + // which in reverse hit analysis means, that we are entering negative space :) and vice versa + } else { + counter += sgn(face_normal.dot(final_ray_dir)); } - } } - } - }); + if (counter == 0) { result[s_idx] -= decrease_step; } + } + } + } + } + }); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: raycast visibility of " << samples.positions.size() << " samples over " << triangles.indices.size() - << " triangles: end"; + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: raycast visibility of " << samples.positions.size() << " samples over " << triangles.indices.size() << " triangles: end"; - return result; + return result; } -std::vector calculate_polygon_angles_at_vertices(const Polygon &polygon, const std::vector &lengths, - float min_arm_length) { - std::vector result(polygon.size()); - - if (polygon.size() == 1) { - result[0] = 0.0f; - } +std::vector calculate_polygon_angles_at_vertices(const Polygon &polygon, const std::vector &lengths, float min_arm_length) +{ + std::vector result(polygon.size()); - size_t idx_prev = 0; - size_t idx_curr = 0; - size_t idx_next = 0; + if (polygon.size() == 1) { result[0] = 0.0f; } - float distance_to_prev = 0; - float distance_to_next = 0; + size_t idx_prev = 0; + size_t idx_curr = 0; + size_t idx_next = 0; - //push idx_prev far enough back as initialization - while (distance_to_prev < min_arm_length) { - idx_prev = Slic3r::prev_idx_modulo(idx_prev, polygon.size()); - distance_to_prev += lengths[idx_prev]; - } + float distance_to_prev = 0; + float distance_to_next = 0; - for (size_t _i = 0; _i < polygon.size(); ++_i) { - // pull idx_prev to current as much as possible, while respecting the min_arm_length - while (distance_to_prev - lengths[idx_prev] > min_arm_length) { - distance_to_prev -= lengths[idx_prev]; - idx_prev = Slic3r::next_idx_modulo(idx_prev, polygon.size()); + // push idx_prev far enough back as initialization + while (distance_to_prev < min_arm_length) { + idx_prev = Slic3r::prev_idx_modulo(idx_prev, polygon.size()); + distance_to_prev += lengths[idx_prev]; } - //push idx_next forward as far as needed - while (distance_to_next < min_arm_length) { - distance_to_next += lengths[idx_next]; - idx_next = Slic3r::next_idx_modulo(idx_next, polygon.size()); - } + for (size_t _i = 0; _i < polygon.size(); ++_i) { + // pull idx_prev to current as much as possible, while respecting the min_arm_length + while (distance_to_prev - lengths[idx_prev] > min_arm_length) { + distance_to_prev -= lengths[idx_prev]; + idx_prev = Slic3r::next_idx_modulo(idx_prev, polygon.size()); + } - // Calculate angle between idx_prev, idx_curr, idx_next. - const Point &p0 = polygon.points[idx_prev]; - const Point &p1 = polygon.points[idx_curr]; - const Point &p2 = polygon.points[idx_next]; - result[idx_curr] = float(angle(p1 - p0, p2 - p1)); + // push idx_next forward as far as needed + while (distance_to_next < min_arm_length) { + distance_to_next += lengths[idx_next]; + idx_next = Slic3r::next_idx_modulo(idx_next, polygon.size()); + } - // increase idx_curr by one - float curr_distance = lengths[idx_curr]; - idx_curr++; - distance_to_prev += curr_distance; - distance_to_next -= curr_distance; - } + // Calculate angle between idx_prev, idx_curr, idx_next. + const Point &p0 = polygon.points[idx_prev]; + const Point &p1 = polygon.points[idx_curr]; + const Point &p2 = polygon.points[idx_next]; + result[idx_curr] = float(angle(p1 - p0, p2 - p1)); + + // increase idx_curr by one + float curr_distance = lengths[idx_curr]; + idx_curr++; + distance_to_prev += curr_distance; + distance_to_next -= curr_distance; + } - return result; + return result; } -struct CoordinateFunctor { - const std::vector *coordinates; - CoordinateFunctor(const std::vector *coords) : - coordinates(coords) { - } - CoordinateFunctor() : - coordinates(nullptr) { - } - - const float& operator()(size_t idx, size_t dim) const { - return coordinates->operator [](idx)[dim]; - } +struct CoordinateFunctor +{ + const std::vector *coordinates; + CoordinateFunctor(const std::vector *coords) : coordinates(coords) {} + CoordinateFunctor() : coordinates(nullptr) {} + + const float &operator()(size_t idx, size_t dim) const { return coordinates->operator[](idx)[dim]; } }; // structure to store global information about the model - occlusion hits, enforcers, blockers -struct GlobalModelInfo { - TriangleSetSamples mesh_samples; - std::vector mesh_samples_visibility; - CoordinateFunctor mesh_samples_coordinate_functor; - KDTreeIndirect<3, float, CoordinateFunctor> mesh_samples_tree { CoordinateFunctor { } }; - float mesh_samples_radius; - - indexed_triangle_set enforcers; - indexed_triangle_set blockers; - AABBTreeIndirect::Tree<3, float> enforcers_tree; - AABBTreeIndirect::Tree<3, float> blockers_tree; - - bool is_enforced(const Vec3f &position, float radius) const { - if (enforcers.empty()) { - return false; - } - float radius_sqr = radius * radius; - return AABBTreeIndirect::is_any_triangle_in_radius(enforcers.vertices, enforcers.indices, - enforcers_tree, position, radius_sqr); - } - - bool is_blocked(const Vec3f &position, float radius) const { - if (blockers.empty()) { - return false; - } - float radius_sqr = radius * radius; - return AABBTreeIndirect::is_any_triangle_in_radius(blockers.vertices, blockers.indices, - blockers_tree, position, radius_sqr); - } - - float calculate_point_visibility(const Vec3f &position) const { - std::vector points = find_nearby_points(mesh_samples_tree, position, mesh_samples_radius); - if (points.empty()) { - return 1.0f; +struct GlobalModelInfo +{ + TriangleSetSamples mesh_samples; + std::vector mesh_samples_visibility; + CoordinateFunctor mesh_samples_coordinate_functor; + KDTreeIndirect<3, float, CoordinateFunctor> mesh_samples_tree{CoordinateFunctor{}}; + float mesh_samples_radius; + + indexed_triangle_set enforcers; + indexed_triangle_set blockers; + AABBTreeIndirect::Tree<3, float> enforcers_tree; + AABBTreeIndirect::Tree<3, float> blockers_tree; + + bool is_enforced(const Vec3f &position, float radius) const + { + if (enforcers.empty()) { return false; } + float radius_sqr = radius * radius; + return AABBTreeIndirect::is_any_triangle_in_radius(enforcers.vertices, enforcers.indices, enforcers_tree, position, radius_sqr); } - auto compute_dist_to_plane = [](const Vec3f &position, const Vec3f &plane_origin, const Vec3f &plane_normal) { - Vec3f orig_to_point = position - plane_origin; - return std::abs(orig_to_point.dot(plane_normal)); - }; - - float total_weight = 0; - float total_visibility = 0; - for (size_t i = 0; i < points.size(); ++i) { - size_t sample_idx = points[i]; - - Vec3f sample_point = this->mesh_samples.positions[sample_idx]; - Vec3f sample_normal = this->mesh_samples.normals[sample_idx]; - - float weight = mesh_samples_radius - compute_dist_to_plane(position, sample_point, sample_normal); - weight += (mesh_samples_radius - (position - sample_point).norm()); - total_visibility += weight * mesh_samples_visibility[sample_idx]; - total_weight += weight; + bool is_blocked(const Vec3f &position, float radius) const + { + if (blockers.empty()) { return false; } + float radius_sqr = radius * radius; + return AABBTreeIndirect::is_any_triangle_in_radius(blockers.vertices, blockers.indices, blockers_tree, position, radius_sqr); } - return total_visibility / total_weight; + float calculate_point_visibility(const Vec3f &position) const + { + std::vector points = find_nearby_points(mesh_samples_tree, position, mesh_samples_radius); + if (points.empty()) { return 1.0f; } + + auto compute_dist_to_plane = [](const Vec3f &position, const Vec3f &plane_origin, const Vec3f &plane_normal) { + Vec3f orig_to_point = position - plane_origin; + return std::abs(orig_to_point.dot(plane_normal)); + }; + + float total_weight = 0; + float total_visibility = 0; + for (size_t i = 0; i < points.size(); ++i) { + size_t sample_idx = points[i]; + + Vec3f sample_point = this->mesh_samples.positions[sample_idx]; + Vec3f sample_normal = this->mesh_samples.normals[sample_idx]; + + float weight = mesh_samples_radius - compute_dist_to_plane(position, sample_point, sample_normal); + weight += (mesh_samples_radius - (position - sample_point).norm()); + total_visibility += weight * mesh_samples_visibility[sample_idx]; + total_weight += weight; + } - } + return total_visibility / total_weight; + } #ifdef DEBUG_FILES - void debug_export(const indexed_triangle_set &obj_mesh) const { + void debug_export(const indexed_triangle_set &obj_mesh) const + { + indexed_triangle_set divided_mesh = obj_mesh; + Slic3r::CNumericLocalesSetter locales_setter; + + { + auto filename = debug_out_path("visiblity.obj"); + FILE *fp = boost::nowide::fopen(filename.c_str(), "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << filename << " for writing"; + return; + } - indexed_triangle_set divided_mesh = obj_mesh; - Slic3r::CNumericLocalesSetter locales_setter; + for (size_t i = 0; i < divided_mesh.vertices.size(); ++i) { + float visibility = calculate_point_visibility(divided_mesh.vertices[i]); + Vec3f color = value_to_rgbf(0.0f, 1.0f, visibility); + fprintf(fp, "v %f %f %f %f %f %f\n", divided_mesh.vertices[i](0), divided_mesh.vertices[i](1), divided_mesh.vertices[i](2), color(0), color(1), color(2)); + } + for (size_t i = 0; i < divided_mesh.indices.size(); ++i) + fprintf(fp, "f %d %d %d\n", divided_mesh.indices[i][0] + 1, divided_mesh.indices[i][1] + 1, divided_mesh.indices[i][2] + 1); + fclose(fp); + } - { - auto filename = debug_out_path("visiblity.obj"); - FILE *fp = boost::nowide::fopen(filename.c_str(), "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) - << "stl_write_obj: Couldn't open " << filename << " for writing"; - return; - } - - for (size_t i = 0; i < divided_mesh.vertices.size(); ++i) { - float visibility = calculate_point_visibility(divided_mesh.vertices[i]); - Vec3f color = value_to_rgbf(0.0f, 1.0f, visibility); - fprintf(fp, "v %f %f %f %f %f %f\n", - divided_mesh.vertices[i](0), divided_mesh.vertices[i](1), divided_mesh.vertices[i](2), - color(0), color(1), color(2)); - } - for (size_t i = 0; i < divided_mesh.indices.size(); ++i) - fprintf(fp, "f %d %d %d\n", divided_mesh.indices[i][0] + 1, divided_mesh.indices[i][1] + 1, - divided_mesh.indices[i][2] + 1); - fclose(fp); - } + { + auto filename = debug_out_path("visiblity_samples.obj"); + FILE *fp = boost::nowide::fopen(filename.c_str(), "w"); + if (fp == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << filename << " for writing"; + return; + } - { - auto filename = debug_out_path("visiblity_samples.obj"); - FILE *fp = boost::nowide::fopen(filename.c_str(), "w"); - if (fp == nullptr) { - BOOST_LOG_TRIVIAL(error) - << "stl_write_obj: Couldn't open " << filename << " for writing"; - return; - } - - for (size_t i = 0; i < mesh_samples.positions.size(); ++i) { - float visibility = mesh_samples_visibility[i]; - Vec3f color = value_to_rgbf(0.0f, 1.0f, visibility); - fprintf(fp, "v %f %f %f %f %f %f\n", - mesh_samples.positions[i](0), mesh_samples.positions[i](1), mesh_samples.positions[i](2), - color(0), color(1), color(2)); - } - fclose(fp); + for (size_t i = 0; i < mesh_samples.positions.size(); ++i) { + float visibility = mesh_samples_visibility[i]; + Vec3f color = value_to_rgbf(0.0f, 1.0f, visibility); + fprintf(fp, "v %f %f %f %f %f %f\n", mesh_samples.positions[i](0), mesh_samples.positions[i](1), mesh_samples.positions[i](2), color(0), color(1), color(2)); + } + fclose(fp); + } } - - } #endif -} -; - -//Extract perimeter polygons of the given layer -Polygons extract_perimeter_polygons(const Layer *layer, std::vector &corresponding_regions_out) { - Polygons polygons; - for (const LayerRegion *layer_region : layer->regions()) { - for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) { - if (ex_entity->is_collection()) { //collection of inner, outer, and overhang perimeters - for (const ExtrusionEntity *perimeter : static_cast(ex_entity)->entities) { - ExtrusionRole role = perimeter->role(); - if (perimeter->is_loop()) { - for (const ExtrusionPath &path : static_cast(perimeter)->paths) { - if (path.role() == ExtrusionRole::erExternalPerimeter) { - role = ExtrusionRole::erExternalPerimeter; - } +}; + +// Extract perimeter polygons of the given layer +Polygons extract_perimeter_polygons(const Layer *layer, const SeamPosition configured_seam_preference, std::vector &corresponding_regions_out) +{ + Polygons polygons; + for (const LayerRegion *layer_region : layer->regions()) { + for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) { + if (ex_entity->is_collection()) { // collection of inner, outer, and overhang perimeters + for (const ExtrusionEntity *perimeter : static_cast(ex_entity)->entities) { + ExtrusionRole role = perimeter->role(); + if (perimeter->is_loop()) { + for (const ExtrusionPath &path : static_cast(perimeter)->paths) { + if (path.role() == ExtrusionRole::erExternalPerimeter) { role = ExtrusionRole::erExternalPerimeter; } + } + } + + if (role == ExtrusionRole::erExternalPerimeter || + (is_perimeter(role) && configured_seam_preference == spRandom)) { // for random seam alignment, extract all perimeters + Points p; + perimeter->collect_points(p); + polygons.emplace_back(std::move(p)); + corresponding_regions_out.push_back(layer_region); + } + } + if (polygons.empty()) { + Points p; + ex_entity->collect_points(p); + polygons.emplace_back(std::move(p)); + corresponding_regions_out.push_back(layer_region); + } + } else { + Points p; + ex_entity->collect_points(p); + polygons.emplace_back(std::move(p)); + corresponding_regions_out.push_back(layer_region); } - } - - if (role == ExtrusionRole::erExternalPerimeter) { - Points p; - perimeter->collect_points(p); - polygons.emplace_back(std::move(p)); - corresponding_regions_out.push_back(layer_region); - } - } - if (polygons.empty()) { - Points p; - ex_entity->collect_points(p); - polygons.emplace_back(std::move(p)); - corresponding_regions_out.push_back(layer_region); } - } else { - Points p; - ex_entity->collect_points(p); - polygons.emplace_back(std::move(p)); - corresponding_regions_out.push_back(layer_region); - } } - } - if (polygons.empty()) { // If there are no perimeter polygons for whatever reason (disabled perimeters .. ) insert dummy point - // it is easier than checking everywhere if the layer is not emtpy, no seam will be placed to this layer anyway - polygons.emplace_back(Points{ { 0, 0 } }); - corresponding_regions_out.push_back(nullptr); - } + if (polygons.empty()) { // If there are no perimeter polygons for whatever reason (disabled perimeters .. ) insert dummy point + // it is easier than checking everywhere if the layer is not emtpy, no seam will be placed to this layer anyway + polygons.emplace_back(std::vector{Point{0, 0}}); + corresponding_regions_out.push_back(nullptr); + } - return polygons; + return polygons; } // Insert SeamCandidates created from perimeter polygons in to the result vector. // Compute its type (Enfrocer,Blocker), angle, and position -//each SeamCandidate also contains pointer to shared Perimeter structure representing the polygon +// each SeamCandidate also contains pointer to shared Perimeter structure representing the polygon // if Custom Seam modifiers are present, oversamples the polygon if necessary to better fit user intentions -void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const LayerRegion *region, - const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) { - if (orig_polygon.size() == 0) { - return; - } - Polygon polygon = orig_polygon; - bool was_clockwise = polygon.make_counter_clockwise(); - float angle_arm_len = region != nullptr ? region->flow(FlowRole::frExternalPerimeter).nozzle_diameter() : 0.5f; - - std::vector lengths { }; - for (size_t point_idx = 0; point_idx < polygon.size() - 1; ++point_idx) { - lengths.push_back((unscale(polygon[point_idx]) - unscale(polygon[point_idx + 1])).norm()); - } - lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1)); - std::vector polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, - angle_arm_len); - - result.perimeters.push_back( { }); - Perimeter &perimeter = result.perimeters.back(); - - std::queue orig_polygon_points { }; - for (size_t index = 0; index < polygon.size(); ++index) { - Vec2f unscaled_p = unscale(polygon[index]).cast(); - orig_polygon_points.emplace(unscaled_p.x(), unscaled_p.y(), z_coord); - } - Vec3f first = orig_polygon_points.front(); - std::queue oversampled_points { }; - size_t orig_angle_index = 0; - perimeter.start_index = result.points.size(); - perimeter.flow_width = region != nullptr ? region->flow(FlowRole::frExternalPerimeter).width() : 0.0f; - bool some_point_enforced = false; - while (!orig_polygon_points.empty() || !oversampled_points.empty()) { - EnforcedBlockedSeamPoint type = EnforcedBlockedSeamPoint::Neutral; - Vec3f position; - float local_ccw_angle = 0; - bool orig_point = false; - if (!oversampled_points.empty()) { - position = oversampled_points.front(); - oversampled_points.pop(); - } else { - position = orig_polygon_points.front(); - orig_polygon_points.pop(); - local_ccw_angle = was_clockwise ? -polygon_angles[orig_angle_index] : polygon_angles[orig_angle_index]; - orig_angle_index++; - orig_point = true; - } - - if (global_model_info.is_enforced(position, perimeter.flow_width)) { - type = EnforcedBlockedSeamPoint::Enforced; +void process_perimeter_polygon( + const Polygon &orig_polygon, float z_coord, const LayerRegion *region, const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) +{ + if (orig_polygon.size() == 0) { return; } + Polygon polygon = orig_polygon; + bool was_clockwise = polygon.make_counter_clockwise(); + float angle_arm_len = region != nullptr ? region->flow(FlowRole::frExternalPerimeter).nozzle_diameter() : 0.5f; + + std::vector lengths{}; + for (size_t point_idx = 0; point_idx < polygon.size() - 1; ++point_idx) { lengths.push_back((unscale(polygon[point_idx]) - unscale(polygon[point_idx + 1])).norm()); } + lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1)); + std::vector polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, angle_arm_len); + + result.perimeters.push_back({}); + Perimeter &perimeter = result.perimeters.back(); + + std::queue orig_polygon_points{}; + for (size_t index = 0; index < polygon.size(); ++index) { + Vec2f unscaled_p = unscale(polygon[index]).cast(); + orig_polygon_points.emplace(unscaled_p.x(), unscaled_p.y(), z_coord); } + Vec3f first = orig_polygon_points.front(); + std::queue oversampled_points{}; + size_t orig_angle_index = 0; + perimeter.start_index = result.points.size(); + perimeter.flow_width = region != nullptr ? region->flow(FlowRole::frExternalPerimeter).width() : 0.0f; + bool some_point_enforced = false; + while (!orig_polygon_points.empty() || !oversampled_points.empty()) { + EnforcedBlockedSeamPoint type = EnforcedBlockedSeamPoint::Neutral; + Vec3f position; + float local_ccw_angle = 0; + bool orig_point = false; + if (!oversampled_points.empty()) { + position = oversampled_points.front(); + oversampled_points.pop(); + } else { + position = orig_polygon_points.front(); + orig_polygon_points.pop(); + local_ccw_angle = was_clockwise ? -polygon_angles[orig_angle_index] : polygon_angles[orig_angle_index]; + orig_angle_index++; + orig_point = true; + } - if (global_model_info.is_blocked(position, perimeter.flow_width)) { - type = EnforcedBlockedSeamPoint::Blocked; - } - some_point_enforced = some_point_enforced || type == EnforcedBlockedSeamPoint::Enforced; - - if (orig_point) { - Vec3f pos_of_next = orig_polygon_points.empty() ? first : orig_polygon_points.front(); - float distance_to_next = (position - pos_of_next).norm(); - if (global_model_info.is_enforced(position, distance_to_next)) { - Vec3f vec_to_next = (pos_of_next - position).normalized(); - float step_size = SeamPlacer::enforcer_oversampling_distance; - float step = step_size; - while (step < distance_to_next) { - oversampled_points.push(position + vec_to_next * step); - step += step_size; + if (global_model_info.is_enforced(position, perimeter.flow_width)) { type = EnforcedBlockedSeamPoint::Enforced; } + + if (global_model_info.is_blocked(position, perimeter.flow_width)) { type = EnforcedBlockedSeamPoint::Blocked; } + some_point_enforced = some_point_enforced || type == EnforcedBlockedSeamPoint::Enforced; + + if (orig_point) { + Vec3f pos_of_next = orig_polygon_points.empty() ? first : orig_polygon_points.front(); + float distance_to_next = (position - pos_of_next).norm(); + if (distance_to_next > perimeter.flow_width * perimeter.flow_width * 4) + oversampled_points.push((position + pos_of_next) / 2); + if (global_model_info.is_enforced(position, distance_to_next)) { + Vec3f vec_to_next = (pos_of_next - position).normalized(); + float step_size = SeamPlacer::enforcer_oversampling_distance; + float step = step_size; + while (step < distance_to_next) { + oversampled_points.push(position + vec_to_next * step); + step += step_size; + } + } } - } - } - result.points.emplace_back(position, perimeter, local_ccw_angle, type); - } + result.points.emplace_back(position, perimeter, local_ccw_angle, type); + } - perimeter.end_index = result.points.size(); + perimeter.end_index = result.points.size(); - if (some_point_enforced) { - // We will patches of enforced points (patch: continuous section of enforced points), choose - // the longest patch, and select the middle point or sharp point (depending on the angle) - // this point will have high priority on this perimeter - size_t perimeter_size = perimeter.end_index - perimeter.start_index; - const auto next_index = [&](size_t idx) { - return perimeter.start_index + Slic3r::next_idx_modulo(idx - perimeter.start_index, perimeter_size); - }; + if (some_point_enforced) { + // We will patches of enforced points (patch: continuous section of enforced points), choose + // the longest patch, and select the middle point or sharp point (depending on the angle) + // this point will have high priority on this perimeter + size_t perimeter_size = perimeter.end_index - perimeter.start_index; + const auto next_index = [&](size_t idx) { return perimeter.start_index + Slic3r::next_idx_modulo(idx - perimeter.start_index, perimeter_size); }; - std::vector patches_starts_ends; - for (size_t i = perimeter.start_index; i < perimeter.end_index; ++i) { - if (result.points[i].type != EnforcedBlockedSeamPoint::Enforced && - result.points[next_index(i)].type == EnforcedBlockedSeamPoint::Enforced) { - patches_starts_ends.push_back(next_index(i)); - } - if (result.points[i].type == EnforcedBlockedSeamPoint::Enforced && - result.points[next_index(i)].type != EnforcedBlockedSeamPoint::Enforced) { - patches_starts_ends.push_back(next_index(i)); - } - } - //if patches_starts_ends are empty, it means that the whole perimeter is enforced.. don't do anything in that case - if (!patches_starts_ends.empty()) { - //if the first point in the patches is not enforced, it marks a patch end. in that case, put it to the end and start on next - // to simplify the processing - assert(patches_starts_ends.size() % 2 == 0); - bool start_on_second = false; - if (result.points[patches_starts_ends[0]].type != EnforcedBlockedSeamPoint::Enforced) { - start_on_second = true; - patches_starts_ends.push_back(patches_starts_ends[0]); - } - //now pick the longest patch - std::pair longest_patch { 0, 0 }; - auto patch_len = [perimeter_size](const std::pair &start_end) { - if (start_end.second < start_end.first) { - return start_end.first + (perimeter_size - start_end.second); - } else { - return start_end.second - start_end.first; - } - }; - for (size_t patch_idx = start_on_second ? 1 : 0; patch_idx < patches_starts_ends.size(); patch_idx += 2) { - std::pair current_patch { patches_starts_ends[patch_idx], patches_starts_ends[patch_idx - + 1] }; - if (patch_len(longest_patch) < patch_len(current_patch)) { - longest_patch = current_patch; + std::vector patches_starts_ends; + for (size_t i = perimeter.start_index; i < perimeter.end_index; ++i) { + if (result.points[i].type != EnforcedBlockedSeamPoint::Enforced && result.points[next_index(i)].type == EnforcedBlockedSeamPoint::Enforced) { + patches_starts_ends.push_back(next_index(i)); + } + if (result.points[i].type == EnforcedBlockedSeamPoint::Enforced && result.points[next_index(i)].type != EnforcedBlockedSeamPoint::Enforced) { + patches_starts_ends.push_back(next_index(i)); + } } - } - std::vector viable_points_indices; - std::vector large_angle_points_indices; - for (size_t point_idx = longest_patch.first; point_idx != longest_patch.second; - point_idx = next_index(point_idx)) { - viable_points_indices.push_back(point_idx); - if (std::abs(result.points[point_idx].local_ccw_angle) - > SeamPlacer::sharp_angle_snapping_threshold) { - large_angle_points_indices.push_back(point_idx); + // if patches_starts_ends are empty, it means that the whole perimeter is enforced.. don't do anything in that case + if (!patches_starts_ends.empty()) { + // if the first point in the patches is not enforced, it marks a patch end. in that case, put it to the end and start on next + // to simplify the processing + assert(patches_starts_ends.size() % 2 == 0); + bool start_on_second = false; + if (result.points[patches_starts_ends[0]].type != EnforcedBlockedSeamPoint::Enforced) { + start_on_second = true; + patches_starts_ends.push_back(patches_starts_ends[0]); + } + // now pick the longest patch + std::pair longest_patch{0, 0}; + auto patch_len = [perimeter_size](const std::pair &start_end) { + if (start_end.second < start_end.first) { + return start_end.first + (perimeter_size - start_end.second); + } else { + return start_end.second - start_end.first; + } + }; + for (size_t patch_idx = start_on_second ? 1 : 0; patch_idx < patches_starts_ends.size(); patch_idx += 2) { + std::pair current_patch{patches_starts_ends[patch_idx], patches_starts_ends[patch_idx + 1]}; + if (patch_len(longest_patch) < patch_len(current_patch)) { longest_patch = current_patch; } + } + std::vector viable_points_indices; + std::vector large_angle_points_indices; + for (size_t point_idx = longest_patch.first; point_idx != longest_patch.second; point_idx = next_index(point_idx)) { + viable_points_indices.push_back(point_idx); + if (std::abs(result.points[point_idx].local_ccw_angle) > SeamPlacer::sharp_angle_snapping_threshold) { large_angle_points_indices.push_back(point_idx); } + } + assert(viable_points_indices.size() > 0); + if (large_angle_points_indices.empty()) { + size_t central_idx = viable_points_indices[viable_points_indices.size() / 2]; + result.points[central_idx].central_enforcer = true; + } else { + size_t central_idx = large_angle_points_indices.size() / 2; + result.points[large_angle_points_indices[central_idx]].central_enforcer = true; + } } - } - assert(viable_points_indices.size() > 0); - if (large_angle_points_indices.empty()) { - size_t central_idx = viable_points_indices[viable_points_indices.size() / 2]; - result.points[central_idx].central_enforcer = true; - } else { - size_t central_idx = large_angle_points_indices.size() / 2; - result.points[large_angle_points_indices[central_idx]].central_enforcer = true; - } } - } - } // Get index of previous and next perimeter point of the layer. Because SeamCandidates of all polygons of the given layer // are sequentially stored in the vector, each perimeter contains info about start and end index. These vales are used to // deduce index of previous and next neigbour in the corresponding perimeter. -std::pair find_previous_and_next_perimeter_point(const std::vector &perimeter_points, - size_t point_index) { - const SeamCandidate ¤t = perimeter_points[point_index]; - int prev = point_index - 1; //for majority of points, it is true that neighbours lie behind and in front of them in the vector - int next = point_index + 1; - - if (point_index == current.perimeter.start_index) { - // if point_index is equal to start, it means that the previous neighbour is at the end - prev = current.perimeter.end_index; - } - - if (point_index == current.perimeter.end_index - 1) { - // if point_index is equal to end, than next neighbour is at the start - next = current.perimeter.start_index; - } - - assert(prev >= 0); - assert(next >= 0); - return {size_t(prev),size_t(next)}; +std::pair find_previous_and_next_perimeter_point(const std::vector &perimeter_points, size_t point_index) +{ + const SeamCandidate ¤t = perimeter_points[point_index]; + int prev = point_index - 1; // for majority of points, it is true that neighbours lie behind and in front of them in the vector + int next = point_index + 1; + + if (point_index == current.perimeter.start_index) { + // if point_index is equal to start, it means that the previous neighbour is at the end + prev = current.perimeter.end_index; + } + + if (point_index == current.perimeter.end_index - 1) { + // if point_index is equal to end, than next neighbour is at the start + next = current.perimeter.start_index; + } + + assert(prev >= 0); + assert(next >= 0); + return {size_t(prev), size_t(next)}; } // Computes all global model info - transforms object, performs raycasting -void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po, - std::function throw_if_canceled) { - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: gather occlusion meshes: start"; - auto obj_transform = po->trafo_centered(); - indexed_triangle_set triangle_set; - indexed_triangle_set negative_volumes_set; - //add all parts - for (const ModelVolume *model_volume : po->model_object()->volumes) { - if (model_volume->type() == ModelVolumeType::MODEL_PART - || model_volume->type() == ModelVolumeType::NEGATIVE_VOLUME) { - auto model_transformation = model_volume->get_matrix(); - indexed_triangle_set model_its = model_volume->mesh().its; - its_transform(model_its, model_transformation); - if (model_volume->type() == ModelVolumeType::MODEL_PART) { - its_merge(triangle_set, model_its); - } else { - its_merge(negative_volumes_set, model_its); - } +void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po, std::function throw_if_canceled) +{ + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: gather occlusion meshes: start"; + auto obj_transform = po->trafo_centered(); + indexed_triangle_set triangle_set; + indexed_triangle_set negative_volumes_set; + // add all parts + for (const ModelVolume *model_volume : po->model_object()->volumes) { + if (model_volume->type() == ModelVolumeType::MODEL_PART || model_volume->type() == ModelVolumeType::NEGATIVE_VOLUME) { + auto model_transformation = model_volume->get_matrix(); + indexed_triangle_set model_its = model_volume->mesh().its; + its_transform(model_its, model_transformation); + if (model_volume->type() == ModelVolumeType::MODEL_PART) { + its_merge(triangle_set, model_its); + } else { + its_merge(negative_volumes_set, model_its); + } + } } - } - throw_if_canceled(); - - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: gather occlusion meshes: end"; - - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: decimate: start"; - its_short_edge_collpase(triangle_set, SeamPlacer::fast_decimation_triangle_count_target); - its_short_edge_collpase(negative_volumes_set, SeamPlacer::fast_decimation_triangle_count_target); - - size_t negative_volumes_start_index = triangle_set.indices.size(); - its_merge(triangle_set, negative_volumes_set); - its_transform(triangle_set, obj_transform); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: decimate: end"; - - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: Compute visibility sample points: start"; - - result.mesh_samples = sample_its_uniform_parallel(SeamPlacer::raycasting_visibility_samples_count, - triangle_set); - result.mesh_samples_coordinate_functor = CoordinateFunctor(&result.mesh_samples.positions); - result.mesh_samples_tree = KDTreeIndirect<3, float, CoordinateFunctor>(result.mesh_samples_coordinate_functor, - result.mesh_samples.positions.size()); - - // The following code determines search area for random visibility samples on the mesh when calculating visibility of each perimeter point - // number of random samples in the given radius (area) is approximately poisson distribution - // to compute ideal search radius (area), we use exponential distribution (complementary distr to poisson) - // parameters of exponential distribution to compute area that will have with probability="probability" more than given number of samples="samples" - float probability = 0.9f; - float samples = 4; - float density = SeamPlacer::raycasting_visibility_samples_count / result.mesh_samples.total_area; - // exponential probability distrubtion function is : f(x) = P(X > x) = e^(l*x) where l is the rate parameter (computed as 1/u where u is mean value) - // probability that sampled area A with S samples contains more than samples count: - // P(S > samples in A) = e^-(samples/(density*A)); express A: - float search_area = samples / (-logf(probability) * density); - float search_radius = sqrt(search_area / PI); - result.mesh_samples_radius = search_radius; - - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: Compute visiblity sample points: end"; - throw_if_canceled(); - - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: Mesh sample raidus: " << result.mesh_samples_radius; - - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: build AABB tree: start"; - auto raycasting_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(triangle_set.vertices, - triangle_set.indices); - - throw_if_canceled(); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: build AABB tree: end"; - result.mesh_samples_visibility = raycast_visibility(raycasting_tree, triangle_set, result.mesh_samples, - negative_volumes_start_index); - throw_if_canceled(); + throw_if_canceled(); + + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: gather occlusion meshes: end"; + + BOOST_LOG_TRIVIAL(debug) + << "SeamPlacer: decimate: start"; + its_short_edge_collpase(triangle_set, SeamPlacer::fast_decimation_triangle_count_target); + its_short_edge_collpase(negative_volumes_set, SeamPlacer::fast_decimation_triangle_count_target); + + size_t negative_volumes_start_index = triangle_set.indices.size(); + its_merge(triangle_set, negative_volumes_set); + its_transform(triangle_set, obj_transform); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: decimate: end"; + + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: Compute visibility sample points: start"; + + result.mesh_samples = sample_its_uniform_parallel(SeamPlacer::raycasting_visibility_samples_count, triangle_set); + result.mesh_samples_coordinate_functor = CoordinateFunctor(&result.mesh_samples.positions); + result.mesh_samples_tree = KDTreeIndirect<3, float, CoordinateFunctor>(result.mesh_samples_coordinate_functor, result.mesh_samples.positions.size()); + + // The following code determines search area for random visibility samples on the mesh when calculating visibility of each perimeter point + // number of random samples in the given radius (area) is approximately poisson distribution + // to compute ideal search radius (area), we use exponential distribution (complementary distr to poisson) + // parameters of exponential distribution to compute area that will have with probability="probability" more than given number of samples="samples" + float probability = 0.9f; + float samples = 4; + float density = SeamPlacer::raycasting_visibility_samples_count / result.mesh_samples.total_area; + // exponential probability distrubtion function is : f(x) = P(X > x) = e^(l*x) where l is the rate parameter (computed as 1/u where u is mean value) + // probability that sampled area A with S samples contains more than samples count: + // P(S > samples in A) = e^-(samples/(density*A)); express A: + float search_area = samples / (-logf(probability) * density); + float search_radius = sqrt(search_area / PI); + result.mesh_samples_radius = search_radius; + + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: Compute visiblity sample points: end"; + throw_if_canceled(); + + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: Mesh sample raidus: " << result.mesh_samples_radius; + + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: build AABB tree: start"; + auto raycasting_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(triangle_set.vertices, triangle_set.indices); + + throw_if_canceled(); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: build AABB tree: end"; + result.mesh_samples_visibility = raycast_visibility(raycasting_tree, triangle_set, result.mesh_samples, negative_volumes_start_index); + throw_if_canceled(); #ifdef DEBUG_FILES - result.debug_export(triangle_set); + result.debug_export(triangle_set); #endif } -void gather_enforcers_blockers(GlobalModelInfo &result, const PrintObject *po) { - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: build AABB trees for raycasting enforcers/blockers: start"; +void gather_enforcers_blockers(GlobalModelInfo &result, const PrintObject *po) +{ + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: build AABB trees for raycasting enforcers/blockers: start"; - auto obj_transform = po->trafo_centered(); + auto obj_transform = po->trafo_centered(); - for (const ModelVolume *mv : po->model_object()->volumes) { - if (mv->is_seam_painted()) { - auto model_transformation = obj_transform * mv->get_matrix(); + for (const ModelVolume *mv : po->model_object()->volumes) { + if (mv->is_seam_painted()) { + auto model_transformation = obj_transform * mv->get_matrix(); - indexed_triangle_set enforcers = mv->seam_facets.get_facets(*mv, EnforcerBlockerType::ENFORCER); - its_transform(enforcers, model_transformation); - its_merge(result.enforcers, enforcers); + indexed_triangle_set enforcers = mv->seam_facets.get_facets(*mv, EnforcerBlockerType::ENFORCER); + its_transform(enforcers, model_transformation); + its_merge(result.enforcers, enforcers); - indexed_triangle_set blockers = mv->seam_facets.get_facets(*mv, EnforcerBlockerType::BLOCKER); - its_transform(blockers, model_transformation); - its_merge(result.blockers, blockers); + indexed_triangle_set blockers = mv->seam_facets.get_facets(*mv, EnforcerBlockerType::BLOCKER); + its_transform(blockers, model_transformation); + its_merge(result.blockers, blockers); + } } - } - result.enforcers_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(result.enforcers.vertices, - result.enforcers.indices); - result.blockers_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(result.blockers.vertices, - result.blockers.indices); + result.enforcers_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(result.enforcers.vertices, result.enforcers.indices); + result.blockers_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(result.blockers.vertices, result.blockers.indices); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: build AABB trees for raycasting enforcers/blockers: end"; + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: build AABB trees for raycasting enforcers/blockers: end"; } -struct SeamComparator { - SeamPosition setup; - float angle_importance; - explicit SeamComparator(SeamPosition setup) : - setup(setup) { - angle_importance = - setup == spNearest ? SeamPlacer::angle_importance_nearest : SeamPlacer::angle_importance_aligned; - } - - // Standard comparator, must respect the requirements of comparators (e.g. give same result on same inputs) for sorting usage - // should return if a is better seamCandidate than b - bool is_first_better(const SeamCandidate &a, const SeamCandidate &b, const Vec2f &preffered_location = Vec2f { 0.0f, - 0.0f }) const { - if (setup == SeamPosition::spAligned && a.central_enforcer != b.central_enforcer) { - return a.central_enforcer; +struct SeamComparator +{ + SeamPosition setup; + float angle_importance; + explicit SeamComparator(SeamPosition setup) : setup(setup) + { + angle_importance = setup == spNearest ? SeamPlacer::angle_importance_nearest : SeamPlacer::angle_importance_aligned; } - // Blockers/Enforcers discrimination, top priority - if (a.type != b.type) { - return a.type > b.type; - } + // Standard comparator, must respect the requirements of comparators (e.g. give same result on same inputs) for sorting usage + // should return if a is better seamCandidate than b + bool is_first_better(const SeamCandidate &a, const SeamCandidate &b, const Vec2f &preffered_location = Vec2f{0.0f, 0.0f}) const + { + if (setup == SeamPosition::spAligned && a.central_enforcer != b.central_enforcer) { return a.central_enforcer; } - //avoid overhangs - if (a.overhang > 0.0f || b.overhang > 0.0f) { - return a.overhang < b.overhang; - } + // Blockers/Enforcers discrimination, top priority + if (a.type != b.type) { return a.type > b.type; } - // prefer hidden points (more than 0.5 mm inside) - if (a.embedded_distance < -0.5f && b.embedded_distance > -0.5f) { - return true; - } - if (b.embedded_distance < -0.5f && a.embedded_distance > -0.5f) { - return false; - } + // avoid overhangs + if (a.overhang > 0.0f || b.overhang > 0.0f) { return a.overhang < b.overhang; } - if (setup == SeamPosition::spRear && a.position.y() != b.position.y()) { - return a.position.y() > b.position.y(); - } + // prefer hidden points (more than 0.5 mm inside) + if (a.embedded_distance < -0.5f && b.embedded_distance > -0.5f) { return true; } + if (b.embedded_distance < -0.5f && a.embedded_distance > -0.5f) { return false; } - float distance_penalty_a = 0.0f; - float distance_penalty_b = 0.0f; - if (setup == spNearest) { - distance_penalty_a = 1.0f - gauss((a.position.head<2>() - preffered_location).norm(), 0.0f, 1.0f, 0.005f); - distance_penalty_b = 1.0f - gauss((b.position.head<2>() - preffered_location).norm(), 0.0f, 1.0f, 0.005f); - } + if (setup == SeamPosition::spRear && a.position.y() != b.position.y()) { return a.position.y() > b.position.y(); } - // the penalites are kept close to range [0-1.x] however, it should not be relied upon - float penalty_a = a.overhang + a.visibility + - angle_importance * compute_angle_penalty(a.local_ccw_angle) - + distance_penalty_a; - float penalty_b = b.overhang + b.visibility + - angle_importance * compute_angle_penalty(b.local_ccw_angle) - + distance_penalty_b; - - return penalty_a < penalty_b; - } - - // Comparator used during alignment. If there is close potential aligned point, it is compared to the current - // seam point of the perimeter, to find out if the aligned point is not much worse than the current seam - // Also used by the random seam generator. - bool is_first_not_much_worse(const SeamCandidate &a, const SeamCandidate &b) const { - // Blockers/Enforcers discrimination, top priority - if (setup == SeamPosition::spAligned && a.central_enforcer != b.central_enforcer) { - // Prefer centers of enforcers. - return a.central_enforcer; - } + float distance_penalty_a = 0.0f; + float distance_penalty_b = 0.0f; + if (setup == spNearest) { + distance_penalty_a = 1.0f - gauss((a.position.head<2>() - preffered_location).norm(), 0.0f, 1.0f, 0.005f); + distance_penalty_b = 1.0f - gauss((b.position.head<2>() - preffered_location).norm(), 0.0f, 1.0f, 0.005f); + } - if (a.type == EnforcedBlockedSeamPoint::Enforced) { - return true; - } + // the penalites are kept close to range [0-1.x] however, it should not be relied upon + float penalty_a = a.overhang + a.visibility + angle_importance * compute_angle_penalty(a.local_ccw_angle) + distance_penalty_a; + float penalty_b = b.overhang + b.visibility + angle_importance * compute_angle_penalty(b.local_ccw_angle) + distance_penalty_b; - if (a.type == EnforcedBlockedSeamPoint::Blocked) { - return false; + return penalty_a < penalty_b; } - if (a.type != b.type) { - return a.type > b.type; - } + // Comparator used during alignment. If there is close potential aligned point, it is compared to the current + // seam point of the perimeter, to find out if the aligned point is not much worse than the current seam + // Also used by the random seam generator. + bool is_first_not_much_worse(const SeamCandidate &a, const SeamCandidate &b) const + { + // Blockers/Enforcers discrimination, top priority + if (setup == SeamPosition::spAligned && a.central_enforcer != b.central_enforcer) { + // Prefer centers of enforcers. + return a.central_enforcer; + } - //avoid overhangs - if ((a.overhang > 0.0f || b.overhang > 0.0f) - && abs(a.overhang - b.overhang) > (0.1f * a.perimeter.flow_width)) { - return a.overhang < b.overhang; - } + if (a.type == EnforcedBlockedSeamPoint::Enforced) { return true; } - // prefer hidden points (more than 0.5 mm inside) - if (a.embedded_distance < -0.5f && b.embedded_distance > -0.5f) { - return true; - } - if (b.embedded_distance < -0.5f && a.embedded_distance > -0.5f) { - return false; - } + if (a.type == EnforcedBlockedSeamPoint::Blocked) { return false; } - if (setup == SeamPosition::spRandom) { - return true; - } + if (a.type != b.type) { return a.type > b.type; } - if (setup == SeamPosition::spRear) { - return a.position.y() + SeamPlacer::seam_align_score_tolerance * 5.0f > b.position.y(); - } + // avoid overhangs + if ((a.overhang > 0.0f || b.overhang > 0.0f) && abs(a.overhang - b.overhang) > (0.1f * a.perimeter.flow_width)) { return a.overhang < b.overhang; } - float penalty_a = a.overhang + a.visibility - + angle_importance * compute_angle_penalty(a.local_ccw_angle); - float penalty_b = b.overhang + b.visibility + - angle_importance * compute_angle_penalty(b.local_ccw_angle); + // prefer hidden points (more than 0.5 mm inside) + if (a.embedded_distance < -0.5f && b.embedded_distance > -0.5f) { return true; } + if (b.embedded_distance < -0.5f && a.embedded_distance > -0.5f) { return false; } - return penalty_a <= penalty_b || penalty_a - penalty_b < SeamPlacer::seam_align_score_tolerance; - } + if (setup == SeamPosition::spRandom) { return true; } - bool are_similar(const SeamCandidate &a, const SeamCandidate &b) const { - return is_first_not_much_worse(a, b) && is_first_not_much_worse(b, a); - } -}; + if (setup == SeamPosition::spRear) { return a.position.y() + SeamPlacer::seam_align_score_tolerance * 5.0f > b.position.y(); } -#ifdef DEBUG_FILES -void debug_export_points(const std::vector &layers, - const BoundingBox &bounding_box, const SeamComparator &comparator) { - for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { - std::string angles_file_name = debug_out_path( - ("angles_" + std::to_string(layer_idx) + ".svg").c_str()); - SVG angles_svg { angles_file_name, bounding_box }; - float min_vis = 0; - float max_vis = min_vis; - - float min_weight = std::numeric_limits::min(); - float max_weight = min_weight; - - for (const SeamCandidate &point : layers[layer_idx].points) { - Vec3i color = value_to_rgbi(-PI, PI, point.local_ccw_angle); - std::string fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + "," - + std::to_string(color.z()) + ")"; - angles_svg.draw(scaled(Vec2f(point.position.head<2>())), fill); - min_vis = std::min(min_vis, point.visibility); - max_vis = std::max(max_vis, point.visibility); - - min_weight = std::min(min_weight, -compute_angle_penalty(point.local_ccw_angle)); - max_weight = std::max(max_weight, -compute_angle_penalty(point.local_ccw_angle)); + float penalty_a = a.overhang + a.visibility + angle_importance * compute_angle_penalty(a.local_ccw_angle); + float penalty_b = b.overhang + b.visibility + angle_importance * compute_angle_penalty(b.local_ccw_angle); + return penalty_a <= penalty_b || penalty_a - penalty_b < SeamPlacer::seam_align_score_tolerance; } - std::string visiblity_file_name = debug_out_path( - ("visibility_" + std::to_string(layer_idx) + ".svg").c_str()); - SVG visibility_svg { visiblity_file_name, bounding_box }; - std::string weights_file_name = debug_out_path( - ("weight_" + std::to_string(layer_idx) + ".svg").c_str()); - SVG weight_svg { weights_file_name, bounding_box }; - std::string overhangs_file_name = debug_out_path( - ("overhang_" + std::to_string(layer_idx) + ".svg").c_str()); - SVG overhangs_svg { overhangs_file_name, bounding_box }; - - for (const SeamCandidate &point : layers[layer_idx].points) { - Vec3i color = value_to_rgbi(min_vis, max_vis, point.visibility); - std::string visibility_fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + "," - + std::to_string(color.z()) + ")"; - visibility_svg.draw(scaled(Vec2f(point.position.head<2>())), visibility_fill); - - Vec3i weight_color = value_to_rgbi(min_weight, max_weight, - -compute_angle_penalty(point.local_ccw_angle)); - std::string weight_fill = "rgb(" + std::to_string(weight_color.x()) + "," + std::to_string(weight_color.y()) - + "," - + std::to_string(weight_color.z()) + ")"; - weight_svg.draw(scaled(Vec2f(point.position.head<2>())), weight_fill); - - Vec3i overhang_color = value_to_rgbi(-0.5, 0.5, std::clamp(point.overhang, -0.5f, 0.5f)); - std::string overhang_fill = "rgb(" + std::to_string(overhang_color.x()) + "," - + std::to_string(overhang_color.y()) - + "," - + std::to_string(overhang_color.z()) + ")"; - overhangs_svg.draw(scaled(Vec2f(point.position.head<2>())), overhang_fill); + bool are_similar(const SeamCandidate &a, const SeamCandidate &b) const { return is_first_not_much_worse(a, b) && is_first_not_much_worse(b, a); } +}; + +#ifdef DEBUG_FILES +void debug_export_points(const std::vector &layers, const BoundingBox &bounding_box, const SeamComparator &comparator) +{ + for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { + std::string angles_file_name = debug_out_path(("angles_" + std::to_string(layer_idx) + ".svg").c_str()); + SVG angles_svg{angles_file_name, bounding_box}; + float min_vis = 0; + float max_vis = min_vis; + + float min_weight = std::numeric_limits::min(); + float max_weight = min_weight; + + for (const SeamCandidate &point : layers[layer_idx].points) { + Vec3i color = value_to_rgbi(-PI, PI, point.local_ccw_angle); + std::string fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + "," + std::to_string(color.z()) + ")"; + angles_svg.draw(scaled(Vec2f(point.position.head<2>())), fill); + min_vis = std::min(min_vis, point.visibility); + max_vis = std::max(max_vis, point.visibility); + + min_weight = std::min(min_weight, -compute_angle_penalty(point.local_ccw_angle)); + max_weight = std::max(max_weight, -compute_angle_penalty(point.local_ccw_angle)); + } + + std::string visiblity_file_name = debug_out_path(("visibility_" + std::to_string(layer_idx) + ".svg").c_str()); + SVG visibility_svg{visiblity_file_name, bounding_box}; + std::string weights_file_name = debug_out_path(("weight_" + std::to_string(layer_idx) + ".svg").c_str()); + SVG weight_svg{weights_file_name, bounding_box}; + std::string overhangs_file_name = debug_out_path(("overhang_" + std::to_string(layer_idx) + ".svg").c_str()); + SVG overhangs_svg{overhangs_file_name, bounding_box}; + + for (const SeamCandidate &point : layers[layer_idx].points) { + Vec3i color = value_to_rgbi(min_vis, max_vis, point.visibility); + std::string visibility_fill = "rgb(" + std::to_string(color.x()) + "," + std::to_string(color.y()) + "," + std::to_string(color.z()) + ")"; + visibility_svg.draw(scaled(Vec2f(point.position.head<2>())), visibility_fill); + + Vec3i weight_color = value_to_rgbi(min_weight, max_weight, -compute_angle_penalty(point.local_ccw_angle)); + std::string weight_fill = "rgb(" + std::to_string(weight_color.x()) + "," + std::to_string(weight_color.y()) + "," + std::to_string(weight_color.z()) + ")"; + weight_svg.draw(scaled(Vec2f(point.position.head<2>())), weight_fill); + + Vec3i overhang_color = value_to_rgbi(-0.5, 0.5, std::clamp(point.overhang, -0.5f, 0.5f)); + std::string overhang_fill = "rgb(" + std::to_string(overhang_color.x()) + "," + std::to_string(overhang_color.y()) + "," + std::to_string(overhang_color.z()) + ")"; + overhangs_svg.draw(scaled(Vec2f(point.position.head<2>())), overhang_fill); + } } - } } #endif // Pick best seam point based on the given comparator -void pick_seam_point(std::vector &perimeter_points, size_t start_index, - const SeamComparator &comparator) { - size_t end_index = perimeter_points[start_index].perimeter.end_index; - - size_t seam_index = start_index; - for (size_t index = start_index; index < end_index; ++index) { - if (comparator.is_first_better(perimeter_points[index], perimeter_points[seam_index])) { - seam_index = index; +void pick_seam_point(std::vector &perimeter_points, size_t start_index, const SeamComparator &comparator) +{ + size_t end_index = perimeter_points[start_index].perimeter.end_index; + + size_t seam_index = start_index; + for (size_t index = start_index; index < end_index; ++index) { + if (comparator.is_first_better(perimeter_points[index], perimeter_points[seam_index])) { seam_index = index; } } - } - perimeter_points[start_index].perimeter.seam_index = seam_index; + perimeter_points[start_index].perimeter.seam_index = seam_index; } -size_t pick_nearest_seam_point_index(const std::vector &perimeter_points, size_t start_index, - const Vec2f &preffered_location) { - size_t end_index = perimeter_points[start_index].perimeter.end_index; - SeamComparator comparator { spNearest }; +size_t pick_nearest_seam_point_index(const std::vector &perimeter_points, size_t start_index, const Vec2f &preffered_location) +{ + size_t end_index = perimeter_points[start_index].perimeter.end_index; + SeamComparator comparator{spNearest}; - size_t seam_index = start_index; - for (size_t index = start_index; index < end_index; ++index) { - if (comparator.is_first_better(perimeter_points[index], perimeter_points[seam_index], preffered_location)) { - seam_index = index; + size_t seam_index = start_index; + for (size_t index = start_index; index < end_index; ++index) { + if (comparator.is_first_better(perimeter_points[index], perimeter_points[seam_index], preffered_location)) { seam_index = index; } } - } - return seam_index; + return seam_index; } // picks random seam point uniformly, respecting enforcers blockers and overhang avoidance. -void pick_random_seam_point(const std::vector &perimeter_points, size_t start_index) { - SeamComparator comparator { spRandom }; - - // algorithm keeps a list of viable points and their lengths. If it finds a point - // that is much better than the viable_example_index (e.g. better type, no overhang; see is_first_not_much_worse) - // then it throws away stored lists and starts from start - // in the end, the list should contain points with same type (Enforced > Neutral > Blocked) and also only those which are not - // big overhang. - size_t viable_example_index = start_index; - size_t end_index = perimeter_points[start_index].perimeter.end_index; - struct Viable { - // Candidate seam point index. - size_t index; - float edge_length; - Vec3f edge; - }; - std::vector viables; - - const Vec3f pseudornd_seed = perimeter_points[viable_example_index].position; - float rand = std::abs(sin(pseudornd_seed.dot(Vec3f(12.9898f,78.233f, 133.3333f))) * 43758.5453f); - rand = rand - (int) rand; - - for (size_t index = start_index; index < end_index; ++index) { - if (comparator.are_similar(perimeter_points[index], perimeter_points[viable_example_index])) { - // index ok, push info into viables - Vec3f edge_to_next { perimeter_points[index == end_index - 1 ? start_index : index + 1].position - - perimeter_points[index].position }; - float dist_to_next = edge_to_next.norm(); - viables.push_back( { index, dist_to_next, edge_to_next }); - } else if (comparator.is_first_not_much_worse(perimeter_points[viable_example_index], - perimeter_points[index])) { - // index is worse then viable_example_index, skip this point - } else { - // index is better than viable example index, update example, clear gathered info, start again - // clear up all gathered info, start from scratch, update example index - viable_example_index = index; - viables.clear(); - - Vec3f edge_to_next = (perimeter_points[index == end_index - 1 ? start_index : index + 1].position - - perimeter_points[index].position); - float dist_to_next = edge_to_next.norm(); - viables.push_back( { index, dist_to_next, edge_to_next }); +void pick_random_seam_point(const std::vector &perimeter_points, size_t start_index) +{ + SeamComparator comparator{spRandom}; + + // algorithm keeps a list of viable points and their lengths. If it finds a point + // that is much better than the viable_example_index (e.g. better type, no overhang; see is_first_not_much_worse) + // then it throws away stored lists and starts from start + // in the end, the list should contain points with same type (Enforced > Neutral > Blocked) and also only those which are not + // big overhang. + size_t viable_example_index = start_index; + size_t end_index = perimeter_points[start_index].perimeter.end_index; + struct Viable + { + // Candidate seam point index. + size_t index; + float edge_length; + Vec3f edge; + }; + std::vector viables; + + const Vec3f pseudornd_seed = perimeter_points[viable_example_index].position; + float rand = std::abs(sin(pseudornd_seed.dot(Vec3f(12.9898f, 78.233f, 133.3333f))) * 43758.5453f); + rand = rand - (int) rand; + + for (size_t index = start_index; index < end_index; ++index) { + if (comparator.are_similar(perimeter_points[index], perimeter_points[viable_example_index])) { + // index ok, push info into viables + Vec3f edge_to_next{perimeter_points[index == end_index - 1 ? start_index : index + 1].position - perimeter_points[index].position}; + float dist_to_next = edge_to_next.norm(); + viables.push_back({index, dist_to_next, edge_to_next}); + } else if (comparator.is_first_not_much_worse(perimeter_points[viable_example_index], perimeter_points[index])) { + // index is worse then viable_example_index, skip this point + } else { + // index is better than viable example index, update example, clear gathered info, start again + // clear up all gathered info, start from scratch, update example index + viable_example_index = index; + viables.clear(); + + Vec3f edge_to_next = (perimeter_points[index == end_index - 1 ? start_index : index + 1].position - perimeter_points[index].position); + float dist_to_next = edge_to_next.norm(); + viables.push_back({index, dist_to_next, edge_to_next}); + } + } + + // now pick random point from the stored options + float len_sum = std::accumulate(viables.begin(), viables.end(), 0.0f, [](const float acc, const Viable &v) { return acc + v.edge_length; }); + float picked_len = len_sum * rand; + + size_t point_idx = 0; + while (picked_len - viables[point_idx].edge_length > 0) { + picked_len = picked_len - viables[point_idx].edge_length; + point_idx++; } - } - - // now pick random point from the stored options - float len_sum = std::accumulate(viables.begin(), viables.end(), 0.0f, [](const float acc, const Viable &v) { - return acc + v.edge_length; - }); - float picked_len = len_sum * rand; - - size_t point_idx = 0; - while (picked_len - viables[point_idx].edge_length > 0) { - picked_len = picked_len - viables[point_idx].edge_length; - point_idx++; - } - - Perimeter &perimeter = perimeter_points[start_index].perimeter; - perimeter.seam_index = viables[point_idx].index; - perimeter.final_seam_position = perimeter_points[perimeter.seam_index].position - + viables[point_idx].edge.normalized() * picked_len; - perimeter.finalized = true; + + Perimeter &perimeter = perimeter_points[start_index].perimeter; + perimeter.seam_index = viables[point_idx].index; + perimeter.final_seam_position = perimeter_points[perimeter.seam_index].position + viables[point_idx].edge.normalized() * picked_len; + perimeter.finalized = true; } +class PerimeterDistancer +{ + std::vector lines; + AABBTreeIndirect::Tree<2, double> tree; + +public: + PerimeterDistancer(const Layer *layer) + { + ExPolygons layer_outline = layer->lslices; + for (const ExPolygon &island : layer_outline) { + assert(island.contour.is_counter_clockwise()); + for (const auto &line : island.contour.lines()) { lines.emplace_back(unscale(line.a), unscale(line.b)); } + for (const Polygon &hole : island.holes) { + assert(hole.is_clockwise()); + for (const auto &line : hole.lines()) { lines.emplace_back(unscale(line.a), unscale(line.b)); } + } + } + tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(lines); + } + + float distance_from_perimeter(const Vec2f &point) const + { + Vec2d p = point.cast(); + size_t hit_idx_out{}; + Vec2d hit_point_out = Vec2d::Zero(); + auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, hit_idx_out, hit_point_out); + if (distance < 0) { return std::numeric_limits::max(); } + + distance = sqrt(distance); + const Linef &line = lines[hit_idx_out]; + Vec2d v1 = line.b - line.a; + Vec2d v2 = p - line.a; + if ((v1.x() * v2.y()) - (v1.y() * v2.x()) > 0.0) { distance *= -1; } + return distance; + } +}; + } // namespace SeamPlacerImpl // Parallel process and extract each perimeter polygon of the given print object. // Gather SeamCandidates of each layer into vector and build KDtree over them // Store results in the SeamPlacer variables m_seam_per_object -void SeamPlacer::gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info) { - using namespace SeamPlacerImpl; - PrintObjectSeamData &seam_data = m_seam_per_object.emplace(po, PrintObjectSeamData { }).first->second; - seam_data.layers.resize(po->layer_count()); - - tbb::parallel_for(tbb::blocked_range(0, po->layers().size()), - [po, &global_model_info, &seam_data] - (tbb::blocked_range r) { - for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { - PrintObjectSeamData::LayerSeams &layer_seams = seam_data.layers[layer_idx]; - const Layer *layer = po->get_layer(layer_idx); - auto unscaled_z = layer->slice_z; - std::vector regions; - //NOTE corresponding region ptr may be null, if the layer has zero perimeters - Polygons polygons = extract_perimeter_polygons(layer, regions); - for (size_t poly_index = 0; poly_index < polygons.size(); ++poly_index) { - process_perimeter_polygon(polygons[poly_index], unscaled_z, - regions[poly_index], global_model_info, layer_seams); - } - auto functor = SeamCandidateCoordinateFunctor { layer_seams.points }; - seam_data.layers[layer_idx].points_tree = - std::make_unique(functor, - layer_seams.points.size()); - } - } - ); +void SeamPlacer::gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info, const SeamPosition configured_seam_preference) +{ + using namespace SeamPlacerImpl; + PrintObjectSeamData &seam_data = m_seam_per_object.emplace(po, PrintObjectSeamData{}).first->second; + seam_data.layers.resize(po->layer_count()); + + tbb::parallel_for(tbb::blocked_range(0, po->layers().size()), [po, configured_seam_preference, &global_model_info, &seam_data](tbb::blocked_range r) { + for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { + PrintObjectSeamData::LayerSeams &layer_seams = seam_data.layers[layer_idx]; + const Layer * layer = po->get_layer(layer_idx); + auto unscaled_z = layer->slice_z; + std::vector regions; + // NOTE corresponding region ptr may be null, if the layer has zero perimeters + Polygons polygons = extract_perimeter_polygons(layer, configured_seam_preference, regions); + for (size_t poly_index = 0; poly_index < polygons.size(); ++poly_index) { + process_perimeter_polygon(polygons[poly_index], unscaled_z, regions[poly_index], global_model_info, layer_seams); + } + auto functor = SeamCandidateCoordinateFunctor{layer_seams.points}; + seam_data.layers[layer_idx].points_tree = std::make_unique(functor, layer_seams.points.size()); + } + }); } -void SeamPlacer::calculate_candidates_visibility(const PrintObject *po, - const SeamPlacerImpl::GlobalModelInfo &global_model_info) { - using namespace SeamPlacerImpl; - - std::vector &layers = m_seam_per_object[po].layers; - tbb::parallel_for(tbb::blocked_range(0, layers.size()), - [&layers, &global_model_info](tbb::blocked_range r) { - for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { - for (auto &perimeter_point : layers[layer_idx].points) { - perimeter_point.visibility = global_model_info.calculate_point_visibility( - perimeter_point.position); - } - } - }); +void SeamPlacer::calculate_candidates_visibility(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info) +{ + using namespace SeamPlacerImpl; + + std::vector &layers = m_seam_per_object[po].layers; + tbb::parallel_for(tbb::blocked_range(0, layers.size()), [&layers, &global_model_info](tbb::blocked_range r) { + for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { + for (auto &perimeter_point : layers[layer_idx].points) { perimeter_point.visibility = global_model_info.calculate_point_visibility(perimeter_point.position); } + } + }); } -void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) { - using namespace SeamPlacerImpl; - using PerimeterDistancer = AABBTreeLines::LinesDistancer; - - std::vector &layers = m_seam_per_object[po].layers; - tbb::parallel_for(tbb::blocked_range(0, layers.size()), - [po, &layers](tbb::blocked_range r) { - std::unique_ptr prev_layer_distancer; - if (r.begin() > 0) { // previous layer exists - prev_layer_distancer = std::make_unique(to_unscaled_linesf(po->layers()[r.begin() - 1]->lslices)); - } - - for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { - size_t regions_with_perimeter = 0; - for (const LayerRegion *region : po->layers()[layer_idx]->regions()) { - if (region->perimeters.entities.size() > 0) { - regions_with_perimeter++; - } - }; - bool should_compute_layer_embedding = regions_with_perimeter > 1; - std::unique_ptr current_layer_distancer = std::make_unique( - to_unscaled_linesf(po->layers()[layer_idx]->lslices)); - - for (SeamCandidate &perimeter_point : layers[layer_idx].points) { - Vec2f point = Vec2f { perimeter_point.position.head<2>() }; - if (prev_layer_distancer.get() != nullptr) { - perimeter_point.overhang = prev_layer_distancer->distance_from_lines(point.cast()) - + 0.6f * perimeter_point.perimeter.flow_width - - tan(SeamPlacer::overhang_angle_threshold) - * po->layers()[layer_idx]->height; - perimeter_point.overhang = - perimeter_point.overhang < 0.0f ? 0.0f : perimeter_point.overhang; - } - - if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam) - perimeter_point.embedded_distance = current_layer_distancer->distance_from_lines(point.cast()) - + 0.6f * perimeter_point.perimeter.flow_width; - } - } +void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) +{ + using namespace SeamPlacerImpl; - prev_layer_distancer.swap(current_layer_distancer); - } - } - ); + std::vector &layers = m_seam_per_object[po].layers; + tbb::parallel_for(tbb::blocked_range(0, layers.size()), [po, &layers](tbb::blocked_range r) { + std::unique_ptr prev_layer_distancer; + if (r.begin() > 0) { // previous layer exists + prev_layer_distancer = std::make_unique(po->layers()[r.begin() - 1]); + } + + for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { + size_t regions_with_perimeter = 0; + for (const LayerRegion *region : po->layers()[layer_idx]->regions()) { + if (region->perimeters.entities.size() > 0) { regions_with_perimeter++; } + }; + bool should_compute_layer_embedding = regions_with_perimeter > 1; + std::unique_ptr current_layer_distancer = std::make_unique(po->layers()[layer_idx]); + + for (SeamCandidate &perimeter_point : layers[layer_idx].points) { + Vec2f point = Vec2f{perimeter_point.position.head<2>()}; + if (prev_layer_distancer.get() != nullptr) { + perimeter_point.overhang = prev_layer_distancer->distance_from_perimeter(point) + 0.6f * perimeter_point.perimeter.flow_width - + tan(SeamPlacer::overhang_angle_threshold) * po->layers()[layer_idx]->height; + perimeter_point.overhang = perimeter_point.overhang < 0.0f ? 0.0f : perimeter_point.overhang; + } + + if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam) + perimeter_point.embedded_distance = current_layer_distancer->distance_from_perimeter(point) + 0.6f * perimeter_point.perimeter.flow_width; + } + } + + prev_layer_distancer.swap(current_layer_distancer); + } + }); } // Estimates, if there is good seam point in the layer_idx which is close to last_point_pos @@ -1097,122 +994,107 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) // If the closest point is good enough to replace current chosen seam, it is stored in potential_string_seams, returns true and updates last_point_pos // Otherwise does nothing, returns false // Used by align_seam_points(). -std::optional> SeamPlacer::find_next_seam_in_layer( - const std::vector &layers, - const Vec3f &projected_position, - const size_t layer_idx, const float max_distance, - const SeamPlacerImpl::SeamComparator &comparator) const { - using namespace SeamPlacerImpl; - std::vector nearby_points_indices = find_nearby_points(*layers[layer_idx].points_tree, projected_position, - max_distance); - - if (nearby_points_indices.empty()) { - return {}; - } +std::optional> SeamPlacer::find_next_seam_in_layer(const std::vector &layers, + const Vec3f & projected_position, + const size_t layer_idx, + const float max_distance, + const SeamPlacerImpl::SeamComparator & comparator) const +{ + using namespace SeamPlacerImpl; + std::vector nearby_points_indices = find_nearby_points(*layers[layer_idx].points_tree, projected_position, max_distance); + + if (nearby_points_indices.empty()) { return {}; } + + size_t best_nearby_point_index = nearby_points_indices[0]; + size_t nearest_point_index = nearby_points_indices[0]; + + // Now find best nearby point, nearest point, and corresponding indices + for (const size_t &nearby_point_index : nearby_points_indices) { + const SeamCandidate &point = layers[layer_idx].points[nearby_point_index]; + if (point.perimeter.finalized) { + continue; // skip over finalized perimeters, try to find some that is not finalized + } + if (comparator.is_first_better(point, layers[layer_idx].points[best_nearby_point_index], projected_position.head<2>()) || + layers[layer_idx].points[best_nearby_point_index].perimeter.finalized) { + best_nearby_point_index = nearby_point_index; + } + if ((point.position - projected_position).squaredNorm() < (layers[layer_idx].points[nearest_point_index].position - projected_position).squaredNorm() || + layers[layer_idx].points[nearest_point_index].perimeter.finalized) { + nearest_point_index = nearby_point_index; + } + } - size_t best_nearby_point_index = nearby_points_indices[0]; - size_t nearest_point_index = nearby_points_indices[0]; + const SeamCandidate &best_nearby_point = layers[layer_idx].points[best_nearby_point_index]; + const SeamCandidate &nearest_point = layers[layer_idx].points[nearest_point_index]; - // Now find best nearby point, nearest point, and corresponding indices - for (const size_t &nearby_point_index : nearby_points_indices) { - const SeamCandidate &point = layers[layer_idx].points[nearby_point_index]; - if (point.perimeter.finalized) { - continue; // skip over finalized perimeters, try to find some that is not finalized + if (nearest_point.perimeter.finalized) { + // all points are from already finalized perimeter, skip + return {}; } - if (comparator.is_first_better(point, layers[layer_idx].points[best_nearby_point_index], - projected_position.head<2>()) - || layers[layer_idx].points[best_nearby_point_index].perimeter.finalized) { - best_nearby_point_index = nearby_point_index; - } - if ((point.position - projected_position).squaredNorm() - < (layers[layer_idx].points[nearest_point_index].position - projected_position).squaredNorm() - || layers[layer_idx].points[nearest_point_index].perimeter.finalized) { - nearest_point_index = nearby_point_index; + + // from the nearest_point, deduce index of seam in the next layer + const SeamCandidate &next_layer_seam = layers[layer_idx].points[nearest_point.perimeter.seam_index]; + + // First try to pick central enforcer if any present + if (next_layer_seam.central_enforcer && (next_layer_seam.position - projected_position).squaredNorm() < sqr(3 * max_distance)) { + return {std::pair{layer_idx, nearest_point.perimeter.seam_index}}; } - } - const SeamCandidate &best_nearby_point = layers[layer_idx].points[best_nearby_point_index]; - const SeamCandidate &nearest_point = layers[layer_idx].points[nearest_point_index]; + // First try to align the nearest, then try the best nearby + if (comparator.is_first_not_much_worse(nearest_point, next_layer_seam)) { return {std::pair{layer_idx, nearest_point_index}}; } + // If nearest point is not good enough, try it with the best nearby point. + if (comparator.is_first_not_much_worse(best_nearby_point, next_layer_seam)) { return {std::pair{layer_idx, best_nearby_point_index}}; } - if (nearest_point.perimeter.finalized) { - //all points are from already finalized perimeter, skip return {}; - } - - //from the nearest_point, deduce index of seam in the next layer - const SeamCandidate &next_layer_seam = layers[layer_idx].points[nearest_point.perimeter.seam_index]; - - // First try to pick central enforcer if any present - if (next_layer_seam.central_enforcer - && (next_layer_seam.position - projected_position).squaredNorm() - < sqr(3 * max_distance)) { - return {std::pair {layer_idx, nearest_point.perimeter.seam_index}}; - } - - // First try to align the nearest, then try the best nearby - if (comparator.is_first_not_much_worse(nearest_point, next_layer_seam)) { - return {std::pair {layer_idx, nearest_point_index}}; - } - // If nearest point is not good enough, try it with the best nearby point. - if (comparator.is_first_not_much_worse(best_nearby_point, next_layer_seam)) { - return {std::pair {layer_idx, best_nearby_point_index}}; - } - - return {}; } -std::vector> SeamPlacer::find_seam_string(const PrintObject *po, - std::pair start_seam, const SeamPlacerImpl::SeamComparator &comparator) const { - const std::vector &layers = m_seam_per_object.find(po)->second.layers; - int layer_idx = start_seam.first; - - //initialize searching for seam string - cluster of nearby seams on previous and next layers - int next_layer = layer_idx + 1; - int step = 1; - std::pair prev_point_index = start_seam; - std::vector> seam_string { start_seam }; - - auto reverse_lookup_direction = [&]() { - step = -1; - prev_point_index = start_seam; - next_layer = layer_idx - 1; - }; - - while (next_layer >= 0) { - if (next_layer >= int(layers.size())) { - reverse_lookup_direction(); - if (next_layer < 0) { - break; - } - } - float max_distance = SeamPlacer::seam_align_tolerable_dist_factor * - layers[start_seam.first].points[start_seam.second].perimeter.flow_width; - Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; - Vec3f projected_position = prev_position; - projected_position.z() = float(po->get_layer(next_layer)->slice_z); - - std::optional> maybe_next_seam = find_next_seam_in_layer(layers, projected_position, - next_layer, - max_distance, comparator); - - if (maybe_next_seam.has_value()) { - // For old macOS (pre 10.14), std::optional does not have .value() method, so the code is using operator*() instead. - seam_string.push_back(maybe_next_seam.operator*()); - prev_point_index = seam_string.back(); - //String added, prev_point_index updated - } else { - if (step == 1) { - reverse_lookup_direction(); - if (next_layer < 0) { - break; +std::vector> SeamPlacer::find_seam_string(const PrintObject * po, + std::pair start_seam, + const SeamPlacerImpl::SeamComparator &comparator) const +{ + const std::vector &layers = m_seam_per_object.find(po)->second.layers; + int layer_idx = start_seam.first; + + // initialize searching for seam string - cluster of nearby seams on previous and next layers + int next_layer = layer_idx + 1; + int step = 1; + std::pair prev_point_index = start_seam; + std::vector> seam_string{start_seam}; + + auto reverse_lookup_direction = [&]() { + step = -1; + prev_point_index = start_seam; + next_layer = layer_idx - 1; + }; + + while (next_layer >= 0) { + if (next_layer >= int(layers.size())) { + reverse_lookup_direction(); + if (next_layer < 0) { break; } + } + float max_distance = SeamPlacer::seam_align_tolerable_dist_factor * layers[start_seam.first].points[start_seam.second].perimeter.flow_width; + Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; + Vec3f projected_position = prev_position; + projected_position.z() = float(po->get_layer(next_layer)->slice_z); + + std::optional> maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, comparator); + + if (maybe_next_seam.has_value()) { + // For old macOS (pre 10.14), std::optional does not have .value() method, so the code is using operator*() instead. + seam_string.push_back(maybe_next_seam.operator*()); + prev_point_index = seam_string.back(); + // String added, prev_point_index updated + } else { + if (step == 1) { + reverse_lookup_direction(); + if (next_layer < 0) { break; } + } else { + break; + } } - } else { - break; - } + next_layer += step; } - next_layer += step; - } - return seam_string; + return seam_string; } // clusters already chosen seam points into strings across multiple layers, and then @@ -1220,398 +1102,284 @@ std::vector> SeamPlacer::find_seam_string(const PrintO // Does not change the positions of the SeamCandidates themselves, instead stores // the new aligned position into the shared Perimeter structure of each perimeter // Note that this position does not necesarilly lay on the perimeter. -void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator) { - using namespace SeamPlacerImpl; +void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator) +{ + using namespace SeamPlacerImpl; - // Prepares Debug files for writing. + // Prepares Debug files for writing. #ifdef DEBUG_FILES - Slic3r::CNumericLocalesSetter locales_setter; - auto clusters_f = debug_out_path("seam_clusters.obj"); - FILE *clusters = boost::nowide::fopen(clusters_f.c_str(), "w"); - if (clusters == nullptr) { - BOOST_LOG_TRIVIAL(error) - << "stl_write_obj: Couldn't open " << clusters_f << " for writing"; - return; - } - auto aligned_f = debug_out_path("aligned_clusters.obj"); - FILE *aligns = boost::nowide::fopen(aligned_f.c_str(), "w"); - if (aligns == nullptr) { - BOOST_LOG_TRIVIAL(error) - << "stl_write_obj: Couldn't open " << clusters_f << " for writing"; - return; - } + Slic3r::CNumericLocalesSetter locales_setter; + auto clusters_f = debug_out_path("seam_clusters.obj"); + FILE * clusters = boost::nowide::fopen(clusters_f.c_str(), "w"); + if (clusters == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << clusters_f << " for writing"; + return; + } + auto aligned_f = debug_out_path("aligned_clusters.obj"); + FILE *aligns = boost::nowide::fopen(aligned_f.c_str(), "w"); + if (aligns == nullptr) { + BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << clusters_f << " for writing"; + return; + } #endif - //gather vector of all seams on the print_object - pair of layer_index and seam__index within that layer - const std::vector &layers = m_seam_per_object[po].layers; - std::vector> seams; - for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { - const std::vector &layer_perimeter_points = layers[layer_idx].points; - size_t current_point_index = 0; - while (current_point_index < layer_perimeter_points.size()) { - seams.emplace_back(layer_idx, layer_perimeter_points[current_point_index].perimeter.seam_index); - current_point_index = layer_perimeter_points[current_point_index].perimeter.end_index; - } - } - - //sort them before alignment. Alignment is sensitive to initializaion, this gives it better chance to choose something nice - std::stable_sort(seams.begin(), seams.end(), - [&comparator, &layers](const std::pair &left, - const std::pair &right) { - return comparator.is_first_better(layers[left.first].points[left.second], - layers[right.first].points[right.second]); - } - ); - - //align the seam points - start with the best, and check if they are aligned, if yes, skip, else start alignment - // Keeping the vectors outside, so with a bit of luck they will not get reallocated after couple of for loop iterations. - std::vector> seam_string; - std::vector> alternative_seam_string; - std::vector observations; - std::vector observation_points; - std::vector weights; - - int global_index = 0; - while (global_index < int(seams.size())) { - size_t layer_idx = seams[global_index].first; - size_t seam_index = seams[global_index].second; - global_index++; - const std::vector &layer_perimeter_points = layers[layer_idx].points; - if (layer_perimeter_points[seam_index].perimeter.finalized) { - // This perimeter is already aligned, skip seam - continue; - } else { - seam_string = this->find_seam_string(po, { layer_idx, seam_index }, comparator); - size_t step_size = 1 + seam_string.size() / 20; - for (size_t alternative_start = 0; alternative_start < seam_string.size(); alternative_start += step_size) { - size_t start_layer_idx = seam_string[alternative_start].first; - size_t seam_idx = - layers[start_layer_idx].points[seam_string[alternative_start].second].perimeter.seam_index; - alternative_seam_string = this->find_seam_string(po, - std::pair(start_layer_idx, seam_idx), comparator); - if (alternative_seam_string.size() > seam_string.size()) { - seam_string = std::move(alternative_seam_string); - } - } - if (seam_string.size() < seam_align_minimum_string_seams) { - //string NOT long enough to be worth aligning, skip - continue; - } - - // String is long enough, all string seams and potential string seams gathered, now do the alignment - //sort by layer index - std::sort(seam_string.begin(), seam_string.end(), - [](const std::pair &left, const std::pair &right) { - return left.first < right.first; - }); - - //repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned. - global_index--; - - // gather all positions of seams and their weights - observations.resize(seam_string.size()); - observation_points.resize(seam_string.size()); - weights.resize(seam_string.size()); - - auto angle_3d = [](const Vec3f& a, const Vec3f& b){ - return std::abs(acosf(a.normalized().dot(b.normalized()))); - }; - - auto angle_weight = [](float angle){ - return 1.0f / (0.1f + compute_angle_penalty(angle)); - }; - - //gather points positions and weights - float total_length = 0.0f; - Vec3f last_point_pos = layers[seam_string[0].first].points[seam_string[0].second].position; - for (size_t index = 0; index < seam_string.size(); ++index) { - const SeamCandidate ¤t = layers[seam_string[index].first].points[seam_string[index].second]; - float layer_angle = 0.0f; - if (index > 0 && index < seam_string.size() - 1) { - layer_angle = angle_3d( - current.position - - layers[seam_string[index - 1].first].points[seam_string[index - 1].second].position, - layers[seam_string[index + 1].first].points[seam_string[index + 1].second].position - - current.position - ); - } - observations[index] = current.position.head<2>(); - observation_points[index] = current.position.z(); - weights[index] = angle_weight(current.local_ccw_angle); - float curling_influence = layer_angle > 2.0 * std::abs(current.local_ccw_angle) ? -0.8f : 1.0f; - if (current.type == EnforcedBlockedSeamPoint::Enforced) { - curling_influence = 1.0f; - weights[index] += 3.0f; - } - total_length += curling_influence * (last_point_pos - current.position).norm(); - last_point_pos = current.position; - } - - if (comparator.setup == spRear) { - total_length *= 0.3f; - } - - // Curve Fitting - size_t number_of_segments = std::max(size_t(1), - size_t(std::max(0.0f,total_length) / SeamPlacer::seam_align_mm_per_segment)); - auto curve = Geometry::fit_cubic_bspline(observations, observation_points, weights, number_of_segments); - - // Do alignment - compute fitted point for each point in the string from its Z coord, and store the position into - // Perimeter structure of the point; also set flag aligned to true - for (size_t index = 0; index < seam_string.size(); ++index) { - const auto &pair = seam_string[index]; - float t = std::min(1.0f, std::pow(std::abs(layers[pair.first].points[pair.second].local_ccw_angle) - / SeamPlacer::sharp_angle_snapping_threshold, 3.0f)); - if (layers[pair.first].points[pair.second].type == EnforcedBlockedSeamPoint::Enforced){ - t = std::max(0.4f, t); + // gather vector of all seams on the print_object - pair of layer_index and seam__index within that layer + const std::vector &layers = m_seam_per_object[po].layers; + std::vector> seams; + for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { + const std::vector &layer_perimeter_points = layers[layer_idx].points; + size_t current_point_index = 0; + while (current_point_index < layer_perimeter_points.size()) { + seams.emplace_back(layer_idx, layer_perimeter_points[current_point_index].perimeter.seam_index); + current_point_index = layer_perimeter_points[current_point_index].perimeter.end_index; } + } + + // sort them before alignment. Alignment is sensitive to initializaion, this gives it better chance to choose something nice + std::stable_sort(seams.begin(), seams.end(), [&comparator, &layers](const std::pair &left, const std::pair &right) { + return comparator.is_first_better(layers[left.first].points[left.second], layers[right.first].points[right.second]); + }); + + // align the seam points - start with the best, and check if they are aligned, if yes, skip, else start alignment + // Keeping the vectors outside, so with a bit of luck they will not get reallocated after couple of for loop iterations. + std::vector> seam_string; + std::vector> alternative_seam_string; + std::vector observations; + std::vector observation_points; + std::vector weights; + + int global_index = 0; + while (global_index < int(seams.size())) { + size_t layer_idx = seams[global_index].first; + size_t seam_index = seams[global_index].second; + global_index++; + const std::vector &layer_perimeter_points = layers[layer_idx].points; + if (layer_perimeter_points[seam_index].perimeter.finalized) { + // This perimeter is already aligned, skip seam + continue; + } else { + seam_string = this->find_seam_string(po, {layer_idx, seam_index}, comparator); + size_t step_size = 1 + seam_string.size() / 20; + for (size_t alternative_start = 0; alternative_start < seam_string.size(); alternative_start += step_size) { + size_t start_layer_idx = seam_string[alternative_start].first; + size_t seam_idx = layers[start_layer_idx].points[seam_string[alternative_start].second].perimeter.seam_index; + alternative_seam_string = this->find_seam_string(po, std::pair(start_layer_idx, seam_idx), comparator); + if (alternative_seam_string.size() > seam_string.size()) { seam_string = std::move(alternative_seam_string); } + } + if (seam_string.size() < seam_align_minimum_string_seams) { + // string NOT long enough to be worth aligning, skip + continue; + } + + // String is long enough, all string seams and potential string seams gathered, now do the alignment + // sort by layer index + std::sort(seam_string.begin(), seam_string.end(), + [](const std::pair &left, const std::pair &right) { return left.first < right.first; }); + + // repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned. + global_index--; + + // gather all positions of seams and their weights + observations.resize(seam_string.size()); + observation_points.resize(seam_string.size()); + weights.resize(seam_string.size()); + + auto angle_3d = [](const Vec3f &a, const Vec3f &b) { return std::abs(acosf(a.normalized().dot(b.normalized()))); }; + + auto angle_weight = [](float angle) { return 1.0f / (0.1f + compute_angle_penalty(angle)); }; + + // gather points positions and weights + float total_length = 0.0f; + Vec3f last_point_pos = layers[seam_string[0].first].points[seam_string[0].second].position; + for (size_t index = 0; index < seam_string.size(); ++index) { + const SeamCandidate ¤t = layers[seam_string[index].first].points[seam_string[index].second]; + float layer_angle = 0.0f; + if (index > 0 && index < seam_string.size() - 1) { + layer_angle = angle_3d(current.position - layers[seam_string[index - 1].first].points[seam_string[index - 1].second].position, + layers[seam_string[index + 1].first].points[seam_string[index + 1].second].position - current.position); + } + observations[index] = current.position.head<2>(); + observation_points[index] = current.position.z(); + weights[index] = angle_weight(current.local_ccw_angle); + float sign = layer_angle > 2.0 * std::abs(current.local_ccw_angle) ? -0.8f : 1.0f; + if (current.type == EnforcedBlockedSeamPoint::Enforced) { + sign = 1.0f; + weights[index] += 3.0f; + } + total_length += sign * (last_point_pos - current.position).norm(); + last_point_pos = current.position; + } + + // Curve Fitting + size_t number_of_segments = std::max(size_t(1), size_t(std::max(0.0f, total_length) / SeamPlacer::seam_align_mm_per_segment)); + auto curve = Geometry::fit_cubic_bspline(observations, observation_points, weights, number_of_segments); - Vec3f current_pos = layers[pair.first].points[pair.second].position; - Vec2f fitted_pos = curve.get_fitted_value(current_pos.z()); + // Do alignment - compute fitted point for each point in the string from its Z coord, and store the position into + // Perimeter structure of the point; also set flag aligned to true + for (size_t index = 0; index < seam_string.size(); ++index) { + const auto &pair = seam_string[index]; + float t = std::min(1.0f, std::pow(std::abs(layers[pair.first].points[pair.second].local_ccw_angle) / SeamPlacer::sharp_angle_snapping_threshold, 3.0f)); + if (layers[pair.first].points[pair.second].type == EnforcedBlockedSeamPoint::Enforced) { t = std::max(0.4f, t); } - //interpolate between current and fitted position, prefer current pos for large weights. - Vec3f final_position = t * current_pos + (1.0f - t) * to_3d(fitted_pos, current_pos.z()); + Vec3f current_pos = layers[pair.first].points[pair.second].position; + Vec2f fitted_pos = curve.get_fitted_value(current_pos.z()); - Perimeter &perimeter = layers[pair.first].points[pair.second].perimeter; - perimeter.seam_index = pair.second; - perimeter.final_seam_position = final_position; - perimeter.finalized = true; - } + // interpolate between current and fitted position, prefer current pos for large weights. + Vec3f final_position = t * current_pos + (1.0f - t) * to_3d(fitted_pos, current_pos.z()); + + Perimeter &perimeter = layers[pair.first].points[pair.second].perimeter; + perimeter.seam_index = pair.second; + perimeter.final_seam_position = final_position; + perimeter.finalized = true; + } #ifdef DEBUG_FILES - auto randf = []() { - return float(rand()) / float(RAND_MAX); - }; - Vec3f color { randf(), randf(), randf() }; - for (size_t i = 0; i < seam_string.size(); ++i) { - auto orig_seam = layers[seam_string[i].first].points[seam_string[i].second]; - fprintf(clusters, "v %f %f %f %f %f %f \n", orig_seam.position[0], - orig_seam.position[1], - orig_seam.position[2], color[0], color[1], - color[2]); - } - - color = Vec3f { randf(), randf(), randf() }; - for (size_t i = 0; i < seam_string.size(); ++i) { - const Perimeter &perimeter = layers[seam_string[i].first].points[seam_string[i].second].perimeter; - fprintf(aligns, "v %f %f %f %f %f %f \n", perimeter.final_seam_position[0], - perimeter.final_seam_position[1], - perimeter.final_seam_position[2], color[0], color[1], - color[2]); - } + auto randf = []() { return float(rand()) / float(RAND_MAX); }; + Vec3f color{randf(), randf(), randf()}; + for (size_t i = 0; i < seam_string.size(); ++i) { + auto orig_seam = layers[seam_string[i].first].points[seam_string[i].second]; + fprintf(clusters, "v %f %f %f %f %f %f \n", orig_seam.position[0], orig_seam.position[1], orig_seam.position[2], color[0], color[1], color[2]); + } + + color = Vec3f{randf(), randf(), randf()}; + for (size_t i = 0; i < seam_string.size(); ++i) { + const Perimeter &perimeter = layers[seam_string[i].first].points[seam_string[i].second].perimeter; + fprintf(aligns, "v %f %f %f %f %f %f \n", perimeter.final_seam_position[0], perimeter.final_seam_position[1], perimeter.final_seam_position[2], color[0], + color[1], color[2]); + } #endif + } } - } #ifdef DEBUG_FILES - fclose(clusters); - fclose(aligns); + fclose(clusters); + fclose(aligns); #endif - } -void SeamPlacer::init(const Print &print, std::function throw_if_canceled_func) { - using namespace SeamPlacerImpl; - m_seam_per_object.clear(); - - for (const PrintObject *po : print.objects()) { - throw_if_canceled_func(); - SeamPosition configured_seam_preference = po->config().seam_position.value; - SeamComparator comparator { configured_seam_preference }; - - { - GlobalModelInfo global_model_info { }; - gather_enforcers_blockers(global_model_info, po); - throw_if_canceled_func(); - if (configured_seam_preference == spAligned || configured_seam_preference == spNearest) { - compute_global_occlusion(global_model_info, po, throw_if_canceled_func); - } - throw_if_canceled_func(); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: gather_seam_candidates: start"; - gather_seam_candidates(po, global_model_info); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: gather_seam_candidates: end"; - throw_if_canceled_func(); - if (configured_seam_preference == spAligned || configured_seam_preference == spNearest) { - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: calculate_candidates_visibility : start"; - calculate_candidates_visibility(po, global_model_info); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: calculate_candidates_visibility : end"; - } - } // destruction of global_model_info (large structure, no longer needed) - throw_if_canceled_func(); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: calculate_overhangs and layer embdedding : start"; - calculate_overhangs_and_layer_embedding(po); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: calculate_overhangs and layer embdedding: end"; - throw_if_canceled_func(); - if (configured_seam_preference != spNearest) { // For spNearest, the seam is picked in the place_seam method with actual nozzle position information - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: pick_seam_point : start"; - //pick seam point - std::vector &layers = m_seam_per_object[po].layers; - tbb::parallel_for(tbb::blocked_range(0, layers.size()), - [&layers, configured_seam_preference, comparator](tbb::blocked_range r) { - for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { - std::vector &layer_perimeter_points = layers[layer_idx].points; - for (size_t current = 0; current < layer_perimeter_points.size(); - current = layer_perimeter_points[current].perimeter.end_index) - if (configured_seam_preference == spRandom) - pick_random_seam_point(layer_perimeter_points, current); - else - pick_seam_point(layer_perimeter_points, current, comparator); - } - }); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: pick_seam_point : end"; - } - throw_if_canceled_func(); - if (configured_seam_preference == spAligned || configured_seam_preference == spRear) { - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: align_seam_points : start"; - align_seam_points(po, comparator); - BOOST_LOG_TRIVIAL(debug) - << "SeamPlacer: align_seam_points : end"; - } +void SeamPlacer::init(const Print &print, std::function throw_if_canceled_func) +{ + using namespace SeamPlacerImpl; + m_seam_per_object.clear(); + + for (const PrintObject *po : print.objects()) { + throw_if_canceled_func(); + SeamPosition configured_seam_preference = po->config().seam_position.value; + SeamComparator comparator{configured_seam_preference}; + + { + GlobalModelInfo global_model_info{}; + gather_enforcers_blockers(global_model_info, po); + throw_if_canceled_func(); + if (configured_seam_preference == spAligned || configured_seam_preference == spNearest) { compute_global_occlusion(global_model_info, po, throw_if_canceled_func); } + throw_if_canceled_func(); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: gather_seam_candidates: start"; + gather_seam_candidates(po, global_model_info, configured_seam_preference); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: gather_seam_candidates: end"; + throw_if_canceled_func(); + if (configured_seam_preference == spAligned || configured_seam_preference == spNearest) { + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: calculate_candidates_visibility : start"; + calculate_candidates_visibility(po, global_model_info); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: calculate_candidates_visibility : end"; + } + } // destruction of global_model_info (large structure, no longer needed) + throw_if_canceled_func(); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: calculate_overhangs and layer embdedding : start"; + calculate_overhangs_and_layer_embedding(po); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: calculate_overhangs and layer embdedding: end"; + throw_if_canceled_func(); + if (configured_seam_preference != spNearest) { // For spNearest, the seam is picked in the place_seam method with actual nozzle position information + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: pick_seam_point : start"; + // pick seam point + std::vector &layers = m_seam_per_object[po].layers; + tbb::parallel_for(tbb::blocked_range(0, layers.size()), [&layers, configured_seam_preference, comparator](tbb::blocked_range r) { + for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { + std::vector &layer_perimeter_points = layers[layer_idx].points; + for (size_t current = 0; current < layer_perimeter_points.size(); current = layer_perimeter_points[current].perimeter.end_index) + if (configured_seam_preference == spRandom) + pick_random_seam_point(layer_perimeter_points, current); + else + pick_seam_point(layer_perimeter_points, current, comparator); + } + }); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: pick_seam_point : end"; + } + throw_if_canceled_func(); + if (configured_seam_preference == spAligned || configured_seam_preference == spRear) { + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: align_seam_points : start"; + align_seam_points(po, comparator); + BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: align_seam_points : end"; + } #ifdef DEBUG_FILES - debug_export_points(m_seam_per_object[po].layers, po->bounding_box(), comparator); + debug_export_points(m_seam_per_object[po].layers, po->bounding_box(), comparator); #endif - } + } } -void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, - const Point &last_pos) const { - using namespace SeamPlacerImpl; - const PrintObject *po = layer->object(); - // Must not be called with supprot layer. - assert(dynamic_cast(layer) == nullptr); - // Object layer IDs are incremented by the number of raft layers. - assert(layer->id() >= po->slicing_parameters().raft_layers()); - const size_t layer_index = layer->id() - po->slicing_parameters().raft_layers(); - const double unscaled_z = layer->slice_z; - - auto get_next_loop_point = [loop](ExtrusionLoop::ClosestPathPoint current) { - current.segment_idx += 1; - if (current.segment_idx >= loop.paths[current.path_idx].polyline.points.size()) { - current.path_idx = next_idx_modulo(current.path_idx, loop.paths.size()); - current.segment_idx = 0; +void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const +{ + using namespace SeamPlacerImpl; + const PrintObject *po = layer->object(); + // Must not be called with supprot layer. + assert(dynamic_cast(layer) == nullptr); + // Object layer IDs are incremented by the number of raft layers. + assert(layer->id() >= po->slicing_parameters().raft_layers()); + const size_t layer_index = layer->id() - po->slicing_parameters().raft_layers(); + const double unscaled_z = layer->slice_z; + + const PrintObjectSeamData::LayerSeams &layer_perimeters = m_seam_per_object.find(layer->object())->second.layers[layer_index]; + + // Find the closest perimeter in the SeamPlacer to the first point of this loop. + size_t closest_perimeter_point_index; + { + const Point &fp = loop.first_point(); + Vec2f unscaled_p = unscaled(fp); + closest_perimeter_point_index = find_closest_point(*layer_perimeters.points_tree.get(), to_3d(unscaled_p, float(unscaled_z))); } - current.foot_pt = loop.paths[current.path_idx].polyline.points[current.segment_idx]; - return current; - }; - - const PrintObjectSeamData::LayerSeams &layer_perimeters = - m_seam_per_object.find(layer->object())->second.layers[layer_index]; - - // Find the closest perimeter in the SeamPlacer to this loop. - // Repeat search until two consecutive points of the loop are found, that result in the same closest_perimeter - // This is beacuse with arachne, T-Junctions may exist and sometimes the wrong perimeter was chosen - size_t closest_perimeter_point_index = 0; - { // local space for the closest_perimeter_point_index - Perimeter *closest_perimeter = nullptr; - ExtrusionLoop::ClosestPathPoint closest_point{0,0,loop.paths[0].polyline.points[0]}; - size_t points_count = std::accumulate(loop.paths.begin(), loop.paths.end(), 0, [](size_t acc,const ExtrusionPath& p) { - return acc + p.polyline.points.size(); - }); - for (size_t i = 0; i < points_count; ++i) { - Vec2f unscaled_p = unscaled(closest_point.foot_pt); - closest_perimeter_point_index = find_closest_point(*layer_perimeters.points_tree.get(), - to_3d(unscaled_p, float(unscaled_z))); - if (closest_perimeter != &layer_perimeters.points[closest_perimeter_point_index].perimeter) { - closest_perimeter = &layer_perimeters.points[closest_perimeter_point_index].perimeter; - closest_point = get_next_loop_point(closest_point); - } else { - break; - } + + Vec3f seam_position; + size_t seam_index; + if (const Perimeter &perimeter = layer_perimeters.points[closest_perimeter_point_index].perimeter; perimeter.finalized) { + seam_position = perimeter.final_seam_position; + seam_index = perimeter.seam_index; + } else { + seam_index = po->config().seam_position == spNearest ? pick_nearest_seam_point_index(layer_perimeters.points, perimeter.start_index, unscaled(last_pos)) : + perimeter.seam_index; + seam_position = layer_perimeters.points[seam_index].position; } - } - - Vec3f seam_position; - size_t seam_index; - if (const Perimeter &perimeter = layer_perimeters.points[closest_perimeter_point_index].perimeter; - perimeter.finalized) { - seam_position = perimeter.final_seam_position; - seam_index = perimeter.seam_index; - } else { - seam_index = - po->config().seam_position == spNearest ? - pick_nearest_seam_point_index(layer_perimeters.points, perimeter.start_index, - unscaled(last_pos)) : - perimeter.seam_index; - seam_position = layer_perimeters.points[seam_index].position; - } - - Point seam_point = Point::new_scale(seam_position.x(), seam_position.y()); - - if (loop.role() == ExtrusionRole::erPerimeter) { //Hopefully inner perimeter - const SeamCandidate &perimeter_point = layer_perimeters.points[seam_index]; - ExtrusionLoop::ClosestPathPoint projected_point = loop.get_closest_path_and_point(seam_point, false); - // determine depth of the seam point. - float depth = (float) unscale(Point(seam_point - projected_point.foot_pt)).norm(); - float beta_angle = cos(perimeter_point.local_ccw_angle / 2.0f); - size_t index_of_prev = - seam_index == perimeter_point.perimeter.start_index ? - perimeter_point.perimeter.end_index - 1 : - seam_index - 1; - size_t index_of_next = - seam_index == perimeter_point.perimeter.end_index - 1 ? - perimeter_point.perimeter.start_index : - seam_index + 1; - - if ((seam_position - perimeter_point.position).squaredNorm() < depth && // seam is on perimeter point - perimeter_point.local_ccw_angle < -EPSILON // In concave angles + + Point seam_point = Point::new_scale(seam_position.x(), seam_position.y()); + + if (const SeamCandidate &perimeter_point = layer_perimeters.points[seam_index]; + (po->config().seam_position == spNearest || po->config().seam_position == spAligned) && loop.role() == ExtrusionRole::erPerimeter && // Hopefully internal perimeter + (seam_position - perimeter_point.position).squaredNorm() < 4.0f && // seam is on perimeter point + perimeter_point.local_ccw_angle < -EPSILON // In concave angles ) { // In this case, we are at internal perimeter, where the external perimeter has seam in concave angle. We want to align - // the internal seam into the concave corner, and not on the perpendicular projection on the closest edge (which is what the split_at function does) - Vec2f dir_to_middle = - ((perimeter_point.position - layer_perimeters.points[index_of_prev].position).head<2>().normalized() - + (perimeter_point.position - layer_perimeters.points[index_of_next].position).head<2>().normalized()) - * 0.5; - depth = 1.4142 * depth / beta_angle; - // There are some nice geometric identities in determination of the correct depth of new seam point. - //overshoot the target depth, in concave angles it will correctly snap to the corner; TODO: find out why such big overshoot is needed. - Vec2f final_pos = perimeter_point.position.head<2>() + depth * dir_to_middle; - projected_point = loop.get_closest_path_and_point(Point::new_scale(final_pos.x(), final_pos.y()), false); - } else { // not concave angle, in that case the nearest point is the good candidate - // but for staggering, we also need to recompute depth of the inner perimter, because in convex corners, the distance is larger than layer width - // we want the perpendicular depth, not distance to nearest point - depth = depth * beta_angle / 1.4142; + // the internal seam into the concave corner, and not on the perpendicular projection on the closest edge (which is what the split_at function does) + size_t index_of_prev = seam_index == perimeter_point.perimeter.start_index ? perimeter_point.perimeter.end_index - 1 : seam_index - 1; + size_t index_of_next = seam_index == perimeter_point.perimeter.end_index - 1 ? perimeter_point.perimeter.start_index : seam_index + 1; + + Vec2f dir_to_middle = ((perimeter_point.position - layer_perimeters.points[index_of_prev].position).head<2>().normalized() + + (perimeter_point.position - layer_perimeters.points[index_of_next].position).head<2>().normalized()) * + 0.5; + + ExtrusionLoop::ClosestPathPoint projected_point = loop.get_closest_path_and_point(seam_point, true); + // get closest projected point, determine depth of the seam point. + float depth = (float) unscale(Point(seam_point - projected_point.foot_pt)).norm(); + float angle_factor = cos(-perimeter_point.local_ccw_angle / 2.0f); // There are some nice geometric identities in determination of the correct depth of new seam point. + // overshoot the target depth, in concave angles it will correctly snap to the corner; TODO: find out why such big overshoot is needed. + Vec2f final_pos = perimeter_point.position.head<2>() + (1.4142 * depth / angle_factor) * dir_to_middle; + seam_point = Point::new_scale(final_pos.x(), final_pos.y()); } - seam_point = projected_point.foot_pt; - - //lastly, for internal perimeters, do the staggering if requested - if (po->config().staggered_inner_seams && loop.length() > 0.0) { - //fix depth, it is sometimes strongly underestimated - depth = std::max(loop.paths[projected_point.path_idx].width, depth); - - while (depth > 0.0f) { - auto next_point = get_next_loop_point(projected_point); - Vec2f a = unscale(projected_point.foot_pt).cast(); - Vec2f b = unscale(next_point.foot_pt).cast(); - float dist = (a - b).norm(); - if (dist > depth) { - Vec2f final_pos = a + (b - a) * depth / dist; - next_point.foot_pt = Point::new_scale(final_pos.x(), final_pos.y()); - } - depth -= dist; - projected_point = next_point; - } - seam_point = projected_point.foot_pt; + // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, + // thus empty path segments will not be produced by G-code export. + if (!loop.split_at_vertex(seam_point, scaled(0.0015))) { + // The point is not in the original loop. + // Insert it. + loop.split_at(seam_point, true); } - } - - // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, - // thus empty path segments will not be produced by G-code export. - if (!loop.split_at_vertex(seam_point, scaled(0.0015))) { - // The point is not in the original loop. - // Insert it. - loop.split_at(seam_point, true); - } - } } // namespace Slic3r diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index a7bb12f4f40..0c431202e1c 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -27,136 +27,139 @@ class Grid; namespace SeamPlacerImpl { +// ************ FOR BACKPORT COMPATIBILITY ONLY *************** +// Angle from v1 to v2, returning double atan2(y, x) normalized to <-PI, PI>. +template inline double angle(const Eigen::MatrixBase &v1, const Eigen::MatrixBase &v2) +{ + static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "angle(): first parameter is not a 2D vector"); + static_assert(Derived2::IsVectorAtCompileTime && int(Derived2::SizeAtCompileTime) == 2, "angle(): second parameter is not a 2D vector"); + auto v1d = v1.template cast(); + auto v2d = v2.template cast(); + return atan2(cross2(v1d, v2d), v1d.dot(v2d)); +} +// *************************** struct GlobalModelInfo; struct SeamComparator; enum class EnforcedBlockedSeamPoint { - Blocked = 0, - Neutral = 1, - Enforced = 2, + Blocked = 0, + Neutral = 1, + Enforced = 2, }; // struct representing single perimeter loop -struct Perimeter { - size_t start_index{}; - size_t end_index{}; //inclusive! - size_t seam_index{}; - float flow_width{}; - - // During alignment, a final position may be stored here. In that case, finalized is set to true. - // Note that final seam position is not limited to points of the perimeter loop. In theory it can be any position - // Random position also uses this flexibility to set final seam point position - bool finalized = false; - Vec3f final_seam_position = Vec3f::Zero(); +struct Perimeter +{ + size_t start_index{}; + size_t end_index{}; // inclusive! + size_t seam_index{}; + float flow_width{}; + + // During alignment, a final position may be stored here. In that case, finalized is set to true. + // Note that final seam position is not limited to points of the perimeter loop. In theory it can be any position + // Random position also uses this flexibility to set final seam point position + bool finalized = false; + Vec3f final_seam_position = Vec3f::Zero(); }; -//Struct over which all processing of perimeters is done. For each perimeter point, its respective candidate is created, +// Struct over which all processing of perimeters is done. For each perimeter point, its respective candidate is created, // then all the needed attributes are computed and finally, for each perimeter one point is chosen as seam. // This seam position can be then further aligned -struct SeamCandidate { - SeamCandidate(const Vec3f &pos, Perimeter &perimeter, - float local_ccw_angle, - EnforcedBlockedSeamPoint type) : - position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), embedded_distance(0.0f), local_ccw_angle( - local_ccw_angle), type(type), central_enforcer(false) { - } - const Vec3f position; - // pointer to Perimeter loop of this point. It is shared across all points of the loop - Perimeter &perimeter; - float visibility; - float overhang; - // distance inside the merged layer regions, for detecting perimeter points which are hidden indside the print (e.g. multimaterial join) - // Negative sign means inside the print, comes from EdgeGrid structure - float embedded_distance; - float local_ccw_angle; - EnforcedBlockedSeamPoint type; - bool central_enforcer; //marks this candidate as central point of enforced segment on the perimeter - important for alignment +struct SeamCandidate +{ + SeamCandidate(const Vec3f &pos, Perimeter &perimeter, float local_ccw_angle, EnforcedBlockedSeamPoint type) + : position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), embedded_distance(0.0f), local_ccw_angle(local_ccw_angle), type(type), central_enforcer(false) + {} + const Vec3f position; + // pointer to Perimeter loop of this point. It is shared across all points of the loop + Perimeter &perimeter; + float visibility; + float overhang; + // distance inside the merged layer regions, for detecting perimeter points which are hidden indside the print (e.g. multimaterial join) + // Negative sign means inside the print, comes from EdgeGrid structure + float embedded_distance; + float local_ccw_angle; + EnforcedBlockedSeamPoint type; + bool central_enforcer; // marks this candidate as central point of enforced segment on the perimeter - important for alignment }; -struct SeamCandidateCoordinateFunctor { - SeamCandidateCoordinateFunctor(const std::vector &seam_candidates) : - seam_candidates(seam_candidates) { - } - const std::vector &seam_candidates; - float operator()(size_t index, size_t dim) const { - return seam_candidates[index].position[dim]; - } +struct SeamCandidateCoordinateFunctor +{ + SeamCandidateCoordinateFunctor(const std::vector &seam_candidates) : seam_candidates(seam_candidates) {} + const std::vector &seam_candidates; + float operator()(size_t index, size_t dim) const { return seam_candidates[index].position[dim]; } }; } // namespace SeamPlacerImpl struct PrintObjectSeamData { - using SeamCandidatesTree = KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>; - - struct LayerSeams - { - Slic3r::deque perimeters; - std::vector points; - std::unique_ptr points_tree; - }; - // Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter - std::vector layers; - // Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD - // tree of all points of the given layer - - void clear() - { - layers.clear(); - } + using SeamCandidatesTree = KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>; + + struct LayerSeams + { + Slic3r::deque perimeters; + std::vector points; + std::unique_ptr points_tree; + }; + // Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter + std::vector layers; + // Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD + // tree of all points of the given layer + + void clear() { layers.clear(); } }; -class SeamPlacer { +class SeamPlacer +{ public: - // Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples - static constexpr size_t raycasting_visibility_samples_count = 30000; - static constexpr size_t fast_decimation_triangle_count_target = 16000; - //square of number of rays per sample point - static constexpr size_t sqr_rays_per_sample_point = 5; - - // snapping angle - angles larger than this value will be snapped to during seam painting - static constexpr float sharp_angle_snapping_threshold = 55.0f * float(PI) / 180.0f; - // overhang angle for seam placement that still yields good results, in degrees, measured from vertical direction - static constexpr float overhang_angle_threshold = 50.0f * float(PI) / 180.0f; - - // determines angle importance compared to visibility ( neutral value is 1.0f. ) - static constexpr float angle_importance_aligned = 0.6f; - static constexpr float angle_importance_nearest = 1.0f; // use much higher angle importance for nearest mode, to combat the visibility info noise - - // For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size - static constexpr float enforcer_oversampling_distance = 0.2f; - - // When searching for seam clusters for alignment: - // following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer - static constexpr float seam_align_score_tolerance = 0.3f; - // seam_align_tolerable_dist_factor - how far to search for seam from current position, final dist is seam_align_tolerable_dist_factor * flow_width - static constexpr float seam_align_tolerable_dist_factor = 4.0f; - // minimum number of seams needed in cluster to make alignment happen - static constexpr size_t seam_align_minimum_string_seams = 6; - // millimeters covered by spline; determines number of splines for the given string - static constexpr size_t seam_align_mm_per_segment = 4.0f; - - //The following data structures hold all perimeter points for all PrintObject. - std::unordered_map m_seam_per_object; - - void init(const Print &print, std::function throw_if_canceled_func); - - void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const; + // Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples + static constexpr size_t raycasting_visibility_samples_count = 30000; + static constexpr size_t fast_decimation_triangle_count_target = 16000; + //square of number of rays per sample point + static constexpr size_t sqr_rays_per_sample_point = 5; + + // snapping angle - angles larger than this value will be snapped to during seam painting + static constexpr float sharp_angle_snapping_threshold = 55.0f * float(PI) / 180.0f; + // overhang angle for seam placement that still yields good results, in degrees, measured from vertical direction + //BBS + static constexpr float overhang_angle_threshold = 45.0f * float(PI) / 180.0f; + + // determines angle importance compared to visibility ( neutral value is 1.0f. ) + static constexpr float angle_importance_aligned = 0.6f; + static constexpr float angle_importance_nearest = 1.0f; // use much higher angle importance for nearest mode, to combat the visibility info noise + + // For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size + static constexpr float enforcer_oversampling_distance = 0.2f; + + // When searching for seam clusters for alignment: + // following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer + static constexpr float seam_align_score_tolerance = 0.3f; + // seam_align_tolerable_dist_factor - how far to search for seam from current position, final dist is seam_align_tolerable_dist_factor * flow_width + static constexpr float seam_align_tolerable_dist_factor = 4.0f; + // minimum number of seams needed in cluster to make alignment happen + static constexpr size_t seam_align_minimum_string_seams = 6; + // millimeters covered by spline; determines number of splines for the given string + static constexpr size_t seam_align_mm_per_segment = 4.0f; + + // The following data structures hold all perimeter points for all PrintObject. + std::unordered_map m_seam_per_object; + + void init(const Print &print, std::function throw_if_canceled_func); + + void place_seam(const Layer *layer, ExtrusionLoop &loop, bool external_first, const Point &last_pos) const; private: - void gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info); - void calculate_candidates_visibility(const PrintObject *po, - const SeamPlacerImpl::GlobalModelInfo &global_model_info); - void calculate_overhangs_and_layer_embedding(const PrintObject *po); - void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator); - std::vector> find_seam_string(const PrintObject *po, - std::pair start_seam, - const SeamPlacerImpl::SeamComparator &comparator) const; - std::optional> find_next_seam_in_layer( - const std::vector &layers, - const Vec3f& projected_position, - const size_t layer_idx, const float max_distance, - const SeamPlacerImpl::SeamComparator &comparator) const; + void gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info, const SeamPosition configured_seam_preference); + void calculate_candidates_visibility(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info); + void calculate_overhangs_and_layer_embedding(const PrintObject *po); + void align_seam_points(const PrintObject *po, const SeamPlacerImpl::SeamComparator &comparator); + std::vector> find_seam_string(const PrintObject *po, std::pair start_seam, const SeamPlacerImpl::SeamComparator &comparator) const; + std::optional> find_next_seam_in_layer(const std::vector &layers, + const Vec3f & projected_position, + const size_t layer_idx, + const float max_distance, + const SeamPlacerImpl::SeamComparator & comparator) const; }; } // namespace Slic3r diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 95c28da2ab3..ee46300447b 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -388,6 +388,11 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto it_per_layer_extruder_override = per_layer_extruder_switches.begin(); unsigned int extruder_override = 0; + // BBS: collect first layer extruders of an object's wall, which will be used by brim generator + int layerCount = 0; + std::vector firstLayerExtruders; + firstLayerExtruders.clear(); + // Collect the object extruders. for (auto layer : object.layers()) { LayerTools &layer_tools = this->tools_for_layer(layer->print_z); @@ -413,8 +418,12 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto something_nonoverriddable = true; } - if (something_nonoverriddable) + if (something_nonoverriddable){ layer_tools.extruders.emplace_back((extruder_override == 0) ? region.config().wall_filament.value : extruder_override); + if (layerCount == 0) { + firstLayerExtruders.emplace_back((extruder_override == 0) ? region.config().wall_filament.value : extruder_override); + } + } layer_tools.has_object = true; } @@ -449,8 +458,12 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto if (has_solid_infill || has_infill) layer_tools.has_object = true; } + layerCount++; } + sort_remove_duplicates(firstLayerExtruders); + const_cast(object).object_first_layer_wall_extruders = firstLayerExtruders; + for (auto& layer : m_layer_tools) { // Sort and remove duplicates sort_remove_duplicates(layer.extruders); @@ -1027,8 +1040,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int if (!object->config().flush_into_infill && !object->config().flush_into_objects && !object->config().flush_into_support) continue; bool wipe_into_infill_only = !object->config().flush_into_objects && object->config().flush_into_infill; - bool is_infill_first = print.default_region_config().wall_infill_order == WallInfillOrder::InfillInnerOuter || - print.default_region_config().wall_infill_order == WallInfillOrder::InfillOuterInner; + bool is_infill_first = print.config().is_infill_first; if (is_infill_first != perimeters_done || wipe_into_infill_only) { for (const ExtrusionEntity* ee : layerm->fills.entities) { // iterate through all infill Collections auto* fill = dynamic_cast(ee); @@ -1082,7 +1094,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int break; auto &entities = this_support_layer->support_fills.entities; - if (support_overriddable && !is_support_overridden(object)) { + if (support_overriddable && !is_support_overridden(object) && !(object_config.support_interface_not_for_body.value && !support_intf_overriddable &&(new_extruder==object_config.support_interface_filament-1||old_extruder==object_config.support_interface_filament-1))) { set_support_extruder_override(object, copy, new_extruder, num_of_copies); for (const ExtrusionEntity* ee : entities) { if (ee->role() == erSupportMaterial || ee->role() == erSupportTransition) @@ -1141,8 +1153,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) if (!object->config().flush_into_infill && !object->config().flush_into_objects) continue; - bool is_infill_first = print.default_region_config().wall_infill_order == WallInfillOrder::InfillInnerOuter || - print.default_region_config().wall_infill_order == WallInfillOrder::InfillOuterInner; + bool is_infill_first = print.config().is_infill_first; for (const ExtrusionEntity* ee : layerm->fills.entities) { // iterate through all infill Collections auto* fill = dynamic_cast(ee); diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index f88e0d56a12..642b07c9ddd 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -770,6 +770,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per "; CP TOOLCHANGE START\n") .comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based + if (tool != (unsigned)(-1)) writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str()) .append(";--------------------\n"); @@ -787,6 +788,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. if (tool != (unsigned int)-1){ // This is not the last change. + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, is_first_layer() ? m_filpar[tool].nozzle_temperature_initial_layer : m_filpar[tool].nozzle_temperature); toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials. @@ -806,8 +808,8 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per writer.travel(Vec2f(0, 0)); writer.travel(initial_position); } - toolchange_Wipe(writer, cleaning_box, wipe_length); // Wipe the newly loaded filament until the end of the assigned wipe area. + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n"); ++ m_num_tool_changes; } else toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].nozzle_temperature); @@ -1185,6 +1187,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool .set_initial_tool(m_current_tool) .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); // Slow down on the 1st layer. bool first_layer = is_first_layer(); @@ -1324,6 +1327,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool writer.add_wipe_point(writer.pos()) .add_wipe_point(target); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n"); // Ask our writer about how much material was consumed. // Skip this in case the layer is sparse and config option to not print sparse layers is enabled. @@ -1601,6 +1605,9 @@ void WipeTower::generate(std::vector> & // BBS //m_internal_rotation += 180.f; + if (m_layer_info->depth < m_perimeter_width) + continue; + if (m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width) { // align y shift to perimeter width float dy = m_extra_spacing * m_perimeter_width; @@ -1687,7 +1694,7 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall() // BBS: Delete some unnecessary travel //if (writer.x() > fill_box.ld.x() + EPSILON) writer.travel(fill_box.ld.x(), writer.y()); //if (writer.y() > fill_box.ld.y() + EPSILON) writer.travel(writer.x(), fill_box.ld.y()); - + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); // outer perimeter (always): // BBS box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width); @@ -1698,6 +1705,8 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall() Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : (writer.pos() == wt_box.rd ? wt_box.ru : (writer.pos() == wt_box.ru ? wt_box.lu : wt_box.ld))); writer.add_wipe_point(writer.pos()).add_wipe_point(target); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n"); + // Ask our writer about how much material was consumed. // Skip this in case the layer is sparse and config option to not print sparse layers is enabled. if (!m_no_sparse_layers || toolchanges_on_layer) diff --git a/src/libslic3r/JumpPointSearch.cpp b/src/libslic3r/JumpPointSearch.cpp new file mode 100644 index 00000000000..f8ef2ff100b --- /dev/null +++ b/src/libslic3r/JumpPointSearch.cpp @@ -0,0 +1,349 @@ +#include "JumpPointSearch.hpp" +#include "BoundingBox.hpp" +#include "ExPolygon.hpp" +#include "Point.hpp" +#include "libslic3r/AStar.hpp" +#include "libslic3r/KDTreeIndirect.hpp" +#include "libslic3r/Polygon.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/libslic3r.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#define DEBUG_FILES +#ifdef DEBUG_FILES +#include "libslic3r/SVG.hpp" +#endif + +namespace Slic3r { + +// execute fn for each pixel on the line. If fn returns false, terminate the iteration +template void dda(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn) +{ + coord_t dx = abs(x1 - x0); + coord_t dy = abs(y1 - y0); + coord_t x = x0; + coord_t y = y0; + coord_t n = 1 + dx + dy; + coord_t x_inc = (x1 > x0) ? 1 : -1; + coord_t y_inc = (y1 > y0) ? 1 : -1; + coord_t error = dx - dy; + dx *= 2; + dy *= 2; + + for (; n > 0; --n) { + if (!fn(x, y)) return; + + if (error > 0) { + x += x_inc; + error -= dy; + } else { + y += y_inc; + error += dx; + } + } +} + +// will draw the line twice, second time with and offset of 1 in the direction of normal +// may call the fn on the same coordiantes multiple times! +template void double_dda_with_offset(coord_t x0, coord_t y0, coord_t x1, coord_t y1, const PointFn &fn) +{ + Vec2d normal = Point{y1 - y0, x1 - x0}.cast().normalized(); + normal.x() = ceil(normal.x()); + normal.y() = ceil(normal.y()); + Point start_offset = Point(x0, y0) + (normal).cast(); + Point end_offset = Point(x1, y1) + (normal).cast(); + + dda(x0, y0, x1, y1, fn); + dda(start_offset.x(), start_offset.y(), end_offset.x(), end_offset.y(), fn); +} + +template class JPSTracer +{ +public: + // Use incoming_dir [0,0] for starting points, so that all directions are checked from that point + struct Node + { + CellPositionType position; + CellPositionType incoming_dir; + }; + + JPSTracer(CellPositionType target, CellQueryFn is_passable) : target(target), is_passable(is_passable) {} + +private: + CellPositionType target; + CellQueryFn is_passable; // should return boolean whether the cell is passable or not + + CellPositionType find_jump_point(CellPositionType start, CellPositionType forward_dir) const + { + CellPositionType next = start + forward_dir; + while (next != target && is_passable(next) && !(is_jump_point(next, forward_dir))) { next = next + forward_dir; } + + if (is_passable(next)) { + return next; + } else { + return start; + } + } + + bool is_jump_point(CellPositionType pos, CellPositionType forward_dir) const + { + if (abs(forward_dir.x()) + abs(forward_dir.y()) == 2) { + // diagonal + CellPositionType horizontal_check_dir = CellPositionType{forward_dir.x(), 0}; + CellPositionType vertical_check_dir = CellPositionType{0, forward_dir.y()}; + + if (!is_passable(pos - horizontal_check_dir) && is_passable(pos + forward_dir - 2 * horizontal_check_dir)) { return true; } + + if (!is_passable(pos - vertical_check_dir) && is_passable(pos + forward_dir - 2 * vertical_check_dir)) { return true; } + + if (find_jump_point(pos, horizontal_check_dir) != pos) { return true; } + + if (find_jump_point(pos, vertical_check_dir) != pos) { return true; } + + return false; + } else { // horizontal or vertical + CellPositionType side_dir = CellPositionType(forward_dir.y(), forward_dir.x()); + + if (!is_passable(pos + side_dir) && is_passable(pos + forward_dir + side_dir)) { return true; } + + if (!is_passable(pos - side_dir) && is_passable(pos + forward_dir - side_dir)) { return true; } + + return false; + } + } + +public: + template void foreach_reachable(const Node &from, Fn &&fn) const + { + const CellPositionType & pos = from.position; + const CellPositionType & forward_dir = from.incoming_dir; + std::vector dirs_to_check{}; + + if (abs(forward_dir.x()) + abs(forward_dir.y()) == 0) { // special case for starting point + dirs_to_check = all_directions; + } else if (abs(forward_dir.x()) + abs(forward_dir.y()) == 2) { + // diagonal + CellPositionType horizontal_check_dir = CellPositionType{forward_dir.x(), 0}; + CellPositionType vertical_check_dir = CellPositionType{0, forward_dir.y()}; + + if (!is_passable(pos - horizontal_check_dir) && is_passable(pos + forward_dir - 2 * horizontal_check_dir)) { + dirs_to_check.push_back(forward_dir - 2 * horizontal_check_dir); + } + + if (!is_passable(pos - vertical_check_dir) && is_passable(pos + forward_dir - 2 * vertical_check_dir)) { + dirs_to_check.push_back(forward_dir - 2 * vertical_check_dir); + } + + dirs_to_check.push_back(horizontal_check_dir); + dirs_to_check.push_back(vertical_check_dir); + dirs_to_check.push_back(forward_dir); + + } else { // horizontal or vertical + CellPositionType side_dir = CellPositionType(forward_dir.y(), forward_dir.x()); + + if (!is_passable(pos + side_dir) && is_passable(pos + forward_dir + side_dir)) { dirs_to_check.push_back(forward_dir + side_dir); } + + if (!is_passable(pos - side_dir) && is_passable(pos + forward_dir - side_dir)) { dirs_to_check.push_back(forward_dir - side_dir); } + dirs_to_check.push_back(forward_dir); + } + + for (const CellPositionType &dir : dirs_to_check) { + CellPositionType jp = find_jump_point(pos, dir); + if (jp != pos) fn(Node{jp, dir}); + } + } + + float distance(Node a, Node b) const { return (a.position - b.position).template cast().norm(); } + + float goal_heuristic(Node n) const { return n.position == target ? -1.f : (target - n.position).template cast().norm(); } + + size_t unique_id(Node n) const { return (static_cast(uint16_t(n.position.x())) << 16) + static_cast(uint16_t(n.position.y())); } + + const std::vector all_directions{{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}}; +}; + +void JPSPathFinder::clear() +{ + inpassable.clear(); + max_search_box.max = Pixel(std::numeric_limits::min(), std::numeric_limits::min()); + max_search_box.min = Pixel(std::numeric_limits::max(), std::numeric_limits::max()); + add_obstacles(bed_shape); +} + +void JPSPathFinder::add_obstacles(const Lines &obstacles) +{ + auto store_obstacle = [&](coord_t x, coord_t y) { + max_search_box.max.x() = std::max(max_search_box.max.x(), x); + max_search_box.max.y() = std::max(max_search_box.max.y(), y); + max_search_box.min.x() = std::min(max_search_box.min.x(), x); + max_search_box.min.y() = std::min(max_search_box.min.y(), y); + inpassable.insert(Pixel{x, y}); + return true; + }; + + for (const Line &l : obstacles) { + Pixel start = pixelize(l.a); + Pixel end = pixelize(l.b); + double_dda_with_offset(start.x(), start.y(), end.x(), end.y(), store_obstacle); + } +} + +Polyline JPSPathFinder::find_path(const Point &p0, const Point &p1) +{ + Pixel start = pixelize(p0); + Pixel end = pixelize(p1); + if (inpassable.empty() || (start - end).cast().norm() < 3.0) { return Polyline{p0, p1}; } + + if (inpassable.find(start) != inpassable.end()) { + dda(start.x(), start.y(), end.x(), end.y(), [&](coord_t x, coord_t y) { + if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable + start = Pixel(x, y); + return false; + } + return true; + }); + } + + if (inpassable.find(end) != inpassable.end()) { + dda(end.x(), end.y(), start.x(), start.y(), [&](coord_t x, coord_t y) { + if (inpassable.find(Pixel(x, y)) == inpassable.end() || start == end) { // new start not found yet, and xy passable + end = Pixel(x, y); + return false; + } + return true; + }); + } + + BoundingBox search_box = max_search_box; + search_box.max -= Pixel(1, 1); + search_box.min += Pixel(1, 1); + + BoundingBox bounding_square(Points{start, end}); + bounding_square.max += Pixel(5, 5); + bounding_square.min -= Pixel(5, 5); + coord_t bounding_square_size = 2 * std::max(bounding_square.size().x(), bounding_square.size().y()); + bounding_square.max.x() += (bounding_square_size - bounding_square.size().x()) / 2; + bounding_square.min.x() -= (bounding_square_size - bounding_square.size().x()) / 2; + bounding_square.max.y() += (bounding_square_size - bounding_square.size().y()) / 2; + bounding_square.min.y() -= (bounding_square_size - bounding_square.size().y()) / 2; + + // Intersection - limit the search box to a square area around the start and end, to fasten the path searching + search_box.max = search_box.max.cwiseMin(bounding_square.max); + search_box.min = search_box.min.cwiseMax(bounding_square.min); + + auto cell_query = [&](Pixel pixel) { return search_box.contains(pixel) && (pixel == start || pixel == end || inpassable.find(pixel) == inpassable.end()); }; + + JPSTracer tracer(end, cell_query); + using QNode = astar::QNode>; + + std::unordered_map astar_cache{}; + std::vector out_path; + std::vector out_nodes; + + if (!astar::search_route(tracer, {start, {0, 0}}, std::back_inserter(out_nodes), astar_cache)) { + // path not found - just reconstruct the best path from astar cache. + // Note that astar_cache is NOT empty - at least the starting point should always be there + auto coordiante_func = [&astar_cache](size_t idx, size_t dim) { return float(astar_cache[idx].node.position[dim]); }; + std::vector keys; + keys.reserve(astar_cache.size()); + for (const auto &pair : astar_cache) { keys.push_back(pair.first); } + KDTreeIndirect<2, float, decltype(coordiante_func)> kd_tree(coordiante_func, keys); + size_t closest_qnode = find_closest_point(kd_tree, end.cast()); + + out_path.push_back(end); + while (closest_qnode != astar::Unassigned) { + out_path.push_back(astar_cache[closest_qnode].node.position); + closest_qnode = astar_cache[closest_qnode].parent; + } + } else { + for (const auto &node : out_nodes) { out_path.push_back(node.position); } + out_path.push_back(start); + } + +#ifdef DEBUG_FILES + auto scaled_points = [](const Points &ps) { + Points r; + for (const Point &p : ps) { r.push_back(Point::new_scale(p.x(), p.y())); } + return r; + }; + auto scaled_point = [](const Point &p) { return Point::new_scale(p.x(), p.y()); }; + ::Slic3r::SVG svg(debug_out_path(("path_jps" + std::to_string(print_z) + "_" + std::to_string(rand() % 1000)).c_str()).c_str(), + BoundingBox(scaled_point(search_box.min), scaled_point(search_box.max))); + for (const auto &p : inpassable) { svg.draw(scaled_point(p), "black", scale_(0.4)); } + for (const auto &qn : astar_cache) { svg.draw(scaled_point(qn.second.node.position), "blue", scale_(0.3)); } + svg.draw(Polyline(scaled_points(out_path)), "yellow", scale_(0.25)); + svg.draw(scaled_point(end), "purple", scale_(0.4)); + svg.draw(scaled_point(start), "green", scale_(0.4)); +#endif + + std::vector tmp_path; + tmp_path.reserve(out_path.size()); + // Some path found, reverse and remove points that do not change direction + std::reverse(out_path.begin(), out_path.end()); + { + tmp_path.push_back(out_path.front()); // first point + for (size_t i = 1; i < out_path.size() - 1; i++) { + if ((out_path[i] - out_path[i - 1]).cast().normalized() != (out_path[i + 1] - out_path[i]).cast().normalized()) { tmp_path.push_back(out_path[i]); } + } + tmp_path.push_back(out_path.back()); // last_point + out_path = tmp_path; + } + +#ifdef DEBUG_FILES + svg.draw(Polyline(scaled_points(out_path)), "orange", scale_(0.20)); +#endif + + tmp_path.clear(); + // remove redundant jump points - there are points that change direction but are not needed - this inefficiency arises from the + // usage of grid search The removal alg tries to find the longest Px Px+k path without obstacles. If Px Px+k+1 is blocked, it will + // insert the Px+k point to result and continue search from Px+k + { + tmp_path.push_back(out_path.front()); // first point + size_t index_of_last_stored_point = 0; + for (size_t i = 1; i < out_path.size(); i++) { + if (i - index_of_last_stored_point < 2) continue; + bool passable = true; + auto store_obstacle = [&](coord_t x, coord_t y) { + if (Pixel(x, y) != start && Pixel(x, y) != end && inpassable.find(Pixel(x, y)) != inpassable.end()) { + passable = false; + return false; + } + return true; + }; + dda(tmp_path.back().x(), tmp_path.back().y(), out_path[i].x(), out_path[i].y(), store_obstacle); + if (!passable) { + tmp_path.push_back(out_path[i - 1]); + index_of_last_stored_point = i - 1; + } + } + tmp_path.push_back(out_path.back()); // last_point + out_path = tmp_path; + } + +#ifdef DEBUG_FILES + svg.draw(Polyline(scaled_points(out_path)), "red", scale_(0.15)); + svg.Close(); +#endif + + // before returing the path, transform it from pixels back to points. + // Also replace the first and last pixel by input points so that result path patches input params exactly. + for (Pixel &p : out_path) { p = unpixelize(p); } + out_path.front() = p0; + out_path.back() = p1; + + return Polyline(out_path); +} + +} // namespace Slic3r diff --git a/src/libslic3r/JumpPointSearch.hpp b/src/libslic3r/JumpPointSearch.hpp new file mode 100644 index 00000000000..86eeb9ce6a4 --- /dev/null +++ b/src/libslic3r/JumpPointSearch.hpp @@ -0,0 +1,38 @@ +#pragma once +#ifndef SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_ +#define SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_ + +#include "BoundingBox.hpp" +#include "Polygon.hpp" +#include "libslic3r/Layer.hpp" +#include "libslic3r/Point.hpp" +#include "libslic3r/Polyline.hpp" +#include "libslic3r/libslic3r.h" +#include +#include + +namespace Slic3r { + +class JPSPathFinder +{ + using Pixel = Point; + std::unordered_set inpassable; + coordf_t print_z; + BoundingBox max_search_box; + Lines bed_shape; + + const coord_t resolution = scaled(1.5); + Pixel pixelize(const Point &p) { return p / resolution; } + Point unpixelize(const Pixel &p) { return p * resolution; } + +public: + JPSPathFinder() = default; + void init_bed_shape(const Points &bed_shape) { this->bed_shape = (to_lines(Polygon{bed_shape})); }; + void clear(); + void add_obstacles(const Lines &obstacles); + Polyline find_path(const Point &start, const Point &end); +}; + +} // namespace Slic3r + +#endif /* SRC_LIBSLIC3R_JUMPPOINTSEARCH_HPP_ */ diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 17d0c0e5351..a0de4c52e54 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -179,7 +179,6 @@ void Layer::make_perimeters() && config.opt_serialize("inner_wall_line_width") == other_config.opt_serialize("inner_wall_line_width") && config.opt_serialize("outer_wall_line_width") == other_config.opt_serialize("outer_wall_line_width") && config.detect_thin_wall == other_config.detect_thin_wall - //&& config.wall_infill_order == other_config.wall_infill_order && config.infill_wall_overlap == other_config.infill_wall_overlap && config.fuzzy_skin == other_config.fuzzy_skin && config.fuzzy_skin_thickness == other_config.fuzzy_skin_thickness diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 77d30a5a953..6c66579d5a5 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -277,6 +277,7 @@ class SupportLayer : public Layer // for tree supports ExPolygons base_areas; + ExPolygons overhang_areas; // Is there any valid extrusion assigned to this LayerRegion? @@ -300,7 +301,6 @@ class SupportLayer : public Layer size_t m_interface_id; // for tree support - ExPolygons overhang_areas; ExPolygons roof_areas; ExPolygons roof_1st_layer; // the layer just below roof. When working with PolySupport, this layer should be printed with regular material ExPolygons floor_areas; @@ -312,6 +312,7 @@ class SupportLayer : public Layer int type; coordf_t dist_to_top; // mm dist to top bool need_infill = false; + bool need_extra_wall = false; AreaGroup(ExPolygon *a, int t, coordf_t d) : area(a), type(t), dist_to_top(d) {} }; enum OverhangType { Detected = 0, Enforced }; diff --git a/src/libslic3r/MeshBoolean.cpp b/src/libslic3r/MeshBoolean.cpp index 61e5cef3e21..50bbc099e8c 100644 --- a/src/libslic3r/MeshBoolean.cpp +++ b/src/libslic3r/MeshBoolean.cpp @@ -223,6 +223,12 @@ indexed_triangle_set cgal_to_indexed_triangle_set(const _Mesh &cgalmesh) return its; } +template TriangleMesh cgal_to_triangle_mesh(const _Mesh &cgalmesh) +{ + indexed_triangle_set its = cgal_to_indexed_triangle_set(cgalmesh); + return TriangleMesh(std::move(its)); +} + std::unique_ptr triangle_mesh_to_cgal(const std::vector &V, const std::vector &F) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 1cd76fc2c5e..3fc6693a782 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -97,9 +97,14 @@ Model& Model::assign_copy(const Model &rhs) ); } + if (rhs.calib_pa_pattern) { + this->calib_pa_pattern = std::make_unique(CalibPressureAdvancePattern(*rhs.calib_pa_pattern)); + } + // BBS: for design info this->design_info = rhs.design_info; this->model_info = rhs.model_info; + this->stl_design_id = rhs.stl_design_id; this->profile_info = rhs.profile_info; return *this; @@ -130,6 +135,7 @@ Model& Model::assign_copy(Model &&rhs) //BBS: add auxiliary path logic // BBS: backup, all in one temp dir + this->stl_design_id = rhs.stl_design_id; this->backup_path = std::move(rhs.backup_path); this->object_backup_id_map = std::move(rhs.object_backup_id_map); this->next_object_backup_id = rhs.next_object_backup_id; @@ -927,6 +933,7 @@ void Model::load_from(Model& model) object_backup_id_map = model.object_backup_id_map; next_object_backup_id = model.next_object_backup_id; design_info = model.design_info; + stl_design_id = model.stl_design_id; model_info = model.model_info; profile_info = model.profile_info; model.design_info.reset(); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 02220c2aad6..219d5b19a41 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -245,6 +245,11 @@ class LayerHeightProfile final : public ObjectWithTimestamp { friend class ModelObject; }; +enum class CutMode : int { + cutPlanar, + cutTongueAndGroove +}; + enum class CutConnectorType : int { Plug , Dowel @@ -267,6 +272,11 @@ enum class CutConnectorShape : int { , Undef //,D-shape }; +struct CutConnectorParas +{ + float snap_space_proportion{0.3}; + float snap_bulge_proportion{0.15}; +}; struct CutConnectorAttributes { @@ -904,8 +914,8 @@ class ModelVolume final : public ObjectBase bool is_support_blocker() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER; } bool is_support_modifier() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER || m_type == ModelVolumeType::SUPPORT_ENFORCER; } t_model_material_id material_id() const { return m_material_id; } - void reset_extra_facets(); void set_material_id(t_model_material_id material_id); + void reset_extra_facets(); ModelMaterial* material() const; void set_material(t_model_material_id material_id, const ModelMaterial &material); // Extract the current extruder ID based on this ModelVolume's config and the parent ModelObject's config. @@ -1488,6 +1498,7 @@ class Model final : public ObjectBase static GlobalSpeedMap printSpeedMap; // DesignInfo of Model + std::string stl_design_id; std::shared_ptr design_info = nullptr; std::shared_ptr model_info = nullptr; std::shared_ptr profile_info = nullptr; diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 4efedc1ccb4..596fc56db4b 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1372,18 +1372,23 @@ static void remove_multiple_edges_in_vertices(MMU_Graph &graph, const std::vecto static void cut_segmented_layers(const std::vector &input_expolygons, std::vector> &segmented_regions, const float cut_width, + const float interlocking_depth, const std::function &throw_on_cancel_callback) { BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - begin"; - tbb::parallel_for(tbb::blocked_range(0, segmented_regions.size()),[&segmented_regions, &input_expolygons, &cut_width, &throw_on_cancel_callback](const tbb::blocked_range& range) { + tbb::parallel_for(tbb::blocked_range(0, segmented_regions.size()), + [&segmented_regions, &input_expolygons, &cut_width, &interlocking_depth, &throw_on_cancel_callback](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); - const size_t num_extruders_plus_one = segmented_regions[layer_idx].size(); - std::vector segmented_regions_cuts(num_extruders_plus_one); // Indexed by extruder_id - for (size_t extruder_idx = 0; extruder_idx < num_extruders_plus_one; ++extruder_idx) - if (const ExPolygons &ex_polygons = segmented_regions[layer_idx][extruder_idx]; !ex_polygons.empty()) - segmented_regions_cuts[extruder_idx] = diff_ex(ex_polygons, offset_ex(input_expolygons[layer_idx], cut_width)); - segmented_regions[layer_idx] = std::move(segmented_regions_cuts); + const float region_cut_width = ((layer_idx % 2 == 0) && (interlocking_depth != 0.f)) ? interlocking_depth : cut_width; + const size_t num_extruders_plus_one = segmented_regions[layer_idx].size(); + if (region_cut_width > 0.f) { + std::vector segmented_regions_cuts(num_extruders_plus_one); // Indexed by extruder_id + for (size_t extruder_idx = 0; extruder_idx < num_extruders_plus_one; ++extruder_idx) + if (const ExPolygons &ex_polygons = segmented_regions[layer_idx][extruder_idx]; !ex_polygons.empty()) + segmented_regions_cuts[extruder_idx] = diff_ex(ex_polygons, offset_ex(input_expolygons[layer_idx], -region_cut_width)); + segmented_regions[layer_idx] = std::move(segmented_regions_cuts); + } } }); // end of parallel_for BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - end"; @@ -1664,9 +1669,12 @@ static inline std::vector> mmu_segmentation_top_and_bott self = union_ex(self); } // Trim one region by the other if some of the regions overlap. - for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++ color_idx) - triangles_by_color_merged[color_idx][layer_idx] = diff_ex(triangles_by_color_merged[color_idx][layer_idx], - triangles_by_color_merged[color_idx - 1][layer_idx]); + ExPolygons painted_regions; + for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++color_idx) { + triangles_by_color_merged[color_idx][layer_idx] = diff_ex(triangles_by_color_merged[color_idx][layer_idx], painted_regions); + append(painted_regions, triangles_by_color_merged[color_idx][layer_idx]); + } + triangles_by_color_merged[0][layer_idx] = diff_ex(triangles_by_color_merged[0][layer_idx], painted_regions); } }); @@ -2039,10 +2047,10 @@ std::vector> multi_material_segmentation_by_painting(con BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - end"; throw_on_cancel_callback(); - //if (auto w = print_object.config().mmu_segmented_region_max_width; w > 0.f) { - // cut_segmented_layers(input_expolygons, segmented_regions, float(-scale_(w)), throw_on_cancel_callback); - // throw_on_cancel_callback(); - //} + if (auto max_width = print_object.config().mmu_segmented_region_max_width, interlocking_depth = print_object.config().mmu_segmented_region_interlocking_depth; max_width > 0.f || interlocking_depth > 0.f) { + cut_segmented_layers(input_expolygons, segmented_regions, float(scale_(max_width)), float(scale_(interlocking_depth)), throw_on_cancel_callback); + throw_on_cancel_callback(); + } // The first index is extruder number (includes default extruder), and the second one is layer number std::vector> top_and_bottom_layers = mmu_segmentation_top_and_bottom_layers(print_object, input_expolygons, throw_on_cancel_callback); diff --git a/src/libslic3r/MutablePriorityQueue.hpp b/src/libslic3r/MutablePriorityQueue.hpp index cc1cae68c9d..2565f417f84 100644 --- a/src/libslic3r/MutablePriorityQueue.hpp +++ b/src/libslic3r/MutablePriorityQueue.hpp @@ -3,7 +3,7 @@ #include #include - +constexpr auto InvalidQueueID = std::numeric_limits::max(); template class MutablePriorityQueue { diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index b9ab300dc2b..1a06c939bd5 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -11,6 +11,7 @@ #include "ClipperUtils.hpp" #include "ExtrusionEntity.hpp" #include "ExtrusionEntityCollection.hpp" +#include "PrintConfig.hpp" #include "ShortestPath.hpp" #include "VariableWidth.hpp" #include "CurveAnalyzer.hpp" @@ -1495,12 +1496,18 @@ void PerimeterGenerator::process_classic() // BBS: don't simplify too much which influence arc fitting when export gcode if arc_fitting is enabled double surface_simplify_resolution = (print_config->enable_arc_fitting && this->config->fuzzy_skin == FuzzySkinType::None) ? 0.2 * m_scaled_resolution : m_scaled_resolution; - for (const Surface &surface : this->slices->surfaces) { + //BBS: reorder the surface to reduce the travel time + ExPolygons surface_exp; + for (const Surface &surface : this->slices->surfaces) + surface_exp.push_back(surface.expolygon); + std::vector surface_order = chain_expolygons(surface_exp); + for (size_t order_idx = 0; order_idx < surface_order.size(); order_idx++) { + const Surface &surface = this->slices->surfaces[surface_order[order_idx]]; // detect how many perimeters must be generated for this island int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops if (this->layer_id == 0 && this->config->only_one_wall_first_layer) loop_number = 0; - //BBS: set the topmost layer to be one wall + // Set the topmost layer to be one wall if (loop_number > 0 && config->only_one_wall_top && this->upper_slices == nullptr) loop_number = 0; @@ -1723,8 +1730,8 @@ void PerimeterGenerator::process_classic() // we continue inwards after having finished the brim // TODO: add test for perimeter order bool is_outer_wall_first = - this->config->wall_infill_order == WallInfillOrder::OuterInnerInfill || - this->config->wall_infill_order == WallInfillOrder::InfillOuterInner; + this->object_config->wall_sequence == WallSequence::OuterInner || + this->object_config->wall_sequence == WallSequence::InnerOuterInner; if (is_outer_wall_first || //BBS: always print outer wall first when there indeed has brim. (this->layer_id == 0 && @@ -1732,7 +1739,7 @@ void PerimeterGenerator::process_classic() this->object_config->brim_width.value > 0)) entities.reverse(); // SoftFever: sandwich mode - else if (this->config->wall_infill_order == WallInfillOrder::InnerOuterInnerInfill) + else if (this->object_config->wall_sequence == WallSequence::InnerOuterInner) if (entities.entities.size() > 1){ int last_outer=0; int outer = 0; @@ -1862,6 +1869,39 @@ void PerimeterGenerator::process_classic() } // for each island } +//BBS: +void PerimeterGenerator::add_infill_contour_for_arachne( ExPolygons infill_contour, + int loops, + coord_t ext_perimeter_spacing, + coord_t perimeter_spacing, + coord_t min_perimeter_infill_spacing, + coord_t spacing, + bool is_inner_part) +{ + if( offset_ex(infill_contour, -float(spacing / 2.)).empty() ) + { + infill_contour.clear(); // Infill region is too small, so let's filter it out. + } + + // create one more offset to be used as boundary for fill + // we offset by half the perimeter spacing (to get to the actual infill boundary) + // and then we offset back and forth by half the infill spacing to only consider the + // non-collapsing regions + coord_t insert = (loops < 0) ? 0: ext_perimeter_spacing; + if (is_inner_part || loops > 0) + insert = perimeter_spacing; + + insert = coord_t(scale_(this->config->infill_wall_overlap.get_abs_value(unscale(insert)))); + + Polygons inner_pp; + for (ExPolygon &ex : infill_contour) + ex.simplify_p(m_scaled_resolution, &inner_pp); + + this->fill_surfaces->append(offset2_ex(union_ex(inner_pp), float(-min_perimeter_infill_spacing / 2.), float(insert + min_perimeter_infill_spacing / 2.)), stInternal); + + append(*this->fill_no_overlap, offset2_ex(union_ex(inner_pp), float(-min_perimeter_infill_spacing / 2.), float(+min_perimeter_infill_spacing / 2.))); +} + // Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper // "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling" void PerimeterGenerator::process_arachne() @@ -1973,7 +2013,7 @@ void PerimeterGenerator::process_arachne() } loop_number = int(perimeters.size()) - 1; -#ifdef ARACHNE_DEBUG + #ifdef ARACHNE_DEBUG { static int iRun = 0; export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour())); @@ -1996,14 +2036,12 @@ void PerimeterGenerator::process_arachne() int direction = -1; bool is_outer_wall_first = - this->config->wall_infill_order == WallInfillOrder::OuterInnerInfill || - this->config->wall_infill_order == WallInfillOrder::InfillOuterInner || - this->config->wall_infill_order == WallInfillOrder::InnerOuterInnerInfill; + this->object_config->wall_sequence == WallSequence::OuterInner || + this->object_config->wall_sequence == WallSequence::InnerOuterInner; if (layer_id == 0){ // disable inner outer inner algorithm after the first layer is_outer_wall_first = - this->config->wall_infill_order == WallInfillOrder::OuterInnerInfill || - this->config->wall_infill_order == WallInfillOrder::InfillOuterInner; + this->object_config->wall_sequence == WallSequence::OuterInner; } if (is_outer_wall_first) { start_perimeter = 0; @@ -2242,8 +2280,9 @@ void PerimeterGenerator::process_arachne() this->loops->append(extrusion_coll); } - ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour()); +ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour()); const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing; + if (offset_ex(infill_contour, -float(spacing / 2.)).empty()) infill_contour.clear(); // Infill region is too small, so let's filter it out. diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index 2ae714473cd..424d6bc375f 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -69,6 +69,8 @@ class PerimeterGenerator { void process_classic(); void process_arachne(); + void add_infill_contour_for_arachne( ExPolygons infill_contour, int loops, coord_t ext_perimeter_spacing, coord_t perimeter_spacing, coord_t min_perimeter_infill_spacing, coord_t spacing, bool is_inner_part ); + double ext_mm3_per_mm() const { return m_ext_mm3_per_mm; } double mm3_per_mm() const { return m_mm3_per_mm; } double mm3_per_mm_overhang() const { return m_mm3_per_mm_overhang; } diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 73252f44597..8bb0a6a41e4 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -83,6 +83,7 @@ using Transform2d = Eigen::Transform; using Transform3d = Eigen::Transform; +// using ColorRGBA = std::array; // I don't know why Eigen::Transform::Identity() return a const object... template Transform identity() { return Transform::Identity(); } inline const auto &identity3f = identity<3, float>; diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 64d197c5bae..18a20586a44 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -683,5 +683,4 @@ Polygon make_circle_num_segments(double radius, size_t num_segments) } return out; } - } \ No newline at end of file diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 9136fec7223..6e8f86e16d1 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -518,6 +518,8 @@ void Preset::save(DynamicPrintConfig* parent_config) else from_str = std::string("Default"); + boost::filesystem::create_directories(fs::path(this->file).parent_path()); + //BBS: only save difference if it has parent if (parent_config) { DynamicPrintConfig temp_config; @@ -530,15 +532,36 @@ void Preset::save(DynamicPrintConfig* parent_config) opt_dst->set(opt_src); } temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string(), this->custom_defined); - } - else + } else if (!filament_id.empty() && inherits().empty()) { + DynamicPrintConfig temp_config = config; + temp_config.set_key_value(BBL_JSON_KEY_FILAMENT_ID, new ConfigOptionString(filament_id)); + temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string(), this->custom_defined); + } else { this->config.save_to_json(this->file, this->name, from_str, this->version.to_string(), this->custom_defined); + } fs::path idx_file(this->file); idx_file.replace_extension(".info"); this->save_info(idx_file.string()); } +void Preset::reload(Preset const &parent) +{ + DynamicPrintConfig config; + // BBS: change to json format + // ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule); + std::map key_values; + std::string reason; + ForwardCompatibilitySubstitutionRule substitution_rule = ForwardCompatibilitySubstitutionRule::Disable; + try { + ConfigSubstitutions config_substitutions = config.load_from_json(file, substitution_rule, key_values, reason); + this->config = parent.config; + this->config.apply(std::move(config)); + } catch (const std::exception &err) { + BOOST_LOG_TRIVIAL(error) << boost::format("Failed loading the user-config file: %1%. Reason: %2%") % file % err.what(); + } +} + // Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty. std::string Preset::label(bool no_alias) const { @@ -665,7 +688,7 @@ std::string Preset::get_printer_type(PresetBundle *preset_bundle) vendor_name = vendor_profile.first; return vendor_model.model_id; } - } + } } return ""; } @@ -686,6 +709,25 @@ std::string Preset::get_current_printer_type(PresetBundle *preset_bundle) return ""; } +bool Preset::has_lidar(PresetBundle *preset_bundle) +{ + bool has_lidar = false; + if (preset_bundle) { + auto config = &preset_bundle->printers.get_edited_preset().config; + std::string vendor_name; + for (auto vendor_profile : preset_bundle->vendors) { + for (auto vendor_model : vendor_profile.second.models) + if (vendor_model.name == config->opt_string("printer_model")) { + vendor_name = vendor_profile.first; + break; + } + } + if (!vendor_name.empty()) + has_lidar = vendor_name.compare("BBL") == 0 ? true : false; + } + return has_lidar; +} + bool Preset::is_custom_defined() { if (custom_defined == "1") @@ -706,7 +748,7 @@ BedType Preset::get_default_bed_type(PresetBundle* preset_bundle) } std::string model_id = this->get_printer_type(preset_bundle); - if (model_id == "BL-P001" || model_id == "BL-P002") { + if (model_id == "BL-P001" || model_id == "BL-P002" || model_id == "C13") { return BedType::btPC; } else if (model_id == "C11") { return BedType::btPEI; @@ -717,7 +759,7 @@ BedType Preset::get_default_bed_type(PresetBundle* preset_bundle) bool Preset::has_cali_lines(PresetBundle* preset_bundle) { std::string model_id = this->get_printer_type(preset_bundle); - if (model_id == "BL-P001" || model_id == "BL-P002") { + if (model_id == "BL-P001" || model_id == "BL-P002" || model_id == "C13") { return true; } return false; @@ -727,7 +769,7 @@ static std::vector s_Preset_print_options { "layer_height", "initial_layer_print_height", "wall_loops", "slice_closing_radius", "spiral_mode", "slicing_mode", "top_shell_layers", "top_shell_thickness", "bottom_shell_layers", "bottom_shell_thickness", "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "overhang_reverse", "overhang_reverse_threshold","overhang_reverse_internal_only", - "seam_position", "staggered_inner_seams", "wall_infill_order", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", + "seam_position", "staggered_inner_seams", "wall_sequence", "is_infill_first", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", "infill_direction", "minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern", "ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", @@ -746,7 +788,7 @@ static std::vector s_Preset_print_options { "support_interface_pattern", "support_interface_spacing", "support_interface_loop_pattern", "support_top_z_distance", "support_on_build_plate_only","support_critical_regions_only", "bridge_no_support", "thick_bridges", "max_bridge_length", "print_sequence", "support_remove_small_overhang", "filename_format", "wall_filament", "support_bottom_z_distance", - "sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament", + "sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament","support_interface_not_for_body", "ooze_prevention", "standby_temperature_delta", "interface_shells", "line_width", "initial_layer_line_width", "inner_wall_line_width", "outer_wall_line_width", "sparse_infill_line_width", "internal_solid_infill_line_width", "top_surface_line_width", "support_line_width", "infill_wall_overlap", "bridge_flow", "internal_bridge_flow", @@ -774,7 +816,7 @@ static std::vector s_Preset_print_options { "make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extruder", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming", "wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic", - "hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted" + "hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth", }; static std::vector s_Preset_filament_options { @@ -819,7 +861,7 @@ static std::vector s_Preset_printer_options { "printer_technology", "printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", "fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs", - "single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", "change_extrusion_role_gcode", + "single_extruder_multi_material", "manual_filament_change", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode", "change_extrusion_role_gcode", "printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "default_print_profile", "inherits", "silent_mode", @@ -1018,8 +1060,13 @@ void PresetCollection::load_presets( // see https://github.com/prusa3d/PrusaSlicer/issues/732 boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / subdir).make_preferred(); + // Load custom roots first + if (fs::exists(dir / "base")) { + load_presets(dir.string(), "base", substitutions, substitution_rule); + } + //BBS: add config related logs - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, load presets from %1%, current type %2%")%dir %Preset::get_type_string(m_type); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, load presets from %1%, current type %2%")%dir %Preset::get_type_string(m_type); //BBS do not parse folder if not exists m_dir_path = dir.string(); if (!fs::exists(dir)) { @@ -1084,8 +1131,12 @@ void PresetCollection::load_presets( } preset.version = *version; + if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end()) + preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID]; if (key_values.find(BBL_JSON_KEY_IS_CUSTOM) != key_values.end()) preset.custom_defined = key_values[BBL_JSON_KEY_IS_CUSTOM]; + if (key_values.find("instantiation") != key_values.end()) + preset.is_visible = key_values["instantiation"] != "false"; //BBS: use inherit config as the base Preset* inherit_preset = nullptr; @@ -1105,12 +1156,12 @@ void PresetCollection::load_presets( preset.filament_id = inherit_preset->filament_id; } else { - if (!preset.is_custom_defined()) { + // We support custom root preset now + auto inherits_config2 = dynamic_cast(inherits_config); + if ((inherits_config2 && !inherits_config2->value.empty()) && !preset.is_custom_defined()) { BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent for config %1%!")%preset.file; continue; } - //should not happen - //BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent for config %1%!")%preset.file; // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. preset.config = default_preset.config; } @@ -1147,6 +1198,7 @@ void PresetCollection::load_presets( fs::remove(file_path); } presets_loaded.emplace_back(preset); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " load config successful and preset name is:" << preset.name; } catch (const std::runtime_error &err) { errors_cummulative += err.what(); errors_cummulative += "\n"; @@ -1219,16 +1271,26 @@ int PresetCollection::get_differed_values_to_update(Preset& preset, std::mapserialize(); } - //add other values - key_values[BBL_JSON_KEY_VERSION] = preset.version.to_string(); - key_values[BBL_JSON_KEY_BASE_ID] = preset.base_id; - key_values[BBL_JSON_KEY_UPDATE_TIME] = std::to_string(preset.updated_time); - key_values[BBL_JSON_KEY_TYPE] = Preset::get_iot_type_string(preset.type); } else { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" Error: can not find the parent! Should not happen, name %1%") %preset.name; - return -1; + for (auto iter = preset.config.cbegin(); iter != preset.config.cend(); ++iter) + { + key_values[iter->first] = iter->second->serialize(); + } } + + //add other values + key_values[BBL_JSON_KEY_VERSION] = preset.version.to_string(); + if (!preset.base_id.empty()) { + key_values[BBL_JSON_KEY_BASE_ID] = preset.base_id; + } else { + key_values.erase(BBL_JSON_KEY_BASE_ID); + if (get_preset_base(preset) == &preset && !preset.filament_id.empty()) { + key_values[BBL_JSON_KEY_FILAMENT_ID] = preset.filament_id; + } + } + key_values[BBL_JSON_KEY_UPDATE_TIME] = std::to_string(preset.updated_time); + key_values[BBL_JSON_KEY_TYPE] = Preset::get_iot_type_string(preset.type); return 0; } @@ -1363,7 +1425,7 @@ bool PresetCollection::reset_project_embedded_presets() return re_select; } -void PresetCollection::set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo) +void PresetCollection::set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo, long long update_time) { lock(); for (auto it = m_presets.begin(); it != m_presets.end(); it++) { @@ -1373,16 +1435,34 @@ void PresetCollection::set_sync_info_and_save(std::string name, std::string sett preset->sync_info.clear(); else preset->sync_info = syncinfo; + if (get_preset_base(*preset) == preset) { + for (auto & preset2 : m_presets) + if (preset2.inherits() == preset->name) { + preset2.base_id = setting_id; + preset2.save_info(); + } + } preset->setting_id = setting_id; - preset->save_info(); + if (update_time > 0) + preset->updated_time = update_time; + preset->sync_info == "update" ? preset->save(nullptr) : preset->save_info(); break; } } unlock(); } +bool PresetCollection::need_sync(std::string name, std::string setting_id, long long update_time) +{ + lock(); + auto preset = find_preset(name, false, true); + bool need = preset == nullptr || preset->setting_id != setting_id || preset->updated_time < update_time; + unlock(); + return need; +} + //BBS: get user presets -int PresetCollection::get_user_presets(std::vector& result_presets) +int PresetCollection::get_user_presets(PresetBundle *preset_bundle, std::vector &result_presets) { int count = 0; result_presets.clear(); @@ -1390,6 +1470,10 @@ int PresetCollection::get_user_presets(std::vector& result_presets) lock(); for (Preset &preset : m_presets) { if (!preset.is_user()) continue; + if (get_preset_base(preset) != &preset && preset.base_id.empty()) continue; + if (!preset.setting_id.empty() && preset.sync_info.empty()) continue; + //if (!preset.is_bbl_vendor_preset(preset_bundle)) continue; + if (preset.sync_info == "hold") continue; result_presets.push_back(preset); count++; @@ -1426,7 +1510,9 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std: for (auto it = m_presets.begin(); it != m_presets.end(); it++) { Preset* preset = &m_presets[it - m_presets.begin()]; if (!preset->is_user()) continue; - preset->file = path_from_name(preset->name); + if (preset->sync_info != "save") continue; + preset->sync_info.clear(); + preset->file = path_for_preset(*preset); if (preset->is_custom_defined()) { preset->save(nullptr); @@ -1434,11 +1520,13 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std: //BBS: only save difference for user preset std::string inherits = Preset::inherits(preset->config); if (inherits.empty()) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find inherits for %1% , should not happen")%preset->name; - // BBS add sync info - preset->sync_info = "delete"; - need_to_delete_list.push_back(preset->setting_id); - delete_name_list.push_back(preset->name); + // We support custom root preset now + //BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find inherits for %1% , should not happen")%preset->name; + //// BBS add sync info + //preset->sync_info = "delete"; + //need_to_delete_list.push_back(preset->setting_id); + //delete_name_list.push_back(preset->name); + preset->save(nullptr); continue; } Preset* parent_preset = this->find_preset(inherits, false, true); @@ -1471,7 +1559,7 @@ bool PresetCollection::load_user_preset(std::string name, std::map presets_loaded; int count = 0; - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, name %1% , total value counts %2%")%name %preset_values.size(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, name %1% , total value counts %2%")%name %preset_values.size(); //if the version is not matching, skip it if (preset_values.find(BBL_JSON_KEY_VERSION) == preset_values.end()) { @@ -1497,13 +1585,6 @@ bool PresetCollection::load_user_preset(std::string name, std::mapname; auto iter = this->find_preset_internal(name); @@ -1535,6 +1610,11 @@ bool PresetCollection::load_user_preset(std::string name, std::mapsync_info = "update"; else iter->sync_info.clear(); + // Fixup possible data lost + iter->setting_id = cloud_setting_id; + fs::path idx_file(iter->file); + idx_file.replace_extension(".info"); + iter->save_info(idx_file.string()); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("preset %1%'s update_time is eqaul or newer, cloud update_time %2%, local update_time %3%")%name %cloud_update_time %iter->updated_time; unlock(); return false; @@ -1542,11 +1622,24 @@ bool PresetCollection::load_user_preset(std::string name, std::mapsync_info.clear(); } } - DynamicPrintConfig new_config, cloud_config; + // base_id + if (preset_values.find(BBL_JSON_KEY_BASE_ID) == preset_values.end()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find base_id, not loading for user preset %1%") % name; + unlock(); + return false; + } + std::string cloud_base_id = preset_values[BBL_JSON_KEY_BASE_ID]; + + //filament_id + std::string cloud_filament_id; + if ((m_type == Preset::TYPE_FILAMENT) && preset_values.find(BBL_JSON_KEY_FILAMENT_ID) != preset_values.end()) { + cloud_filament_id = preset_values[BBL_JSON_KEY_FILAMENT_ID]; + } + + DynamicPrintConfig new_config, cloud_config; try { ConfigSubstitutions config_substitutions = cloud_config.load_string_map(preset_values, rule); if (! config_substitutions.empty()) @@ -1570,12 +1663,16 @@ bool PresetCollection::load_user_preset(std::string name, std::mapconfig; } else { + // We support custom root preset now + auto inherits_config2 = dynamic_cast(inherits_config); + if (inherits_config2 && !inherits_config2->value.empty()) { + //we should skip this preset here + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip")%name; + unlock(); + return false; + } // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. - //new_config = default_preset.config; - //we should skip this preset here - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip")%name; - unlock(); - return false; + new_config = default_preset.config; } new_config.apply(std::move(cloud_config)); Preset::normalize(new_config); @@ -1591,7 +1688,8 @@ bool PresetCollection::load_user_preset(std::string name, std::mapconfig = new_config; iter->updated_time = cloud_update_time; - iter->version = cloud_version.value(); + iter->sync_info = "save"; + iter->version = cloud_version.value(); iter->user_id = cloud_user_id; iter->setting_id = cloud_setting_id; iter->base_id = cloud_base_id; @@ -1607,7 +1705,8 @@ bool PresetCollection::load_user_preset(std::string name, std::map::iterator it = this->find_preset_internal(original_name); - bool found = it != m_presets.end() && it->name == original_name && (it->is_system || it->is_default); + std::deque::iterator it = this->find_preset_internal(preset_name); + bool found = (it != m_presets.end()) && (it->name == preset_name) && (it->is_system || it->is_default); if (!found) { - it = this->find_preset_renamed(original_name); + it = this->find_preset_renamed(preset_name); found = it != m_presets.end() && (it->is_system || it->is_default); } if (!found) { - if (!inherit.empty()) { - it = this->find_preset_internal(inherit); - found = it != m_presets.end() && it->name == inherit && (it->is_system || it->is_default); + if (!inherit_name.empty()) { + it = this->find_preset_internal(inherit_name); + found = it != m_presets.end() && it->name == inherit_name && (it->is_system || it->is_default); + if (found) + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": preset_name %1%, inherit_name %2%, found inherit in list")%preset_name %inherit_name; + else + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": preset_name %1%, inherit_name %2%, can not found preset and inherit in list")%preset_name %inherit_name; } else { //inherit is null , should not happen , just consider it as valid found = false; - BOOST_LOG_TRIVIAL(warning) << boost::format(": name %1%, printer_settings %2%, no inherit, set to not found")%name %original_name; + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": preset_name %1%, no inherit, set to not found")%preset_name; } } - BOOST_LOG_TRIVIAL(warning) << boost::format(": name %1%, printer_settings %2%, inherit %3%, found result %4%")%name %original_name % inherit % found; + else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": preset_name %1%, found in list")%preset_name; + } return found; } @@ -1945,7 +2049,7 @@ std::pair PresetCollection::load_external_preset( } else { //external config - preset.file = path_from_name(preset.name); + preset.file = path_for_preset(preset); //BBS: save full config here for external //we can not reach here preset.save(nullptr); @@ -1985,6 +2089,113 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string return preset; } +bool PresetCollection::clone_presets(std::vector const &presets, std::vector &failures, std::function modifier, bool force_rewritten) +{ + std::vector new_presets; + for (auto curr_preset : presets) { + new_presets.push_back(*curr_preset); + auto &preset = new_presets.back(); + preset.vendor = nullptr; + preset.renamed_from.clear(); + preset.setting_id.clear(); + preset.inherits().clear(); + preset.is_default = false; + preset.is_system = false; + preset.is_external = false; + preset.is_visible = true; + preset.is_project_embedded = false; + modifier(preset, m_type); + if (find_preset(preset.name) && !force_rewritten) { + failures.push_back(preset.name); + } + preset.file = this->path_for_preset(preset); + if (m_type == Preset::TYPE_PRINT) + preset.config.option("print_settings_id", true)->value = preset.name; + else if (m_type == Preset::TYPE_FILAMENT) + preset.config.option("filament_settings_id", true)->values[0] = preset.name; + else if (m_type == Preset::TYPE_PRINTER) + preset.config.option("printer_settings_id", true)->value = preset.name; + } + if (!failures.empty() && !force_rewritten) + return false; + lock(); + auto old_name = this->get_edited_preset().name; + for (auto preset : new_presets) { + preset.alias.clear(); + auto it = this->find_preset_internal(preset.name); + assert((it == m_presets.end() || it->name != preset.name) || force_rewritten); + if (it == m_presets.end() || it->name != preset.name) { + Preset &new_preset = *m_presets.insert(it, preset); + new_preset.save(nullptr); + } else if (force_rewritten) { + *it = preset; + (*it).save(nullptr); + } + } + this->select_preset_by_name(old_name, true); + unlock(); + return true; +} + +bool PresetCollection::clone_presets_for_printer(std::vector const &presets, std::vector &failures, std::string const &printer, bool force_rewritten) +{ + return clone_presets(presets, failures, [printer](Preset &preset, Preset::Type &type) { + std::string prefix = preset.name.substr(0, preset.name.find(" @")); + std::replace(prefix.begin(), prefix.end(), '/', '-'); + preset.name = prefix + " @" + printer; + //preset.alias = ""; + auto *compatible_printers = dynamic_cast(preset.config.option("compatible_printers")); + compatible_printers->values = std::vector{ printer }; + }, force_rewritten); +} + +bool PresetCollection::create_presets_from_template_for_printer(std::vector const & templates, + std::vector & failures, + std::string const & printer, + std::function create_filament_id, + bool force_rewritten) +{ + return clone_presets(templates, failures, [printer, create_filament_id](Preset &preset, Preset::Type &type) { + std::string prefix = preset.name.substr(0, preset.name.find(" @")); + std::replace(prefix.begin(), prefix.end(), '/', '-'); + preset.name = prefix + " @" + printer; + auto *compatible_printers = dynamic_cast(preset.config.option("compatible_printers")); + compatible_printers->values = std::vector{printer}; + preset.is_visible = true; + if (type == Preset::TYPE_FILAMENT) + preset.filament_id = create_filament_id(prefix); + }, force_rewritten); +} + +bool PresetCollection::clone_presets_for_filament(Preset const *const & preset, + std::vector &failures, + std::string const & filament_name, + std::string const & filament_id, + const DynamicConfig & dynamic_config, + const std::string & compatible_printers, + bool force_rewritten) +{ + std::vector const presets = {preset}; + return clone_presets(presets, failures, [&filament_name, &filament_id, &dynamic_config, &compatible_printers](Preset &preset, Preset::Type &type) { + preset.name = filament_name + " @" + compatible_printers; + if (type == Preset::TYPE_FILAMENT) { + preset.config.apply_only(dynamic_config, {"filament_vendor", "compatible_printers", "filament_type"},true); + + preset.filament_id = filament_id; + } + }, + force_rewritten); +} + +std::map> PresetCollection::get_filament_presets() const +{ + std::map> filament_presets; + for (auto &preset : m_presets) { + if (get_preset_base(preset) == &preset) { filament_presets[preset.filament_id].push_back(&preset); } + } + return filament_presets; +} + //BBS: add project embedded preset logic void PresetCollection::save_current_preset(const std::string &new_name, bool detach, bool save_to_project, Preset* _curr_preset) { @@ -2020,15 +2231,27 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": save preset %1% , with detach")%new_name; } //BBS: add lock logic for sync preset in background + + if (m_type == Preset::TYPE_PRINT) + preset.config.option("print_settings_id", true)->value = new_name; + else if (m_type == Preset::TYPE_FILAMENT) + preset.config.option("filament_settings_id", true)->values[0] = new_name; + else if (m_type == Preset::TYPE_PRINTER) + preset.config.option("printer_settings_id", true)->value = new_name; final_inherits = preset.inherits(); unlock(); + // TODO: apply change from custom root to devided presets. + if (preset.inherits().empty()) { + for (auto &preset2 : m_presets) + if (preset2.inherits() == preset.name) + preset2.reload(preset); + } } else { // Creating a new preset. Preset &preset = *m_presets.insert(it, curr_preset); std::string &inherits = preset.inherits(); std::string old_name = preset.name; preset.name = new_name; - preset.file = this->path_from_name(new_name); preset.vendor = nullptr; preset.alias.clear(); preset.renamed_from.clear(); @@ -2037,19 +2260,16 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det // Clear the link to the parent profile. inherits.clear(); BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": save preset %1% , with detach")%new_name; - } else if (preset.is_system) { - // Inheriting from a system preset. - inherits = /* preset.vendor->name + "/" + */ old_name; - } else if (inherits.empty()) { - // Inheriting from a user preset. Link the new preset to the old preset. - // inherits = old_name; } else { // Inherited from a user preset. Just maintain the "inherited" flag, // meaning it will inherit from either the system preset, or the inherited user preset. + auto base = get_preset_base(curr_preset); + inherits = base ? base->name : ""; } preset.is_default = false; preset.is_system = false; preset.is_external = false; + preset.file = this->path_for_preset(preset); // The newly saved preset will be activated -> make it visible. preset.is_visible = true; // Just system presets have aliases @@ -2061,11 +2281,11 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det else preset.is_project_embedded = false; if (m_type == Preset::TYPE_PRINT) - preset.config.option("print_settings_id", true)->value = preset.name; + preset.config.option("print_settings_id", true)->value = new_name; else if (m_type == Preset::TYPE_FILAMENT) - preset.config.option("filament_settings_id", true)->values[0] = preset.name; + preset.config.option("filament_settings_id", true)->values[0] = new_name; else if (m_type == Preset::TYPE_PRINTER) - preset.config.option("printer_settings_id", true)->value = preset.name; + preset.config.option("printer_settings_id", true)->value = new_name; //BBS: add lock logic for sync preset in background final_inherits = inherits; unlock(); @@ -2081,7 +2301,6 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det this->get_selected_preset().base_id = parent_preset->setting_id; } } - this->get_selected_preset().updated_time = (long long)Slic3r::Utils::get_current_time_utc(); if (parent_preset) this->get_selected_preset().save(&(parent_preset->config)); else @@ -2093,6 +2312,13 @@ bool PresetCollection::delete_current_preset() Preset &selected = this->get_selected_preset(); if (selected.is_default) return false; + + if (get_preset_base(selected) == &selected) { + for (auto &preset2 : m_presets) + if (preset2.inherits() == selected.name) + return false; + } + //BBS: add project embedded preset logic and refine is_external //if (! selected.is_external && ! selected.is_system) { if (! selected.is_system) { @@ -2142,7 +2368,7 @@ const Preset* PresetCollection::get_selected_preset_parent() const return nullptr; const Preset &selected_preset = this->get_selected_preset(); - if (selected_preset.is_system || selected_preset.is_default) + if (get_preset_base(selected_preset) == &selected_preset) return &selected_preset; const Preset &edited_preset = this->get_edited_preset(); @@ -2190,6 +2416,17 @@ const Preset* PresetCollection::get_preset_parent(const Preset& child) const preset; } +const Preset *PresetCollection::get_preset_base(const Preset &child) const +{ + if (child.is_system || child.is_default) + return &child; + // Handle user preset + if (child.inherits().empty()) + return &child; // this is user root + auto inherits = find_preset(child.inherits()); + return inherits ? get_preset_base(*inherits) : nullptr; +} + // Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist. PresetWithVendorProfile PresetCollection::get_preset_with_vendor_profile(const Preset &preset) const { @@ -2614,12 +2851,20 @@ std::vector PresetCollection::system_preset_names() const } // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. -std::string PresetCollection::path_from_name(const std::string &new_name) const +std::string PresetCollection::path_from_name(const std::string &new_name, bool detach) const { //BBS: change to json format //std::string file_name = boost::iends_with(new_name, ".ini") ? new_name : (new_name + ".ini"); std::string file_name = boost::iends_with(new_name, ".json") ? new_name : (new_name + ".json"); - return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string(); + if (detach) + return (boost::filesystem::path(m_dir_path) / "base" / file_name).make_preferred().string(); + else + return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string(); +} + +std::string PresetCollection::path_for_preset(const Preset &preset) const +{ + return path_from_name(preset.name, get_preset_base(preset) == &preset); } const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const @@ -2643,6 +2888,21 @@ const Preset* PrinterPresetCollection::find_system_preset_by_model_and_variant(c return it != cend() ? &*it : nullptr; } +const Preset *PrinterPresetCollection::find_custom_preset_by_model_and_variant(const std::string &model_id, const std::string &variant) const +{ + if (model_id.empty()) { return nullptr; } + + const auto it = std::find_if(cbegin(), cend(), [&](const Preset &preset) { + if (preset.config.opt_string("printer_model") != model_id) + return false; + if (variant.empty()) + return true; + return preset.config.opt_string("printer_variant") == variant; + }); + + return it != cend() ? &*it : nullptr; +} + bool PrinterPresetCollection::only_default_printers() const { for (const auto& printer : get_presets()) { diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 8cacf8397ac..15dd3d579c6 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -20,6 +20,10 @@ #define PRESET_PRINTER_NAME "machine" #define PRESET_SLA_PRINT_NAME "sla_print" #define PRESET_SLA_MATERIALS_NAME "sla_materials" +#define PRESET_PROFILES_DIR "profiles" +#define PRESET_PROFILES_TEMOLATE_DIR "profiles_template" +#define PRESET_TEMPLATE_DIR "Template" +#define PRESET_CUSTOM_VENDOR "Custom" //BBS: iot preset type strings #define PRESET_IOT_PRINTER_TYPE "printer" @@ -57,6 +61,8 @@ #define BBL_JSON_KEY_DEFAULT_MATERIALS "default_materials" #define BBL_JSON_KEY_MODEL_ID "model_id" +//BBL: json path + namespace Slic3r { @@ -171,6 +177,8 @@ class Preset // This type is here to support PresetConfigSubstitutions for physical printers, however it does not belong to the Preset class, // PhysicalPrinter class is used instead. TYPE_PHYSICAL_PRINTER, + // BBS: plate config + TYPE_PLATE, // BBS: model config TYPE_MODEL, }; @@ -245,6 +253,7 @@ class Preset //BBS: add logic for only difference save //if parent_config is null, save all keys, otherwise, only save difference void save(DynamicPrintConfig* parent_config); + void reload(Preset const & parent); // Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty. std::string label(bool no_alias) const; @@ -300,6 +309,8 @@ class Preset std::string get_filament_type(std::string &display_filament_type); std::string get_printer_type(PresetBundle *preset_bundle); // get edited preset type std::string get_current_printer_type(PresetBundle *preset_bundle); // get current preset type + + bool has_lidar(PresetBundle *preset_bundle); bool is_custom_defined(); BedType get_default_bed_type(PresetBundle *preset_bundle); @@ -386,8 +397,8 @@ class PresetCollection typedef std::function SyncFunc; //BBS get m_presets begin Iterator lbegin() { return m_presets.begin(); } - //BBS: validate_printers - bool validate_printers(const std::string &name, DynamicPrintConfig& config, std::string &inherit); + //BBS: validate_preset + bool validate_preset(const std::string &name, std::string &inherit); Iterator begin() { return m_presets.begin() + m_num_default_presets; } ConstIterator begin() const { return m_presets.cbegin() + m_num_default_presets; } @@ -425,8 +436,9 @@ class PresetCollection bool load_user_preset(std::string name, std::map preset_values, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule); void update_after_user_presets_loaded(); //BBS: get user presets - int get_user_presets(std::vector& result_presets); - void set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo); + int get_user_presets(PresetBundle *preset_bundle, std::vector &result_presets); + void set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo, long long update_time); + bool need_sync(std::string name, std::string setting_id, long long update_time); //BBS: add function to generate differed preset for save //the pointer should be freed by the caller @@ -444,6 +456,20 @@ class PresetCollection Preset& load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select = true, Semver file_version = Semver(), bool is_custom_defined = false); Preset& load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select = true, Semver file_version = Semver(), bool is_custom_defined = false); + bool clone_presets(std::vector const &presets, std::vector &failures, std::function modifier, bool force_rewritten = false); + bool clone_presets_for_printer(std::vector const &presets, std::vector &failures, std::string const &printer, bool force_rewritten = false); + bool create_presets_from_template_for_printer( + std::vector const &templates, std::vector &failures, std::string const &printer, std::function create_filament_id, bool force_rewritten = false); + bool clone_presets_for_filament(Preset const *const & preset, + std::vector &failures, + std::string const & filament_name, + std::string const & filament_id, + const DynamicConfig & dynamic_config, + const std::string & compatible_printers, + bool force_rewritten = false); + + std::map> get_filament_presets() const; + // Returns a loaded preset, returns true if an existing preset was selected AND modified from config. // In that case the successive filament loaded for a multi material printer should not be modified, but // an external preset should be created instead. @@ -514,6 +540,7 @@ class PresetCollection // Get parent preset for a child preset, based on the "inherits" field of a child, // where the "inherits" profile name is searched for in both m_presets and m_map_system_profile_renamed. const Preset* get_preset_parent(const Preset& child) const; + const Preset* get_preset_base(const Preset& child) const; // Return the selected preset including the user modifications. Preset& get_edited_preset() { return m_edited_preset; } const Preset& get_edited_preset() const { return m_edited_preset; } @@ -648,7 +675,8 @@ class PresetCollection bool select_preset_by_name(const std::string &name, bool force); // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. - std::string path_from_name(const std::string &new_name) const; + std::string path_from_name(const std::string &new_name, bool detach = false) const; + std::string path_for_preset(const Preset & preset) const; size_t num_default_presets() { return m_num_default_presets; } @@ -754,6 +782,7 @@ class PrinterPresetCollection : public PresetCollection const Preset& default_preset_for(const DynamicPrintConfig &config) const override; const Preset* find_system_preset_by_model_and_variant(const std::string &model_id, const std::string &variant) const; + const Preset* find_custom_preset_by_model_and_variant(const std::string &model_id, const std::string &variant) const; bool only_default_printers() const; private: diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index a54b6d14c40..c5d1973c2b6 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -21,6 +21,7 @@ #include #include #include +#include // Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir. @@ -540,6 +541,7 @@ std::string PresetBundle::get_hotend_model_for_printer_model(std::string model_n PresetsConfigSubstitutions PresetBundle::load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule substitution_rule) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " entry and user is: " << user; PresetsConfigSubstitutions substitutions; std::string errors_cummulative; @@ -600,9 +602,14 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(AppConfig & remove_users_preset(config, &my_presets); std::map>::iterator it; + for (int pass = 0; pass < 2; ++pass) for (it = my_presets.begin(); it != my_presets.end(); it++) { std::string name = it->first; std::map& value_map = it->second; + // Load user root presets at first pass + std::map::iterator inherits_iter = value_map.find(BBL_JSON_KEY_INHERITS); + if ((pass == 1) == (inherits_iter == value_map.end() || inherits_iter->second.empty())) + continue; //get the type first std::map::iterator type_iter = value_map.find(BBL_JSON_KEY_TYPE); if (type_iter == value_map.end()) { @@ -659,101 +666,189 @@ PresetsConfigSubstitutions PresetBundle::import_presets(std::vector std::function override_confirm, ForwardCompatibilitySubstitutionRule rule) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry"; PresetsConfigSubstitutions substitutions; int overwrite = 0; std::vector result; for (auto &file : files) { if (Slic3r::is_json_file(file)) { - try { - DynamicPrintConfig config; - // BBS: change to json format - // ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule); - std::map key_values; - std::string reason; - ConfigSubstitutions config_substitutions = config.load_from_json(file, rule, key_values, reason); - std::string name = key_values[BBL_JSON_KEY_NAME]; - std::string version_str = key_values[BBL_JSON_KEY_VERSION]; - boost::optional version = Semver::parse(version_str); - if (!version) continue; - Semver app_version = *(Semver::parse(SLIC3R_VERSION)); - if (version->maj() != app_version.maj()) { - BOOST_LOG_TRIVIAL(warning) << "Preset incompatibla, not loading: " << name; - continue; - } - - PresetCollection * collection = nullptr; - if (config.has("printer_settings_id")) - collection = &printers; - else if (config.has("print_settings_id")) - collection = &prints; - else if (config.has("filament_settings_id")) - collection = &filaments; - if (collection == nullptr) { - BOOST_LOG_TRIVIAL(warning) << "Preset type is unknown, not loading: " << name; - continue; - } - if (overwrite == 0) overwrite = 1; - if (auto p = collection->find_preset(name, false)) { - if (p->is_default || p->is_system) { - BOOST_LOG_TRIVIAL(warning) << "Preset already present and is system preset, not loading: " << name; - continue; + import_json_presets(substitutions, file, override_confirm, rule, overwrite, result); + } + // Determine if it is a preset bundle + if (boost::iends_with(file, ".bbscfg") || boost::iends_with(file, ".bbsflmt") || boost::iends_with(file, ".zip")) { + boost::system::error_code ec; + // create user folder + fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR); + if (!fs::exists(user_folder)) fs::create_directory(user_folder, ec); + if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message(); + // create default folder + fs::path default_folder(user_folder / DEFAULT_USER_FOLDER_NAME); + if (!fs::exists(default_folder)) fs::create_directory(default_folder, ec); + if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message(); + //create temp folder + //std::string user_default_temp_dir = data_dir() + "/" + PRESET_USER_DIR + "/" + DEFAULT_USER_FOLDER_NAME + "/" + "temp"; + fs::path temp_folder(default_folder / "temp"); + std::string user_default_temp_dir = temp_folder.make_preferred().string(); + if (fs::exists(temp_folder)) fs::remove_all(temp_folder); + fs::create_directory(temp_folder, ec); + if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message(); + + file = boost::filesystem::path(file).make_preferred().string(); + mz_zip_archive zip_archive; + mz_zip_zero_struct(&zip_archive); + mz_bool status; + + /*if (!open_zip_reader(&zip_archive, file)) { + BOOST_LOG_TRIVIAL(info) << "Failed to initialize reader ZIP archive"; + return substitutions; + } else { + BOOST_LOG_TRIVIAL(info) << "Success to initialize reader ZIP archive"; + }*/ + + FILE *zipFile = boost::nowide::fopen(file.c_str(), "rb"); + status = mz_zip_reader_init_cfile(&zip_archive, zipFile, 0, MZ_ZIP_FLAG_CASE_SENSITIVE | MZ_ZIP_FLAG_IGNORE_PATH); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Failed to initialize reader ZIP archive"; + return substitutions; + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Success to initialize reader ZIP archive"; + } + + // Extract Files + int num_files = mz_zip_reader_get_num_files(&zip_archive); + for (int i = 0; i < num_files; i++) { + mz_zip_archive_file_stat file_stat; + status = mz_zip_reader_file_stat(&zip_archive, i, &file_stat); + if (status) { + std::string file_name = file_stat.m_filename; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Form zip file: " << file << ". Read file name: " << file_stat.m_filename; + size_t index = file_name.find_last_of('/'); + if (std::string::npos != index) { + file_name = file_name.substr(index + 1); + } + if (BUNDLE_STRUCTURE_JSON_NAME == file_name) continue; + // create target file path + std::string target_file_path = boost::filesystem::path(temp_folder / file_name).make_preferred().string(); + + status = mz_zip_reader_extract_to_file(&zip_archive, i, encode_path(target_file_path.c_str()).c_str(), MZ_ZIP_FLAG_CASE_SENSITIVE); + // target file is opened + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Failed to open target file: " << target_file_path; + } else { + bool is_success = import_json_presets(substitutions, target_file_path, override_confirm, rule, overwrite, result); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " import target file: " << target_file_path << " import result" << is_success; } - overwrite = override_confirm(name); - } - if (overwrite == 0 || overwrite == 2) { - BOOST_LOG_TRIVIAL(warning) << "Preset already present, not loading: " << name; - continue; - } - - DynamicPrintConfig new_config; - Preset * inherit_preset = nullptr; - ConfigOption *inherits_config = config.option(BBL_JSON_KEY_INHERITS); - std::string inherits_value; - if (inherits_config) { - ConfigOptionString *option_str = dynamic_cast(inherits_config); - inherits_value = option_str->value; - inherit_preset = collection->find_preset(inherits_value, false, true); - } - if (inherit_preset) { - new_config = inherit_preset->config; - } else { - // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. - // new_config = default_preset.config; - // we should skip this preset here - BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip") % name; - continue; } - new_config.apply(std::move(config)); - - Preset &preset = collection->load_preset(collection->path_from_name(name), name, std::move(new_config), false); - preset.is_external = true; - preset.version = *version; - inherit_preset = collection->find_preset(inherits_value, false, true); // pointer maybe wrong after insert, redo find - if (inherit_preset) - preset.base_id = inherit_preset->setting_id; - Preset::normalize(preset.config); - // Report configuration fields, which are misplaced into a wrong group. - const Preset &default_preset = collection->default_preset_for(new_config); - std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config); - if (!incorrect_keys.empty()) - BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << preset.file << "\" contains the following incorrect keys: " << incorrect_keys - << ", which were removed"; - if (!config_substitutions.empty()) - substitutions.push_back({name, collection->type(), PresetConfigSubstitutions::Source::UserFile, file, std::move(config_substitutions)}); - - preset.save(inherit_preset ? &inherit_preset->config : nullptr); - result.push_back(file); - } catch (const std::ifstream::failure &err) { - BOOST_LOG_TRIVIAL(error) << boost::format("The config cannot be loaded: %1%. Reason: %2%") % file % err.what(); - } catch (const std::runtime_error &err) { - BOOST_LOG_TRIVIAL(error) << boost::format("Failed importing config file: %1%. Reason: %2%") % file % err.what(); } + fclose(zipFile); + if (fs::exists(temp_folder)) fs::remove_all(temp_folder, ec); + if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " remove directory failed: " << ec.message(); } } files = result; return substitutions; } +bool PresetBundle::import_json_presets(PresetsConfigSubstitutions & substitutions, + std::string & file, + std::function override_confirm, + ForwardCompatibilitySubstitutionRule rule, + int & overwrite, + std::vector & result) +{ + try { + DynamicPrintConfig config; + // BBS: change to json format + // ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule); + std::map key_values; + std::string reason; + ConfigSubstitutions config_substitutions = config.load_from_json(file, rule, key_values, reason); + std::string name = key_values[BBL_JSON_KEY_NAME]; + std::string version_str = key_values[BBL_JSON_KEY_VERSION]; + boost::optional version = Semver::parse(version_str); + if (!version) return false; + Semver app_version = *(Semver::parse(SLIC3R_VERSION)); + if (version->maj() != app_version.maj()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset incompatibla, not loading: " << name; + return false; + } + + PresetCollection *collection = nullptr; + if (config.has("printer_settings_id")) + collection = &printers; + else if (config.has("print_settings_id")) + collection = &prints; + else if (config.has("filament_settings_id")) + collection = &filaments; + if (collection == nullptr) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset type is unknown, not loading: " << name; + return false; + } + if (overwrite == 0) overwrite = 1; + if (auto p = collection->find_preset(name, false)) { + if (p->is_default || p->is_system) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset already present and is system preset, not loading: " << name; + return false; + } + if (overwrite != 2 && overwrite != 3) overwrite = override_confirm(name); //3: yes to all 2: no to all + } + if (overwrite == 0 || overwrite == 2) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset already present, not loading: " << name; + return false; + } + + DynamicPrintConfig new_config; + Preset * inherit_preset = nullptr; + ConfigOption * inherits_config = config.option(BBL_JSON_KEY_INHERITS); + std::string inherits_value; + if (inherits_config) { + ConfigOptionString *option_str = dynamic_cast(inherits_config); + inherits_value = option_str->value; + inherit_preset = collection->find_preset(inherits_value, false, true); + } + if (inherit_preset) { + new_config = inherit_preset->config; + } else { + // We support custom root preset now + auto inherits_config2 = dynamic_cast(inherits_config); + if (inherits_config2 && !inherits_config2->value.empty()) { + // we should skip this preset here + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip") % name; + return false; + } + // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field. + const Preset &default_preset = collection->default_preset_for(config); + new_config = default_preset.config; + } + new_config.apply(std::move(config)); + + Preset &preset = collection->load_preset(collection->path_from_name(name, inherit_preset == nullptr), name, std::move(new_config), false); + if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end()) + preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID]; + preset.is_external = true; + preset.version = *version; + inherit_preset = collection->find_preset(inherits_value, false, true); // pointer maybe wrong after insert, redo find + if (inherit_preset) preset.base_id = inherit_preset->setting_id; + Preset::normalize(preset.config); + // Report configuration fields, which are misplaced into a wrong group. + const Preset &default_preset = collection->default_preset_for(new_config); + std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config); + if (!incorrect_keys.empty()) + BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << preset.file << "\" contains the following incorrect keys: " << incorrect_keys + << ", which were removed"; + if (!config_substitutions.empty()) + substitutions.push_back({name, collection->type(), PresetConfigSubstitutions::Source::UserFile, file, std::move(config_substitutions)}); + + preset.save(inherit_preset ? &inherit_preset->config : nullptr); + result.push_back(file); + } catch (const std::ifstream::failure &err) { + BOOST_LOG_TRIVIAL(error) << boost::format("The config cannot be loaded: %1%. Reason: %2%") % file % err.what(); + } catch (const std::runtime_error &err) { + BOOST_LOG_TRIVIAL(error) << boost::format("Failed importing config file: %1%. Reason: %2%") % file % err.what(); + } + return true; +} + //BBS save user preset to user_id preset folder void PresetBundle::save_user_presets(AppConfig& config, std::vector& need_to_delete_list) { @@ -867,26 +962,80 @@ void PresetBundle::update_system_preset_setting_ids(std::map gcodes_key_set = {"filament_end_gcode", "filament_start_gcode", "change_filament_gcode", "layer_change_gcode", "machine_end_gcode", "machine_pause_gcode", "machine_start_gcode", + "template_custom_gcode", "printing_by_object_gcode", "before_layer_change_gcode", "time_lapse_gcode"}; +int PresetBundle::validate_presets(const std::string &file_name, DynamicPrintConfig& config, std::set& different_gcodes) { - // BBS TODO: -#if 0 - std::vector inherits_values; - PrinterTechnology printer_technology = Preset::printer_technology(config); - size_t num_extruders = (printer_technology == ptFFF) ? - std::min(config.option("nozzle_diameter" )->values.size(), - config.option("filament_diameter")->values.size()) : 1; - inherits_values.resize(num_extruders + 2, std::string()); - inherits_values = config.option("inherits_group", true)->values; + bool validated = false; + std::vector inherits_values = config.option("inherits_group", true)->values; + std::vector filament_preset_name = config.option("filament_settings_id", true)->values; + std::string printer_preset = config.option("printer_settings_id", true)->value; + bool has_different_settings_to_system = config.option("different_settings_to_system")?true:false; + std::vector different_values; + int ret = VALIDATE_PRESETS_SUCCESS; - std::string inherits; - if (inherits_values.size() >= (num_extruders + 2)) - inherits = inherits_values[num_extruders + 1]; + if (has_different_settings_to_system) + different_values = config.option("different_settings_to_system", true)->values; - return this->printers.validate_printers(name, config, inherits); -#else - return true; -#endif + //PrinterTechnology printer_technology = Preset::printer_technology(config); + size_t filament_count = config.option("filament_diameter")->values.size(); + inherits_values.resize(filament_count + 2, std::string()); + different_values.resize(filament_count + 2, std::string()); + filament_preset_name.resize(filament_count, std::string()); + + std::string printer_inherits = inherits_values[filament_count + 1]; + + validated = this->printers.validate_preset(printer_preset, printer_inherits); + if (!validated) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found the printer preset not inherit from system") % file_name; + different_gcodes.emplace(printer_preset); + ret = VALIDATE_PRESETS_PRINTER_NOT_FOUND; + } + for(unsigned int index = 0; index < filament_count; index ++) + { + std::string filament_preset = filament_preset_name[index]; + std::string filament_inherits = inherits_values[index+1]; + + validated = this->filaments.validate_preset(filament_preset, filament_inherits); + if (!validated) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found the filament %2% preset not inherit from system") % file_name %(index+1); + different_gcodes.emplace(filament_preset); + ret = VALIDATE_PRESETS_FILAMENTS_NOT_FOUND; + } + } + + //self defined presets, return directly + if (ret) + { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found self defined presets, count %2%") %file_name %different_gcodes.size(); + return ret; + } + + for(unsigned int index = 1; index < filament_count+2; index ++) + { + std::string different_settingss = different_values[index]; + + std::vector different_keys; + + Slic3r::unescape_strings_cstyle(different_settingss, different_keys); + + for (unsigned int j = 0; j < different_keys.size(); j++) { + if (gcodes_key_set.find(different_keys[j]) != gcodes_key_set.end()) { + different_gcodes.emplace(different_keys[j]); + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":preset index %1%, different key %2%") %index %different_keys[j]; + } + } + } + + if (!different_gcodes.empty()) + { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found different gcodes count %2%") %file_name %different_gcodes.size(); + return VALIDATE_PRESETS_MODIFIED_GCODES; + } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":file_name %1%, validate presets success!") % file_name; + + return VALIDATE_PRESETS_SUCCESS; } void PresetBundle::remove_users_preset(AppConfig &config, std::map> *my_presets) @@ -1113,6 +1262,116 @@ std::pair PresetBundle::load_system_pre return std::make_pair(std::move(substitutions), errors_cummulative); } +std::pair PresetBundle::load_system_models_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule) +{ + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, compatibility_rule %1%") % compatibility_rule; + if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent) + // Loading system presets, don't log substitutions. + compatibility_rule = ForwardCompatibilitySubstitutionRule::EnableSilent; + else if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem) + // Loading system presets, throw on unknown option value. + compatibility_rule = ForwardCompatibilitySubstitutionRule::Disable; + + // Here the vendor specific read only Config Bundles are stored. + boost::filesystem::path dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred(); + PresetsConfigSubstitutions substitutions; + std::string errors_cummulative; + for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) { + std::string vendor_file = dir_entry.path().string(); + if (Slic3r::is_json_file(vendor_file)) { + std::string vendor_name = dir_entry.path().filename().string(); + // Remove the .json suffix. + vendor_name.erase(vendor_name.size() - 5); + try { + // Load the config bundle, flatten it. + append(substitutions, load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadVendorOnly, compatibility_rule).first); + } catch (const std::runtime_error &err) { + errors_cummulative += err.what(); + errors_cummulative += "\n"; + } + } + } + + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, errors_cummulative %1%") % errors_cummulative; + return std::make_pair(std::move(substitutions), errors_cummulative); +} + +std::pair PresetBundle::load_system_filaments_json(ForwardCompatibilitySubstitutionRule compatibility_rule) +{ + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, compatibility_rule %1%") % compatibility_rule; + if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent) + // Loading system presets, don't log substitutions. + compatibility_rule = ForwardCompatibilitySubstitutionRule::EnableSilent; + else if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem) + // Loading system presets, throw on unknown option value. + compatibility_rule = ForwardCompatibilitySubstitutionRule::Disable; + + // Here the vendor specific read only Config Bundles are stored. + boost::filesystem::path dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred(); + PresetsConfigSubstitutions substitutions; + std::string errors_cummulative; + bool first = true; + for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) { + std::string vendor_file = dir_entry.path().string(); + if (Slic3r::is_json_file(vendor_file)) { + std::string vendor_name = dir_entry.path().filename().string(); + // Remove the .json suffix. + vendor_name.erase(vendor_name.size() - 5); + try { + if (first) { + // Reset this PresetBundle and load the first vendor config. + append(substitutions, this->load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule).first); + first = false; + } else { + // Load the other vendor configs, merge them with this PresetBundle. + // Report duplicate profiles. + PresetBundle other; + append(substitutions, other.load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule).first); + std::vector duplicates = this->merge_presets(std::move(other)); + if (!duplicates.empty()) { + errors_cummulative += "Found duplicated settings in vendor " + vendor_name + "'s json file lists: "; + for (size_t i = 0; i < duplicates.size(); ++i) { + if (i > 0) errors_cummulative += ", "; + errors_cummulative += duplicates[i]; + } + } + } + } catch (const std::runtime_error &err) { + errors_cummulative += err.what(); + errors_cummulative += "\n"; + } + } + } + + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, errors_cummulative %1%") % errors_cummulative; + return std::make_pair(std::move(substitutions), errors_cummulative); +} + +VendorProfile PresetBundle::get_custom_vendor_models() const +{ + VendorProfile vendor; + vendor.name = PRESET_CUSTOM_VENDOR; + vendor.id = PRESET_CUSTOM_VENDOR; + for (auto &preset : printers.get_presets()) { + if (preset.is_system) continue; + if (printers.get_preset_base(preset) != &preset) continue; + if (preset.is_default) continue; + auto model = preset.config.opt_string("printer_model"); + auto variant = preset.config.opt_string("printer_variant"); + auto iter_model = std::find_if(vendor.models.begin(), vendor.models.end(), [model](VendorProfile::PrinterModel &m) { + return m.name == model; + }); + if (iter_model == vendor.models.end()) { + iter_model = vendor.models.emplace(vendor.models.end(), VendorProfile::PrinterModel{}); + iter_model->id = model; + iter_model->name = model; + iter_model->variants = {VendorProfile::PrinterVariant(variant)}; + } else { + iter_model->variants.push_back(VendorProfile::PrinterVariant(variant)); + } + } + return vendor; +} // Merge one vendor's presets with the other vendor's presets, report duplicates. std::vector PresetBundle::merge_presets(PresetBundle &&other) @@ -1181,6 +1440,28 @@ const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& p return presets.get_preset_name_by_alias(alias); } +//BBS: get filament required hrc by filament type +const int PresetBundle::get_required_hrc_by_filament_type(const std::string& filament_type) const +{ + static std::unordered_mapfilament_type_to_hrc; + if (filament_type_to_hrc.empty()) { + for (auto iter = filaments.m_presets.begin(); iter != filaments.m_presets.end(); iter++) { + if (iter->vendor && iter->vendor->id == "BBL") { + if (iter->config.has("filament_type") && iter->config.has("required_nozzle_HRC")) { + auto type = iter->config.opt_string("filament_type", 0); + auto hrc = iter->config.opt_int("required_nozzle_HRC", 0); + filament_type_to_hrc[type] = hrc; + } + } + } + } + auto iter = filament_type_to_hrc.find(filament_type); + if (iter != filament_type_to_hrc.end()) + return iter->second; + else + return 0; +} + //BBS: add project embedded preset logic void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector& unselected_options, bool save_to_project) @@ -1570,7 +1851,8 @@ unsigned int PresetBundle::sync_ams_list(unsigned int &unknowns) filament_colors.push_back(filament_color); continue; } - auto iter = std::find_if(filaments.begin(), filaments.end(), [&filament_id](auto &f) { return f.is_compatible && f.is_system && f.filament_id == filament_id; }); + auto iter = std::find_if(filaments.begin(), filaments.end(), [this, &filament_id](auto &f) { + return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; }); if (iter == filaments.end()) { BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id; auto filament_type = ams.opt_string("filament_type", 0u); @@ -1582,7 +1864,9 @@ unsigned int PresetBundle::sync_ams_list(unsigned int &unknowns) }); } if (iter == filaments.end()) - iter = std::find_if(filaments.begin(), filaments.end(), [&filament_type](auto &f) { return f.is_compatible && f.is_system; }); + iter = std::find_if(filaments.begin(), filaments.end(), [&filament_type](auto &f) { + return f.is_compatible && f.is_system; + }); if (iter == filaments.end()) continue; ++unknowns; @@ -2087,7 +2371,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool if (is_external) presets.load_external_preset(name_or_path, name, config.opt_string(key, true), config, different_keys, PresetCollection::LoadAndSelect::Always, file_version, filament_id); else - presets.load_preset(presets.path_from_name(name), name, config, selected, file_version, is_custom_defined).save(nullptr); + presets.load_preset(presets.path_from_name(name, inherits.empty()), name, config, selected, file_version, is_custom_defined).save(nullptr); }; switch (Preset::printer_technology(config)) { @@ -2156,7 +2440,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool loaded = this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config, filament_different_keys_set, PresetCollection::LoadAndSelect::Always, file_version, filament_id).first; else { // called from Config Wizard. - loaded= &this->filaments.load_preset(this->filaments.path_from_name(name), name, config, true, file_version, is_custom_defined); + loaded= &this->filaments.load_preset(this->filaments.path_from_name(name, inherits.empty()), name, config, true, file_version, is_custom_defined); loaded->save(nullptr); } this->filament_presets.clear(); @@ -2831,10 +3115,9 @@ std::pair PresetBundle::load_vendor_configs_ // Enable substitutions for user config bundle, throw an exception when loading a system profile. ConfigSubstitutionContext substitution_context { compatibility_rule }; PresetsConfigSubstitutions substitutions; - std::string vendor_system_path = data_dir() + "/" + PRESET_SYSTEM_DIR; //BBS: add config related logs - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, path %1%, compatibility_rule %2%")%path.c_str()%compatibility_rule; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, path %1%, compatibility_rule %2%")%path.c_str()%compatibility_rule; if (flags.has(LoadConfigBundleAttribute::ResetUserProfile) || flags.has(LoadConfigBundleAttribute::LoadSystem)) // Reset this bundle, delete user profile files if SaveImported. this->reset(flags.has(LoadConfigBundleAttribute::SaveImported)); @@ -2885,7 +3168,7 @@ std::pair PresetBundle::load_vendor_configs_ auto config_version = Semver::parse(version_str); if (! config_version) { throw ConfigurationError((boost::format("vendor %1%'s config version: %2% invalid\nSuggest cleaning the directory %3% firstly") - % vendor_name % version_str %vendor_system_path).str()); + % vendor_name % version_str % path).str()); } else { vendor_profile.config_version = std::move(*config_version); } @@ -2923,10 +3206,16 @@ std::pair PresetBundle::load_vendor_configs_ catch(nlohmann::detail::parse_error &err) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "< PresetBundle::load_vendor_configs_ catch(nlohmann::detail::parse_error &err) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<< subfile <<" got a nlohmann::detail::parse_error, reason = " << err.what(); throw ConfigurationError((boost::format("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% firstly") - %subfile %err.what() %vendor_system_path).str()); + %subfile %err.what() % path).str()); } if (! model.id.empty() && ! model.variants.empty()) @@ -3091,7 +3380,7 @@ std::pair PresetBundle::load_vendor_configs_ } config = *default_config; config.apply(config_src); - if (instantiation == "false") { + if (instantiation == "false" && "Template" != vendor_name) { config_maps.emplace(preset_name, std::move(config)); if ((presets_collection->type() == Preset::TYPE_FILAMENT) && (!filament_id.empty())) filament_id_maps.emplace(preset_name, filament_id); @@ -3169,7 +3458,7 @@ std::pair PresetBundle::load_vendor_configs_ loaded.setting_id = setting_id; loaded.filament_id = filament_id; if (presets_collection->type() == Preset::TYPE_FILAMENT) { - if (filament_id.empty()) { + if (filament_id.empty() && "Template" != vendor_name) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": can not find filament_id for " << preset_name; //throw ConfigurationError(format("can not find inherits %1% for %2%", inherits, preset_name)); reason = "Can not find filament_id for " + preset_name; @@ -3221,7 +3510,7 @@ std::pair PresetBundle::load_vendor_configs_ //parse error std::string subfile_path = path + "/" + vendor_name + "/" + subfile.second; BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", got error when parse process setting from %1%") % subfile_path; - throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path %vendor_system_path).str()); + throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path % path).str()); } } @@ -3236,7 +3525,7 @@ std::pair PresetBundle::load_vendor_configs_ //parse error std::string subfile_path = path + "/" + vendor_name + "/" + subfile.second; BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", got error when parse filament setting from %1%") % subfile_path; - throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path %vendor_system_path).str()); + throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path % path).str()); } } @@ -3251,7 +3540,7 @@ std::pair PresetBundle::load_vendor_configs_ //parse error std::string subfile_path = path + "/" + vendor_name + "/" + subfile.second; BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", got error when parse printer setting from %1%") % subfile_path; - throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path %vendor_system_path).str()); + throw ConfigurationError((boost::format("Failed loading configuration file %1%\nSuggest cleaning the directory %2% firstly") % subfile_path % path).str()); } } diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index 3d0fe208587..9af153b49c3 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -9,7 +9,14 @@ #include #include -#define DEFAULT_USER_FOLDER_NAME "default" +#define DEFAULT_USER_FOLDER_NAME "default" +#define BUNDLE_STRUCTURE_JSON_NAME "bundle_structure.json" + +#define VALIDATE_PRESETS_SUCCESS 0 +#define VALIDATE_PRESETS_PRINTER_NOT_FOUND 1 +#define VALIDATE_PRESETS_FILAMENTS_NOT_FOUND 2 +#define VALIDATE_PRESETS_MODIFIED_GCODES 3 + // define an enum class of vendor type enum class VendorType { @@ -57,6 +64,12 @@ class PresetBundle PresetsConfigSubstitutions load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule rule); PresetsConfigSubstitutions load_user_presets(AppConfig &config, std::map>& my_presets, ForwardCompatibilitySubstitutionRule rule); PresetsConfigSubstitutions import_presets(std::vector &files, std::function override_confirm, ForwardCompatibilitySubstitutionRule rule); + bool import_json_presets(PresetsConfigSubstitutions & substitutions, + std::string & file, + std::function override_confirm, + ForwardCompatibilitySubstitutionRule rule, + int & overwrite, + std::vector & result); void save_user_presets(AppConfig& config, std::vector& need_to_delete_list); void remove_users_preset(AppConfig &config, std::map> * my_presets = nullptr); void update_user_presets_directory(const std::string preset_folder); @@ -64,7 +77,7 @@ class PresetBundle void update_system_preset_setting_ids(std::map>& system_presets); //BBS: add API to get previous machine - bool validate_printers(const std::string &name, DynamicPrintConfig& config); + int validate_presets(const std::string &file_name, DynamicPrintConfig& config, std::set& different_gcodes); //BBS: add function to generate differed preset for save //the pointer should be freed by the caller @@ -173,6 +186,7 @@ class PresetBundle // Load a system config bundle. LoadSystem, LoadVendorOnly, + LoadFilamentOnly, }; using LoadConfigBundleAttributes = enum_bitmask; // Load the config bundle based on the flags. @@ -189,7 +203,7 @@ class PresetBundle //void export_current_configbundle(const std::string &path); //BBS: add a function to export system presets for cloud-slicer //void export_system_configs(const std::string &path); - std::vector export_current_configs(const std::string &path, std::function override_confirm, + std::vector export_current_configs(const std::string &path, std::function override_confirm, bool include_modify, bool export_system_settings = false); // Enable / disable the "- default -" preset. @@ -218,11 +232,16 @@ class PresetBundle const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias) const; + const int get_required_hrc_by_filament_type(const std::string& filament_type) const; // Save current preset of a provided type under a new name. If the name is different from the old one, // Unselected option would be reverted to the beginning values //BBS: add project embedded preset logic void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector& unselected_options, bool save_to_project = false); + std::pair load_system_models_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule); + std::pair load_system_filaments_json(ForwardCompatibilitySubstitutionRule compatibility_rule); + VendorProfile get_custom_vendor_models() const; + //BBS: add BBL as default static const char *BBL_BUNDLE; static const char *BBL_DEFAULT_PRINTER_MODEL; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 33cdcab5be2..4510890c3c1 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -31,7 +31,7 @@ #include "Geometry/ConvexHull.hpp" #include "I18N.hpp" #include "ShortestPath.hpp" -#include "SupportMaterial.hpp" +#include "Support/SupportMaterial.hpp" #include "Thread.hpp" #include "Time.hpp" #include "GCode.hpp" @@ -102,6 +102,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "printable_area", //BBS: add bed_exclude_area "bed_exclude_area", + "thumbnail_size", "before_layer_change_gcode", "enable_pressure_advance", "pressure_advance", @@ -113,6 +114,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "deretraction_speed", "close_fan_the_first_x_layers", "machine_end_gcode", + "printing_by_object_gcode", "filament_end_gcode", "post_process", "extruder_clearance_height_to_rod", @@ -183,6 +185,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "nozzle_hrc", "required_nozzle_HRC", "upward_compatible_machine", + "is_infill_first", // Orca "chamber_temperature", "thumbnails", @@ -310,7 +313,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n //|| opt_key == "resolution" //BBS: when enable arc fitting, we must re-generate perimeter || opt_key == "enable_arc_fitting" - || opt_key == "wall_infill_order") { + || opt_key == "wall_sequence") { osteps.emplace_back(posPerimeters); osteps.emplace_back(posEstimateCurledExtrusions); osteps.emplace_back(posInfill); @@ -1145,19 +1148,19 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam || std::abs((filament_diam - first_filament_diam) / first_filament_diam) > 0.1) // BBS: remove L() - return { ("Different nozzle diameters and different filament diameters is not allowed when prime tower is enabled.") }; + return { L("Different nozzle diameters and different filament diameters is not allowed when prime tower is enabled.") }; } if (! m_config.use_relative_e_distances) - return { ("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") }; + return { L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).") }; if (m_config.ooze_prevention) - return { ("Ooze prevention is currently not supported with the prime tower enabled.") }; + return { L("Ooze prevention is currently not supported with the prime tower enabled.") }; // BBS: remove following logic and _L() #if 0 if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && m_config.gcode_flavor != gcfMarlinFirmware) - return {("The prime tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors.")}; + return { L("The prime tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors.")}; if ((m_config.print_sequence == PrintSequence::ByObject) && extruders.size() > 1) return { L("The prime tower is not supported in \"By object\" print."), nullptr, "enable_prime_tower" }; @@ -1339,13 +1342,6 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* if (layer_height > min_nozzle_diameter) return {L("Layer height cannot exceed nozzle diameter"), object, "layer_height"}; - for (auto range : object->m_model_object->layer_config_ranges) { - double range_layer_height = range.second.opt_float("layer_height"); - if (range_layer_height > object->m_slicing_params.max_layer_height || - range_layer_height < object->m_slicing_params.min_layer_height) - return { L("Layer height cannot exceed nozzle diameter"), nullptr, "layer_height" }; - } - // Validate extrusion widths. std::string err_msg; if (!validate_extrusion_width(object->config(), "line_width", layer_height, err_msg)) @@ -1626,16 +1622,21 @@ std::map getObjectExtruderMap(const Print& print) { std::map objectExtruderMap; for (const PrintObject* object : print.objects()) { // BBS - unsigned int objectFirstLayerFirstExtruder = print.config().filament_diameter.size(); - auto firstLayerRegions = object->layers().front()->regions(); - if (!firstLayerRegions.empty()) { - for (const LayerRegion* regionPtr : firstLayerRegions) { - if (regionPtr -> has_extrusions()) - objectFirstLayerFirstExtruder = std::min(objectFirstLayerFirstExtruder, - regionPtr->region().extruder(frExternalPerimeter)); + if (object->object_first_layer_wall_extruders.empty()){ + unsigned int objectFirstLayerFirstExtruder = print.config().filament_diameter.size(); + auto firstLayerRegions = object->layers().front()->regions(); + if (!firstLayerRegions.empty()) { + for (const LayerRegion* regionPtr : firstLayerRegions) { + if (regionPtr->has_extrusions()) + objectFirstLayerFirstExtruder = std::min(objectFirstLayerFirstExtruder, + regionPtr->region().extruder(frExternalPerimeter)); + } } + objectExtruderMap.insert(std::make_pair(object->id(), objectFirstLayerFirstExtruder)); + } + else { + objectExtruderMap.insert(std::make_pair(object->id(), object->object_first_layer_wall_extruders.front())); } - objectExtruderMap.insert(std::make_pair(object->id(), objectFirstLayerFirstExtruder)); } return objectExtruderMap; } @@ -1841,6 +1842,7 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) obj->infill(); obj->ironing(); obj->generate_support_material(); + obj->detect_overhangs_for_lift(); obj->estimate_curled_extrusions(); } } @@ -1980,7 +1982,15 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) } // BBS - if(!m_no_check) + bool has_adaptive_layer_height = false; + for (PrintObject* obj : m_objects) { + if (obj->model_object()->layer_height_profile.empty() == false) { + has_adaptive_layer_height = true; + break; + } + } + // TODO adaptive layer height won't work with conflict checker because m_fake_wipe_tower's path is generated using fixed layer height + if(!m_no_check && !has_adaptive_layer_height) { using Clock = std::chrono::high_resolution_clock; auto startTime = Clock::now(); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index eba85dbcfa0..440d72e05ed 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -437,6 +437,9 @@ class PrintObject : public PrintObjectBaseWithState object_first_layer_wall_extruders; + // SoftFever size_t get_id() const { return m_id; } void set_id(size_t id) { m_id = id; } @@ -528,6 +531,7 @@ class PrintObject : public PrintObjectBaseWithState firstLayerObjSliceByVolume; std::vector firstLayerObjSliceByGroups; + // BBS: per object skirt ExtrusionEntityCollection m_skirt; @@ -590,8 +594,6 @@ struct FakeWipeTower std::vector getFakeExtrusionPathsFromWipeTower() const { - float h = height; - float lh = layer_height; int d = scale_(depth); int w = scale_(width); int bd = scale_(brim_width); @@ -599,13 +601,13 @@ struct FakeWipeTower Point maxCorner = {minCorner.x() + w, minCorner.y() + d}; std::vector paths; - for (float hh = 0.f; hh < h; hh += lh) { - ExtrusionPath path(ExtrusionRole::erWipeTower, 0.0, 0.0, lh); + for (float h = 0.f; h < height; h += layer_height) { + ExtrusionPath path(ExtrusionRole::erWipeTower, 0.0, 0.0, layer_height); path.polyline = {minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner}; paths.push_back({path}); - if (hh == 0.f) { // add brim - ExtrusionPath fakeBrim(ExtrusionRole::erBrim, 0.0, 0.0, lh); + if (h == 0.f) { // add brim + ExtrusionPath fakeBrim(ExtrusionRole::erBrim, 0.0, 0.0, layer_height); Point wtbminCorner = {minCorner - Point{bd, bd}}; Point wtbmaxCorner = {maxCorner + Point{bd, bd}}; fakeBrim.polyline = {wtbminCorner, {wtbmaxCorner.x(), wtbminCorner.y()}, wtbmaxCorner, {wtbminCorner.x(), wtbmaxCorner.y()}, wtbminCorner}; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index f7c31038b2b..aecef8a238c 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -22,6 +22,7 @@ enum StringExceptionType { STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMP = 2, STRING_EXCEPT_OBJECT_COLLISION_IN_SEQ_PRINT = 3, STRING_EXCEPT_OBJECT_COLLISION_IN_LAYER_PRINT = 4, + STRING_EXCEPT_LAYER_HEIGHT_EXCEEDS_LIMIT = 5, STRING_EXCEPT_COUNT }; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index cecda027f89..bc6321771a1 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -179,6 +179,15 @@ static t_config_enum_values s_keys_map_WallInfillOrder { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(WallInfillOrder) +//BBS +static t_config_enum_values s_keys_map_WallSequence { + { "inner wall/outer wall", int(WallSequence::InnerOuter) }, + { "outer wall/inner wall", int(WallSequence::OuterInner) }, + { "inner-outer-inner wall", int(WallSequence::InnerOuterInner)} + +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(WallSequence) + //BBS static t_config_enum_values s_keys_map_PrintSequence { { "by layer", int(PrintSequence::ByLayer) }, @@ -309,6 +318,13 @@ static const t_config_enum_values s_keys_map_BedType = { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BedType) +// BBS +static const t_config_enum_values s_keys_map_FirstLayerSeq = { + { "Auto", flsAuto }, + { "Customize", flsCutomize }, +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FirstLayerSeq) + static t_config_enum_values s_keys_map_NozzleType { { "undefine", int(NozzleType::ntUndefine) }, { "hardened_steel", int(NozzleType::ntHardenedSteel) }, @@ -405,11 +421,13 @@ void PrintConfigDef::init_common_params() def = this->add("bed_custom_texture", coString); def->label = L("Bed custom texture"); def->mode = comAdvanced; + def->gui_type = ConfigOptionDef::GUIType::one_string; def->set_default_value(new ConfigOptionString("")); def = this->add("bed_custom_model", coString); def->label = L("Bed custom model"); def->mode = comAdvanced; + def->gui_type = ConfigOptionDef::GUIType::one_string; def->set_default_value(new ConfigOptionString("")); def = this->add("elefant_foot_compensation", coFloat); @@ -677,6 +695,17 @@ void PrintConfigDef::init_fff_params() def->max = 16; def->set_default_value(new ConfigOptionInts{0}); + def = this->add("first_layer_sequence_choice", coEnum); + def->category = L("Quality"); + def->label = L("First layer filament sequence"); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("Auto"); + def->enum_values.push_back("Customize"); + def->enum_labels.push_back(L("Auto")); + def->enum_labels.push_back(L("Customize")); + def->mode = comSimple; + def->set_default_value(new ConfigOptionEnum(flsAuto)); + def = this->add("before_layer_change_gcode", coString); def->label = L("Before layer change G-code"); def->tooltip = L("This G-code is inserted at every layer change before lifting z"); @@ -1191,6 +1220,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionString("M104 S0 ; turn off temperature\nG28 X0 ; home X axis\nM84 ; disable motors\n")); + def = this->add("printing_by_object_gcode", coString); + def->label = L("Between Object Gcode"); + def->tooltip = L("Insert Gcode between objects. This parameter will only come into effect when you print your models object by object"); + def->multiline = true; + def->full_width = true; + def->height = 12; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionString("")); + def = this->add("filament_end_gcode", coStrings); def->label = L("End G-code"); def->tooltip = L("End G-code when finish the printing of this filament"); @@ -1292,23 +1330,26 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0)); - def = this->add("wall_infill_order", coEnum); - def->label = L("Order of inner wall/outer wall/infil"); + def = this->add("wall_sequence", coEnum); + def->label = L("Order of walls"); + def->category = L("Quality"); + def->tooltip = L("Print sequence of inner wall and outer wall. "); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("inner wall/outer wall"); + def->enum_values.push_back("outer wall/inner wall"); + def->enum_values.push_back("inner-outer-inner wall"); + def->enum_labels.push_back(L("inner/outer")); + def->enum_labels.push_back(L("outer/inner")); + def->enum_labels.push_back(L("inner wall/outer wall/inner wall")); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionEnum(WallSequence::InnerOuter)); + + def = this->add("is_infill_first",coBool); + def->label = L("Print infill first"); + def->tooltip = L("Order of wall/infill. false means print wall first. "); def->category = L("Quality"); - def->tooltip = L("Print sequence of inner wall, outer wall and infill. "); - def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); - def->enum_values.push_back("inner wall/outer wall/infill"); - def->enum_values.push_back("outer wall/inner wall/infill"); - def->enum_values.push_back("infill/inner wall/outer wall"); - def->enum_values.push_back("infill/outer wall/inner wall"); - def->enum_values.push_back("inner-outer-inner wall/infill"); - def->enum_labels.push_back(L("inner/outer/infill")); - def->enum_labels.push_back(L("outer/inner/infill")); - def->enum_labels.push_back(L("infill/inner/outer")); - def->enum_labels.push_back(L("infill/outer/inner")); - def->enum_labels.push_back(L("inner-outer-inner/infill")); - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionEnum(WallInfillOrder::InnerOuterInfill)); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool{false}); def = this->add("extruder", coInt); def->gui_type = ConfigOptionDef::GUIType::i_enum_open; @@ -1906,7 +1947,7 @@ def = this->add("filament_loading_speed", coFloats); def = this->add("accel_to_decel_factor", coPercent); def->label = L("accel_to_decel"); def->tooltip = L("Klipper's max_accel_to_decel will be adjusted to this %% of acceleration"); - def->sidetext = L("%%"); + def->sidetext = L("%"); def->min = 1; def->max = 100; def->mode = comAdvanced; @@ -2390,6 +2431,27 @@ def = this->add("filament_loading_speed", coFloats); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); + def = this->add("mmu_segmented_region_max_width", coFloat); + def->label = L("Maximum width of a segmented region"); + def->tooltip = L("Maximum width of a segmented region. Zero disables this feature."); + def->sidetext = L("mm"); + def->min = 0; + def->category = L("Advanced"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.)); + + def = this->add("mmu_segmented_region_interlocking_depth", coFloat); + def->label = L("Interlocking depth of a segmented region"); + //def->tooltip = L("Interlocking depth of a segmented region. It will be ignored if " + // "\"mmu_segmented_region_max_width\" is zero or if \"mmu_segmented_region_interlocking_depth\"" + // "is bigger then \"mmu_segmented_region_max_width\". Zero disables this feature."); + def->tooltip = L("Interlocking depth of a segmented region. Zero disables this feature."); + def->sidetext = L("mm"); //(zero to disable) + def->min = 0; + def->category = L("Advanced"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.)); + def = this->add("ironing_type", coEnum); def->label = L("Ironing Type"); def->category = L("Quality"); @@ -3072,8 +3134,27 @@ def = this->add("filament_loading_speed", coFloats); "Using spiral line to lift z can prevent stringing"); def->sidetext = L("mm"); def->mode = comSimple; + def->min = 0; + def->max = 5; def->set_default_value(new ConfigOptionFloats { 0.4 }); + def = this->add("retract_lift_above", coFloats); + def->label = L("Z hop lower boundary"); + def->tooltip = L("Z hop will only come into effect when Z is above this value and is below the parameter: \"Z hop upper boundary\""); + def->sidetext = L("mm"); + def->mode = comAdvanced; + def->min = 0; + def->set_default_value(new ConfigOptionFloats{0.}); + + def = this->add("retract_lift_below", coFloats); + def->label = L("Z hop upper boundary"); + def->tooltip = L("If this value is positive, Z hop will only come into effect when Z is above the parameter: \"Z hop lower boundary\" and is below this value"); + def->sidetext = L("mm"); + def->mode = comAdvanced; + def->min = 0; + def->set_default_value(new ConfigOptionFloats{0.}); + + def = this->add("z_hop_types", coEnums); def->label = L("Z hop type"); def->tooltip = L("Z hop type"); @@ -3223,7 +3304,7 @@ def = this->add("filament_loading_speed", coFloats); def->tooltip = L("Distance from skirt to brim or object"); def->sidetext = L("mm"); def->min = 0; - def->max = 10; + def->max = 60; def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(2)); @@ -3570,7 +3651,14 @@ def = this->add("filament_loading_speed", coFloats); def->tooltip = L("Filament to print support base and raft. \"Default\" means no specific filament for support and current filament is used"); def->min = 0; def->mode = comSimple; - def->set_default_value(new ConfigOptionInt(1)); + def->set_default_value(new ConfigOptionInt(0)); + + def = this->add("support_interface_not_for_body",coBool); + def->label = L("Reduce interface filament for base"); + def->category = L("Support"); + def->tooltip = L("Avoid using support interface filament to print support base"); + def->mode = comSimple; + def->set_default_value(new ConfigOptionBool(true)); def = this->add("support_line_width", coFloatOrPercent); def->label = L("Support"); @@ -3599,7 +3687,7 @@ def = this->add("filament_loading_speed", coFloats); def->min = 0; // BBS def->mode = comSimple; - def->set_default_value(new ConfigOptionInt(1)); + def->set_default_value(new ConfigOptionInt(0)); auto support_interface_top_layers = def = this->add("support_interface_top_layers", coInt); def->gui_type = ConfigOptionDef::GUIType::i_enum_open; @@ -3623,14 +3711,12 @@ def = this->add("filament_loading_speed", coFloats); def->gui_type = ConfigOptionDef::GUIType::i_enum_open; def->label = L("Bottom interface layers"); def->category = L("Support"); - //def->tooltip = L("Number of bottom interface layers. " - // "-1 means same with use top interface layers"); + def->tooltip = L("Number of bottom interface layers"); def->sidetext = L("layers"); def->min = -1; def->enum_values.push_back("-1"); append(def->enum_values, support_interface_top_layers->enum_values); - //TRN To be shown in Print Settings "Bottom interface layers". Have to be as short as possible - def->enum_labels.push_back("-1"); + def->enum_labels.push_back(L("Same as top")); append(def->enum_labels, support_interface_top_layers->enum_labels); def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(0)); @@ -3681,7 +3767,7 @@ def = this->add("filament_loading_speed", coFloats); def->enum_labels.push_back(L("Lightning")); def->enum_labels.push_back(L("Hollow")); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionEnum(smpRectilinear)); + def->set_default_value(new ConfigOptionEnum(smpDefault)); def = this->add("support_interface_pattern", coEnum); def->label = L("Interface pattern"); @@ -3701,7 +3787,7 @@ def = this->add("filament_loading_speed", coFloats); def->enum_labels.push_back(L("Rectilinear Interlaced")); def->enum_labels.push_back(L("Grid")); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionEnum(smipRectilinear)); + def->set_default_value(new ConfigOptionEnum(smipAuto)); def = this->add("support_base_pattern_spacing", coFloat); def->label = L("Base pattern spacing"); @@ -3919,12 +4005,12 @@ def = this->add("filament_loading_speed", coFloats); def->set_default_value(new ConfigOptionFloat(3.)); def = this->add("tree_support_wall_count", coInt); - def->label = L("Tree support wall loops"); + def->label = L("Support wall loops"); def->category = L("Support"); - def->tooltip = L("This setting specify the count of walls around tree support"); + def->tooltip = L("This setting specify the count of walls around support"); def->min = 0; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionInt(1)); + def->set_default_value(new ConfigOptionInt(0)); def = this->add("tree_support_with_infill", coBool); def->label = L("Tree support with infill"); @@ -4126,7 +4212,7 @@ def = this->add("filament_loading_speed", coFloats); //def->sidetext = L("mm"); def->mode = comDevelop; // BBS: change data type to floats to add partplate logic - def->set_default_value(new ConfigOptionFloats{ 165.-10. }); + def->set_default_value(new ConfigOptionFloats{ 15. }); def = this->add("wipe_tower_y", coFloats); //def->label = L("Position Y"); @@ -5207,6 +5293,19 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va } } else if (opt_key == "overhang_fan_threshold" && value == "5%") { value = "10%"; + } else if( opt_key == "wall_infill_order" ) { + if (value == "inner wall/outer wall/infill" || value == "infill/inner wall/outer wall") { + opt_key = "wall_sequence"; + value = "inner wall/outer wall"; + } else if (value == "outer wall/inner wall/infill" || value == "infill/outer wall/inner wall") { + opt_key = "wall_sequence"; + value = "outer wall/inner wall"; + } else if (value == "inner-outer-inner wall/infill") { + opt_key = "wall_sequence"; + value = "inner-outer-inner wall"; + } else { + opt_key = "wall_sequence"; + } } else if(opt_key == "single_extruder_multi_material") { value = "1"; } @@ -5229,6 +5328,9 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va else if (opt_key == "initial_layer_flow_ratio") { opt_key = "bottom_solid_infill_flow_ratio"; } + else if(opt_key == "ironing_direction") { + opt_key = "ironing_angle"; + } // Ignore the following obsolete configuration keys: static std::set ignore = { @@ -5245,7 +5347,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va "can_switch_nozzle_type", "can_add_auxiliary_fan", "extra_flush_volume", "spaghetti_detector", "adaptive_layer_height", "z_hop_type", "z_lift_type", "bed_temperature_difference", "extruder_type", - "internal_bridge_support_thickness","extruder_clearance_max_radius" + "internal_bridge_support_thickness","extruder_clearance_max_radius", "top_area_threshold" }; if (ignore.find(opt_key) != ignore.end()) { @@ -5888,20 +5990,20 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->set_default_value(new ConfigOptionBool(false));*/ def = this->add("export_3mf", coString); - def->label = L("Export 3MF"); - def->tooltip = L("Export project as 3MF."); + def->label = "Export 3MF"; + def->tooltip = "Export project as 3MF."; def->cli_params = "filename.3mf"; def->set_default_value(new ConfigOptionString("output.3mf")); def = this->add("export_slicedata", coString); - def->label = L("Export slicing data"); - def->tooltip = L("Export slicing data to a folder."); + def->label = "Export slicing data"; + def->tooltip = "Export slicing data to a folder."; def->cli_params = "slicing_data_directory"; def->set_default_value(new ConfigOptionString("cached_data")); def = this->add("load_slicedata", coStrings); - def->label = L("Load slicing data"); - def->tooltip = L("Load cached slicing data from directory"); + def->label = "Load slicing data"; + def->tooltip = "Load cached slicing data from directory"; def->cli_params = "slicing_data_directory"; def->set_default_value(new ConfigOptionString("cached_data")); @@ -5911,8 +6013,8 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->set_default_value(new ConfigOptionBool(false));*/ def = this->add("export_stl", coBool); - def->label = L("Export STL"); - def->tooltip = L("Export the objects as multiple STL."); + def->label = "Export STL"; + def->tooltip = "Export the objects as multiple STL."; def->set_default_value(new ConfigOptionBool(false)); /*def = this->add("export_gcode", coBool); @@ -5929,27 +6031,33 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->set_default_value(new ConfigOptionBool(false));*/ def = this->add("slice", coInt); - def->label = L("Slice"); - def->tooltip = L("Slice the plates: 0-all plates, i-plate i, others-invalid"); + def->label = "Slice"; + def->tooltip = "Slice the plates: 0-all plates, i-plate i, others-invalid"; def->cli = "slice"; def->cli_params = "option"; def->set_default_value(new ConfigOptionInt(0)); def = this->add("help", coBool); - def->label = L("Help"); - def->tooltip = L("Show command help."); + def->label = "Help"; + def->tooltip = "Show command help."; def->cli = "help|h"; def->set_default_value(new ConfigOptionBool(false)); def = this->add("uptodate", coBool); - def->label = L("UpToDate"); - def->tooltip = L("Update the configs values of 3mf to latest."); + def->label = "UpToDate"; + def->tooltip = "Update the configs values of 3mf to latest."; def->cli = "uptodate"; def->set_default_value(new ConfigOptionBool(false)); def = this->add("load_defaultfila", coBool); - def->label = L("Load default filaments"); - def->tooltip = L("Load first filament as default for those not loaded"); + def->label = "Load default filaments"; + def->tooltip = "Load first filament as default for those not loaded"; + def->cli_params = "option"; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("min_save", coBool); + def->label = "Minimum save"; + def->tooltip = "export 3mf with minimum size."; def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(false)); @@ -5960,15 +6068,15 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->set_default_value(new ConfigOptionBool(false)); def = this->add("mtcpp", coInt); - def->label = L("mtcpp"); - def->tooltip = L("max triangle count per plate for slicing."); + def->label = "mtcpp"; + def->tooltip = "max triangle count per plate for slicing."; def->cli = "mtcpp"; def->cli_params = "count"; def->set_default_value(new ConfigOptionInt(1000000)); def = this->add("mstpp", coInt); - def->label = L("mstpp"); - def->tooltip = L("max slicing time per plate in seconds."); + def->label = "mstpp"; + def->tooltip = "max slicing time per plate in seconds."; def->cli = "mstpp"; def->cli_params = "time"; def->set_default_value(new ConfigOptionInt(300)); @@ -5977,12 +6085,11 @@ CLIActionsConfigDef::CLIActionsConfigDef() def = this->add("no_check", coBool); def->label = L("No check"); def->tooltip = L("Do not run any validity checks, such as gcode path conflicts check."); - def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(false)); def = this->add("normative_check", coBool); - def->label = L("Normative check"); - def->tooltip = L("Check the normative items."); + def->label = "Normative check"; + def->tooltip = "Check the normative items."; def->cli_params = "option"; def->set_default_value(new ConfigOptionBool(true)); @@ -5997,19 +6104,19 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->set_default_value(new ConfigOptionBool(false));*/ def = this->add("info", coBool); - def->label = L("Output Model Info"); - def->tooltip = L("Output the model's information."); + def->label = "Output Model Info"; + def->tooltip = "Output the model's information."; def->set_default_value(new ConfigOptionBool(false)); def = this->add("export_settings", coString); - def->label = L("Export Settings"); - def->tooltip = L("Export settings to a file."); + def->label = "Export Settings"; + def->tooltip = "Export settings to a file."; def->cli_params = "settings.json"; def->set_default_value(new ConfigOptionString("output.json")); def = this->add("pipe", coString); - def->label = L("Send progress to pipe"); - def->tooltip = L("Send progress to pipe."); + def->label = "Send progress to pipe"; + def->tooltip = "Send progress to pipe."; def->cli_params = "pipename"; def->set_default_value(new ConfigOptionString("")); } @@ -6053,15 +6160,15 @@ CLITransformConfigDef::CLITransformConfigDef() def->set_default_value(new ConfigOptionPoint(Vec2d(100,100)));*/ def = this->add("arrange", coInt); - def->label = L("Arrange Options"); - def->tooltip = L("Arrange options: 0-disable, 1-enable, others-auto"); + def->label = "Arrange Options"; + def->tooltip = "Arrange options: 0-disable, 1-enable, others-auto"; def->cli_params = "option"; //def->cli = "arrange|a"; def->set_default_value(new ConfigOptionInt(0)); def = this->add("repetitions", coInt); - def->label = L("Repetions count"); - def->tooltip = L("Repetions count of the whole model"); + def->label = "Repetions count"; + def->tooltip = "Repetions count of the whole model"; def->cli_params = "count"; def->set_default_value(new ConfigOptionInt(1)); @@ -6078,16 +6185,17 @@ CLITransformConfigDef::CLITransformConfigDef() /*def = this->add("duplicate_grid", coPoint); def->label = L("Duplicate by grid"); - def->tooltip = L("Multiply copies by creating a grid."); + def->tooltip = L("Multiply copies by creating a grid.");*/ def = this->add("assemble", coBool); - def->label = L("Assemble"); - def->tooltip = L("Arrange the supplied models in a plate and merge them in a single model in order to perform actions once."); - def->cli = "merge|m";*/ + def->label = "Assemble"; + def->tooltip = "Arrange the supplied models in a plate and merge them in a single model in order to perform actions once."; + //def->cli = "merge|m"; + def->set_default_value(new ConfigOptionBool(false)); def = this->add("convert_unit", coBool); - def->label = L("Convert Unit"); - def->tooltip = L("Convert the units of model"); + def->label = "Convert Unit"; + def->tooltip = "Convert the units of model"; def->set_default_value(new ConfigOptionBool(false)); def = this->add("orient", coInt); @@ -6107,8 +6215,8 @@ CLITransformConfigDef::CLITransformConfigDef() def->set_default_value(new ConfigOptionFloat(0)); def = this->add("rotate_x", coFloat); - def->label = L("Rotate around X"); - def->tooltip = L("Rotation angle around the X axis in degrees."); + def->label = "Rotate around X"; + def->tooltip = "Rotation angle around the X axis in degrees."; def->set_default_value(new ConfigOptionFloat(0)); def = this->add("rotate_y", coFloat); @@ -6117,8 +6225,8 @@ CLITransformConfigDef::CLITransformConfigDef() def->set_default_value(new ConfigOptionFloat(0)); def = this->add("scale", coFloat); - def->label = L("Scale"); - def->tooltip = L("Scale the model by a float factor"); + def->label = "Scale"; + def->tooltip = "Scale the model by a float factor"; def->cli_params = "factor"; def->set_default_value(new ConfigOptionFloat(1.f)); @@ -6159,29 +6267,47 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->tooltip = L("Load configuration from the specified file. It can be used more than once to load options from multiple files.");*/ def = this->add("load_settings", coStrings); - def->label = L("Load General Settings"); - def->tooltip = L("Load process/machine settings from the specified file"); + def->label = "Load General Settings"; + def->tooltip = "Load process/machine settings from the specified file"; def->cli_params = "\"setting1.json;setting2.json\""; def->set_default_value(new ConfigOptionStrings()); def = this->add("load_filaments", coStrings); - def->label = L("Load Filament Settings"); - def->tooltip = L("Load filament settings from the specified file list"); + def->label = "Load Filament Settings"; + def->tooltip = "Load filament settings from the specified file list"; def->cli_params = "\"filament1.json;filament2.json;...\""; def->set_default_value(new ConfigOptionStrings()); def = this->add("skip_objects", coInts); - def->label = L("Skip Objects"); - def->tooltip = L("Skip some objects in this print"); + def->label = "Skip Objects"; + def->tooltip = "Skip some objects in this print"; def->cli_params = "\"3,5,10,77\""; def->set_default_value(new ConfigOptionInts()); + def = this->add("clone_objects", coInts); + def->label = "Clone Objects"; + def->tooltip = "Clone objects in the load list"; + def->cli_params = "\"1,3,1,10\""; + def->set_default_value(new ConfigOptionInts()); + def = this->add("uptodate_settings", coStrings); - def->label = L("load uptodate process/machine settings when using uptodate"); - def->tooltip = L("load uptodate process/machine settings from the specified file when using uptodate"); + def->label = "load uptodate process/machine settings when using uptodate"; + def->tooltip = "load uptodate process/machine settings from the specified file when using uptodate"; def->cli_params = "\"setting1.json;setting2.json\""; def->set_default_value(new ConfigOptionStrings()); + def = this->add("uptodate_filaments", coStrings); + def->label = "load uptodate filament settings when using uptodate"; + def->tooltip = "load uptodate filament settings from the specified file when using uptodate"; + def->cli_params = "\"filament1.json;filament2.json;...\""; + def->set_default_value(new ConfigOptionStrings()); + + def = this->add("load_assemble_list", coString); + def->label = "Load assemble list"; + def->tooltip = "Load assemble object list from config file"; + def->cli_params = "assemble_list.json"; + def->set_default_value(new ConfigOptionString()); + /*def = this->add("output", coString); def->label = L("Output File"); def->tooltip = L("The file where the output will be written (if not specified, it will be based on the input file)."); @@ -6205,18 +6331,23 @@ CLIMiscConfigDef::CLIMiscConfigDef() def = this->add("outputdir", coString); - def->label = L("Output directory"); - def->tooltip = L("Output directory for the exported files."); + def->label = "Output directory"; + def->tooltip = "Output directory for the exported files."; def->cli_params = "dir"; def->set_default_value(new ConfigOptionString()); def = this->add("debug", coInt); - def->label = L("Debug level"); - def->tooltip = L("Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n"); + def->label = "Debug level"; + def->tooltip = "Sets debug logging level. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n"; def->min = 0; def->cli_params = "level"; def->set_default_value(new ConfigOptionInt(1)); + def = this->add("enable_timelapse", coBool); + def->label = "Enable timeplapse for print"; + def->tooltip = "If enabled, this slicing will be considered using timelapse"; + def->set_default_value(new ConfigOptionBool(false)); + #if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(SLIC3R_GUI) /*def = this->add("sw_renderer", coBool); def->label = L("Render with a software renderer"); @@ -6229,6 +6360,33 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->tooltip = L("Load custom gcode from json"); def->cli_params = "custom_gcode_toolchange.json"; def->set_default_value(new ConfigOptionString()); + + def = this->add("load_filament_ids", coInts); + def->label = "Load filament ids"; + def->tooltip = "Load filament ids for each object"; + def->cli_params = "\"1,2,3,1\""; + def->set_default_value(new ConfigOptionInts()); + + def = this->add("allow_multicolor_oneplate", coBool); + def->label = "Allow multiple color on one plate"; + def->tooltip = "If enabled, the arrange will allow multiple color on one plate"; + def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("allow_rotations", coBool); + def->label = "Allow rotatations when arrange"; + def->tooltip = "If enabled, the arrange will allow rotations when place object"; + def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("avoid_extrusion_cali_region", coBool); + def->label = "Avoid extrusion calibrate region when doing arrange"; + def->tooltip = "If enabled, the arrange will avoid extrusion calibrate region when place object"; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("skip_modified_gcodes", coBool); + def->label = "Skip modified gcodes in 3mf"; + def->tooltip = "Skip the modified gcodes in 3mf from Printer or filament Presets"; + def->cli_params = "option"; + def->set_default_value(new ConfigOptionBool(false)); } const CLIActionsConfigDef cli_actions_config_def; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 7cdd605142d..b9f877ac504 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -90,6 +90,14 @@ enum class WallInfillOrder { InnerOuterInnerInfill, Count, }; + +// BBS +enum class WallSequence { + InnerOuter, + OuterInner, + InnerOuterInner, + Count, +}; //BBS enum class PrintSequence { ByLayer, @@ -216,6 +224,12 @@ enum BedType { btCount }; +// BBS +enum FirstLayerSeq { + flsAuto, + flsCutomize +}; + // BBS enum NozzleType { ntUndefine = 0, @@ -348,7 +362,6 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeThumbnailsFormat) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrintHostType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(AuthorizationType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PerimeterGeneratorType) - #undef CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS // Defines each and every confiuration option of Slic3r, including the properties of the GUI dialogs. @@ -687,6 +700,8 @@ PRINT_CONFIG_CLASS_DEFINE( // Force the generation of solid shells between adjacent materials/volumes. ((ConfigOptionBool, interface_shells)) ((ConfigOptionFloat, layer_height)) + ((ConfigOptionFloat, mmu_segmented_region_max_width)) + ((ConfigOptionFloat, mmu_segmented_region_interlocking_depth)) ((ConfigOptionFloat, raft_contact_distance)) ((ConfigOptionFloat, raft_expansion)) ((ConfigOptionPercent, raft_first_layer_density)) @@ -709,6 +724,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, enforce_support_layers)) ((ConfigOptionInt, support_filament)) ((ConfigOptionFloatOrPercent, support_line_width)) + ((ConfigOptionBool, support_interface_not_for_body)) ((ConfigOptionBool, support_interface_loop_pattern)) ((ConfigOptionInt, support_interface_filament)) ((ConfigOptionInt, support_interface_top_layers)) @@ -735,6 +751,7 @@ PRINT_CONFIG_CLASS_DEFINE( // BBS ((ConfigOptionBool, flush_into_infill)) ((ConfigOptionBool, flush_into_support)) + ((ConfigOptionEnum, wall_sequence)) // BBS ((ConfigOptionFloat, tree_support_branch_distance)) ((ConfigOptionFloat, tree_support_tip_diameter)) @@ -824,6 +841,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionEnum, ironing_pattern)) ((ConfigOptionPercent, ironing_flow)) ((ConfigOptionFloat, ironing_spacing)) + ((ConfigOptionFloat, ironing_direction)) ((ConfigOptionFloat, ironing_speed)) ((ConfigOptionFloat, ironing_angle)) // Detect bridging perimeters @@ -917,7 +935,8 @@ PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE( GCodeConfig, - ((ConfigOptionString, before_layer_change_gcode)) + ((ConfigOptionString, before_layer_change_gcode)) + ((ConfigOptionString, printing_by_object_gcode)) ((ConfigOptionFloats, deretraction_speed)) //BBS ((ConfigOptionBool, enable_arc_fitting)) @@ -941,6 +960,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInts, required_nozzle_HRC)) // BBS ((ConfigOptionBool, scan_first_layer)) + ((ConfigOptionPoints, thumbnail_size)) // ((ConfigOptionBool, spaghetti_detector)) ((ConfigOptionBool, gcode_add_line_number)) ((ConfigOptionBool, bbl_bed_temperature_gcode)) @@ -1037,6 +1057,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( //BBS: add bed_exclude_area ((ConfigOptionPoints, bed_exclude_area)) // BBS + ((ConfigOptionString, bed_custom_texture)) + ((ConfigOptionString, bed_custom_model)) ((ConfigOptionEnum, curr_bed_type)) ((ConfigOptionInts, cool_plate_temp)) ((ConfigOptionInts, eng_plate_temp)) @@ -1141,12 +1163,13 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionInt, slow_down_layers)) ((ConfigOptionInts, support_material_interface_fan_speed)) // Orca: notes for profiles from PrusaSlicer - ((ConfigOptionStrings, filament_notes)) - ((ConfigOptionString, notes)) - ((ConfigOptionString, printer_notes)) + ((ConfigOptionStrings, filament_notes)) + ((ConfigOptionString, notes)) + ((ConfigOptionString, printer_notes)) ((ConfigOptionBools, activate_chamber_temp_control)) ((ConfigOptionInts , chamber_temperature)) + ((ConfigOptionBool, is_infill_first)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 092427fd04b..a7ebfdc7f96 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -68,7 +68,6 @@ using namespace std::literals; #endif // #define SLIC3R_DEBUG - // Make assert active if SLIC3R_DEBUG #ifdef SLIC3R_DEBUG #undef NDEBUG @@ -912,7 +911,8 @@ bool PrintObject::invalidate_state_by_config_options( } } else if ( opt_key == "wall_loops" - || opt_key == "only_one_wall_top" + || opt_key == "top_one_wall_type" + || opt_key == "min_width_top_surface" || opt_key == "only_one_wall_first_layer" || opt_key == "extra_perimeters_on_overhangs" || opt_key == "initial_layer_line_width" @@ -945,6 +945,8 @@ bool PrintObject::invalidate_state_by_config_options( steps.emplace_back(posPerimeters); } else if ( opt_key == "layer_height" + || opt_key == "mmu_segmented_region_max_width" + || opt_key == "mmu_segmented_region_interlocking_depth" || opt_key == "raft_layers" || opt_key == "raft_contact_distance" || opt_key == "slice_closing_radius" @@ -995,6 +997,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "support_interface_pattern" || opt_key == "support_interface_loop_pattern" || opt_key == "support_interface_filament" + || opt_key == "support_interface_not_for_body" || opt_key == "support_interface_spacing" || opt_key == "support_bottom_interface_spacing" //BBS || opt_key == "support_base_pattern" diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index ba6fb7032e2..4de75edc42c 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -398,14 +398,14 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po) auto bb = bounding_box(m); Eigen::AlignedBox ebb{bb.min.cast(), bb.max.cast()}; - - AABBTreeIndirect::traverse( - tree, - AABBTreeIndirect::intersecting(ebb), - [&part_to_drill, &hollowed_mesh](size_t faceid) - { - part_to_drill.indices.emplace_back(hollowed_mesh.its.indices[faceid]); - }); + //BBS + //AABBTreeIndirect::traverse( + // tree, + // AABBTreeIndirect::intersecting(ebb), + // [&part_to_drill, &hollowed_mesh](size_t faceid) + //{ + // part_to_drill.indices.emplace_back(hollowed_mesh.its.indices[faceid]); + //}); auto cgal_meshpart = MeshBoolean::cgal::triangle_mesh_to_cgal( remove_unconnected_vertices(part_to_drill)); diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 989610c7ac0..72e231c3149 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -430,16 +430,16 @@ std::vector smooth_height_profile(const std::vector& profile, co // return false; //}; - //int count = 0; - //std::vector ret = profile; - //bool has_steep_change = has_steep_height_change(ret, LAYER_HEIGHT_CHANGE_STEP); - //while (has_steep_change && count < 6) { - // ret = gauss_blur(ret, smoothing_params); - // has_steep_change = has_steep_height_change(ret, LAYER_HEIGHT_CHANGE_STEP); - // count++; - //} - //return ret; - return gauss_blur(profile, smoothing_params); + int count = 0; + std::vector ret = profile; + // bool has_steep_change = has_steep_height_change(ret, LAYER_HEIGHT_CHANGE_STEP); + while (/*has_steep_change &&*/ count < 6) { + ret = gauss_blur(ret, smoothing_params); + //has_steep_change = has_steep_height_change(ret, LAYER_HEIGHT_CHANGE_STEP); + count++; + } + return ret; + // return gauss_blur(profile, smoothing_params); } void adjust_layer_height_profile( diff --git a/src/libslic3r/Support/TreeSupport3D.cpp b/src/libslic3r/Support/TreeSupport3D.cpp new file mode 100644 index 00000000000..434036e5000 --- /dev/null +++ b/src/libslic3r/Support/TreeSupport3D.cpp @@ -0,0 +1,4798 @@ +// Tree supports by Thomas Rahm, losely based on Tree Supports by CuraEngine. +// Original source of Thomas Rahm's tree supports: +// https://github.com/ThomasRahm/CuraEngine +// +// Original CuraEngine copyright: +// Copyright (c) 2021 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "TreeSupport3D.hpp" +#include "AABBTreeIndirect.hpp" +#include "AABBTreeLines.hpp" +#include "BuildVolume.hpp" +#include "ClipperUtils.hpp" +#include "EdgeGrid.hpp" +#include "Fill/Fill.hpp" +#include "Layer.hpp" +#include "Print.hpp" +#include "MultiPoint.hpp" +#include "Polygon.hpp" +#include "Polyline.hpp" +#include "MutablePolygon.hpp" +#include "SupportMaterial.hpp" +#include "TriangleMeshSlicer.hpp" +#include "TreeSupport.hpp" +#include "I18N.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TBB_PREVIEW_GLOBAL_CONTROL 1 +#include +#include +#include + +#if defined(TREE_SUPPORT_SHOW_ERRORS) && defined(_WIN32) + #define TREE_SUPPORT_SHOW_ERRORS_WIN32 +#endif + +#define TREE_SUPPORT_ORGANIC_NUDGE_NEW 1 + +#ifndef TREE_SUPPORT_ORGANIC_NUDGE_NEW + // Old version using OpenVDB, works but it is extremely slow for complex meshes. + #include "OpenVDBUtilsLegacy.hpp" + #include +#endif // TREE_SUPPORT_ORGANIC_NUDGE_NEW + +#ifndef _L +#define _L(s) Slic3r::I18N::translate(s) +#endif + + //#define TREESUPPORT_DEBUG_SVG + +namespace Slic3r +{ + +namespace TreeSupport3D +{ + +enum class LineStatus +{ + INVALID, + TO_MODEL, + TO_MODEL_GRACIOUS, + TO_MODEL_GRACIOUS_SAFE, + TO_BP, + TO_BP_SAFE +}; + +using LineInformation = std::vector>; +using LineInformations = std::vector; +using namespace std::literals; + +static inline void validate_range(const Point &pt) +{ + static constexpr const int32_t hi = 65536 * 16384; + if (pt.x() > hi || pt.y() > hi || -pt.x() > hi || -pt.y() > hi) + throw ClipperLib::clipperException("Coordinate outside allowed range"); +} + +static inline void validate_range(const Points &points) +{ + for (const Point &p : points) + validate_range(p); +} + +static inline void validate_range(const MultiPoint &mp) +{ + validate_range(mp.points); +} + +static inline void validate_range(const Polygons &polygons) +{ + for (const Polygon &p : polygons) + validate_range(p); +} + +static inline void validate_range(const Polylines &polylines) +{ + for (const Polyline &p : polylines) + validate_range(p); +} + +static inline void validate_range(const LineInformation &lines) +{ + for (const auto& p : lines) + validate_range(p.first); +} + +static inline void validate_range(const LineInformations &lines) +{ + for (const LineInformation &l : lines) + validate_range(l); +} + +static inline void check_self_intersections(const Polygons &polygons, const std::string_view message) +{ +#ifdef TREE_SUPPORT_SHOW_ERRORS_WIN32 + if (!intersecting_edges(polygons).empty()) + ::MessageBoxA(nullptr, (std::string("TreeSupport infill self intersections: ") + std::string(message)).c_str(), "Bug detected!", MB_OK | MB_SYSTEMMODAL | MB_SETFOREGROUND | MB_ICONWARNING); +#endif // TREE_SUPPORT_SHOW_ERRORS_WIN32 +} +static inline void check_self_intersections(const ExPolygon &expoly, const std::string_view message) +{ +#ifdef TREE_SUPPORT_SHOW_ERRORS_WIN32 + check_self_intersections(to_polygons(expoly), message); +#endif // TREE_SUPPORT_SHOW_ERRORS_WIN32 +} + +static constexpr const auto tiny_area_threshold = sqr(scaled(0.001)); + +static std::vector>> group_meshes(const Print &print, const std::vector &print_object_ids) +{ + std::vector>> grouped_meshes; + + //FIXME this is ugly, it does not belong here. + for (size_t object_id : print_object_ids) { + const PrintObject &print_object = *print.get_object(object_id); + const PrintObjectConfig &object_config = print_object.config(); + if (object_config.support_top_z_distance < EPSILON) + // || min_feature_size < scaled(0.1) that is the minimum line width + TreeSupportSettings::soluble = true; + } + + size_t largest_printed_mesh_idx = 0; + + // Group all meshes that can be processed together. NOTE this is different from mesh-groups! Only one setting object is needed per group, + // as different settings in the same group may only occur in the tip, which uses the original settings objects from the meshes. + for (size_t object_id : print_object_ids) { + const PrintObject &print_object = *print.get_object(object_id); +#ifndef NDEBUG + const PrintObjectConfig &object_config = print_object.config(); +#endif // NDEBUG + // Support must be enabled and set to Tree style. + //assert(object_config.support_material); + //assert(object_config.support_material_style == smsTree || object_config.support_material_style == smsOrganic); + + bool found_existing_group = false; + TreeSupportSettings next_settings{ TreeSupportMeshGroupSettings{ print_object }, print_object.slicing_parameters() }; + //FIXME for now only a single object per group is enabled. +#if 0 + for (size_t idx = 0; idx < grouped_meshes.size(); ++ idx) + if (next_settings == grouped_meshes[idx].first) { + found_existing_group = true; + grouped_meshes[idx].second.emplace_back(object_id); + // handle some settings that are only used for performance reasons. This ensures that a horrible set setting intended to improve performance can not reduce it drastically. + grouped_meshes[idx].first.performance_interface_skip_layers = std::min(grouped_meshes[idx].first.performance_interface_skip_layers, next_settings.performance_interface_skip_layers); + } +#endif + if (! found_existing_group) + grouped_meshes.emplace_back(next_settings, std::vector{ object_id }); + + // no need to do this per mesh group as adaptive layers and raft setting are not setable per mesh. + if (print.get_object(largest_printed_mesh_idx)->layers().back()->print_z < print_object.layers().back()->print_z) + largest_printed_mesh_idx = object_id; + } + +#if 0 + { + std::vector known_z(storage.meshes[largest_printed_mesh_idx].layers.size()); + for (size_t z = 0; z < storage.meshes[largest_printed_mesh_idx].layers.size(); z++) + known_z[z] = storage.meshes[largest_printed_mesh_idx].layers[z].printZ; + for (size_t idx = 0; idx < grouped_meshes.size(); ++ idx) + grouped_meshes[idx].first.setActualZ(known_z); + } +#endif + + return grouped_meshes; +} + +#if 0 +// todo remove as only for debugging relevant +[[nodiscard]] static std::string getPolygonAsString(const Polygons& poly) +{ + std::string ret; + for (auto path : poly) + for (Point p : path) { + if (ret != "") + ret += ","; + ret += "(" + std::to_string(p.x()) + "," + std::to_string(p.y()) + ")"; + } + return ret; +} +#endif + +[[nodiscard]] static const std::vector generate_overhangs(const TreeSupportSettings &settings, const PrintObject &print_object, std::function throw_on_cancel) +{ + const size_t num_raft_layers = settings.raft_layers.size(); + const size_t num_object_layers = print_object.layer_count(); + const size_t num_layers = num_object_layers + num_raft_layers; + std::vector out(num_layers, Polygons{}); + + const PrintConfig &print_config = print_object.print()->config(); + const PrintObjectConfig &config = print_object.config(); + const bool support_auto = is_auto(config.support_type.value); + const int support_enforce_layers = config.enforce_support_layers.value; + std::vector enforcers_layers{ print_object.slice_support_enforcers() }; + std::vector blockers_layers{ print_object.slice_support_blockers() }; + print_object.project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers_layers); + print_object.project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers_layers); + const int support_threshold = config.support_threshold_angle.value; + const bool support_threshold_auto = support_threshold == 0; + // +1 makes the threshold inclusive + double tan_threshold = support_threshold_auto ? 0. : tan(M_PI * double(support_threshold + 1) / 180.); + //FIXME this is a fudge constant! + double support_tree_tip_diameter = 0.8; + auto enforcer_overhang_offset = scaled(support_tree_tip_diameter); + + size_t num_overhang_layers = support_auto ? num_object_layers : std::min(num_object_layers, std::max(size_t(support_enforce_layers), enforcers_layers.size())); + tbb::parallel_for(tbb::blocked_range(1, num_overhang_layers), + [&print_object, &config, &print_config, &enforcers_layers, &blockers_layers, + support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, num_raft_layers, &throw_on_cancel, &out] + (const tbb::blocked_range &range) { + for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) { + const Layer ¤t_layer = *print_object.get_layer(layer_id); + const Layer &lower_layer = *print_object.get_layer(layer_id - 1); + // Full overhangs with zero lower_layer_offset and no blockers applied. + Polygons raw_overhangs; + bool raw_overhangs_calculated = false; + // Final overhangs. + Polygons overhangs; + // For how many layers full overhangs shall be supported. + const bool enforced_layer = layer_id < support_enforce_layers; + if (support_auto || enforced_layer) { + float lower_layer_offset; + if (enforced_layer) + lower_layer_offset = 0; + else if (support_threshold_auto) { + float external_perimeter_width = 0; + for (const LayerRegion *layerm : lower_layer.regions()) + external_perimeter_width += layerm->flow(frExternalPerimeter).scaled_width(); + external_perimeter_width /= lower_layer.region_count(); + lower_layer_offset = float(0.5 * external_perimeter_width); + } else + lower_layer_offset = scaled(lower_layer.height / tan_threshold); + overhangs = lower_layer_offset == 0 ? + diff(current_layer.lslices, lower_layer.lslices) : + diff(current_layer.lslices, offset(lower_layer.lslices, lower_layer_offset)); + if (lower_layer_offset == 0) { + raw_overhangs = overhangs; + raw_overhangs_calculated = true; + } + if (! (enforced_layer || blockers_layers.empty() || blockers_layers[layer_id].empty())) + overhangs = diff(overhangs, blockers_layers[layer_id], ApplySafetyOffset::Yes); + //if (config.bridge_no_support) { + // for (const LayerRegion *layerm : current_layer.regions()) + // remove_bridges_from_contacts(print_config, lower_layer, *layerm, + // float(layerm->flow(frExternalPerimeter).scaled_width()), overhangs); + //} + } + //check_self_intersections(overhangs, "generate_overhangs1"); + if (! enforcers_layers.empty() && ! enforcers_layers[layer_id].empty()) { + // Has some support enforcers at this layer, apply them to the overhangs, don't apply the support threshold angle. + //enforcers_layers[layer_id] = union_(enforcers_layers[layer_id]); + //check_self_intersections(enforcers_layers[layer_id], "generate_overhangs - enforcers"); + //check_self_intersections(to_polygons(lower_layer.lslices), "generate_overhangs - lowerlayers"); + if (Polygons enforced_overhangs = intersection(raw_overhangs_calculated ? raw_overhangs : diff(current_layer.lslices, lower_layer.lslices), enforcers_layers[layer_id] /*, ApplySafetyOffset::Yes */); + ! enforced_overhangs.empty()) { + //FIXME this is a hack to make enforcers work on steep overhangs. + //check_self_intersections(enforced_overhangs, "generate_overhangs - enforced overhangs1"); + //Polygons enforced_overhangs_prev = enforced_overhangs; + //check_self_intersections(to_polygons(union_ex(enforced_overhangs)), "generate_overhangs - enforced overhangs11"); + //check_self_intersections(offset(union_ex(enforced_overhangs), + //FIXME enforcer_overhang_offset is a fudge constant! + enforced_overhangs = diff(offset(union_ex(enforced_overhangs), enforcer_overhang_offset), + lower_layer.lslices); +#ifdef TREESUPPORT_DEBUG_SVG +// if (! intersecting_edges(enforced_overhangs).empty()) + { + static int irun = 0; + SVG::export_expolygons(debug_out_path("treesupport-self-intersections-%d.svg", ++irun), + { { { current_layer.lslices }, { "current_layer.lslices", "yellow", 0.5f } }, + { { lower_layer.lslices }, { "lower_layer.lslices", "gray", 0.5f } }, + { { union_ex(enforced_overhangs) }, { "enforced_overhangs", "red", "black", "", scaled(0.1f), 0.5f } } }); + } +#endif // TREESUPPORT_DEBUG_SVG + //check_self_intersections(enforced_overhangs, "generate_overhangs - enforced overhangs2"); + overhangs = overhangs.empty() ? std::move(enforced_overhangs) : union_(overhangs, enforced_overhangs); + //check_self_intersections(overhangs, "generate_overhangs - enforcers"); + } + } + out[layer_id + num_raft_layers] = std::move(overhangs); + throw_on_cancel(); + } + }); + + return out; +} + +/*! + * \brief Precalculates all avoidances, that could be required. + */ +[[nodiscard]] static LayerIndex precalculate(const Print &print, const std::vector &overhangs, const TreeSupportSettings &config, const std::vector &object_ids, TreeModelVolumes &volumes, std::function throw_on_cancel) +{ + // calculate top most layer that is relevant for support + LayerIndex max_layer = 0; + for (size_t object_id : object_ids) { + const PrintObject &print_object = *print.get_object(object_id); + const int num_raft_layers = int(config.raft_layers.size()); + const int num_layers = int(print_object.layer_count()) + num_raft_layers; + int max_support_layer_id = 0; + for (int layer_id = std::max(num_raft_layers, 1); layer_id < num_layers; ++ layer_id) + if (! overhangs[layer_id].empty()) + max_support_layer_id = layer_id; + max_layer = std::max(max_support_layer_id - int(config.z_distance_top_layers), 0); + } + if (max_layer > 0) + // The actual precalculation happens in TreeModelVolumes. + volumes.precalculate(*print.get_object(object_ids.front()), max_layer, throw_on_cancel); + return max_layer; +} + +/*! + * \brief Converts a Polygons object representing a line into the internal format. + * + * \param polylines[in] The Polyline that will be converted. + * \param layer_idx[in] The current layer. + * \return All lines of the \p polylines object, with information for each point regarding in which avoidance it is currently valid in. + */ +// Called by generate_initial_areas() +[[nodiscard]] static LineInformations convert_lines_to_internal( + const TreeModelVolumes &volumes, const TreeSupportSettings &config, + const Polylines &polylines, LayerIndex layer_idx) +{ + const bool min_xy_dist = config.xy_distance > config.xy_min_distance; + + LineInformations result; + // Also checks if the position is valid, if it is NOT, it deletes that point + for (const Polyline &line : polylines) { + LineInformation res_line; + for (Point p : line) { + if (! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::FastSafe, false, min_xy_dist), p)) + res_line.emplace_back(p, LineStatus::TO_BP_SAFE); + else if (! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::Fast, false, min_xy_dist), p)) + res_line.emplace_back(p, LineStatus::TO_BP); + else if (config.support_rests_on_model && ! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::FastSafe, true, min_xy_dist), p)) + res_line.emplace_back(p, LineStatus::TO_MODEL_GRACIOUS_SAFE); + else if (config.support_rests_on_model && ! contains(volumes.getAvoidance(config.getRadius(0), layer_idx, TreeModelVolumes::AvoidanceType::Fast, true, min_xy_dist), p)) + res_line.emplace_back(p, LineStatus::TO_MODEL_GRACIOUS); + else if (config.support_rests_on_model && ! contains(volumes.getCollision(config.getRadius(0), layer_idx, min_xy_dist), p)) + res_line.emplace_back(p, LineStatus::TO_MODEL); + else if (!res_line.empty()) { + result.emplace_back(res_line); + res_line.clear(); + } + } + if (!res_line.empty()) { + result.emplace_back(res_line); + res_line.clear(); + } + } + + validate_range(result); + return result; +} + +#if 0 +/*! + * \brief Converts lines in internal format into a Polygons object representing these lines. + * + * \param lines[in] The lines that will be converted. + * \return All lines of the \p lines object as a Polygons object. + */ +[[nodiscard]] static Polylines convert_internal_to_lines(LineInformations lines) +{ + Polylines result; + for (LineInformation line : lines) { + Polyline path; + for (auto point_data : line) + path.points.emplace_back(point_data.first); + result.emplace_back(std::move(path)); + } + validate_range(result); + return result; +} +#endif + +/*! + * \brief Evaluates if a point has to be added now. Required for a split_lines call in generate_initial_areas(). + * + * \param current_layer[in] The layer on which the point lies, point and its status. + * \return whether the point is valid. + */ +[[nodiscard]] static bool evaluate_point_for_next_layer_function( + const TreeModelVolumes &volumes, const TreeSupportSettings &config, + size_t current_layer, const std::pair &p) +{ + using AvoidanceType = TreeModelVolumes::AvoidanceType; + const bool min_xy_dist = config.xy_distance > config.xy_min_distance; + if (! contains(volumes.getAvoidance(config.getRadius(0), current_layer - 1, p.second == LineStatus::TO_BP_SAFE ? AvoidanceType::FastSafe : AvoidanceType::Fast, false, min_xy_dist), p.first)) + return true; + if (config.support_rests_on_model && (p.second != LineStatus::TO_BP && p.second != LineStatus::TO_BP_SAFE)) + return ! contains( + p.second == LineStatus::TO_MODEL_GRACIOUS || p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE ? + volumes.getAvoidance(config.getRadius(0), current_layer - 1, p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE ? AvoidanceType::FastSafe : AvoidanceType::Fast, true, min_xy_dist) : + volumes.getCollision(config.getRadius(0), current_layer - 1, min_xy_dist), + p.first); + return false; +} + +/*! + * \brief Evaluates which points of some lines are not valid one layer below and which are. Assumes all points are valid on the current layer. Validity is evaluated using supplied lambda. + * + * \param lines[in] The lines that have to be evaluated. + * \param evaluatePoint[in] The function used to evaluate the points. + * \return A pair with which points are still valid in the first slot and which are not in the second slot. + */ +template +[[nodiscard]] static std::pair split_lines(const LineInformations &lines, EvaluatePointFn evaluatePoint) +{ + // assumes all Points on the current line are valid + + LineInformations keep; + LineInformations set_free; + for (const std::vector> &line : lines) { + bool current_keep = true; + LineInformation resulting_line; + for (const std::pair &me : line) { + if (evaluatePoint(me) != current_keep) { + if (! resulting_line.empty()) + (current_keep ? &keep : &set_free)->emplace_back(std::move(resulting_line)); + current_keep = !current_keep; + } + resulting_line.emplace_back(me); + } + if (! resulting_line.empty()) + (current_keep ? &keep : &set_free)->emplace_back(std::move(resulting_line)); + } + validate_range(keep); + validate_range(set_free); + return std::pair>>, std::vector>>>(keep, set_free); +} + +// Ported from CURA's PolygonUtils::getNextPointWithDistance() +// Sample a next point at distance "dist" from start_pt on polyline segment (start_idx, start_idx + 1). +// Returns sample point and start index of its segment on polyline if such sample exists. +static std::optional> polyline_sample_next_point_at_distance(const Points &polyline, const Point &start_pt, size_t start_idx, double dist) +{ + const double dist2 = sqr(dist); + const auto dist2i = int64_t(dist2); + static constexpr const auto eps = scaled(0.01); + + for (size_t i = start_idx + 1; i < polyline.size(); ++ i) { + const Point p1 = polyline[i]; + if ((p1 - start_pt).cast().squaredNorm() >= dist2i) { + // The end point is outside the circle with center "start_pt" and radius "dist". + const Point p0 = polyline[i - 1]; + Vec2d v = (p1 - p0).cast(); + double l2v = v.squaredNorm(); + if (l2v < sqr(eps)) { + // Very short segment. + Point c = (p0 + p1) / 2; + if (std::abs((start_pt - c).cast().norm() - dist) < eps) + return std::pair{ c, i - 1 }; + else + continue; + } + Vec2d p0f = (start_pt - p0).cast(); + // Foot point of start_pt into v. + Vec2d foot_pt = v * (p0f.dot(v) / l2v); + // Vector from foot point of "start_pt" to "start_pt". + Vec2d xf = p0f - foot_pt; + // Squared distance of "start_pt" from the ray (p0, p1). + double l2_from_line = xf.squaredNorm(); + // Squared distance of an intersection point of a circle with center at the foot point. + if (double l2_intersection = dist2 - l2_from_line; + l2_intersection > - SCALED_EPSILON) { + // The ray (p0, p1) touches or intersects a circle centered at "start_pt" with radius "dist". + // Distance of the circle intersection point from the foot point. + l2_intersection = std::max(l2_intersection, 0.); + if ((v - foot_pt).cast().squaredNorm() >= l2_intersection) { + // Intersection of the circle with the segment (p0, p1) is on the right side (close to p1) from the foot point. + Point p = p0 + (foot_pt + v * sqrt(l2_intersection / l2v)).cast(); + validate_range(p); + return std::pair{ p, i - 1 }; + } + } + } + } + return {}; +} + +/*! + * \brief Eensures that every line segment is about distance in length. The resulting lines may differ from the original but all points are on the original + * + * \param input[in] The lines on which evenly spaced points should be placed. + * \param distance[in] The distance the points should be from each other. + * \param min_points[in] The amount of points that have to be placed. If not enough can be placed the distance will be reduced to place this many points. + * \return A Polygons object containing the evenly spaced points. Does not represent an area, more a collection of points on lines. + */ +[[nodiscard]] static Polylines ensure_maximum_distance_polyline(const Polylines &input, double distance, size_t min_points) +{ + Polylines result; + for (Polyline part : input) { + if (part.empty()) + continue; + + double len = length(part.points); + Polyline line; + double current_distance = std::max(distance, scaled(0.1)); + if (len < 2 * distance && min_points <= 1) + { + // Insert the opposite point of the first one. + //FIXME pretty expensive + Polyline pl(part); + pl.clip_end(len / 2); + line.points.emplace_back(pl.points.back()); + } + else + { + size_t optimal_end_index = part.size() - 1; + + if (part.front() == part.back()) { + size_t optimal_start_index = 0; + // If the polyline was a polygon, there is a high chance it was an overhang. Overhangs that are <60� tend to be very thin areas, so lets get the beginning and end of them and ensure that they are supported. + // The first point of the line will always be supported, so rotate the order of points in this polyline that one of the two corresponding points that are furthest from each other is in the beginning. + // The other will be manually added (optimal_end_index) + coord_t max_dist2_between_vertecies = 0; + for (size_t idx = 0; idx < part.size() - 1; ++ idx) { + for (size_t inner_idx = 0; inner_idx < part.size() - 1; inner_idx++) { + if ((part[idx] - part[inner_idx]).cast().squaredNorm() > max_dist2_between_vertecies) { + optimal_start_index = idx; + optimal_end_index = inner_idx; + max_dist2_between_vertecies = (part[idx] - part[inner_idx]).cast().squaredNorm(); + } + } + } + std::rotate(part.begin(), part.begin() + optimal_start_index, part.end() - 1); + part[part.size() - 1] = part[0]; // restore that property that this polyline ends where it started. + optimal_end_index = (part.size() + optimal_end_index - optimal_start_index - 1) % (part.size() - 1); + } + + while (line.size() < min_points && current_distance >= scaled(0.1)) + { + line.clear(); + Point current_point = part[0]; + line.points.emplace_back(part[0]); + if (min_points > 1 || (part[0] - part[optimal_end_index]).cast().norm() > current_distance) + line.points.emplace_back(part[optimal_end_index]); + size_t current_index = 0; + std::optional> next_point; + double next_distance = current_distance; + // Get points so that at least min_points are added and they each are current_distance away from each other. If that is impossible, decrease current_distance a bit. + // The input are lines, that means that the line from the last to the first vertex does not have to exist, so exclude all points that are on this line! + while ((next_point = polyline_sample_next_point_at_distance(part.points, current_point, current_index, next_distance))) { + // Not every point that is distance away, is valid, as it may be much closer to another point. This is especially the case when the overhang is very thin. + // So this ensures that the points are actually a certain distance from each other. + // This assurance is only made on a per polygon basis, as different but close polygon may not be able to use support below the other polygon. + double min_distance_to_existing_point = std::numeric_limits::max(); + for (Point p : line) + min_distance_to_existing_point = std::min(min_distance_to_existing_point, (p - next_point->first).cast().norm()); + if (min_distance_to_existing_point >= current_distance) { + // viable point was found. Add to possible result. + line.points.emplace_back(next_point->first); + current_point = next_point->first; + current_index = next_point->second; + next_distance = current_distance; + } else { + if (current_point == next_point->first) { + // In case a fixpoint is encountered, better aggressively overcompensate so the code does not become stuck here... + BOOST_LOG_TRIVIAL(warning) << "Tree Support: Encountered a fixpoint in polyline_sample_next_point_at_distance. This is expected to happen if the distance (currently " << next_distance << + ") is smaller than 100"; + tree_supports_show_error("Encountered issue while placing tips. Some tips may be missing."sv, true); + if (next_distance > 2 * current_distance) + // This case should never happen, but better safe than sorry. + break; + next_distance += current_distance; + continue; + } + // if the point was too close, the next possible viable point is at least distance-min_distance_to_existing_point away from the one that was just checked. + next_distance = std::max(current_distance - min_distance_to_existing_point, scaled(0.1)); + current_point = next_point->first; + current_index = next_point->second; + } + } + current_distance *= 0.9; + } + } + result.emplace_back(std::move(line)); + } + validate_range(result); + return result; +} + +/*! + * \brief Returns Polylines representing the (infill) lines that will result in slicing the given area + * + * \param area[in] The area that has to be filled with infill. + * \param roof[in] Whether the roofing or regular support settings should be used. + * \param layer_idx[in] The current layer index. + * \param support_infill_distance[in] The distance that should be between the infill lines. + * + * \return A Polygons object that represents the resulting infill lines. + */ +[[nodiscard]] static Polylines generate_support_infill_lines( + const Polygons &polygon, + const SupportParameters &support_params, + bool roof, LayerIndex layer_idx, coord_t support_infill_distance) +{ +#if 0 + Polygons gaps; + // as we effectivly use lines to place our supportPoints we may use the Infill class for it, while not made for it it works perfect + + const EFillMethod pattern = roof ? config.roof_pattern : config.support_pattern; + +// const bool zig_zaggify_infill = roof ? pattern == EFillMethod::ZIG_ZAG : config.zig_zaggify_support; + const bool connect_polygons = false; + constexpr coord_t support_roof_overlap = 0; + constexpr size_t infill_multiplier = 1; + constexpr coord_t outline_offset = 0; + const int support_shift = roof ? 0 : support_infill_distance / 2; + const size_t wall_line_count = include_walls && !roof ? config.support_wall_count : 0; + const Point infill_origin; + constexpr Polygons* perimeter_gaps = nullptr; + constexpr bool use_endpieces = true; + const bool connected_zigzags = roof ? false : config.connect_zigzags; + const size_t zag_skip_count = roof ? 0 : config.zag_skip_count; + constexpr coord_t pocket_size = 0; + std::vector angles = roof ? config.support_roof_angles : config.support_infill_angles; + std::vector toolpaths; + + const coord_t z = config.getActualZ(layer_idx); + int divisor = static_cast(angles.size()); + int index = ((layer_idx % divisor) + divisor) % divisor; + const AngleRadians fill_angle = angles[index]; + Infill roof_computation(pattern, true /* zig_zaggify_infill */, connect_polygons, polygon, + roof ? config.support_roof_line_width : config.support_line_width, support_infill_distance, support_roof_overlap, infill_multiplier, + fill_angle, z, support_shift, config.resolution, wall_line_count, infill_origin, + perimeter_gaps, connected_zigzags, use_endpieces, false /* skip_some_zags */, zag_skip_count, pocket_size); + Polygons polygons; + Polygons lines; + roof_computation.generate(toolpaths, polygons, lines, config.settings); + append(lines, to_polylines(polygons)); + return lines; +#else + const Flow &flow = roof ? support_params.support_material_interface_flow : support_params.support_material_flow; + std::unique_ptr filler = std::unique_ptr(Fill::new_from_type(roof ? support_params.interface_fill_pattern : support_params.base_fill_pattern)); + FillParams fill_params; + + filler->layer_id = layer_idx; + filler->spacing = flow.spacing(); + filler->angle = roof ? + //fixme support_layer.interface_id() instead of layer_idx + (support_params.interface_angle + (layer_idx & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)) : + support_params.base_angle; + + fill_params.density = float(roof ? support_params.interface_density : scaled(filler->spacing) / (scaled(filler->spacing) + float(support_infill_distance))); + fill_params.dont_adjust = true; + + Polylines out; + for (ExPolygon &expoly : union_ex(polygon)) { + // The surface type does not matter. + assert(area(expoly) > 0.); +#ifdef TREE_SUPPORT_SHOW_ERRORS_WIN32 + if (area(expoly) <= 0.) + ::MessageBoxA(nullptr, "TreeSupport infill negative area", "Bug detected!", MB_OK | MB_SYSTEMMODAL | MB_SETFOREGROUND | MB_ICONWARNING); +#endif // TREE_SUPPORT_SHOW_ERRORS_WIN32 + assert(intersecting_edges(to_polygons(expoly)).empty()); + check_self_intersections(expoly, "generate_support_infill_lines"); + Surface surface(stInternal, std::move(expoly)); + try { + Polylines pl = filler->fill_surface(&surface, fill_params); + assert(pl.empty() || get_extents(surface.expolygon).inflated(SCALED_EPSILON).contains(get_extents(pl))); +#ifdef TREE_SUPPORT_SHOW_ERRORS_WIN32 + if (! pl.empty() && ! get_extents(surface.expolygon).inflated(SCALED_EPSILON).contains(get_extents(pl))) + ::MessageBoxA(nullptr, "TreeSupport infill failure", "Bug detected!", MB_OK | MB_SYSTEMMODAL | MB_SETFOREGROUND | MB_ICONWARNING); +#endif // TREE_SUPPORT_SHOW_ERRORS_WIN32 + append(out, std::move(pl)); + } catch (InfillFailedException &) { + } + } + validate_range(out); + return out; +#endif +} + +/*! + * \brief Unions two Polygons. Ensures that if the input is non empty that the output also will be non empty. + * \param first[in] The first Polygon. + * \param second[in] The second Polygon. + * \return The union of both Polygons + */ +[[nodiscard]] static Polygons safe_union(const Polygons first, const Polygons second = {}) +{ + // unionPolygons can slowly remove Polygons under certain circumstances, because of rounding issues (Polygons that have a thin area). + // This does not cause a problem when actually using it on large areas, but as influence areas (representing centerpoints) can be very thin, this does occur so this ugly workaround is needed + // Here is an example of a Polygons object that will loose vertices when unioning, and will be gone after a few times unionPolygons was called: + /* + Polygons example; + Polygon exampleInner; + exampleInner.add(Point(120410,83599));//A + exampleInner.add(Point(120384,83643));//B + exampleInner.add(Point(120399,83618));//C + exampleInner.add(Point(120414,83591));//D + exampleInner.add(Point(120423,83570));//E + exampleInner.add(Point(120419,83580));//F + example.add(exampleInner); + for(int i=0;i<10;i++){ + log("Iteration %d Example area: %f\n",i,area(example)); + example=example.unionPolygons(); + } +*/ + + Polygons result; + if (! first.empty() || ! second.empty()) { + result = union_(first, second); + if (result.empty()) { + BOOST_LOG_TRIVIAL(debug) << "Caught an area destroying union, enlarging areas a bit."; + // just take the few lines we have, and offset them a tiny bit. Needs to be offsetPolylines, as offset may aleady have problems with the area. + result = union_(offset(to_polylines(first), scaled(0.002), jtMiter, 1.2), offset(to_polylines(second), scaled(0.002), jtMiter, 1.2)); + } + } + + return result; +} + +/*! + * \brief Offsets (increases the area of) a polygons object in multiple steps to ensure that it does not lag through over a given obstacle. + * \param me[in] Polygons object that has to be offset. + * \param distance[in] The distance by which me should be offset. Expects values >=0. + * \param collision[in] The area representing obstacles. + * \param last_step_offset_without_check[in] The most it is allowed to offset in one step. + * \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Polygons get very small. Required as arcTolerance is not exposed in offset, which should result with a similar result. + * \return The resulting Polygons object. + */ +[[nodiscard]] static Polygons safe_offset_inc(const Polygons& me, coord_t distance, const Polygons& collision, coord_t safe_step_size, coord_t last_step_offset_without_check, size_t min_amount_offset) +{ + bool do_final_difference = last_step_offset_without_check == 0; + Polygons ret = safe_union(me); // ensure sane input + + // Trim the collision polygons with the region of interest for diff() efficiency. + Polygons collision_trimmed_buffer; + auto collision_trimmed = [&collision_trimmed_buffer, &collision, &ret, distance]() -> const Polygons& { + if (collision_trimmed_buffer.empty() && ! collision.empty()) + collision_trimmed_buffer = ClipperUtils::clip_clipper_polygons_with_subject_bbox(collision, get_extents(ret).inflated(std::max(0, distance) + SCALED_EPSILON)); + return collision_trimmed_buffer; + }; + + if (distance == 0) + return do_final_difference ? diff(ret, collision_trimmed()) : union_(ret); + if (safe_step_size < 0 || last_step_offset_without_check < 0) { + BOOST_LOG_TRIVIAL(error) << "Offset increase got invalid parameter!"; + tree_supports_show_error("Negative offset distance... How did you manage this ?"sv, true); + return do_final_difference ? diff(ret, collision_trimmed()) : union_(ret); + } + + coord_t step_size = safe_step_size; + int steps = distance > last_step_offset_without_check ? (distance - last_step_offset_without_check) / step_size : 0; + if (distance - steps * step_size > last_step_offset_without_check) { + if ((steps + 1) * step_size <= distance) + // This will be the case when last_step_offset_without_check >= safe_step_size + ++ steps; + else + do_final_difference = true; + } + if (steps + (distance < last_step_offset_without_check || (distance % step_size) != 0) < int(min_amount_offset) && min_amount_offset > 1) { + // yes one can add a bool as the standard specifies that a result from compare operators has to be 0 or 1 + // reduce the stepsize to ensure it is offset the required amount of times + step_size = distance / min_amount_offset; + if (step_size >= safe_step_size) { + // effectivly reduce last_step_offset_without_check + step_size = safe_step_size; + steps = min_amount_offset; + } else + steps = distance / step_size; + } + // offset in steps + for (int i = 0; i < steps; ++ i) { + ret = diff(offset(ret, step_size, ClipperLib::jtRound, scaled(0.01)), collision_trimmed()); + // ensure that if many offsets are done the performance does not suffer extremely by the new vertices of jtRound. + if (i % 10 == 7) + ret = polygons_simplify(ret, scaled(0.015)); + } + // offset the remainder + float last_offset = distance - steps * step_size; + if (last_offset > SCALED_EPSILON) + ret = offset(ret, distance - steps * step_size, ClipperLib::jtRound, scaled(0.01)); + ret = polygons_simplify(ret, scaled(0.015)); + + if (do_final_difference) + ret = diff(ret, collision_trimmed()); + return union_(ret); +} + +class RichInterfacePlacer : public InterfacePlacer { +public: + RichInterfacePlacer( + const InterfacePlacer &interface_placer, + const TreeModelVolumes &volumes, + bool force_tip_to_roof, + size_t num_support_layers, + std::vector &move_bounds) + : + InterfacePlacer(interface_placer), + volumes(volumes), force_tip_to_roof(force_tip_to_roof), move_bounds(move_bounds) + { + m_already_inserted.assign(num_support_layers, {}); + this->min_xy_dist = this->config.xy_distance > this->config.xy_min_distance; + } + const TreeModelVolumes &volumes; + // Radius of the tree tip is large enough to be covered by an interface. + const bool force_tip_to_roof; + bool min_xy_dist; + +public: + // called by sample_overhang_area() + void add_points_along_lines( + // Insert points (tree tips or top contact interfaces) along these lines. + LineInformations lines, + // Start at this layer. + LayerIndex insert_layer_idx, + // Insert this number of interface layers. + size_t roof_tip_layers, + // True if an interface is already generated above these lines. + size_t supports_roof_layers, + // The element tries to not move until this dtt is reached. + size_t dont_move_until) + { + validate_range(lines); + // Add tip area as roof (happens when minimum roof area > minimum tip area) if possible + size_t dtt_roof_tip; + for (dtt_roof_tip = 0; dtt_roof_tip < roof_tip_layers && insert_layer_idx - dtt_roof_tip >= 1; ++ dtt_roof_tip) { + size_t this_layer_idx = insert_layer_idx - dtt_roof_tip; + auto evaluateRoofWillGenerate = [&](const std::pair &p) { + //FIXME Vojtech: The circle is just shifted, it has a known size, the infill should fit all the time! + #if 0 + Polygon roof_circle; + for (Point corner : base_circle) + roof_circle.points.emplace_back(p.first + corner * config.min_radius); + return !generate_support_infill_lines({ roof_circle }, config, true, insert_layer_idx - dtt_roof_tip, config.support_roof_line_distance).empty(); + #else + return true; + #endif + }; + + { + std::pair split = + // keep all lines that are still valid on the next layer + split_lines(lines, [this, this_layer_idx](const std::pair &p) + { return evaluate_point_for_next_layer_function(volumes, config, this_layer_idx, p); }); + LineInformations points = std::move(split.second); + // Not all roofs are guaranteed to actually generate lines, so filter these out and add them as points. + split = split_lines(split.first, evaluateRoofWillGenerate); + lines = std::move(split.first); + append(points, split.second); + // add all points that would not be valid + for (const LineInformation &line : points) + for (const std::pair &point_data : line) + add_point_as_influence_area(point_data, this_layer_idx, + // don't move until + roof_tip_layers - dtt_roof_tip, + // supports roof + dtt_roof_tip + supports_roof_layers > 0, + // disable ovalization + false); + } + + // add all tips as roof to the roof storage + Polygons new_roofs; + for (const LineInformation &line : lines) + //FIXME sweep the tip radius along the line? + for (const std::pair &p : line) { + Polygon roof_circle{ m_base_circle }; + roof_circle.scale(config.min_radius / m_base_radius); + roof_circle.translate(p.first); + new_roofs.emplace_back(std::move(roof_circle)); + } + this->add_roof(std::move(new_roofs), this_layer_idx, dtt_roof_tip + supports_roof_layers); + } + + for (const LineInformation &line : lines) { + // If a line consists of enough tips, the assumption is that it is not a single tip, but part of a simulated support pattern. + // Ovalisation should be disabled for these to improve the quality of the lines when tip_diameter=line_width + bool disable_ovalistation = config.min_radius < 3 * config.support_line_width && roof_tip_layers == 0 && dtt_roof_tip == 0 && line.size() > 5; + for (const std::pair &point_data : line) + add_point_as_influence_area(point_data, insert_layer_idx - dtt_roof_tip, + // don't move until + dont_move_until > dtt_roof_tip ? dont_move_until - dtt_roof_tip : 0, + // supports roof + dtt_roof_tip + supports_roof_layers > 0, + disable_ovalistation); + } + } + +private: + // called by this->add_points_along_lines() + void add_point_as_influence_area(std::pair p, LayerIndex insert_layer, size_t dont_move_until, bool roof, bool skip_ovalisation) + { + bool to_bp = p.second == LineStatus::TO_BP || p.second == LineStatus::TO_BP_SAFE; + bool gracious = to_bp || p.second == LineStatus::TO_MODEL_GRACIOUS || p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE; + bool safe_radius = p.second == LineStatus::TO_BP_SAFE || p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE; + if (! config.support_rests_on_model && ! to_bp) { + BOOST_LOG_TRIVIAL(warning) << "Tried to add an invalid support point"; + tree_supports_show_error("Unable to add tip. Some overhang may not be supported correctly."sv, true); + return; + } + Polygons circle{ m_base_circle }; + circle.front().translate(p.first); + { + Point hash_pos = p.first / ((config.min_radius + 1) / 10); + std::lock_guard critical_section_movebounds(m_mutex_movebounds); + if (!m_already_inserted[insert_layer].count(hash_pos)) { + // normalize the point a bit to also catch points which are so close that inserting it would achieve nothing + m_already_inserted[insert_layer].emplace(hash_pos); + static constexpr const size_t dtt = 0; + SupportElementState state; + state.target_height = insert_layer; + state.target_position = p.first; + state.next_position = p.first; + state.layer_idx = insert_layer; + state.effective_radius_height = dtt; + state.to_buildplate = to_bp; + state.distance_to_top = dtt; + state.result_on_layer = p.first; + assert(state.result_on_layer_is_set()); + state.increased_to_model_radius = 0; + state.to_model_gracious = gracious; + state.elephant_foot_increases = 0; + state.use_min_xy_dist = min_xy_dist; + state.supports_roof = roof; + state.dont_move_until = dont_move_until; + state.can_use_safe_radius = safe_radius; + state.missing_roof_layers = force_tip_to_roof ? dont_move_until : 0; + state.skip_ovalisation = skip_ovalisation; + move_bounds[insert_layer].emplace_back(state, std::move(circle)); + } + } + } + + // Outputs + std::vector &move_bounds; + + // Temps + static constexpr const auto m_base_radius = scaled(0.01); + const Polygon m_base_circle { make_circle(m_base_radius, SUPPORT_TREE_CIRCLE_RESOLUTION) }; + + // Mutexes, guards + std::mutex m_mutex_movebounds; + std::vector> m_already_inserted; +}; + + +int generate_raft_contact( + const PrintObject &print_object, + const TreeSupportSettings &config, + InterfacePlacer &interface_placer) +{ + int raft_contact_layer_idx = -1; + if (print_object.has_raft() && print_object.layer_count() > 0) { + // Produce raft contact layer outside of the tree support loop, so that no trees will be generated for the raft contact layer. + // Raft layers supporting raft contact interface will be produced by the classic raft generator. + // Find the raft contact layer. + raft_contact_layer_idx = int(config.raft_layers.size()) - 1; + while (raft_contact_layer_idx > 0 && config.raft_layers[raft_contact_layer_idx] > print_object.slicing_parameters().raft_contact_top_z + EPSILON) + -- raft_contact_layer_idx; + // Create the raft contact layer. + const ExPolygons &lslices = print_object.get_layer(0)->lslices; + double expansion = print_object.config().raft_expansion.value; + interface_placer.add_roof_unguarded(expansion > 0 ? offset(lslices, scaled(expansion)) : to_polygons(lslices), raft_contact_layer_idx, 0); + } + return raft_contact_layer_idx; +} + +void finalize_raft_contact( + const PrintObject &print_object, + const int raft_contact_layer_idx, + SupportGeneratorLayersPtr &top_contacts, + std::vector &move_bounds) +{ + if (raft_contact_layer_idx >= 0) { + const size_t first_tree_layer = print_object.slicing_parameters().raft_layers() - 1; + // Remove tree tips that start below the raft contact, + // remove interface layers below the raft contact. + for (size_t i = 0; i < first_tree_layer; ++i) { + top_contacts[i] = nullptr; + move_bounds[i].clear(); + } + if (raft_contact_layer_idx >= 0 && print_object.config().raft_expansion.value > 0) { + // If any tips at first_tree_layer now are completely inside the expanded raft layer, remove them as well before they are propagated to the ground. + Polygons &raft_polygons = top_contacts[raft_contact_layer_idx]->polygons; + EdgeGrid::Grid grid(get_extents(raft_polygons).inflated(SCALED_EPSILON)); + grid.create(raft_polygons, Polylines{}, coord_t(scale_(10.))); + SupportElements &first_layer_move_bounds = move_bounds[first_tree_layer]; + double threshold = scaled(print_object.config().raft_expansion.value) * 2.; + first_layer_move_bounds.erase(std::remove_if(first_layer_move_bounds.begin(), first_layer_move_bounds.end(), + [&grid, threshold](const SupportElement &el) { + coordf_t dist; + if (grid.signed_distance_edges(el.state.result_on_layer, threshold, dist)) { + assert(std::abs(dist) < threshold + SCALED_EPSILON); + // Support point is inside the expanded raft, remove it. + return dist < - 0.; + } + return false; + }), first_layer_move_bounds.end()); + #if 0 + // Remove the remaining tips from the raft: Closing operation on tip circles. + if (! first_layer_move_bounds.empty()) { + const double eps = 0.1; + // All tips supporting this layer are expected to have the same radius. + double radius = support_element_radius(config, first_layer_move_bounds.front()); + // Connect the tips with the following closing radius. + double closing_distance = radius; + Polygon circle = make_circle(radius + closing_distance, eps); + Polygons circles; + circles.reserve(first_layer_move_bounds.size()); + for (const SupportElement &el : first_layer_move_bounds) { + circles.emplace_back(circle); + circles.back().translate(el.state.result_on_layer); + } + raft_polygons = diff(raft_polygons, offset(union_(circles), - closing_distance)); + } + #endif + } + } +} + +// Called by generate_initial_areas(), used in parallel by multiple layers. +// Produce +// 1) Maximum num_support_roof_layers roof (top interface & contact) layers. +// 2) Tree tips supporting either the roof layers or the object itself. +// num_support_roof_layers should always be respected: +// If num_support_roof_layers contact layers could not be produced, then the tree tip +// is augmented with SupportElementState::missing_roof_layers +// and the top "missing_roof_layers" of such particular tree tips are supposed to be coverted to +// roofs aka interface layers by the tool path generator. +void sample_overhang_area( + // Area to support + Polygons&& overhang_area, + // If true, then the overhang_area is likely large and wide, thus it is worth to try + // to cover it with continuous interfaces supported by zig-zag patterned tree tips. + const bool large_horizontal_roof, + // Index of the top suport layer generated by this function. + const size_t layer_idx, + // Maximum number of roof (contact, interface) layers between the overhang and tree tips to be generated. + const size_t num_support_roof_layers, + // + const coord_t connect_length, + // Configuration classes + const TreeSupportMeshGroupSettings& mesh_group_settings, + // Configuration & Output + RichInterfacePlacer& interface_placer) +{ + // Assumption is that roof will support roof further up to avoid a lot of unnecessary branches. Each layer down it is checked whether the roof area + // is still large enough to be a roof and aborted as soon as it is not. This part was already reworked a few times, and there could be an argument + // made to change it again if there are actual issues encountered regarding supporting roofs. + // Main problem is that some patterns change each layer, so just calculating points and checking if they are still valid an layer below is not useful, + // as the pattern may be different one layer below. Same with calculating which points are now no longer being generated as result from + // a decreasing roof, as there is no guarantee that a line will be above these points. Implementing a separate roof support behavior + // for each pattern harms maintainability as it very well could be >100 LOC + auto generate_roof_lines = [&interface_placer, &mesh_group_settings](const Polygons& area, LayerIndex layer_idx) -> Polylines { + return generate_support_infill_lines(area, interface_placer.support_parameters, true, layer_idx, mesh_group_settings.support_roof_line_distance); + }; + + LineInformations overhang_lines; + // Track how many top contact / interface layers were already generated. + size_t dtt_roof = 0; + size_t layer_generation_dtt = 0; + + if (large_horizontal_roof) { + assert(num_support_roof_layers > 0); + // Sometimes roofs could be empty as the pattern does not generate lines if the area is narrow enough (i am looking at you, concentric infill). + // To catch these cases the added roofs are saved to be evaluated later. + std::vector added_roofs(num_support_roof_layers); + Polygons last_overhang = overhang_area; + for (dtt_roof = 0; dtt_roof < num_support_roof_layers && layer_idx - dtt_roof >= 1; ++dtt_roof) { + // here the roof is handled. If roof can not be added the branches will try to not move instead + Polygons forbidden_next; + { + const bool min_xy_dist = interface_placer.config.xy_distance > interface_placer.config.xy_min_distance; + const Polygons& forbidden_next_raw = interface_placer.config.support_rests_on_model ? + interface_placer.volumes.getCollision(interface_placer.config.getRadius(0), layer_idx - (dtt_roof + 1), min_xy_dist) : + interface_placer.volumes.getAvoidance(interface_placer.config.getRadius(0), layer_idx - (dtt_roof + 1), TreeModelVolumes::AvoidanceType::Fast, false, min_xy_dist); + // prevent rounding errors down the line + //FIXME maybe use SafetyOffset::Yes at the following diff() instead? + forbidden_next = offset(union_ex(forbidden_next_raw), scaled(0.005), jtMiter, 1.2); + } + Polygons overhang_area_next = diff(overhang_area, forbidden_next); + if (area(overhang_area_next) < mesh_group_settings.minimum_roof_area) { + // Next layer down the roof area would be to small so we have to insert our roof support here. + if (dtt_roof > 0) { + size_t dtt_before = dtt_roof - 1; + // Produce support head points supporting an interface layer: First produce the interface lines, then sample them. + overhang_lines = split_lines( + convert_lines_to_internal(interface_placer.volumes, interface_placer.config, + ensure_maximum_distance_polyline(generate_roof_lines(last_overhang, layer_idx - dtt_before), connect_length, 1), layer_idx - dtt_before), + [&interface_placer, layer_idx, dtt_before](const std::pair& p) + { return evaluate_point_for_next_layer_function(interface_placer.volumes, interface_placer.config, layer_idx - dtt_before, p); }) + .first; + } + break; + } + added_roofs[dtt_roof] = overhang_area; + last_overhang = std::move(overhang_area); + overhang_area = std::move(overhang_area_next); + } + + layer_generation_dtt = std::max(dtt_roof, size_t(1)) - 1; // 1 inside max and -1 outside to avoid underflow. layer_generation_dtt=dtt_roof-1 if dtt_roof!=0; + // if the roof should be valid, check that the area does generate lines. This is NOT guaranteed. + if (overhang_lines.empty() && dtt_roof != 0 && generate_roof_lines(overhang_area, layer_idx - layer_generation_dtt).empty()) + for (size_t idx = 0; idx < dtt_roof; idx++) { + // check for every roof area that it has resulting lines. Remember idx 1 means the 2. layer of roof => higher idx == lower layer + if (generate_roof_lines(added_roofs[idx], layer_idx - idx).empty()) { + dtt_roof = idx; + layer_generation_dtt = std::max(dtt_roof, size_t(1)) - 1; + break; + } + } + added_roofs.erase(added_roofs.begin() + dtt_roof, added_roofs.end()); + interface_placer.add_roofs(std::move(added_roofs), layer_idx); + } + + if (overhang_lines.empty()) { + // support_line_width to form a line here as otherwise most will be unsupported. Technically this violates branch distance, but not only is this the only reasonable choice, + // but it ensures consistant behaviour as some infill patterns generate each line segment as its own polyline part causing a similar line forming behaviour. + // This is not doen when a roof is above as the roof will support the model and the trees only need to support the roof + bool supports_roof = dtt_roof > 0; + bool continuous_tips = !supports_roof && large_horizontal_roof; + Polylines polylines = ensure_maximum_distance_polyline( + generate_support_infill_lines(overhang_area, interface_placer.support_parameters, supports_roof, layer_idx - layer_generation_dtt, + supports_roof ? mesh_group_settings.support_roof_line_distance : mesh_group_settings.support_tree_branch_distance), + continuous_tips ? interface_placer.config.min_radius / 2 : connect_length, 1); + size_t point_count = 0; + for (const Polyline& poly : polylines) + point_count += poly.size(); + const size_t min_support_points = std::max(coord_t(1), std::min(coord_t(3), coord_t(total_length(overhang_area) / connect_length))); + if (point_count <= min_support_points) { + // add the outer wall (of the overhang) to ensure it is correct supported instead. Try placing the support points in a way that they fully support the outer wall, instead of just the with half of the the support line width. + // I assume that even small overhangs are over one line width wide, so lets try to place the support points in a way that the full support area generated from them + // will support the overhang (if this is not done it may only be half). This WILL NOT be the case when supporting an angle of about < 60 degrees so there is a fallback, + // as some support is better than none. + Polygons reduced_overhang_area = offset(union_ex(overhang_area), -interface_placer.config.support_line_width / 2.2, jtMiter, 1.2); + polylines = ensure_maximum_distance_polyline( + to_polylines( + !reduced_overhang_area.empty() && + area(offset(diff_ex(overhang_area, reduced_overhang_area), std::max(interface_placer.config.support_line_width, connect_length), jtMiter, 1.2)) < sqr(scaled(0.001)) ? + reduced_overhang_area : + overhang_area), + connect_length, min_support_points); + } + overhang_lines = convert_lines_to_internal(interface_placer.volumes, interface_placer.config, polylines, layer_idx - dtt_roof); + } + + assert(dtt_roof <= layer_idx); + if (dtt_roof >= layer_idx && large_horizontal_roof) + // Reached buildplate when generating contact, interface and base interface layers. + interface_placer.add_roof_build_plate(std::move(overhang_area), dtt_roof); + else { + // normal trees have to be generated + const bool roof_enabled = num_support_roof_layers > 0; + interface_placer.add_points_along_lines( + // Sample along these lines + overhang_lines, + // First layer index to insert the tree tips or interfaces. + layer_idx - dtt_roof, + // Remaining roof tip layers. + interface_placer.force_tip_to_roof ? num_support_roof_layers - dtt_roof : 0, + // Supports roof already? How many roof layers were already produced above these tips? + dtt_roof, + // Don't move until the following distance to top is reached. + roof_enabled ? num_support_roof_layers - dtt_roof : 0); + } +} + +inline SupportGeneratorLayer& layer_allocate( + SupportGeneratorLayerStorage& layer_storage, + SupporLayerType layer_type, + const SlicingParameters &slicing_params, + size_t layer_idx) +{ + auto& layer = layer_storage.allocate(layer_type); + return layer_initialize(layer, layer_type, slicing_params, layer_idx); +} + +/*! + * \brief Creates the initial influence areas (that can later be propagated down) by placing them below the overhang. + * + * Generates Points where the Model should be supported and creates the areas where these points have to be placed. + * + * \param mesh[in] The mesh that is currently processed. + * \param move_bounds[out] Storage for the influence areas. + * \param storage[in] Background storage, required for adding roofs. + */ +void generate_initial_areas( + const PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const std::vector &overhangs, + std::vector &move_bounds, + InterfacePlacer &interface_placer, + std::function throw_on_cancel) +{ + using AvoidanceType = TreeModelVolumes::AvoidanceType; + TreeSupportMeshGroupSettings mesh_group_settings(print_object); + + const size_t z_distance_delta = config.z_distance_top_layers + 1; + + const bool min_xy_dist = config.xy_distance > config.xy_min_distance; + +#if 0 + if (mesh.overhang_areas.size() <= z_distance_delta) + return; +#endif + + const coord_t connect_length = (config.support_line_width * 100. / mesh_group_settings.support_tree_top_rate) + std::max(2. * config.min_radius - 1.0 * config.support_line_width, 0.0); + // As r*r=x*x+y*y (circle equation): If a circle with center at (0,0) the top most point is at (0,r) as in y=r. + // This calculates how far one has to move on the x-axis so that y=r-support_line_width/2. + // In other words how far does one need to move on the x-axis to be support_line_width/2 away from the circle line. + // As a circle is round this length is identical for every axis as long as the 90 degrees angle between both remains. + const coord_t circle_length_to_half_linewidth_change = config.min_radius < config.support_line_width ? + config.min_radius / 2 : + scale_(sqrt(sqr(unscale(config.min_radius)) - sqr(unscale(config.min_radius - config.support_line_width / 2)))); + // Extra support offset to compensate for larger tip radiis. Also outset a bit more when z overwrites xy, because supporting something with a part of a support line is better than not supporting it at all. + //FIXME Vojtech: This is not sufficient for support enforcers to work. + //FIXME There is no account for the support overhang angle. + //FIXME There is no account for the width of the collision regions. + const coord_t extra_outset = std::max(coord_t(0), config.min_radius - config.support_line_width / 2) + (min_xy_dist ? config.support_line_width / 2 : 0) + //FIXME this is a heuristic value for support enforcers to work. +// + 10 * mesh_config.support_line_width; + ; + const size_t num_support_roof_layers = mesh_group_settings.support_roof_layers; + const bool roof_enabled = num_support_roof_layers > 0; + const bool force_tip_to_roof = roof_enabled && (interface_placer.support_parameters.soluble_interface || sqr(config.min_radius) * M_PI > mesh_group_settings.minimum_roof_area); + // cap for how much layer below the overhang a new support point may be added, as other than with regular support every new inserted point + // may cause extra material and time cost. Could also be an user setting or differently calculated. Idea is that if an overhang + // does not turn valid in double the amount of layers a slope of support angle would take to travel xy_distance, nothing reasonable will come from it. + // The 2*z_distance_delta is only a catch for when the support angle is very high. + // Used only if not min_xy_dist. + coord_t max_overhang_insert_lag = 0; + if (config.z_distance_top_layers > 0) { + max_overhang_insert_lag = 2 * config.z_distance_top_layers; + + //FIXME + if (mesh_group_settings.support_angle > EPSILON && mesh_group_settings.support_angle < 0.5 * M_PI - EPSILON) { + //FIXME mesh_group_settings.support_angle does not apply to enforcers and also it does not apply to automatic support angle (by half the external perimeter width). + // take the least restrictive avoidance possible + const auto max_overhang_speed = coord_t(tan(mesh_group_settings.support_angle) * config.layer_height); + max_overhang_insert_lag = std::max(max_overhang_insert_lag, round_up_divide(config.xy_distance, max_overhang_speed / 2)); + } + } + + size_t num_support_layers; + int raft_contact_layer_idx; + // Layers with their overhang regions. + std::vector> raw_overhangs; + + { + const size_t num_raft_layers = config.raft_layers.size(); + const size_t first_support_layer = std::max(int(num_raft_layers) - int(z_distance_delta), 1); + num_support_layers = size_t(std::max(0, int(print_object.layer_count()) + int(num_raft_layers) - int(z_distance_delta))); + raft_contact_layer_idx = generate_raft_contact(print_object, config, interface_placer); + // Enumerate layers for which the support tips may be generated from overhangs above. + raw_overhangs.reserve(num_support_layers - first_support_layer); + for (size_t layer_idx = first_support_layer; layer_idx < num_support_layers; ++ layer_idx) + if (const size_t overhang_idx = layer_idx + z_distance_delta; ! overhangs[overhang_idx].empty()) + raw_overhangs.push_back({ layer_idx, &overhangs[overhang_idx] }); + } + + RichInterfacePlacer rich_interface_placer{ interface_placer, volumes, force_tip_to_roof, num_support_layers, move_bounds }; + + tbb::parallel_for(tbb::blocked_range(0, raw_overhangs.size()), + [&volumes, &config, &raw_overhangs, &mesh_group_settings, + min_xy_dist, roof_enabled, num_support_roof_layers, extra_outset, circle_length_to_half_linewidth_change, connect_length, + &rich_interface_placer, &throw_on_cancel](const tbb::blocked_range &range) { + for (size_t raw_overhang_idx = range.begin(); raw_overhang_idx < range.end(); ++ raw_overhang_idx) { + size_t layer_idx = raw_overhangs[raw_overhang_idx].first; + const Polygons &overhang_raw = *raw_overhangs[raw_overhang_idx].second; + + // take the least restrictive avoidance possible + Polygons relevant_forbidden; + { + const Polygons &relevant_forbidden_raw = config.support_rests_on_model ? + volumes.getCollision(config.getRadius(0), layer_idx, min_xy_dist) : + volumes.getAvoidance(config.getRadius(0), layer_idx, AvoidanceType::Fast, false, min_xy_dist); + // prevent rounding errors down the line, points placed directly on the line of the forbidden area may not be added otherwise. + relevant_forbidden = offset(union_ex(relevant_forbidden_raw), scaled(0.005), jtMiter, 1.2); + } + + // every overhang has saved if a roof should be generated for it. This can NOT be done in the for loop as an area may NOT have a roof + // even if it is larger than the minimum_roof_area when it is only larger because of the support horizontal expansion and + // it would not have a roof if the overhang is offset by support roof horizontal expansion instead. (At least this is the current behavior of the regular support) + Polygons overhang_regular; + { + // When support_offset = 0 safe_offset_inc will only be the difference between overhang_raw and relevant_forbidden, that has to be calculated anyway. + overhang_regular = safe_offset_inc(overhang_raw, mesh_group_settings.support_offset, relevant_forbidden, config.min_radius * 1.75 + config.xy_min_distance, 0, 1); + //check_self_intersections(overhang_regular, "overhang_regular1"); + + // offset ensures that areas that could be supported by a part of a support line, are not considered unsupported overhang + Polygons remaining_overhang = intersection( + diff(mesh_group_settings.support_offset == 0 ? + overhang_raw : + offset(union_ex(overhang_raw), mesh_group_settings.support_offset, jtMiter, 1.2), + offset(union_ex(overhang_regular), config.support_line_width * 0.5, jtMiter, 1.2)), + relevant_forbidden); + + // Offset the area to compensate for large tip radiis. Offset happens in multiple steps to ensure the tip is as close to the original overhang as possible. + //+config.support_line_width / 80 to avoid calculating very small (useless) offsets because of rounding errors. + //FIXME likely a better approach would be to find correspondences between the full overhang and the trimmed overhang + // and if there is no correspondence, project the missing points to the clipping curve. + for (coord_t extra_total_offset_acc = 0; ! remaining_overhang.empty() && extra_total_offset_acc + config.support_line_width / 8 < extra_outset; ) { + const coord_t offset_current_step = std::min( + extra_total_offset_acc + 2 * config.support_line_width > config.min_radius ? + config.support_line_width / 8 : + circle_length_to_half_linewidth_change, + extra_outset - extra_total_offset_acc); + extra_total_offset_acc += offset_current_step; + const Polygons &raw_collision = volumes.getCollision(0, layer_idx, true); + const coord_t offset_step = config.xy_min_distance + config.support_line_width; + // Reducing the remaining overhang by the areas already supported. + //FIXME 1.5 * extra_total_offset_acc seems to be too much, it may remove some remaining overhang without being supported at all. + remaining_overhang = diff(remaining_overhang, safe_offset_inc(overhang_regular, 1.5 * extra_total_offset_acc, raw_collision, offset_step, 0, 1)); + // Extending the overhangs by the inflated remaining overhangs. + overhang_regular = union_(overhang_regular, diff(safe_offset_inc(remaining_overhang, extra_total_offset_acc, raw_collision, offset_step, 0, 1), relevant_forbidden)); + //check_self_intersections(overhang_regular, "overhang_regular2"); + } +#if 0 + // If the xy distance overrides the z distance, some support needs to be inserted further down. + //=> Analyze which support points do not fit on this layer and check if they will fit a few layers down (while adding them an infinite amount of layers down would technically be closer the the setting description, it would not produce reasonable results. ) + if (! min_xy_dist) { + LineInformations overhang_lines; + { + //Vojtech: Generate support heads at support_tree_branch_distance spacing by producing a zig-zag infill at support_tree_branch_distance spacing, + // which is then resmapled + // support_line_width to form a line here as otherwise most will be unsupported. Technically this violates branch distance, + // mbut not only is this the only reasonable choice, but it ensures consistent behavior as some infill patterns generate + // each line segment as its own polyline part causing a similar line forming behavior. Also it is assumed that + // the area that is valid a layer below is to small for support roof. + Polylines polylines = ensure_maximum_distance_polyline( + generate_support_infill_lines(remaining_overhang, support_params, false, layer_idx, mesh_group_settings.support_tree_branch_distance), + config.min_radius, 1); + if (polylines.size() <= 3) + // add the outer wall to ensure it is correct supported instead + polylines = ensure_maximum_distance_polyline(to_polylines(remaining_overhang), connect_length, 3); + for (const auto &line : polylines) { + LineInformation res_line; + for (Point p : line) + res_line.emplace_back(p, LineStatus::INVALID); + overhang_lines.emplace_back(res_line); + } + validate_range(overhang_lines); + } + for (size_t lag_ctr = 1; lag_ctr <= max_overhang_insert_lag && !overhang_lines.empty() && layer_idx - coord_t(lag_ctr) >= 1; lag_ctr++) { + // get least restricted avoidance for layer_idx-lag_ctr + const Polygons &relevant_forbidden_below = config.support_rests_on_model ? + volumes.getCollision(config.getRadius(0), layer_idx - lag_ctr, min_xy_dist) : + volumes.getAvoidance(config.getRadius(0), layer_idx - lag_ctr, AvoidanceType::Fast, false, min_xy_dist); + // it is not required to offset the forbidden area here as the points wont change: If points here are not inside the forbidden area neither will they be later when placing these points, as these are the same points. + auto evaluatePoint = [&](std::pair p) { return contains(relevant_forbidden_below, p.first); }; + + std::pair split = split_lines(overhang_lines, evaluatePoint); // keep all lines that are invalid + overhang_lines = split.first; + // Set all now valid lines to their correct LineStatus. Easiest way is to just discard Avoidance information for each point and evaluate them again. + LineInformations fresh_valid_points = convert_lines_to_internal(volumes, config, convert_internal_to_lines(split.second), layer_idx - lag_ctr); + validate_range(fresh_valid_points); + + rich_interface_placer.add_points_along_lines(fresh_valid_points, (force_tip_to_roof && lag_ctr <= num_support_roof_layers) ? num_support_roof_layers : 0, layer_idx - lag_ctr, false, roof_enabled ? num_support_roof_layers : 0); + } + } +#endif + } + + throw_on_cancel(); + + if (roof_enabled) { + static constexpr const coord_t support_roof_offset = 0; + Polygons overhang_roofs = safe_offset_inc(overhang_raw, support_roof_offset, relevant_forbidden, config.min_radius * 2 + config.xy_min_distance, 0, 1); + if (mesh_group_settings.minimum_support_area > 0) + remove_small(overhang_roofs, mesh_group_settings.minimum_roof_area); + overhang_regular = diff(overhang_regular, overhang_roofs, ApplySafetyOffset::Yes); + //check_self_intersections(overhang_regular, "overhang_regular3"); + for (ExPolygon &roof_part : union_ex(overhang_roofs)) { + sample_overhang_area(to_polygons(std::move(roof_part)), true, layer_idx, num_support_roof_layers, connect_length, + mesh_group_settings, rich_interface_placer); + throw_on_cancel(); + } + } + // Either the roof is not enabled, then these are all the overhangs to be supported, + // or roof is enabled and these are the thin overhangs at object slopes (not horizontal overhangs). + if (mesh_group_settings.minimum_support_area > 0) + remove_small(overhang_regular, mesh_group_settings.minimum_support_area); + + for (ExPolygon &support_part : union_ex(overhang_regular)) { + sample_overhang_area(to_polygons(std::move(support_part)), + false, layer_idx, num_support_roof_layers, connect_length, + mesh_group_settings, rich_interface_placer); + throw_on_cancel(); + } + } + }); + + finalize_raft_contact(print_object, raft_contact_layer_idx, interface_placer.top_contacts_mutable(), move_bounds); +} + +static unsigned int move_inside(const Polygons &polygons, Point &from, int distance = 0, int64_t maxDist2 = std::numeric_limits::max()) +{ + Point ret = from; + double bestDist2 = std::numeric_limits::max(); + auto bestPoly = static_cast(-1); + bool is_already_on_correct_side_of_boundary = false; // whether [from] is already on the right side of the boundary + for (unsigned int poly_idx = 0; poly_idx < polygons.size(); ++ poly_idx) { + const Polygon &poly = polygons[poly_idx]; + if (poly.size() < 2) + continue; + Point p0 = poly[poly.size() - 2]; + Point p1 = poly.back(); + // because we compare with vSize2 here (no division by zero), we also need to compare by vSize2 inside the loop + // to avoid integer rounding edge cases + bool projected_p_beyond_prev_segment = (p1 - p0).cast().dot((from - p0).cast()) >= (p1 - p0).cast().squaredNorm(); + for (const Point& p2 : poly) { + // X = A + Normal(B-A) * (((B-A) dot (P-A)) / VSize(B-A)); + // = A + (B-A) * ((B-A) dot (P-A)) / VSize2(B-A); + // X = P projected on AB + const Point& a = p1; + const Point& b = p2; + const Point& p = from; + auto ab = (b - a).cast(); + auto ap = (p - a).cast(); + int64_t ab_length2 = ab.squaredNorm(); + if (ab_length2 <= 0) { //A = B, i.e. the input polygon had two adjacent points on top of each other. + p1 = p2; //Skip only one of the points. + continue; + } + int64_t dot_prod = ab.dot(ap); + if (dot_prod <= 0) { // x is projected to before ab + if (projected_p_beyond_prev_segment) { + // case which looks like: > . + projected_p_beyond_prev_segment = false; + Point& x = p1; + + auto dist2 = (x - p).cast().squaredNorm(); + if (dist2 < bestDist2) { + bestDist2 = dist2; + bestPoly = poly_idx; + if (distance == 0) + ret = x; + else { + Vec2d abd = ab.cast(); + Vec2d p1p2 = (p1 - p0).cast(); + double lab = abd.norm(); + double lp1p2 = p1p2.norm(); + // inward direction irrespective of sign of [distance] + auto inward_dir = perp(abd * (scaled(10.0) / lab) + p1p2 * (scaled(10.0) / lp1p2)); + // MM2INT(10.0) to retain precision for the eventual normalization + ret = x + (inward_dir * (distance / inward_dir.norm())).cast(); + is_already_on_correct_side_of_boundary = inward_dir.dot((p - x).cast()) * distance >= 0; + } + } + } else { + projected_p_beyond_prev_segment = false; + p0 = p1; + p1 = p2; + continue; + } + } else if (dot_prod >= ab_length2) { + // x is projected to beyond ab + projected_p_beyond_prev_segment = true; + p0 = p1; + p1 = p2; + continue; + } else { + // x is projected to a point properly on the line segment (not onto a vertex). The case which looks like | . + projected_p_beyond_prev_segment = false; + Point x = a + (ab.cast() * (double(dot_prod) / double(ab_length2))).cast(); + auto dist2 = (p - x).cast().squaredNorm(); + if (dist2 < bestDist2) { + bestDist2 = dist2; + bestPoly = poly_idx; + if (distance == 0) + ret = x; + else { + Vec2d abd = ab.cast(); + Vec2d inward_dir = perp(abd * (distance / abd.norm())); // inward or outward depending on the sign of [distance] + ret = x + inward_dir.cast(); + is_already_on_correct_side_of_boundary = inward_dir.dot((p - x).cast()) >= 0; + } + } + } + p0 = p1; + p1 = p2; + } + } + // when the best point is already inside and we're moving inside, or when the best point is already outside and we're moving outside + if (is_already_on_correct_side_of_boundary) { + if (bestDist2 < distance * distance) + from = ret; + else { + // from = from; // original point stays unaltered. It is already inside by enough distance + } + return bestPoly; + } else if (bestDist2 < maxDist2) { + from = ret; + return bestPoly; + } + return -1; +} + +static Point move_inside_if_outside(const Polygons &polygons, Point from, int distance = 0, int64_t maxDist2 = std::numeric_limits::max()) +{ + if (! contains(polygons, from)) + move_inside(polygons, from); + return from; +} + +/*! + * \brief Checks if an influence area contains a valid subsection and returns the corresponding metadata and the new Influence area. + * + * Calculates an influence areas of the layer below, based on the influence area of one element on the current layer. + * Increases every influence area by maximum_move_distance_slow. If this is not enough, as in we would change our gracious or to_buildplate status the influence areas are instead increased by maximum_move_distance_slow. + * Also ensures that increasing the radius of a branch, does not cause it to change its status (like to_buildplate ). If this were the case, the radius is not increased instead. + * + * Warning: The used format inside this is different as the SupportElement does not have a valid area member. Instead this area is saved as value of the dictionary. This was done to avoid not needed heap allocations. + * + * \param settings[in] Which settings have to be used to check validity. + * \param layer_idx[in] Number of the current layer. + * \param parent[in] The metadata of the parents influence area. + * \param relevant_offset[in] The maximal possible influence area. No guarantee regarding validity with current layer collision required, as it is ensured in-function! + * \param to_bp_data[out] The part of the Influence area that can reach the buildplate. + * \param to_model_data[out] The part of the Influence area that do not have to reach the buildplate. This has overlap with new_layer_data. + * \param increased[out] Area than can reach all further up support points. No assurance is made that the buildplate or the model can be reached in accordance to the user-supplied settings. + * \param overspeed[in] How much should the already offset area be offset again. Usually this is 0. + * \param mergelayer[in] Will the merge method be called on this layer. This information is required as some calculation can be avoided if they are not required for merging. + * \return A valid support element for the next layer regarding the calculated influence areas. Empty if no influence are can be created using the supplied influence area and settings. + */ +[[nodiscard]] static std::optional increase_single_area( + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const AreaIncreaseSettings &settings, + const LayerIndex layer_idx, + const SupportElement &parent, + const Polygons &relevant_offset, + Polygons &to_bp_data, + Polygons &to_model_data, + Polygons &increased, + const coord_t overspeed, + const bool mergelayer) +{ + SupportElementState current_elem{ SupportElementState::propagate_down(parent.state) }; + Polygons check_layer_data; + if (settings.increase_radius) + current_elem.effective_radius_height += 1; + coord_t radius = support_element_collision_radius(config, current_elem); + + if (settings.move) { + increased = relevant_offset; + if (overspeed > 0) { + const coord_t safe_movement_distance = + (current_elem.use_min_xy_dist ? config.xy_min_distance : config.xy_distance) + + (std::min(config.z_distance_top_layers, config.z_distance_bottom_layers) > 0 ? config.min_feature_size : 0); + // The difference to ensure that the result not only conforms to wall_restriction, but collision/avoidance is done later. + // The higher last_safe_step_movement_distance comes exactly from the fact that the collision will be subtracted later. + increased = safe_offset_inc(increased, overspeed, volumes.getWallRestriction(support_element_collision_radius(config, parent.state), layer_idx, parent.state.use_min_xy_dist), + safe_movement_distance, safe_movement_distance + radius, 1); + } + if (settings.no_error && settings.move) + // as ClipperLib::jtRound has to be used for offsets this simplify is VERY important for performance. + polygons_simplify(increased, scaled(0.025)); + } else + // if no movement is done the areas keep parent area as no move == offset(0) + increased = parent.influence_area; + + if (mergelayer || current_elem.to_buildplate) { + to_bp_data = safe_union(diff_clipped(increased, volumes.getAvoidance(radius, layer_idx - 1, settings.type, false, settings.use_min_distance))); + if (! current_elem.to_buildplate && area(to_bp_data) > tiny_area_threshold) { + // mostly happening in the tip, but with merges one should check every time, just to be sure. + current_elem.to_buildplate = true; // sometimes nodes that can reach the buildplate are marked as cant reach, tainting subtrees. This corrects it. + BOOST_LOG_TRIVIAL(debug) << "Corrected taint leading to a wrong to model value on layer " << layer_idx - 1 << " targeting " << + current_elem.target_height << " with radius " << radius; + } + } + if (config.support_rests_on_model) { + if (mergelayer || current_elem.to_model_gracious) + to_model_data = safe_union(diff_clipped(increased, volumes.getAvoidance(radius, layer_idx - 1, settings.type, true, settings.use_min_distance))); + + if (!current_elem.to_model_gracious) { + if (mergelayer && area(to_model_data) >= tiny_area_threshold) { + current_elem.to_model_gracious = true; + BOOST_LOG_TRIVIAL(debug) << "Corrected taint leading to a wrong non gracious value on layer " << layer_idx - 1 << " targeting " << + current_elem.target_height << " with radius " << radius; + } else + to_model_data = safe_union(diff_clipped(increased, volumes.getCollision(radius, layer_idx - 1, settings.use_min_distance))); + } + } + + check_layer_data = current_elem.to_buildplate ? to_bp_data : to_model_data; + + if (settings.increase_radius && area(check_layer_data) > tiny_area_threshold) { + auto validWithRadius = [&](coord_t next_radius) { + if (volumes.ceilRadius(next_radius, settings.use_min_distance) <= volumes.ceilRadius(radius, settings.use_min_distance)) + return true; + + Polygons to_bp_data_2; + if (current_elem.to_buildplate) + // regular union as output will not be used later => this area should always be a subset of the safe_union one (i think) + to_bp_data_2 = diff_clipped(increased, volumes.getAvoidance(next_radius, layer_idx - 1, settings.type, false, settings.use_min_distance)); + Polygons to_model_data_2; + if (config.support_rests_on_model && !current_elem.to_buildplate) + to_model_data_2 = diff_clipped(increased, + current_elem.to_model_gracious ? + volumes.getAvoidance(next_radius, layer_idx - 1, settings.type, true, settings.use_min_distance) : + volumes.getCollision(next_radius, layer_idx - 1, settings.use_min_distance)); + Polygons check_layer_data_2 = current_elem.to_buildplate ? to_bp_data_2 : to_model_data_2; + return area(check_layer_data_2) > tiny_area_threshold; + }; + coord_t ceil_radius_before = volumes.ceilRadius(radius, settings.use_min_distance); + + if (support_element_collision_radius(config, current_elem) < config.increase_radius_until_radius && support_element_collision_radius(config, current_elem) < support_element_radius(config, current_elem)) { + coord_t target_radius = std::min(support_element_radius(config, current_elem), config.increase_radius_until_radius); + coord_t current_ceil_radius = volumes.getRadiusNextCeil(radius, settings.use_min_distance); + + while (current_ceil_radius < target_radius && validWithRadius(volumes.getRadiusNextCeil(current_ceil_radius + 1, settings.use_min_distance))) + current_ceil_radius = volumes.getRadiusNextCeil(current_ceil_radius + 1, settings.use_min_distance); + size_t resulting_eff_dtt = current_elem.effective_radius_height; + while (resulting_eff_dtt + 1 < current_elem.distance_to_top && + config.getRadius(resulting_eff_dtt + 1, current_elem.elephant_foot_increases) <= current_ceil_radius && + config.getRadius(resulting_eff_dtt + 1, current_elem.elephant_foot_increases) <= support_element_radius(config, current_elem)) + ++ resulting_eff_dtt; + current_elem.effective_radius_height = resulting_eff_dtt; + } + radius = support_element_collision_radius(config, current_elem); + + const coord_t foot_radius_increase = std::max(config.bp_radius_increase_per_layer - config.branch_radius_increase_per_layer, 0.0); + // Is nearly all of the time 1, but sometimes an increase of 1 could cause the radius to become bigger than recommendedMinRadius, + // which could cause the radius to become bigger than precalculated. + double planned_foot_increase = std::min(1.0, double(config.recommendedMinRadius(layer_idx - 1) - support_element_radius(config, current_elem)) / foot_radius_increase); +//FIXME + bool increase_bp_foot = planned_foot_increase > 0 && current_elem.to_buildplate; +// bool increase_bp_foot = false; + + if (increase_bp_foot && support_element_radius(config, current_elem) >= config.branch_radius && support_element_radius(config, current_elem) >= config.increase_radius_until_radius) + if (validWithRadius(config.getRadius(current_elem.effective_radius_height, current_elem.elephant_foot_increases + planned_foot_increase))) { + current_elem.elephant_foot_increases += planned_foot_increase; + radius = support_element_collision_radius(config, current_elem); + } + + if (ceil_radius_before != volumes.ceilRadius(radius, settings.use_min_distance)) { + if (current_elem.to_buildplate) + to_bp_data = safe_union(diff_clipped(increased, volumes.getAvoidance(radius, layer_idx - 1, settings.type, false, settings.use_min_distance))); + if (config.support_rests_on_model && (!current_elem.to_buildplate || mergelayer)) + to_model_data = safe_union(diff_clipped(increased, + current_elem.to_model_gracious ? + volumes.getAvoidance(radius, layer_idx - 1, settings.type, true, settings.use_min_distance) : + volumes.getCollision(radius, layer_idx - 1, settings.use_min_distance) + )); + check_layer_data = current_elem.to_buildplate ? to_bp_data : to_model_data; + if (area(check_layer_data) < tiny_area_threshold) { + BOOST_LOG_TRIVIAL(error) << "Lost area by doing catch up from " << ceil_radius_before << " to radius " << + volumes.ceilRadius(support_element_collision_radius(config, current_elem), settings.use_min_distance); + tree_supports_show_error("Area lost catching up radius. May not cause visible malformation."sv, true); + } + } + } + + return area(check_layer_data) > tiny_area_threshold ? std::optional(current_elem) : std::optional(); +} + +struct SupportElementInfluenceAreas { + // All influence areas: both to build plate and model. + Polygons influence_areas; + // Influence areas just to build plate. + Polygons to_bp_areas; + // Influence areas just to model. + Polygons to_model_areas; + + void clear() { + this->influence_areas.clear(); + this->to_bp_areas.clear(); + this->to_model_areas.clear(); + } +}; + +struct SupportElementMerging { + SupportElementState state; + /*! + * \brief All elements in the layer above the current one that are supported by this element + */ + SupportElement::ParentIndices parents; + + SupportElementInfluenceAreas areas; + // Bounding box of all influence areas. + Eigen::AlignedBox bbox_data; + + const Eigen::AlignedBox& bbox() const { return bbox_data;} + const Point centroid() const { return (bbox_data.min() + bbox_data.max()) / 2; } + void set_bbox(const BoundingBox& abbox) + { Point eps { coord_t(SCALED_EPSILON), coord_t(SCALED_EPSILON) }; bbox_data = { abbox.min - eps, abbox.max + eps }; } + + // Called by the AABBTree builder to get an index into the vector of source elements. + // Not needed, thus zero is returned. + static size_t idx() { return 0; } +}; + +/*! + * \brief Increases influence areas as far as required. + * + * Calculates influence areas of the layer below, based on the influence areas of the current layer. + * Increases every influence area by maximum_move_distance_slow. If this is not enough, as in it would change the gracious or to_buildplate status, the influence areas are instead increased by maximum_move_distance. + * Also ensures that increasing the radius of a branch, does not cause it to change its status (like to_buildplate ). If this were the case, the radius is not increased instead. + * + * Warning: The used format inside this is different as the SupportElement does not have a valid area member. Instead this area is saved as value of the dictionary. This was done to avoid not needed heap allocations. + * + * \param to_bp_areas[out] Influence areas that can reach the buildplate + * \param to_model_areas[out] Influence areas that do not have to reach the buildplate. This has overlap with new_layer_data, as areas that can reach the buildplate are also considered valid areas to the model. + * This redundancy is required if a to_buildplate influence area is allowed to merge with a to model influence area. + * \param influence_areas[out] Area than can reach all further up support points. No assurance is made that the buildplate or the model can be reached in accordance to the user-supplied settings. + * \param bypass_merge_areas[out] Influence areas ready to be added to the layer below that do not need merging. + * \param last_layer[in] Influence areas of the current layer. + * \param layer_idx[in] Number of the current layer. + * \param mergelayer[in] Will the merge method be called on this layer. This information is required as some calculation can be avoided if they are not required for merging. + */ +static void increase_areas_one_layer( + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + // New areas at the layer below layer_idx + std::vector &merging_areas, + // Layer above merging_areas. + const LayerIndex layer_idx, + // Layer elements above merging_areas. + SupportElements &layer_elements, + // If false, the merging_areas will not be merged for performance reasons. + const bool mergelayer, + std::function throw_on_cancel) +{ + using AvoidanceType = TreeModelVolumes::AvoidanceType; + + tbb::parallel_for(tbb::blocked_range(0, merging_areas.size(), 1), + [&](const tbb::blocked_range &range) { + for (size_t merging_area_idx = range.begin(); merging_area_idx < range.end(); ++ merging_area_idx) { + SupportElementMerging &merging_area = merging_areas[merging_area_idx]; + assert(merging_area.parents.size() == 1); + SupportElement &parent = layer_elements[merging_area.parents.front()]; + SupportElementState elem = SupportElementState::propagate_down(parent.state); + const Polygons &wall_restriction = + // Abstract representation of the model outline. If an influence area would move through it, it could teleport through a wall. + volumes.getWallRestriction(support_element_collision_radius(config, parent.state), layer_idx, parent.state.use_min_xy_dist); + +#ifdef TREESUPPORT_DEBUG_SVG + SVG::export_expolygons(debug_out_path("treesupport-increase_areas_one_layer-%d-%ld.svg", layer_idx, int(merging_area_idx)), + { { { union_ex(wall_restriction) }, { "wall_restricrictions", "gray", 0.5f } }, + { { union_ex(parent.influence_area) }, { "parent", "red", "black", "", scaled(0.1f), 0.5f } } }); +#endif // TREESUPPORT_DEBUG_SVG + + Polygons to_bp_data, to_model_data; + coord_t radius = support_element_collision_radius(config, elem); + + // When the radius increases, the outer "support wall" of the branch will have been moved farther away from the center (as this is the definition of radius). + // As it is not specified that the support_tree_angle has to be one of the center of the branch, it is here seen as the smaller angle of the outer wall of the branch, to the outer wall of the same branch one layer above. + // As the branch may have become larger the distance between these 2 walls is smaller than the distance of the center points. + // These extra distance is added to the movement distance possible for this layer. + + coord_t extra_speed = 5; // The extra speed is added to both movement distances. Also move 5 microns faster than allowed to avoid rounding errors, this may cause issues at VERY VERY small layer heights. + coord_t extra_slow_speed = 0; // Only added to the slow movement distance. + const coord_t ceiled_parent_radius = volumes.ceilRadius(support_element_collision_radius(config, parent.state), parent.state.use_min_xy_dist); + coord_t projected_radius_increased = config.getRadius(parent.state.effective_radius_height + 1, parent.state.elephant_foot_increases); + coord_t projected_radius_delta = projected_radius_increased - support_element_collision_radius(config, parent.state); + + // When z distance is more than one layer up and down the Collision used to calculate the wall restriction will always include the wall (and not just the xy_min_distance) of the layer above and below like this (d = blocked area because of z distance): + /* + * layer z+1:dddddiiiiiioooo + * layer z+0:xxxxxdddddddddd + * layer z-1:dddddxxxxxxxxxx + * For more detailed visualisation see calculateWallRestrictions + */ + const coord_t safe_movement_distance = + (elem.use_min_xy_dist ? config.xy_min_distance : config.xy_distance) + + (std::min(config.z_distance_top_layers, config.z_distance_bottom_layers) > 0 ? config.min_feature_size : 0); + if (ceiled_parent_radius == volumes.ceilRadius(projected_radius_increased, parent.state.use_min_xy_dist) || + projected_radius_increased < config.increase_radius_until_radius) + // If it is guaranteed possible to increase the radius, the maximum movement speed can be increased, as it is assumed that the maximum movement speed is the one of the slower moving wall + extra_speed += projected_radius_delta; + else + // if a guaranteed radius increase is not possible, only increase the slow speed + // Ensure that the slow movement distance can not become larger than the fast one. + extra_slow_speed += std::min(projected_radius_delta, (config.maximum_move_distance + extra_speed) - (config.maximum_move_distance_slow + extra_slow_speed)); + + if (config.layer_start_bp_radius > layer_idx && + config.recommendedMinRadius(layer_idx - 1) < config.getRadius(elem.effective_radius_height + 1, elem.elephant_foot_increases)) { + // can guarantee elephant foot radius increase + if (ceiled_parent_radius == volumes.ceilRadius(config.getRadius(parent.state.effective_radius_height + 1, parent.state.elephant_foot_increases + 1), parent.state.use_min_xy_dist)) + extra_speed += config.bp_radius_increase_per_layer; + else + extra_slow_speed += std::min(coord_t(config.bp_radius_increase_per_layer), + config.maximum_move_distance - (config.maximum_move_distance_slow + extra_slow_speed)); + } + + const coord_t fast_speed = config.maximum_move_distance + extra_speed; + const coord_t slow_speed = config.maximum_move_distance_slow + extra_speed + extra_slow_speed; + + Polygons offset_slow, offset_fast; + + bool add = false; + bool bypass_merge = false; + constexpr bool increase_radius = true, no_error = true, use_min_radius = true, move = true; // aliases for better readability + + // Determine in which order configurations are checked if they result in a valid influence area. Check will stop if a valid area is found + std::vector order; + auto insertSetting = [&](AreaIncreaseSettings settings, bool back) { + if (std::find(order.begin(), order.end(), settings) == order.end()) { + if (back) + order.emplace_back(settings); + else + order.insert(order.begin(), settings); + } + }; + + const bool parent_moved_slow = elem.last_area_increase.increase_speed < config.maximum_move_distance; + const bool avoidance_speed_mismatch = parent_moved_slow && elem.last_area_increase.type != AvoidanceType::Slow; + if (elem.last_area_increase.move && elem.last_area_increase.no_error && elem.can_use_safe_radius && !mergelayer && + !avoidance_speed_mismatch && (elem.distance_to_top >= config.tip_layers || parent_moved_slow)) { + // assume that the avoidance type that was best for the parent is best for me. Makes this function about 7% faster. + insertSetting({ elem.last_area_increase.type, elem.last_area_increase.increase_speed < config.maximum_move_distance ? slow_speed : fast_speed, + increase_radius, elem.last_area_increase.no_error, !use_min_radius, elem.last_area_increase.move }, true); + insertSetting({ elem.last_area_increase.type, elem.last_area_increase.increase_speed < config.maximum_move_distance ? slow_speed : fast_speed, + !increase_radius, elem.last_area_increase.no_error, !use_min_radius, elem.last_area_increase.move }, true); + } + // branch may still go though a hole, so a check has to be done whether the hole was already passed, and the regular avoidance can be used. + if (!elem.can_use_safe_radius) { + // if the radius until which it is always increased can not be guaranteed, move fast. This is to avoid holes smaller than the real branch radius. + // This does not guarantee the avoidance of such holes, but ensures they are avoided if possible. + // order.emplace_back(AvoidanceType::Slow,!increase_radius,no_error,!use_min_radius,move); + insertSetting({ AvoidanceType::Slow, slow_speed, increase_radius, no_error, !use_min_radius, !move }, true); // did we go through the hole + // in many cases the definition of hole is overly restrictive, so to avoid unnecessary fast movement in the tip, it is ignored there for a bit. + // This CAN cause a branch to go though a hole it otherwise may have avoided. + if (elem.distance_to_top < round_up_divide(config.tip_layers, size_t(2))) + insertSetting({ AvoidanceType::Fast, slow_speed, increase_radius, no_error, !use_min_radius, !move }, true); + insertSetting({ AvoidanceType::FastSafe, fast_speed, increase_radius, no_error, !use_min_radius, !move }, true); // did we manage to avoid the hole + insertSetting({ AvoidanceType::FastSafe, fast_speed, !increase_radius, no_error, !use_min_radius, move }, true); + insertSetting({ AvoidanceType::Fast, fast_speed, !increase_radius, no_error, !use_min_radius, move }, true); + } else { + insertSetting({ AvoidanceType::Slow, slow_speed, increase_radius, no_error, !use_min_radius, move }, true); + // while moving fast to be able to increase the radius (b) may seems preferable (over a) this can cause the a sudden skip in movement, + // which looks similar to a layer shift and can reduce stability. + // as such idx have chosen to only use the user setting for radius increases as a friendly recommendation. + insertSetting({ AvoidanceType::Slow, slow_speed, !increase_radius, no_error, !use_min_radius, move }, true); // a + if (elem.distance_to_top < config.tip_layers) + insertSetting({ AvoidanceType::FastSafe, slow_speed, increase_radius, no_error, !use_min_radius, move }, true); + insertSetting({ AvoidanceType::FastSafe, fast_speed, increase_radius, no_error, !use_min_radius, move }, true); // b + insertSetting({ AvoidanceType::FastSafe, fast_speed, !increase_radius, no_error, !use_min_radius, move }, true); + } + + if (elem.use_min_xy_dist) { + std::vector new_order; + // if the branch currently has to use min_xy_dist check if the configuration would also be valid + // with the regular xy_distance before checking with use_min_radius (Only happens when Support Distance priority is z overrides xy ) + for (AreaIncreaseSettings settings : order) { + new_order.emplace_back(settings); + new_order.push_back({ settings.type, settings.increase_speed, settings.increase_radius, settings.no_error, use_min_radius, settings.move }); + } + order = new_order; + } + if (elem.to_buildplate || (elem.to_model_gracious && intersection(parent.influence_area, volumes.getPlaceableAreas(radius, layer_idx, throw_on_cancel)).empty())) { + // error case + // it is normal that we wont be able to find a new area at some point in time if we wont be able to reach layer 0 aka have to connect with the model + insertSetting({ AvoidanceType::Fast, fast_speed, !increase_radius, !no_error, elem.use_min_xy_dist, move }, true); + } + if (elem.distance_to_top < elem.dont_move_until && elem.can_use_safe_radius) // only do not move when holes would be avoided in every case. + // Only do not move when already in a no hole avoidance with the regular xy distance. + insertSetting({ AvoidanceType::Slow, 0, increase_radius, no_error, !use_min_radius, !move }, false); + + Polygons inc_wo_collision; + // Check whether it is faster to calculate the area increased with the fast speed independently from the slow area, or time could be saved by reusing the slow area to calculate the fast one. + // Calculated by comparing the steps saved when calcualting idependently with the saved steps when not. + bool offset_independant_faster = radius / safe_movement_distance - int(config.maximum_move_distance + extra_speed < radius + safe_movement_distance) > + round_up_divide((extra_speed + extra_slow_speed + config.maximum_move_distance_slow), safe_movement_distance); + for (const AreaIncreaseSettings &settings : order) { + if (settings.move) { + if (offset_slow.empty() && (settings.increase_speed == slow_speed || ! offset_independant_faster)) { + // offsetting in 2 steps makes our offsetted area rounder preventing (rounding) errors created by to pointy areas. At this point one can see that the Polygons class + // was never made for precision in the single digit micron range. + offset_slow = safe_offset_inc(parent.influence_area, extra_speed + extra_slow_speed + config.maximum_move_distance_slow, + wall_restriction, safe_movement_distance, offset_independant_faster ? safe_movement_distance + radius : 0, 2); +#ifdef TREESUPPORT_DEBUG_SVG + SVG::export_expolygons(debug_out_path("treesupport-increase_areas_one_layer-slow-%d-%ld.svg", layer_idx, int(merging_area_idx)), + { { { union_ex(wall_restriction) }, { "wall_restricrictions", "gray", 0.5f } }, + { { union_ex(offset_slow) }, { "offset_slow", "red", "black", "", scaled(0.1f), 0.5f } } }); +#endif // TREESUPPORT_DEBUG_SVG + } + if (offset_fast.empty() && settings.increase_speed != slow_speed) { + if (offset_independant_faster) + offset_fast = safe_offset_inc(parent.influence_area, extra_speed + config.maximum_move_distance, + wall_restriction, safe_movement_distance, offset_independant_faster ? safe_movement_distance + radius : 0, 1); + else { + const coord_t delta_slow_fast = config.maximum_move_distance - (config.maximum_move_distance_slow + extra_slow_speed); + offset_fast = safe_offset_inc(offset_slow, delta_slow_fast, wall_restriction, safe_movement_distance, safe_movement_distance + radius, offset_independant_faster ? 2 : 1); + } +#ifdef TREESUPPORT_DEBUG_SVG + SVG::export_expolygons(debug_out_path("treesupport-increase_areas_one_layer-fast-%d-%ld.svg", layer_idx, int(merging_area_idx)), + { { { union_ex(wall_restriction) }, { "wall_restricrictions", "gray", 0.5f } }, + { { union_ex(offset_fast) }, { "offset_fast", "red", "black", "", scaled(0.1f), 0.5f } } }); +#endif // TREESUPPORT_DEBUG_SVG + } + } + std::optional result; + inc_wo_collision.clear(); + if (!settings.no_error) { + // ERROR CASE + // if the area becomes for whatever reason something that clipper sees as a line, offset would stop working, so ensure that even if if wrongly would be a line, it still actually has an area that can be increased + Polygons lines_offset = offset(to_polylines(parent.influence_area), scaled(0.005), jtMiter, 1.2); + Polygons base_error_area = union_(parent.influence_area, lines_offset); + result = increase_single_area(volumes, config, settings, layer_idx, parent, + base_error_area, to_bp_data, to_model_data, inc_wo_collision, (config.maximum_move_distance + extra_speed) * 1.5, mergelayer); +#ifdef TREE_SUPPORT_SHOW_ERRORS + BOOST_LOG_TRIVIAL(error) +#else // TREE_SUPPORT_SHOW_ERRORS + BOOST_LOG_TRIVIAL(warning) +#endif // TREE_SUPPORT_SHOW_ERRORS + << "Influence area could not be increased! Data about the Influence area: " + "Radius: " << radius << " at layer: " << layer_idx - 1 << " NextTarget: " << elem.layer_idx << " Distance to top: " << elem.distance_to_top << + " Elephant foot increases " << elem.elephant_foot_increases << " use_min_xy_dist " << elem.use_min_xy_dist << " to buildplate " << elem.to_buildplate << + " gracious " << elem.to_model_gracious << " safe " << elem.can_use_safe_radius << " until move " << elem.dont_move_until << " \n " + "Parent " << &parent << ": Radius: " << support_element_collision_radius(config, parent.state) << " at layer: " << layer_idx << " NextTarget: " << parent.state.layer_idx << + " Distance to top: " << parent.state.distance_to_top << " Elephant foot increases " << parent.state.elephant_foot_increases << " use_min_xy_dist " << parent.state.use_min_xy_dist << + " to buildplate " << parent.state.to_buildplate << " gracious " << parent.state.to_model_gracious << " safe " << parent.state.can_use_safe_radius << " until move " << parent.state.dont_move_until; + tree_supports_show_error("Potentially lost branch!"sv, true); + } else + result = increase_single_area(volumes, config, settings, layer_idx, parent, + settings.increase_speed == slow_speed ? offset_slow : offset_fast, to_bp_data, to_model_data, inc_wo_collision, 0, mergelayer); + + if (result) { + elem = *result; + radius = support_element_collision_radius(config, elem); + elem.last_area_increase = settings; + add = true; + // do not merge if the branch should not move or the priority has to be to get farther away from the model. + bypass_merge = !settings.move || (settings.use_min_distance && elem.distance_to_top < config.tip_layers); + if (settings.move) + elem.dont_move_until = 0; + else + elem.result_on_layer = parent.state.result_on_layer; + + elem.can_use_safe_radius = settings.type != AvoidanceType::Fast; + + if (!settings.use_min_distance) + elem.use_min_xy_dist = false; + if (!settings.no_error) +#ifdef TREE_SUPPORT_SHOW_ERRORS + BOOST_LOG_TRIVIAL(error) +#else // TREE_SUPPORT_SHOW_ERRORS + BOOST_LOG_TRIVIAL(info) +#endif // TREE_SUPPORT_SHOW_ERRORS + << "Trying to keep area by moving faster than intended: Success"; + break; + } else if (!settings.no_error) + BOOST_LOG_TRIVIAL(error) << "Trying to keep area by moving faster than intended: FAILURE! WRONG BRANCHES LIKLY!"; + } + + if (add) { + // Union seems useless, but some rounding errors somewhere can cause to_bp_data to be slightly bigger than it should be. + assert(! inc_wo_collision.empty() || ! to_bp_data.empty() || ! to_model_data.empty()); + Polygons max_influence_area = safe_union( + diff_clipped(inc_wo_collision, volumes.getCollision(radius, layer_idx - 1, elem.use_min_xy_dist)), + safe_union(to_bp_data, to_model_data)); + merging_area.state = elem; + assert(!max_influence_area.empty()); + merging_area.set_bbox(get_extents(max_influence_area)); + merging_area.areas.influence_areas = std::move(max_influence_area); + if (! bypass_merge) { + if (elem.to_buildplate) + merging_area.areas.to_bp_areas = std::move(to_bp_data); + if (config.support_rests_on_model) + merging_area.areas.to_model_areas = std::move(to_model_data); + } + } else { + // If the bottom most point of a branch is set, later functions will assume that the position is valid, and ignore it. + // But as branches connecting with the model that are to small have to be culled, the bottom most point has to be not set. + // A point can be set on the top most tip layer (maybe more if it should not move for a few layers). + parent.state.result_on_layer_reset(); + parent.state.to_model_gracious = false; + } + throw_on_cancel(); + } + }, tbb::simple_partitioner()); +} + +[[nodiscard]] static SupportElementState merge_support_element_states( + const SupportElementState &first, const SupportElementState &second, const Point &next_position, const coord_t layer_idx, + const TreeSupportSettings &config) +{ + SupportElementState out; + out.next_position = next_position; + out.layer_idx = layer_idx; + out.use_min_xy_dist = first.use_min_xy_dist || second.use_min_xy_dist; + out.supports_roof = first.supports_roof || second.supports_roof; + out.dont_move_until = std::max(first.dont_move_until, second.dont_move_until); + out.can_use_safe_radius = first.can_use_safe_radius || second.can_use_safe_radius; + out.missing_roof_layers = std::min(first.missing_roof_layers, second.missing_roof_layers); + out.skip_ovalisation = false; + if (first.target_height > second.target_height) { + out.target_height = first.target_height; + out.target_position = first.target_position; + } else { + out.target_height = second.target_height; + out.target_position = second.target_position; + } + out.effective_radius_height = std::max(first.effective_radius_height, second.effective_radius_height); + out.distance_to_top = std::max(first.distance_to_top, second.distance_to_top); + + out.to_buildplate = first.to_buildplate && second.to_buildplate; + out.to_model_gracious = first.to_model_gracious && second.to_model_gracious; // valid as we do not merge non-gracious with gracious + + out.elephant_foot_increases = 0; + if (config.bp_radius_increase_per_layer > 0) { + coord_t foot_increase_radius = std::abs(std::max(support_element_collision_radius(config, second), support_element_collision_radius(config, first)) - support_element_collision_radius(config, out)); + // elephant_foot_increases has to be recalculated, as when a smaller tree with a larger elephant_foot_increases merge with a larger branch + // the elephant_foot_increases may have to be lower as otherwise the radius suddenly increases. This results often in a non integer value. + out.elephant_foot_increases = foot_increase_radius / (config.bp_radius_increase_per_layer - config.branch_radius_increase_per_layer); + } + + // set last settings to the best out of both parents. If this is wrong, it will only cause a small performance penalty instead of weird behavior. + out.last_area_increase = { + std::min(first.last_area_increase.type, second.last_area_increase.type), + std::min(first.last_area_increase.increase_speed, second.last_area_increase.increase_speed), + first.last_area_increase.increase_radius || second.last_area_increase.increase_radius, + first.last_area_increase.no_error || second.last_area_increase.no_error, + first.last_area_increase.use_min_distance && second.last_area_increase.use_min_distance, + first.last_area_increase.move || second.last_area_increase.move }; + + return out; +} + +static bool merge_influence_areas_two_elements( + const TreeModelVolumes &volumes, const TreeSupportSettings &config, const LayerIndex layer_idx, + SupportElementMerging &dst, SupportElementMerging &src) +{ + // Don't merge gracious with a non gracious area as bad placement could negatively impact reliability of the whole subtree. + const bool merging_gracious_and_non_gracious = dst.state.to_model_gracious != src.state.to_model_gracious; + // Could cause some issues with the increase of one area, as it is assumed that if the smaller is increased + // by the delta to the larger it is engulfed by it already. But because a different collision + // may be removed from the in draw_area() generated circles, this assumption could be wrong. + const bool merging_min_and_regular_xy = dst.state.use_min_xy_dist != src.state.use_min_xy_dist; + + if (merging_gracious_and_non_gracious || merging_min_and_regular_xy) + return false; + + const bool dst_radius_bigger = support_element_collision_radius(config, dst.state) > support_element_collision_radius(config, src.state); + const SupportElementMerging &smaller_rad = dst_radius_bigger ? src : dst; + const SupportElementMerging &bigger_rad = dst_radius_bigger ? dst : src; + const coord_t real_radius_delta = std::abs(support_element_radius(config, bigger_rad.state) - support_element_radius(config, smaller_rad.state)); + { + // Testing intersection of bounding boxes. + // Expand the smaller radius branch bounding box to match the lambda intersect_small_with_bigger() below. + // Because the lambda intersect_small_with_bigger() applies a rounded offset, a snug offset of the bounding box + // is sufficient. On the other side, if a mitered offset was used by the lambda, + // the bounding box expansion would have to account for the mitered extension of the sharp corners. + Eigen::AlignedBox smaller_bbox = smaller_rad.bbox(); + smaller_bbox.min() -= Point{ real_radius_delta, real_radius_delta }; + smaller_bbox.max() += Point{ real_radius_delta, real_radius_delta }; + if (! smaller_bbox.intersects(bigger_rad.bbox())) + return false; + } + + // Accumulator of a radius increase of a "to model" branch by merging in a "to build plate" branch. + coord_t increased_to_model_radius = 0; + const bool merging_to_bp = dst.state.to_buildplate && src.state.to_buildplate; + if (! merging_to_bp) { + // Get the real radius increase as the user does not care for the collision model. + if (dst.state.to_buildplate != src.state.to_buildplate) { + // Merging a "to build plate" branch with a "to model" branch. + // Don't allow merging a thick "to build plate" branch into a thinner "to model" branch. + const coord_t rdst = support_element_radius(config, dst.state); + const coord_t rsrc = support_element_radius(config, src.state); + if (dst.state.to_buildplate) { + if (rsrc < rdst) + increased_to_model_radius = src.state.increased_to_model_radius + rdst - rsrc; + } else { + if (rsrc > rdst) + increased_to_model_radius = dst.state.increased_to_model_radius + rsrc - rdst; + } + if (increased_to_model_radius > config.max_to_model_radius_increase) + return false; + } + // if a merge could place a stable branch on unstable ground, would be increasing the radius further + // than allowed to when merging to model and to_bp trees or would merge to model before it is known + // they will even been drawn the merge is skipped + if (! dst.state.supports_roof && ! src.state.supports_roof && + std::max(src.state.distance_to_top, dst.state.distance_to_top) < config.min_dtt_to_model) + return false; + } + + // Area of the bigger radius is used to ensure correct placement regarding the relevant avoidance, + // so if that would change an invalid area may be created. + if (! bigger_rad.state.can_use_safe_radius && smaller_rad.state.can_use_safe_radius) + return false; + + // the bigger radius is used to verify that the area is still valid after the increase with the delta. + // If there were a point where the big influence area could be valid with can_use_safe_radius + // the element would already be can_use_safe_radius. + // the smaller radius, which gets increased by delta may reach into the area where use_min_xy_dist is no longer required. + const bool use_min_radius = bigger_rad.state.use_min_xy_dist && smaller_rad.state.use_min_xy_dist; + + // The idea is that the influence area with the smaller collision radius is increased by the radius difference. + // If this area has any intersections with the influence area of the larger collision radius, a branch (of the larger collision radius) placed in this intersection, has already engulfed the branch of the smaller collision radius. + // Because of this a merge may happen even if the influence areas (that represent possible center points of branches) do not intersect yet. + // Remember that collision radius <= real radius as otherwise this assumption would be false. + const coord_t smaller_collision_radius = support_element_collision_radius(config, smaller_rad.state); + const Polygons &collision = volumes.getCollision(smaller_collision_radius, layer_idx - 1, use_min_radius); + auto intersect_small_with_bigger = [real_radius_delta, smaller_collision_radius, &collision, &config](const Polygons &small, const Polygons &bigger) { + return intersection( + safe_offset_inc( + small, real_radius_delta, collision, + // -3 avoids possible rounding errors + 2 * (config.xy_distance + smaller_collision_radius - 3), 0, 0), + bigger); + }; + Polygons intersect = intersect_small_with_bigger( + merging_to_bp ? smaller_rad.areas.to_bp_areas : smaller_rad.areas.to_model_areas, + merging_to_bp ? bigger_rad.areas.to_bp_areas : bigger_rad.areas.to_model_areas); + + // dont use empty as a line is not empty, but for this use-case it very well may be (and would be one layer down as union does not keep lines) + // check if the overlap is large enough (Small ares tend to attract rounding errors in clipper). + if (area(intersect) <= tiny_area_threshold) + return false; + + // While 0.025 was guessed as enough, i did not have reason to change it. + if (area(offset(intersect, scaled(-0.025), jtMiter, 1.2)) <= tiny_area_threshold) + return false; + + // Do the actual merge now that the branches are confirmed to be able to intersect. + // calculate which point is closest to the point of the last merge (or tip center if no merge above it has happened) + // used at the end to estimate where to best place the branch on the bottom most layer + // could be replaced with a random point inside the new area + Point new_pos = move_inside_if_outside(intersect, dst.state.next_position); + + SupportElementState new_state = merge_support_element_states(dst.state, src.state, new_pos, layer_idx - 1, config); + new_state.increased_to_model_radius = increased_to_model_radius == 0 ? + // increased_to_model_radius was not set yet. Propagate maximum. + std::max(dst.state.increased_to_model_radius, src.state.increased_to_model_radius) : + increased_to_model_radius; + + // Rather unioning with "intersect" due to some rounding errors. + Polygons influence_areas = safe_union( + intersect_small_with_bigger(smaller_rad.areas.influence_areas, bigger_rad.areas.influence_areas), + intersect); + + Polygons to_model_areas; + if (merging_to_bp && config.support_rests_on_model) + to_model_areas = new_state.to_model_gracious ? + // Rather unioning with "intersect" due to some rounding errors. + safe_union( + intersect_small_with_bigger(smaller_rad.areas.to_model_areas, bigger_rad.areas.to_model_areas), + intersect) : + influence_areas; + + dst.parents.insert(dst.parents.end(), src.parents.begin(), src.parents.end()); + dst.state = new_state; + dst.areas.influence_areas = std::move(influence_areas); + dst.areas.to_bp_areas.clear(); + dst.areas.to_model_areas.clear(); + if (merging_to_bp) { + dst.areas.to_bp_areas = std::move(intersect); + if (config.support_rests_on_model) + dst.areas.to_model_areas = std::move(to_model_areas); + } else + dst.areas.to_model_areas = std::move(intersect); + // Update the bounding box. + BoundingBox bbox(get_extents(dst.areas.influence_areas)); + bbox.merge(get_extents(dst.areas.to_bp_areas)); + bbox.merge(get_extents(dst.areas.to_model_areas)); + dst.set_bbox(bbox); + // Clear the source data. + src.areas.clear(); + src.parents.clear(); + return true; +} + +/*! + * \brief Merges Influence Areas if possible. + * + * Branches which do overlap have to be merged. This helper merges all elements in input with the elements into reduced_new_layer. + * Elements in input_aabb are merged together if possible, while elements reduced_new_layer_aabb are not checked against each other. + * + * \param reduced_aabb[in,out] The already processed elements. + * \param input_aabb[in] Not yet processed elements + * \param to_bp_areas[in] The Elements of the current Layer that will reach the buildplate. Value is the influence area where the center of a circle of support may be placed. + * \param to_model_areas[in] The Elements of the current Layer that do not have to reach the buildplate. Also contains main as every element that can reach the buildplate is not forced to. + * Value is the influence area where the center of a circle of support may be placed. + * \param influence_areas[in] The influence areas without avoidance removed. + * \param insert_bp_areas[out] Elements to be inserted into the main dictionary after the Helper terminates. + * \param insert_model_areas[out] Elements to be inserted into the secondary dictionary after the Helper terminates. + * \param insert_influence[out] Elements to be inserted into the dictionary containing the largest possibly valid influence area (ignoring if the area may not be there because of avoidance) + * \param erase[out] Elements that should be deleted from the above dictionaries. + * \param layer_idx[in] The Index of the current Layer. + */ + +static SupportElementMerging* merge_influence_areas_leaves( + const TreeModelVolumes &volumes, const TreeSupportSettings &config, const LayerIndex layer_idx, + SupportElementMerging * const dst_begin, SupportElementMerging *dst_end) +{ + // Merging at the lowest level of the AABB tree. Checking one against each other, O(n^2). + assert(dst_begin < dst_end); + for (SupportElementMerging *i = dst_begin; i + 1 < dst_end;) { + for (SupportElementMerging *j = i + 1; j != dst_end;) + if (merge_influence_areas_two_elements(volumes, config, layer_idx, *i, *j)) { + // i was merged with j, j is empty. + if (j != -- dst_end) + *j = std::move(*dst_end); + goto merged; + } else + ++ j; + // not merged + ++ i; + merged: + ; + } + return dst_end; +} + +static SupportElementMerging* merge_influence_areas_two_sets( + const TreeModelVolumes &volumes, const TreeSupportSettings &config, const LayerIndex layer_idx, + SupportElementMerging * const dst_begin, SupportElementMerging * dst_end, + SupportElementMerging * src_begin, SupportElementMerging * const src_end) +{ + // Merging src into dst. + // Areas of src should not overlap with areas of another elements of src. + // Areas of dst should not overlap with areas of another elements of dst. + // The memory from dst_begin to src_end is reserved for the merging operation, + // src follows dst. + assert(src_begin < src_end); + assert(dst_begin < dst_end); + assert(dst_end <= src_begin); + for (SupportElementMerging *src = src_begin; src != src_end; ++ src) { + SupportElementMerging *dst = dst_begin; + SupportElementMerging *merged = nullptr; + for (; dst != dst_end; ++ dst) + if (merge_influence_areas_two_elements(volumes, config, layer_idx, *dst, *src)) { + merged = dst ++; + if (src != src_begin) + // Compactify src. + *src = std::move(*src_begin); + ++ src_begin; + break; + } + for (; dst != dst_end;) + if (merge_influence_areas_two_elements(volumes, config, layer_idx, *merged, *dst)) { + // Compactify dst. + if (dst != -- dst_end) + *dst = std::move(*dst_end); + } else + ++ dst; + } + // Compactify src elements that were not merged with dst to the end of dst. + assert(dst_end <= src_begin); + if (dst_end == src_begin) + dst_end = src_end; + else + while (src_begin != src_end) + *dst_end ++ = std::move(*src_begin ++); + + return dst_end; +} + +/*! + * \brief Merges Influence Areas at one layer if possible. + * + * Branches which do overlap have to be merged. This manages the helper and uses a divide and conquer approach to parallelize this problem. This parallelization can at most accelerate the merging by a factor of 2. + * + * \param to_bp_areas[in] The Elements of the current Layer that will reach the buildplate. + * Value is the influence area where the center of a circle of support may be placed. + * \param to_model_areas[in] The Elements of the current Layer that do not have to reach the buildplate. Also contains main as every element that can reach the buildplate is not forced to. + * Value is the influence area where the center of a circle of support may be placed. + * \param influence_areas[in] The Elements of the current Layer without avoidances removed. This is the largest possible influence area for this layer. + * Value is the influence area where the center of a circle of support may be placed. + * \param layer_idx[in] The current layer. + */ +static void merge_influence_areas( + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const LayerIndex layer_idx, + std::vector &influence_areas, + std::function throw_on_cancel) +{ + const size_t input_size = influence_areas.size(); + if (input_size == 0) + return; + + // Merging by divide & conquer. + // The majority of time is consumed by Clipper polygon operations, intersection is accelerated by bounding boxes. + // Sorting input into an AABB tree helps to perform most of the intersections at first iterations, + // thus reducing computation when merging larger subtrees. + // The actual merge logic is found in merge_influence_areas_two_sets. + + // Build an AABB tree over the influence areas. + //FIXME A full tree does not need to be built, the lowest level branches will be always bucketed. + // However the additional time consumed is negligible. + AABBTreeIndirect::Tree<2, coord_t> tree; + // Sort influence_areas in place. + tree.build_modify_input(influence_areas); + + throw_on_cancel(); + + // Prepare the initial buckets as ranges of influence areas. The initial buckets contain power of 2 influence areas to follow + // the branching of the AABB tree. + // Vectors of ranges of influence areas, following the branching of the AABB tree: + std::vector> buckets; + // Initial number of buckets for 1st round of merging. + size_t num_buckets_initial; + { + // How many buckets per first merge iteration? + const size_t num_threads = tbb::this_task_arena::max_concurrency(); + // 4 buckets per thread if possible, + const size_t num_buckets_min = (input_size + 2) / 4; + // 2 buckets per thread otherwise. + const size_t num_buckets_max = input_size / 2; + num_buckets_initial = num_buckets_min >= num_threads ? num_buckets_min : num_buckets_max; + const size_t bucket_size = num_buckets_min >= num_threads ? 4 : 2; + // Fill in the buckets. + SupportElementMerging *it = influence_areas.data(); + // Reserve one more bucket to keep a single influence area which will not be merged in the first iteration. + buckets.reserve(num_buckets_initial + 1); + for (size_t i = 0; i < num_buckets_initial; ++ i, it += bucket_size) + buckets.emplace_back(std::make_pair(it, it + bucket_size)); + SupportElementMerging *it_end = influence_areas.data() + influence_areas.size(); + if (buckets.back().second >= it_end) { + // Last bucket is less than size 4, but bigger than size 1. + buckets.back().second = std::min(buckets.back().second, it_end); + } else { + // Last bucket is size 1, it will not be merged in the first iteration. + assert(it + 1 == it_end); + buckets.emplace_back(std::make_pair(it, it_end)); + } + } + + // 1st merge iteration, merge one with each other. + tbb::parallel_for(tbb::blocked_range(0, num_buckets_initial), + [&](const tbb::blocked_range &range) { + for (size_t idx = range.begin(); idx < range.end(); ++ idx) { + // Merge bucket_count adjacent to each other, merging uneven bucket numbers into even buckets + buckets[idx].second = merge_influence_areas_leaves(volumes, config, layer_idx, buckets[idx].first, buckets[idx].second); + throw_on_cancel(); + } + }); + + // Further merge iterations, merging one AABB subtree with another one, hopefully minimizing intersections between the elements + // of each of the subtree. + while (buckets.size() > 1) { + tbb::parallel_for(tbb::blocked_range(0, buckets.size() / 2), + [&](const tbb::blocked_range &range) { + for (size_t idx = range.begin(); idx < range.end(); ++ idx) { + const size_t bucket_pair_idx = idx * 2; + // Merge bucket_count adjacent to each other, merging uneven bucket numbers into even buckets + buckets[bucket_pair_idx].second = merge_influence_areas_two_sets(volumes, config, layer_idx, + buckets[bucket_pair_idx].first, buckets[bucket_pair_idx].second, + buckets[bucket_pair_idx + 1].first, buckets[bucket_pair_idx + 1].second); + throw_on_cancel(); + } + }); + // Remove odd buckets, which were merged into even buckets. + size_t new_size = (buckets.size() + 1) / 2; + for (size_t i = 1; i < new_size; ++ i) + buckets[i] = std::move(buckets[i * 2]); + buckets.erase(buckets.begin() + new_size, buckets.end()); + } +} + +/*! + * \brief Propagates influence downwards, and merges overlapping ones. + * + * \param move_bounds[in,out] All currently existing influence areas + */ +void create_layer_pathing(const TreeModelVolumes &volumes, const TreeSupportSettings &config, std::vector &move_bounds, std::function throw_on_cancel) +{ +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + const double data_size_inverse = 1 / double(move_bounds.size()); + double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES; +#endif // SLIC3R_TREESUPPORTS_PROGRESS + + auto dur_inc = std::chrono::duration_values::zero(); + auto dur_total = std::chrono::duration_values::zero(); + + LayerIndex last_merge_layer_idx = move_bounds.size(); + bool new_element = false; + + // Ensures at least one merge operation per 3mm height, 50 layers, 1 mm movement of slow speed or 5mm movement of fast speed (whatever is lowest). Values were guessed. + size_t max_merge_every_x_layers = std::min(std::min(5000 / (std::max(config.maximum_move_distance, coord_t(100))), 1000 / std::max(config.maximum_move_distance_slow, coord_t(20))), 3000 / config.layer_height); + size_t merge_every_x_layers = 1; + // Calculate the influence areas for each layer below (Top down) + // This is done by first increasing the influence area by the allowed movement distance, and merging them with other influence areas if possible + for (int layer_idx = int(move_bounds.size()) - 1; layer_idx > 0; -- layer_idx) + if (SupportElements &prev_layer = move_bounds[layer_idx]; ! prev_layer.empty()) { + // merging is expensive and only parallelized to a max speedup of 2. As such it may be useful in some cases to only merge every few layers to improve performance. + bool had_new_element = new_element; + const bool merge_this_layer = had_new_element || size_t(last_merge_layer_idx - layer_idx) >= merge_every_x_layers; + if (had_new_element) + merge_every_x_layers = 1; + const auto ta = std::chrono::high_resolution_clock::now(); + + // ### Increase the influence areas by the allowed movement distance + std::vector influence_areas; + influence_areas.reserve(prev_layer.size()); + for (int32_t element_idx = 0; element_idx < int32_t(prev_layer.size()); ++ element_idx) { + SupportElement &el = prev_layer[element_idx]; + assert(!el.influence_area.empty()); + SupportElement::ParentIndices parents; + parents.emplace_back(element_idx); + influence_areas.push_back({ el.state, parents }); + } + increase_areas_one_layer(volumes, config, influence_areas, layer_idx, prev_layer, merge_this_layer, throw_on_cancel); + + // Place already fully constructed elements to the output, remove them from influence_areas. + SupportElements &this_layer = move_bounds[layer_idx - 1]; + influence_areas.erase(std::remove_if(influence_areas.begin(), influence_areas.end(), + [&this_layer, layer_idx](SupportElementMerging &elem) { + if (elem.areas.influence_areas.empty()) + // This area was removed completely due to collisions. + return true; + if (elem.areas.to_bp_areas.empty() && elem.areas.to_model_areas.empty()) { + if (area(elem.areas.influence_areas) < tiny_area_threshold) { + BOOST_LOG_TRIVIAL(error) << "Insert Error of Influence area bypass on layer " << layer_idx - 1; + tree_supports_show_error("Insert error of area after bypassing merge.\n"sv, true); + } + // Move the area to output. + this_layer.emplace_back(elem.state, std::move(elem.parents), std::move(elem.areas.influence_areas)); + return true; + } + // Keep the area. + return false; + }), + influence_areas.end()); + + dur_inc += std::chrono::high_resolution_clock::now() - ta; + new_element = ! move_bounds[layer_idx - 1].empty(); + if (merge_this_layer) { + bool reduced_by_merging = false; + if (size_t count_before_merge = influence_areas.size(); count_before_merge > 1) { + // ### Calculate which influence areas overlap, and merge them into a new influence area (simplified: an intersection of influence areas that have such an intersection) + merge_influence_areas(volumes, config, layer_idx, influence_areas, throw_on_cancel); + reduced_by_merging = count_before_merge > influence_areas.size(); + } + last_merge_layer_idx = layer_idx; + if (! reduced_by_merging && ! had_new_element) + merge_every_x_layers = std::min(max_merge_every_x_layers, merge_every_x_layers + 1); + } + + dur_total += std::chrono::high_resolution_clock::now() - ta; + + // Save calculated elements to output, and allocate Polygons on heap, as they will not be changed again. + for (SupportElementMerging &elem : influence_areas) + if (! elem.areas.influence_areas.empty()) { + Polygons new_area = safe_union(elem.areas.influence_areas); + if (area(new_area) < tiny_area_threshold) { + BOOST_LOG_TRIVIAL(error) << "Insert Error of Influence area on layer " << layer_idx - 1 << ". Origin of " << elem.parents.size() << " areas. Was to bp " << elem.state.to_buildplate; + tree_supports_show_error("Insert error of area after merge.\n"sv, true); + } + this_layer.emplace_back(elem.state, std::move(elem.parents), std::move(new_area)); + } + + #ifdef SLIC3R_TREESUPPORTS_PROGRESS + progress_total += data_size_inverse * TREE_PROGRESS_AREA_CALC; + Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * m_progress_multiplier + m_progress_offset, TREE_PROGRESS_TOTAL); + #endif + throw_on_cancel(); + } + + BOOST_LOG_TRIVIAL(info) << "Time spent with creating influence areas' subtasks: Increasing areas " << dur_inc.count() / 1000000 << + " ms merging areas: " << (dur_total - dur_inc).count() / 1000000 << " ms"; +} + +/*! + * \brief Sets the result_on_layer for all parents based on the SupportElement supplied. + * + * \param elem[in] The SupportElements, which parent's position should be determined. + */ +static void set_points_on_areas(const SupportElement &elem, SupportElements *layer_above) +{ + assert(!elem.state.deleted); + assert(layer_above != nullptr || elem.parents.empty()); + + // Based on the branch center point of the current layer, the point on the next (further up) layer is calculated. + if (! elem.state.result_on_layer_is_set()) { + BOOST_LOG_TRIVIAL(error) << "Uninitialized support element"; + tree_supports_show_error("Uninitialized support element. A branch may be missing.\n"sv, true); + return; + } + + if (layer_above) + for (int32_t next_elem_idx : elem.parents) { + assert(next_elem_idx >= 0); + SupportElement &next_elem = (*layer_above)[next_elem_idx]; + assert(! next_elem.state.deleted); + // if the value was set somewhere else it it kept. This happens when a branch tries not to move after being unable to create a roof. + if (! next_elem.state.result_on_layer_is_set()) { + // Move inside has edgecases (see tests) so DONT use Polygons.inside to confirm correct move, Error with distance 0 is <= 1 + // it is not required to check if how far this move moved a point as is can be larger than maximum_movement_distance. + // While this seems like a problem it may for example occur after merges. + next_elem.state.result_on_layer = move_inside_if_outside(next_elem.influence_area, elem.state.result_on_layer); + // do not call recursive because then amount of layers would be restricted by the stack size + } + // Mark the parent element as accessed from a valid child element. + next_elem.state.marked = true; + } +} + +static void set_to_model_contact_simple(SupportElement &elem) +{ + const Point best = move_inside_if_outside(elem.influence_area, elem.state.next_position); + elem.state.result_on_layer = best; + BOOST_LOG_TRIVIAL(debug) << "Added NON gracious Support On Model Point (" << best.x() << "," << best.y() << "). The current layer is " << elem.state.layer_idx; +} + +/*! + * \brief Get the best point to connect to the model and set the result_on_layer of the relevant SupportElement accordingly. + * + * \param move_bounds[in,out] All currently existing influence areas + * \param first_elem[in,out] SupportElement that did not have its result_on_layer set meaning that it does not have a child element. + * \param layer_idx[in] The current layer. + */ +static void set_to_model_contact_to_model_gracious( + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + std::vector &move_bounds, + SupportElement &first_elem, + std::function throw_on_cancel) +{ + SupportElement *last_successfull_layer = nullptr; + + // check for every layer upwards, up to the point where this influence area was created (either by initial insert or merge) if the branch could be placed on it, and highest up layer index. + { + SupportElement *elem = &first_elem; + for (LayerIndex layer_check = elem->state.layer_idx; + ! intersection(elem->influence_area, volumes.getPlaceableAreas(support_element_collision_radius(config, elem->state), layer_check, throw_on_cancel)).empty(); + elem = &move_bounds[++ layer_check][elem->parents.front()]) { + assert(elem->state.layer_idx == layer_check); + assert(! elem->state.deleted); + assert(elem->state.to_model_gracious); + last_successfull_layer = elem; + if (elem->parents.size() != 1) + // Reached merge point. + break; + } + } + + // Could not find valid placement, even though it should exist => error handling + if (last_successfull_layer == nullptr) { + BOOST_LOG_TRIVIAL(warning) << "No valid placement found for to model gracious element on layer " << first_elem.state.layer_idx; + tree_supports_show_error("Could not fine valid placement on model! Just placing it down anyway. Could cause floating branches."sv, true); + first_elem.state.to_model_gracious = false; + set_to_model_contact_simple(first_elem); + } else { + // Found a gracious area above first_elem. Remove all below last_successfull_layer. + { + LayerIndex parent_layer_idx = first_elem.state.layer_idx; + for (SupportElement *elem = &first_elem; elem != last_successfull_layer; elem = &move_bounds[++ parent_layer_idx][elem->parents.front()]) { + assert(! elem->state.deleted); + elem->state.deleted = true; + } + } + // Guess a point inside the influence area, in which the branch will be placed in. + const Point best = move_inside_if_outside(last_successfull_layer->influence_area, last_successfull_layer->state.next_position); + last_successfull_layer->state.result_on_layer = best; + BOOST_LOG_TRIVIAL(debug) << "Added gracious Support On Model Point (" << best.x() << "," << best.y() << "). The current layer is " << last_successfull_layer; + } +} + +// Remove elements marked as "deleted", update indices to parents. +static void remove_deleted_elements(std::vector &move_bounds) +{ + std::vector map_parents; + std::vector map_current; + for (LayerIndex layer_idx = LayerIndex(move_bounds.size()) - 1; layer_idx >= 0; -- layer_idx) { + SupportElements &layer = move_bounds[layer_idx]; + map_current.clear(); + for (int32_t i = 0; i < int32_t(layer.size());) { + SupportElement &element = layer[i]; + if (element.state.deleted) { + if (map_current.empty()) { + // Initialize with identity map. + map_current.assign(layer.size(), 0); + std::iota(map_current.begin(), map_current.end(), 0); + } + // Delete all "deleted" elements from the end of the layer vector. + while (i < int32_t(layer.size()) && layer.back().state.deleted) { + layer.pop_back(); + // Mark as deleted in the map. + map_current[layer.size()] = -1; + } + assert(i == layer.size() || i + 1 < layer.size()); + if (i + 1 < int32_t(layer.size())) { + element = std::move(layer.back()); + layer.pop_back(); + // Mark the current element as deleted. + map_current[i] = -1; + // Mark the moved element as moved to index i. + map_current[layer.size()] = i; + } + } else { + // Current element is not deleted. Update its parent indices. + if (! map_parents.empty()) + for (int32_t &parent_idx : element.parents) + parent_idx = map_parents[parent_idx]; + ++ i; + } + } + std::swap(map_current, map_parents); + } +} + +/*! + * \brief Set the result_on_layer point for all influence areas + * + * \param move_bounds[in,out] All currently existing influence areas + */ +void create_nodes_from_area( + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + std::vector &move_bounds, + std::function throw_on_cancel) +{ + // Initialize points on layer 0, with a "random" point in the influence area. + // Point is chosen based on an inaccurate estimate where the branches will split into two, but every point inside the influence area would produce a valid result. + { + SupportElements *layer_above = move_bounds.size() > 1 ? &move_bounds[1] : nullptr; + if (layer_above) { + for (SupportElement &elem : *layer_above) + elem.state.marked = false; + } + for (SupportElement &init : move_bounds.front()) { + init.state.result_on_layer = move_inside_if_outside(init.influence_area, init.state.next_position); + // Also set the parent nodes, as these will be required for the first iteration of the loop below and mark the parent nodes. + set_points_on_areas(init, layer_above); + } + } + + throw_on_cancel(); + + for (LayerIndex layer_idx = 1; layer_idx < LayerIndex(move_bounds.size()); ++ layer_idx) { + auto &layer = move_bounds[layer_idx]; + auto *layer_above = layer_idx + 1 < LayerIndex(move_bounds.size()) ? &move_bounds[layer_idx + 1] : nullptr; + if (layer_above) + for (SupportElement &elem : *layer_above) + elem.state.marked = false; + for (SupportElement &elem : layer) { + assert(! elem.state.deleted); + assert(elem.state.layer_idx == layer_idx); + // check if the resulting center point is not yet set + if (! elem.state.result_on_layer_is_set()) { + if (elem.state.to_buildplate || (elem.state.distance_to_top < config.min_dtt_to_model && ! elem.state.supports_roof)) { + if (elem.state.to_buildplate) { + BOOST_LOG_TRIVIAL(error) << "Uninitialized Influence area targeting " << elem.state.target_position.x() << "," << elem.state.target_position.y() << ") " + "at target_height: " << elem.state.target_height << " layer: " << layer_idx; + tree_supports_show_error("Uninitialized support element! A branch could be missing or exist partially."sv, true); + } + // we dont need to remove yet the parents as they will have a lower dtt and also no result_on_layer set + elem.state.deleted = true; + } else { + // set the point where the branch will be placed on the model + if (elem.state.to_model_gracious) + set_to_model_contact_to_model_gracious(volumes, config, move_bounds, elem, throw_on_cancel); + else + set_to_model_contact_simple(elem); + } + } + if (! elem.state.deleted && ! elem.state.marked && elem.state.target_height == layer_idx) + // Just a tip surface with no supporting element. + elem.state.deleted = true; + if (elem.state.deleted) { + for (int32_t parent_idx : elem.parents) + // When the roof was not able to generate downwards enough, the top elements may have not moved, and have result_on_layer already set. + // As this branch needs to be removed => all parents result_on_layer have to be invalidated. + (*layer_above)[parent_idx].state.result_on_layer_reset(); + } + if (! elem.state.deleted) { + // Element is valid now setting points in the layer above and mark the parent nodes. + set_points_on_areas(elem, layer_above); + } + } + throw_on_cancel(); + } + +#ifndef NDEBUG + // Verify the tree connectivity including the branch slopes. + for (LayerIndex layer_idx = 0; layer_idx + 1 < LayerIndex(move_bounds.size()); ++ layer_idx) { + auto &layer = move_bounds[layer_idx]; + auto &above = move_bounds[layer_idx + 1]; + for (SupportElement &elem : layer) + if (! elem.state.deleted) { + for (int32_t iparent : elem.parents) { + SupportElement &parent = above[iparent]; + assert(! parent.state.deleted); + assert(elem.state.result_on_layer_is_set() == parent.state.result_on_layer_is_set()); + if (elem.state.result_on_layer_is_set()) { + double radius_increase = support_element_radius(config, elem) - support_element_radius(config, parent); + assert(radius_increase >= 0); + double shift = (elem.state.result_on_layer - parent.state.result_on_layer).cast().norm(); + //FIXME this assert fails a lot. Is it correct? + //assert(shift < radius_increase + 2. * config.maximum_move_distance_slow); + } + } + } + } +#endif // NDEBUG + + remove_deleted_elements(move_bounds); + +#ifndef NDEBUG + // Verify the tree connectivity including the branch slopes. + for (LayerIndex layer_idx = 0; layer_idx + 1 < LayerIndex(move_bounds.size()); ++ layer_idx) { + auto &layer = move_bounds[layer_idx]; + auto &above = move_bounds[layer_idx + 1]; + for (SupportElement &elem : layer) { + assert(! elem.state.deleted); + for (int32_t iparent : elem.parents) { + SupportElement &parent = above[iparent]; + assert(! parent.state.deleted); + assert(elem.state.result_on_layer_is_set() == parent.state.result_on_layer_is_set()); + if (elem.state.result_on_layer_is_set()) { + double radius_increase = support_element_radius(config, elem) - support_element_radius(config, parent); + assert(radius_increase >= 0); + double shift = (elem.state.result_on_layer - parent.state.result_on_layer).cast().norm(); + //FIXME this assert fails a lot. Is it correct? + //assert(shift < radius_increase + 2. * config.maximum_move_distance_slow); + } + } + } + } +#endif // NDEBUG +} + +// For producing circular / elliptical areas from SupportElements (one DrawArea per one SupportElement) +// and for smoothing those areas along the tree branches. +struct DrawArea +{ + // Element to be processed. + SupportElement *element; + // Element below, if there is such an element. nullptr if element is a root of a tree. + SupportElement *child_element; + // Polygons to be extruded for this element. + Polygons polygons; +}; + +/*! + * \brief Draws circles around result_on_layer points of the influence areas + * + * \param linear_data[in] All currently existing influence areas with the layer they are on + * \param layer_tree_polygons[out] Resulting branch areas with the layerindex they appear on. layer_tree_polygons.size() has to be at least linear_data.size() as each Influence area in linear_data will save have at least one (that's why it's a vector) corresponding branch area in layer_tree_polygons. + * \param inverse_tree_order[in] A mapping that returns the child of every influence area. + */ +static void generate_branch_areas( + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const std::vector &move_bounds, + std::vector &linear_data, + std::function throw_on_cancel) +{ +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC; + constexpr int progress_report_steps = 10; + const size_t progress_inserts_check_interval = linear_data.size() / progress_report_steps; + std::mutex critical_sections; +#endif // SLIC3R_TREESUPPORTS_PROGRESS + + // Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time. + const Polygon branch_circle = make_circle(config.branch_radius, SUPPORT_TREE_CIRCLE_RESOLUTION); + + tbb::parallel_for(tbb::blocked_range(0, linear_data.size()), + [&volumes, &config, &move_bounds, &linear_data, &branch_circle, &throw_on_cancel](const tbb::blocked_range &range) { + for (size_t idx = range.begin(); idx < range.end(); ++ idx) { + DrawArea &draw_area = linear_data[idx]; + const LayerIndex layer_idx = draw_area.element->state.layer_idx; + const coord_t radius = support_element_radius(config, *draw_area.element); + bool parent_uses_min = false; + + // Calculate multiple ovalized circles, to connect with every parent and child. Also generate regular circle for the current layer. Merge all these into one area. + std::vector> movement_directions{ std::pair(Point(0, 0), radius) }; + if (! draw_area.element->state.skip_ovalisation) { + if (draw_area.child_element != nullptr) { + const Point movement = draw_area.child_element->state.result_on_layer - draw_area.element->state.result_on_layer; + movement_directions.emplace_back(movement, radius); + } + const SupportElements *layer_above = layer_idx + 1 < LayerIndex(move_bounds.size()) ? &move_bounds[layer_idx + 1] : nullptr; + for (int32_t parent_idx : draw_area.element->parents) { + const SupportElement &parent = (*layer_above)[parent_idx]; + const Point movement = parent.state.result_on_layer - draw_area.element->state.result_on_layer; + //FIXME why max(..., config.support_line_width)? + movement_directions.emplace_back(movement, std::max(support_element_radius(config, parent), config.support_line_width)); + parent_uses_min |= parent.state.use_min_xy_dist; + } + } + + const Polygons &collision = volumes.getCollision(0, layer_idx, parent_uses_min || draw_area.element->state.use_min_xy_dist); + auto generateArea = [&collision, &draw_area, &branch_circle, branch_radius = config.branch_radius, support_line_width = config.support_line_width, &movement_directions] + (coord_t aoffset, double &max_speed) { + Polygons poly; + max_speed = 0; + for (std::pair movement : movement_directions) { + max_speed = std::max(max_speed, movement.first.cast().norm()); + + // Visualization: https://jsfiddle.net/0zvcq39L/2/ + // Ovalizes the circle to an ellipse, that contains both old center and new target position. + double used_scale = (movement.second + aoffset) / (1.0 * branch_radius); + Point center_position = draw_area.element->state.result_on_layer + movement.first / 2; + const double moveX = movement.first.x() / (used_scale * branch_radius); + const double moveY = movement.first.y() / (used_scale * branch_radius); + const double vsize_inv = 0.5 / (0.01 + std::sqrt(moveX * moveX + moveY * moveY)); + + double matrix[] = { + used_scale * (1 + moveX * moveX * vsize_inv), + used_scale * (0 + moveX * moveY * vsize_inv), + used_scale * (0 + moveX * moveY * vsize_inv), + used_scale * (1 + moveY * moveY * vsize_inv), + }; + Polygon circle; + for (Point vertex : branch_circle) + circle.points.emplace_back(center_position + Point(matrix[0] * vertex.x() + matrix[1] * vertex.y(), matrix[2] * vertex.x() + matrix[3] * vertex.y())); + poly.emplace_back(std::move(circle)); + } + + // There seem to be some rounding errors, causing a branch to be a tiny bit further away from the model that it has to be. + // This can cause the tip to be slightly further away front the overhang (x/y wise) than optimal. This fixes it, and for every other part, 0.05mm will not be noticed. + poly = diff_clipped(offset(union_(poly), std::min(coord_t(50), support_line_width / 4), jtMiter, 1.2), collision); + return poly; + }; + + // Ensure branch area will not overlap with model/collision. This can happen because of e.g. ovalization or increase_until_radius. + double max_speed; + Polygons polygons = generateArea(0, max_speed); + const bool fast_relative_movement = max_speed > radius * 0.75; + + if (fast_relative_movement || support_element_radius(config, *draw_area.element) - support_element_collision_radius(config, draw_area.element->state) > config.support_line_width) { + // Simulate the path the nozzle will take on the outermost wall. + // If multiple parts exist, the outer line will not go all around the support part potentially causing support material to be printed mid air. + ExPolygons nozzle_path = offset_ex(polygons, - config.support_line_width / 2); + if (nozzle_path.size() > 1) { + // Just try to make the area a tiny bit larger. + polygons = generateArea(config.support_line_width / 2, max_speed); + nozzle_path = offset_ex(polygons, -config.support_line_width / 2); + // If larger area did not fix the problem, all parts off the nozzle path that do not contain the center point are removed, hoping for the best. + if (nozzle_path.size() > 1) { + ExPolygons polygons_with_correct_center; + for (ExPolygon &part : nozzle_path) { + bool drop = false; + if (! part.contains(draw_area.element->state.result_on_layer)) { + // try a fuzzy inside as sometimes the point should be on the border, but is not because of rounding errors... + Point pt = draw_area.element->state.result_on_layer; + move_inside(to_polygons(part), pt, 0); + drop = (draw_area.element->state.result_on_layer - pt).cast().norm() >= scaled(0.025); + } + if (! drop) + polygons_with_correct_center.emplace_back(std::move(part)); + } + // Increase the area again, to ensure the nozzle path when calculated later is very similar to the one assumed above. + assert(contains(polygons, draw_area.element->state.result_on_layer)); + polygons = diff_clipped(offset(polygons_with_correct_center, config.support_line_width / 2, jtMiter, 1.2), + //FIXME Vojtech: Clipping may split the region into multiple pieces again, reversing the fixing effort. + collision); + } + } + } + + draw_area.polygons = std::move(polygons); + +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + if (idx % progress_inserts_check_interval == 0) { + std::lock_guard critical_section_progress(critical_sections); + progress_total += TREE_PROGRESS_GENERATE_BRANCH_AREAS / progress_report_steps; + Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * m_progress_multiplier + m_progress_offset, TREE_PROGRESS_TOTAL); + } +#endif + throw_on_cancel(); + } + }); +} + +/*! + * \brief Applies some smoothing to the outer wall, intended to smooth out sudden jumps as they can happen when a branch moves though a hole. + * + * \param layer_tree_polygons[in,out] Resulting branch areas with the layerindex they appear on. + */ +static void smooth_branch_areas( + const TreeSupportSettings &config, + std::vector &move_bounds, + std::vector &linear_data, + const std::vector &linear_data_layers, + std::function throw_on_cancel) +{ +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS; +#endif // SLIC3R_TREESUPPORTS_PROGRESS + + const coord_t max_radius_change_per_layer = 1 + config.support_line_width / 2; // this is the upper limit a radius may change per layer. +1 to avoid rounding errors + + // smooth upwards + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()) - 1; ++ layer_idx) { + const size_t processing_base = linear_data_layers[layer_idx]; + const size_t processing_base_above = linear_data_layers[layer_idx + 1]; + const SupportElements &layer_above = move_bounds[layer_idx + 1]; + tbb::parallel_for(tbb::blocked_range(0, processing_base_above - processing_base), + [&](const tbb::blocked_range &range) { + for (size_t processing_idx = range.begin(); processing_idx < range.end(); ++ processing_idx) { + DrawArea &draw_area = linear_data[processing_base + processing_idx]; + assert(draw_area.element->state.layer_idx == layer_idx); + double max_outer_wall_distance = 0; + bool do_something = false; + for (int32_t parent_idx : draw_area.element->parents) { + const SupportElement &parent = layer_above[parent_idx]; + assert(parent.state.layer_idx == layer_idx + 1); + if (support_element_radius(config, parent) != support_element_collision_radius(config, parent)) { + do_something = true; + max_outer_wall_distance = std::max(max_outer_wall_distance, + (draw_area.element->state.result_on_layer - parent.state.result_on_layer).cast().norm() - (support_element_radius(config, *draw_area.element) - support_element_radius(config, parent))); + } + } + max_outer_wall_distance += max_radius_change_per_layer; // As this change is a bit larger than what usually appears, lost radius can be slowly reclaimed over the layers. + if (do_something) { + assert(contains(draw_area.polygons, draw_area.element->state.result_on_layer)); + Polygons max_allowed_area = offset(draw_area.polygons, float(max_outer_wall_distance), jtMiter, 1.2); + for (int32_t parent_idx : draw_area.element->parents) { + const SupportElement &parent = layer_above[parent_idx]; +#ifndef NDEBUG + assert(parent.state.layer_idx == layer_idx + 1); + assert(contains(linear_data[processing_base_above + parent_idx].polygons, parent.state.result_on_layer)); + double radius_increase = support_element_radius(config, *draw_area.element) - support_element_radius(config, parent); + assert(radius_increase >= 0); + double shift = (draw_area.element->state.result_on_layer - parent.state.result_on_layer).cast().norm(); + assert(shift < radius_increase + 2. * config.maximum_move_distance_slow); +#endif // NDEBUG + if (support_element_radius(config, parent) != support_element_collision_radius(config, parent)) { + // No other element on this layer than the current one may be connected to &parent, + // thus it is safe to update parent's DrawArea directly. + Polygons &dst = linear_data[processing_base_above + parent_idx].polygons; +// Polygons orig = dst; + if (! dst.empty()) { + dst = intersection(dst, max_allowed_area); +#if 0 + if (dst.empty()) { + static int irun = 0; + SVG::export_expolygons(debug_out_path("treesupport-extrude_areas-smooth-error-%d.svg", irun ++), + { { { union_ex(max_allowed_area) }, { "max_allowed_area", "yellow", 0.5f } }, + { { union_ex(orig) }, { "orig", "red", "black", "", scaled(0.1f), 0.5f } } }); + ::MessageBoxA(nullptr, "TreeSupport smoothing bug", "Bug detected!", MB_OK | MB_SYSTEMMODAL | MB_SETFOREGROUND | MB_ICONWARNING); + } +#endif + } + } + } + } + throw_on_cancel(); + } + }); + } + +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + progress_total += TREE_PROGRESS_SMOOTH_BRANCH_AREAS / 2; + Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * m_progress_multiplier + m_progress_offset, TREE_PROGRESS_TOTAL); // It is just assumed that both smoothing loops together are one third of the time spent in this function. This was guessed. As the whole function is only 10%, and the smoothing is hard to predict a progress report in the loop may be not useful. +#endif + + // smooth downwards + for (auto& element : move_bounds.back()) + element.state.marked = false; + for (int layer_idx = int(move_bounds.size()) - 2; layer_idx >= 0; -- layer_idx) { + const size_t processing_base = linear_data_layers[layer_idx]; + const size_t processing_base_above = linear_data_layers[layer_idx + 1]; + const SupportElements &layer_above = move_bounds[layer_idx + 1]; + tbb::parallel_for(tbb::blocked_range(0, processing_base_above - processing_base), + [&](const tbb::blocked_range &range) { + for (size_t processing_idx = range.begin(); processing_idx < range.end(); ++ processing_idx) { + DrawArea &draw_area = linear_data[processing_base + processing_idx]; + bool do_something = false; + Polygons max_allowed_area; + for (int32_t parent_idx : draw_area.element->parents) { + const SupportElement &parent = layer_above[parent_idx]; + coord_t max_outer_line_increase = max_radius_change_per_layer; + Polygons result = offset(linear_data[processing_base_above + parent_idx].polygons, max_outer_line_increase, jtMiter, 1.2); + Point direction = draw_area.element->state.result_on_layer - parent.state.result_on_layer; + // move the polygons object + for (auto &outer : result) + for (Point& p : outer) + p += direction; + append(max_allowed_area, std::move(result)); + do_something = do_something || parent.state.marked || support_element_collision_radius(config, parent) != support_element_radius(config, parent); + } + if (do_something) { + // Trim the current drawing areas with max_allowed_area. + Polygons result = intersection(max_allowed_area, draw_area.polygons); + if (area(result) < area(draw_area.polygons)) { + // Mark parent as modified to propagate down. + draw_area.element->state.marked = true; + draw_area.polygons = std::move(result); + } + } + throw_on_cancel(); + } + }); + } + +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + progress_total += TREE_PROGRESS_SMOOTH_BRANCH_AREAS / 2; + Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * m_progress_multiplier + m_progress_offset, TREE_PROGRESS_TOTAL); +#endif +} + +/*! + * \brief Drop down areas that do rest non-gracefully on the model to ensure the branch actually rests on something. + * + * \param layer_tree_polygons[in] Resulting branch areas with the layerindex they appear on. + * \param linear_data[in] All currently existing influence areas with the layer they are on + * \param dropped_down_areas[out] Areas that have to be added to support all non-graceful areas. + * \param inverse_tree_order[in] A mapping that returns the child of every influence area. + */ +static void drop_non_gracious_areas( + const TreeModelVolumes &volumes, + const std::vector &linear_data, + std::vector &support_layer_storage, + std::function throw_on_cancel) +{ + std::vector>> dropped_down_areas(linear_data.size()); + tbb::parallel_for(tbb::blocked_range(0, linear_data.size()), + [&](const tbb::blocked_range &range) { + for (size_t idx = range.begin(); idx < range.end(); ++ idx) { + // If a element has no child, it connects to whatever is below as no support further down for it will exist. + if (const DrawArea &draw_element = linear_data[idx]; ! draw_element.element->state.to_model_gracious && draw_element.child_element == nullptr) { + Polygons rest_support; + const LayerIndex layer_idx_first = draw_element.element->state.layer_idx - 1; + for (LayerIndex layer_idx = layer_idx_first; area(rest_support) > tiny_area_threshold && layer_idx >= 0; -- layer_idx) { + rest_support = diff_clipped(layer_idx == layer_idx_first ? draw_element.polygons : rest_support, volumes.getCollision(0, layer_idx, false)); + dropped_down_areas[idx].emplace_back(layer_idx, rest_support); + } + } + throw_on_cancel(); + } + }); + + for (coord_t i = 0; i < static_cast(dropped_down_areas.size()); i++) + for (std::pair &pair : dropped_down_areas[i]) + append(support_layer_storage[pair.first], std::move(pair.second)); +} + +/*! + * \brief Generates Support Floor, ensures Support Roof can not cut of branches, and saves the branches as support to storage + * + * \param support_layer_storage[in] Areas where support should be generated. + * \param support_roof_storage[in] Areas where support was replaced with roof. + * \param storage[in,out] The storage where the support should be stored. + */ +static void finalize_interface_and_support_areas( + const PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const std::vector &overhangs, + std::vector &support_layer_storage, + std::vector &support_roof_storage, + + SupportGeneratorLayersPtr &bottom_contacts, + SupportGeneratorLayersPtr &top_contacts, + SupportGeneratorLayersPtr &intermediate_layers, + SupportGeneratorLayerStorage &layer_storage, + + std::function throw_on_cancel) +{ + assert(std::all_of(bottom_contacts.begin(), bottom_contacts.end(), [](auto *p) { return p == nullptr; })); + assert(std::all_of(intermediate_layers.begin(), intermediate_layers.end(), [](auto* p) { return p == nullptr; })); + InterfacePreference interface_pref = config.interface_preference; // InterfacePreference::SupportLinesOverwriteInterface; + +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS + TREE_PROGRESS_SMOOTH_BRANCH_AREAS; +#endif // SLIC3R_TREESUPPORTS_PROGRESS + + // Iterate over the generated circles in parallel and clean them up. Also add support floor. + tbb::parallel_for(tbb::blocked_range(0, support_layer_storage.size()), + [&](const tbb::blocked_range &range) { + for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) { + // Subtract support lines of the branches from the roof + SupportGeneratorLayer* support_roof = layer_idx < top_contacts.size() ? top_contacts[layer_idx] : nullptr; + Polygons support_roof_polygons; + if (Polygons &src = support_roof_storage[layer_idx]; ! src.empty()) { + if (support_roof != nullptr && ! support_roof->polygons.empty()) { + support_roof_polygons = union_(src, support_roof->polygons); + support_roof->polygons.clear(); + } else + support_roof_polygons = std::move(src); + } else if (support_roof != nullptr) { + support_roof_polygons = std::move(support_roof->polygons); + support_roof->polygons.clear(); + } + + //assert(intermediate_layers[layer_idx] == nullptr); + Polygons base_layer_polygons = std::move(support_layer_storage[layer_idx]); + + if (! base_layer_polygons.empty()) { + // Most of the time in this function is this union call. Can take 300+ ms when a lot of areas are to be unioned. + base_layer_polygons = smooth_outward(union_(base_layer_polygons), config.support_line_width); //FIXME was .smooth(50); + //smooth_outward(closing(std::move(bottom), closing_distance + minimum_island_radius, closing_distance, SUPPORT_SURFACES_OFFSET_PARAMETERS), smoothing_distance) : + // simplify a bit, to ensure the output does not contain outrageous amounts of vertices. Should not be necessary, just a precaution. + base_layer_polygons = polygons_simplify(base_layer_polygons, std::min(scaled(0.03), double(config.resolution))); + } + if (! support_roof_polygons.empty() && ! base_layer_polygons.empty()) { +// if (area(intersection(base_layer_polygons, support_roof_polygons)) > tiny_area_threshold) + { + switch (interface_pref) { + case InterfacePreference::InterfaceAreaOverwritesSupport: + base_layer_polygons = diff(base_layer_polygons, support_roof_polygons); + break; + case InterfacePreference::SupportAreaOverwritesInterface: + support_roof_polygons = diff(support_roof_polygons, base_layer_polygons); + break; + //FIXME + #if 1 + case InterfacePreference::InterfaceLinesOverwriteSupport: + case InterfacePreference::SupportLinesOverwriteInterface: + assert(false); + [[fallthrough]]; + #else + case InterfacePreference::InterfaceLinesOverwriteSupport: + { + // Hatch the support roof interfaces, offset them by their line width and subtract them from support base. + Polygons interface_lines = offset(to_polylines( + generate_support_infill_lines(support_roof->polygons, true, layer_idx, config.support_roof_line_distance)), + config.support_roof_line_width / 2); + base_layer_polygons = diff(base_layer_polygons, interface_lines); + break; + } + case InterfacePreference::SupportLinesOverwriteInterface: + { + // Hatch the support roof interfaces, offset them by their line width and subtract them from support base. + Polygons tree_lines = union_(offset(to_polylines( + generate_support_infill_lines(base_layer_polygons, false, layer_idx, config.support_line_distance, true)), + config.support_line_width / 2)); + // do not draw roof where the tree is. I prefer it this way as otherwise the roof may cut of a branch from its support below. + support_roof->polygons = diff(support_roof->polygons, tree_lines); + break; + } + #endif + case InterfacePreference::Nothing: + break; + } + } + } + + // Subtract support floors from the support area and add them to the support floor instead. + if (config.support_bottom_layers > 0 && ! base_layer_polygons.empty()) { + SupportGeneratorLayer*& support_bottom = bottom_contacts[layer_idx]; + Polygons layer_outset = diff_clipped( + config.support_bottom_offset > 0 ? offset(base_layer_polygons, config.support_bottom_offset, jtMiter, 1.2) : base_layer_polygons, + volumes.getCollision(0, layer_idx, false)); + Polygons floor_layer; + size_t layers_below = 0; + while (layers_below <= config.support_bottom_layers) { + // one sample at 0 layers below, another at config.support_bottom_layers. In-between samples at config.performance_interface_skip_layers distance from each other. + const size_t sample_layer = static_cast(std::max(0, (static_cast(layer_idx) - static_cast(layers_below)) - static_cast(config.z_distance_bottom_layers))); + //FIXME subtract the wipe tower + append(floor_layer, intersection(layer_outset, overhangs[sample_layer])); + if (layers_below < config.support_bottom_layers) + layers_below = std::min(layers_below + 1, config.support_bottom_layers); + else + break; + } + if (! floor_layer.empty()) { + if (support_bottom == nullptr) + support_bottom = &layer_allocate(layer_storage, SupporLayerType::sltBottomContact, print_object.slicing_parameters(), config, layer_idx); + support_bottom->polygons = union_(floor_layer, support_bottom->polygons); + base_layer_polygons = diff_clipped(base_layer_polygons, offset(support_bottom->polygons, scaled(0.01), jtMiter, 1.2)); // Subtract the support floor from the normal support. + } + } + + if (! support_roof_polygons.empty()) { + if (support_roof == nullptr) + support_roof = top_contacts[layer_idx] = &layer_allocate(layer_storage, SupporLayerType::sltTopContact, print_object.slicing_parameters(), config, layer_idx); + support_roof->polygons = union_(support_roof_polygons); + } + if (! base_layer_polygons.empty()) { + SupportGeneratorLayer *base_layer = intermediate_layers[layer_idx] = &layer_allocate(layer_storage, SupporLayerType::sltBase, print_object.slicing_parameters(), config, layer_idx); + base_layer->polygons = union_(base_layer_polygons); + } + +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + { + std::lock_guard critical_section_progress(critical_sections); + progress_total += TREE_PROGRESS_FINALIZE_BRANCH_AREAS / support_layer_storage.size(); + Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * m_progress_multiplier + m_progress_offset, TREE_PROGRESS_TOTAL); + } +#endif +#if 0 + { + std::lock_guard lock(critical_sections); + if (!storage.support.supportLayers[layer_idx].support_infill_parts.empty() || !storage.support.supportLayers[layer_idx].support_roof.empty()) + storage.support.layer_nr_max_filled_layer = std::max(storage.support.layer_nr_max_filled_layer, static_cast(layer_idx)); + } +#endif + throw_on_cancel(); + } + }); +} + +/*! + * \brief Draws circles around result_on_layer points of the influence areas and applies some post processing. + * + * \param move_bounds[in] All currently existing influence areas + * \param storage[in,out] The storage where the support should be stored. + */ +static void draw_areas( + PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const std::vector &overhangs, + std::vector &move_bounds, + + SupportGeneratorLayersPtr &bottom_contacts, + SupportGeneratorLayersPtr &top_contacts, + SupportGeneratorLayersPtr &intermediate_layers, + SupportGeneratorLayerStorage &layer_storage, + std::function throw_on_cancel) +{ + std::vector support_layer_storage(move_bounds.size()); + std::vector support_roof_storage(move_bounds.size()); + // All SupportElements are put into a layer independent storage to improve parallelization. + std::vector linear_data; + std::vector linear_data_layers; + { + std::vector> map_downwards_old; + std::vector> map_downwards_new; + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()); ++ layer_idx) { + SupportElements *layer_above = layer_idx + 1 < LayerIndex(move_bounds.size()) ? &move_bounds[layer_idx + 1] : nullptr; + map_downwards_new.clear(); + linear_data_layers.emplace_back(linear_data.size()); + std::sort(map_downwards_old.begin(), map_downwards_old.end(), [](auto &l, auto &r) { return l.first < r.first; }); + for (SupportElement &elem : move_bounds[layer_idx]) { + SupportElement *child = nullptr; + if (layer_idx > 0) { + auto it = std::lower_bound(map_downwards_old.begin(), map_downwards_old.end(), &elem, [](auto &l, const SupportElement *r) { return l.first < r; }); + if (it != map_downwards_old.end() && it->first == &elem) { + child = it->second; + // Only one link points to a node above from below. + assert(! (++ it != map_downwards_old.end() && it->first == &elem)); + } + assert(child ? child->state.result_on_layer_is_set() : elem.state.target_height > layer_idx); + } + for (int32_t parent_idx : elem.parents) { + SupportElement &parent = (*layer_above)[parent_idx]; + if (parent.state.result_on_layer_is_set()) + map_downwards_new.emplace_back(&parent, &elem); + } + linear_data.push_back({ &elem, child }); + } + std::swap(map_downwards_old, map_downwards_new); + } + linear_data_layers.emplace_back(linear_data.size()); + } + + throw_on_cancel(); + +#ifndef NDEBUG + for (size_t i = 0; i < move_bounds.size(); ++ i) { + size_t begin = linear_data_layers[i]; + size_t end = linear_data_layers[i + 1]; + for (size_t j = begin; j < end; ++ j) + assert(linear_data[j].element == &move_bounds[i][j - begin]); + } +#endif // NDEBUG + + auto t_start = std::chrono::high_resolution_clock::now(); + // Generate the circles that will be the branches. + generate_branch_areas(volumes, config, move_bounds, linear_data, throw_on_cancel); + +#if 0 + assert(linear_data_layers.size() == move_bounds.size() + 1); + for (const auto &draw_area : linear_data) + assert(contains(draw_area.polygons, draw_area.element->state.result_on_layer)); + for (size_t i = 0; i < move_bounds.size(); ++ i) { + size_t begin = linear_data_layers[i]; + size_t end = linear_data_layers[i + 1]; + for (size_t j = begin; j < end; ++ j) { + const auto &draw_area = linear_data[j]; + assert(draw_area.element == &move_bounds[i][j - begin]); + assert(contains(draw_area.polygons, draw_area.element->state.result_on_layer)); + } + } +#endif + +#if 0 + for (size_t area_layer_idx = 0; area_layer_idx + 1 < linear_data_layers.size(); ++ area_layer_idx) { + size_t begin = linear_data_layers[area_layer_idx]; + size_t end = linear_data_layers[area_layer_idx + 1]; + Polygons polygons; + for (size_t area_idx = begin; area_idx < end; ++ area_idx) { + DrawArea &area = linear_data[area_idx]; + append(polygons, area.polygons); + } + SVG::export_expolygons(debug_out_path("treesupport-extrude_areas-raw-%d.svg", area_layer_idx), + { { { union_ex(polygons) }, { "parent", "red", "black", "", scaled(0.1f), 0.5f } } }); + } +#endif + + auto t_generate = std::chrono::high_resolution_clock::now(); + // In some edgecases a branch may go though a hole, where the regular radius does not fit. This can result in an apparent jump in branch radius. As such this cases need to be caught and smoothed out. + smooth_branch_areas(config, move_bounds, linear_data, linear_data_layers, throw_on_cancel); + +#if 0 + for (size_t area_layer_idx = 0; area_layer_idx + 1 < linear_data_layers.size(); ++area_layer_idx) { + size_t begin = linear_data_layers[area_layer_idx]; + size_t end = linear_data_layers[area_layer_idx + 1]; + Polygons polygons; + for (size_t area_idx = begin; area_idx < end; ++area_idx) { + DrawArea& area = linear_data[area_idx]; + append(polygons, area.polygons); + } + SVG::export_expolygons(debug_out_path("treesupport-extrude_areas-smooth-%d.svg", area_layer_idx), + { { { union_ex(polygons) }, { "parent", "red", "black", "", scaled(0.1f), 0.5f } } }); + } +#endif + + auto t_smooth = std::chrono::high_resolution_clock::now(); + // drop down all trees that connect non gracefully with the model + drop_non_gracious_areas(volumes, linear_data, support_layer_storage, throw_on_cancel); + auto t_drop = std::chrono::high_resolution_clock::now(); + + // Single threaded combining all support areas to the right layers. + { + auto begin = linear_data.begin(); + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()); ++ layer_idx) { + size_t cnt_roofs = 0; + size_t cnt_layers = 0; + auto end = begin; + for (; end != linear_data.end() && end->element->state.layer_idx == layer_idx; ++ end) + ++ (end->element->state.missing_roof_layers > end->element->state.distance_to_top ? cnt_roofs : cnt_layers); + auto &this_roofs = support_roof_storage[layer_idx]; + auto &this_layers = support_layer_storage[layer_idx]; + this_roofs.reserve(this_roofs.size() + cnt_roofs); + this_layers.reserve(this_layers.size() + cnt_layers); + for (auto it = begin; it != end; ++ it) + std::move(std::begin(it->polygons), std::end(it->polygons), std::back_inserter(it->element->state.missing_roof_layers > it->element->state.distance_to_top ? this_roofs : this_layers)); + begin = end; + } + } + + finalize_interface_and_support_areas(print_object, volumes, config, overhangs, support_layer_storage, support_roof_storage, + bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel); + auto t_end = std::chrono::high_resolution_clock::now(); + + auto dur_gen_tips = 0.001 * std::chrono::duration_cast(t_generate - t_start).count(); + auto dur_smooth = 0.001 * std::chrono::duration_cast(t_smooth - t_generate).count(); + auto dur_drop = 0.001 * std::chrono::duration_cast(t_drop - t_smooth).count(); + auto dur_finalize = 0.001 * std::chrono::duration_cast(t_end - t_drop).count(); + + BOOST_LOG_TRIVIAL(info) << + "Time used for drawing subfuctions: generate_branch_areas: " << dur_gen_tips << " ms " + "smooth_branch_areas: " << dur_smooth << " ms " + "drop_non_gracious_areas: " << dur_drop << " ms " + "finalize_interface_and_support_areas " << dur_finalize << " ms"; +} + +#if 1 +// Test whether two circles, each on its own plane in 3D intersect. +// Circles are considered intersecting, if the lowest point on one circle is below the other circle's plane. +// Assumption: The two planes are oriented the same way. +static bool circles_intersect( + const Vec3d &p1, const Vec3d &n1, const double r1, + const Vec3d &p2, const Vec3d &n2, const double r2) +{ + assert(n1.dot(n2) >= 0); + + const Vec3d z = n1.cross(n2); + const Vec3d dir1 = z.cross(n1); + const Vec3d lowest_point1 = p1 + dir1 * (r1 / dir1.norm()); + assert(n2.dot(p1) >= n2.dot(lowest_point1)); + if (n2.dot(lowest_point1) <= 0) + return true; + const Vec3d dir2 = z.cross(n2); + const Vec3d lowest_point2 = p2 + dir2 * (r2 / dir2.norm()); + assert(n1.dot(p2) >= n1.dot(lowest_point2)); + return n1.dot(lowest_point2) <= 0; +} + +template +void triangulate_fan(indexed_triangle_set &its, int ifan, int ibegin, int iend) +{ + // at least 3 vertices, increasing order. + assert(ibegin + 3 <= iend); + assert(ibegin >= 0 && iend <= its.vertices.size()); + assert(ifan >= 0 && ifan < its.vertices.size()); + int num_faces = iend - ibegin; + its.indices.reserve(its.indices.size() + num_faces * 3); + for (int v = ibegin, u = iend - 1; v < iend; u = v ++) { + if (flip_normals) + its.indices.push_back({ ifan, u, v }); + else + its.indices.push_back({ ifan, v, u }); + } +} + +static void triangulate_strip(indexed_triangle_set &its, int ibegin1, int iend1, int ibegin2, int iend2) +{ + // at least 3 vertices, increasing order. + assert(ibegin1 + 3 <= iend1); + assert(ibegin1 >= 0 && iend1 <= its.vertices.size()); + assert(ibegin2 + 3 <= iend2); + assert(ibegin2 >= 0 && iend2 <= its.vertices.size()); + int n1 = iend1 - ibegin1; + int n2 = iend2 - ibegin2; + its.indices.reserve(its.indices.size() + (n1 + n2) * 3); + + // For the first vertex of 1st strip, find the closest vertex on the 2nd strip. + int istart2 = ibegin2; + { + const Vec3f &p1 = its.vertices[ibegin1]; + auto d2min = std::numeric_limits::max(); + for (int i = ibegin2; i < iend2; ++ i) { + const Vec3f &p2 = its.vertices[i]; + const float d2 = (p2 - p1).squaredNorm(); + if (d2 < d2min) { + d2min = d2; + istart2 = i; + } + } + } + + // Now triangulate the strip zig-zag fashion taking always the shortest connection if possible. + for (int u = ibegin1, v = istart2; n1 > 0 || n2 > 0;) { + bool take_first; + int u2, v2; + auto update_u2 = [&u2, u, ibegin1, iend1]() { + u2 = u; + if (++ u2 == iend1) + u2 = ibegin1; + }; + auto update_v2 = [&v2, v, ibegin2, iend2]() { + v2 = v; + if (++ v2 == iend2) + v2 = ibegin2; + }; + if (n1 == 0) { + take_first = false; + update_v2(); + } else if (n2 == 0) { + take_first = true; + update_u2(); + } else { + update_u2(); + update_v2(); + float l1 = (its.vertices[u2] - its.vertices[v]).squaredNorm(); + float l2 = (its.vertices[v2] - its.vertices[u]).squaredNorm(); + take_first = l1 < l2; + } + if (take_first) { + its.indices.push_back({ u, u2, v }); + -- n1; + u = u2; + } else { + its.indices.push_back({ u, v2, v }); + -- n2; + v = v2; + } + } +} + +// Discretize 3D circle, append to output vector, return ranges of indices of the points added. +static std::pair discretize_circle(const Vec3f ¢er, const Vec3f &normal, const float radius, const float eps, std::vector &pts) +{ + // Calculate discretization step and number of steps. + float angle_step = 2. * acos(1. - eps / radius); + auto nsteps = int(ceil(2 * M_PI / angle_step)); + angle_step = 2 * M_PI / nsteps; + + // Prepare coordinate system for the circle plane. + Vec3f x = normal.cross(Vec3f(0.f, -1.f, 0.f)).normalized(); + Vec3f y = normal.cross(x).normalized(); + assert(std::abs(x.cross(y).dot(normal) - 1.f) < EPSILON); + + // Discretize the circle. + int begin = int(pts.size()); + pts.reserve(pts.size() + nsteps); + float angle = 0; + x *= radius; + y *= radius; + for (int i = 0; i < nsteps; ++ i) { + pts.emplace_back(center + x * cos(angle) + y * sin(angle)); + angle += angle_step; + } + return { begin, int(pts.size()) }; +} + +// Discretize polygon, append to output vector, return ranges of indices of the points added. +static std::pair discretize_polygon(const Vec3f& center, const Polygons& polys, std::vector& pts) +{ + const Polygon& poly = polys.front(); + size_t nsteps = poly.size(); + // Discretize the circle. + int begin = int(pts.size()); + pts.reserve(pts.size() + nsteps); + for (int i = 0; i < nsteps; ++i) { + Vec3f pt(poly.points[i].x(), poly.points[i].y(), center.z()); + pts.emplace_back(pt); + } + return { begin, int(pts.size()) }; +} + +// Returns Z span of the generated mesh. +static std::pair extrude_branch( + const std::vector&path, + const TreeSupportSettings &config, + const SlicingParameters &slicing_params, + const std::vector &move_bounds, + indexed_triangle_set &result) +{ + Vec3d p1, p2, p3; + Vec3d v1, v2; + Vec3d nprev; + Vec3d ncurrent; + assert(path.size() >= 2); + static constexpr const float eps = 0.015f; + std::pair prev_strip; + float zmin = 0; + float zmax = 0; + + for (size_t ipath = 1; ipath < path.size(); ++ ipath) { + const SupportElement &prev = *path[ipath - 1]; + const SupportElement ¤t = *path[ipath]; + assert(prev.state.layer_idx + 1 == current.state.layer_idx); + p1 = to_3d(unscaled(prev .state.result_on_layer), layer_z(slicing_params, config, prev .state.layer_idx)); + p2 = to_3d(unscaled(current.state.result_on_layer), layer_z(slicing_params, config, current.state.layer_idx)); + v1 = (p2 - p1).normalized(); + if (ipath == 1) { + nprev = v1; + // Extrude the bottom half sphere. + float radius = unscaled(support_element_radius(config, prev)); + float angle_step = 2. * acos(1. - eps / radius); + auto nsteps = int(ceil(M_PI / (2. * angle_step))); + angle_step = M_PI / (2. * nsteps); + int ifan = int(result.vertices.size()); + result.vertices.emplace_back((p1 - nprev * radius).cast()); + zmin = result.vertices.back().z(); + float angle = angle_step; + std::pair strip; + if (current.state.type == TreeSupport::NodeType::ePolygon) { + strip = discretize_polygon(p1.cast(), current.influence_area, result.vertices); + prev_strip = strip; + strip = discretize_polygon(p2.cast(), current.influence_area, result.vertices); + } + else { + for (int i = 1; i < nsteps; ++i, angle += angle_step) { + strip = discretize_circle((p1 - nprev * radius * cos(angle)).cast(), nprev.cast(), radius * sin(angle), eps, result.vertices); + if (i == 1) + triangulate_fan(result, ifan, strip.first, strip.second); + else + triangulate_strip(result, prev_strip.first, prev_strip.second, strip.first, strip.second); + // sprintf(fname, "d:\\temp\\meshes\\tree-partial-%d.obj", ++ irun); + // its_write_obj(result, fname); + prev_strip = strip; + } + } + } + if (ipath + 1 == path.size()) { + // End of the tube. + ncurrent = v1; + // Extrude the top half sphere. + float radius = unscaled(support_element_radius(config, current)); + float angle_step = 2. * acos(1. - eps / radius); + auto nsteps = int(ceil(M_PI / (2. * angle_step))); + angle_step = M_PI / (2. * nsteps); + auto angle = float(M_PI / 2.); + std::pair strip; + if (current.state.type == TreeSupport::NodeType::ePolygon) { + strip = discretize_polygon(p2.cast(), current.influence_area, result.vertices); + } + else { + for (int i = 0; i < nsteps; ++i, angle -= angle_step) { + strip = discretize_circle((p2 + ncurrent * radius * cos(angle)).cast(), ncurrent.cast(), radius * sin(angle), eps, result.vertices); + triangulate_strip(result, prev_strip.first, prev_strip.second, strip.first, strip.second); + // sprintf(fname, "d:\\temp\\meshes\\tree-partial-%d.obj", ++ irun); + // its_write_obj(result, fname); + prev_strip = strip; + } + int ifan = int(result.vertices.size()); + result.vertices.emplace_back((p2 + ncurrent * radius).cast()); + zmax = result.vertices.back().z(); + triangulate_fan(result, ifan, prev_strip.first, prev_strip.second); + // sprintf(fname, "d:\\temp\\meshes\\tree-partial-%d.obj", ++ irun); + // its_write_obj(result, fname); + } + } else { + const SupportElement &next = *path[ipath + 1]; + assert(current.state.layer_idx + 1 == next.state.layer_idx); + p3 = to_3d(unscaled(next.state.result_on_layer), layer_z(slicing_params, config, next.state.layer_idx)); + v2 = (p3 - p2).normalized(); + ncurrent = (v1 + v2).normalized(); + float radius = unscaled(support_element_radius(config, current)); + std::pair strip; + if (current.state.type == TreeSupport::NodeType::ePolygon) { + strip = discretize_polygon(p2.cast(), current.influence_area, result.vertices); + } + else { + strip = discretize_circle(p2.cast(), ncurrent.cast(), radius, eps, result.vertices); + } + triangulate_strip(result, prev_strip.first, prev_strip.second, strip.first, strip.second); + prev_strip = strip; +// sprintf(fname, "d:\\temp\\meshes\\tree-partial-%d.obj", ++irun); +// its_write_obj(result, fname); + } +#if 0 + if (circles_intersect(p1, nprev, support_element_radius(settings, prev), p2, ncurrent, support_element_radius(settings, current))) { + // Cannot connect previous and current slice using a simple zig-zag triangulation, + // because the two circles intersect. + + } else { + // Continue with chaining. + + } +#endif + } + + return std::make_pair(zmin, zmax); +} +#endif + +#ifdef TREE_SUPPORT_ORGANIC_NUDGE_NEW +// New version using per layer AABB trees of lines for nudging spheres away from an object. +void organic_smooth_branches_avoid_collisions( + const PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const std::vector> &elements_with_link_down, + const std::vector &linear_data_layers, + std::function throw_on_cancel) +{ + struct LayerCollisionCache { + coord_t min_element_radius{ std::numeric_limits::max() }; + bool min_element_radius_known() const { return this->min_element_radius != std::numeric_limits::max(); } + coord_t collision_radius{ 0 }; + std::vector lines; + AABBTreeIndirect::Tree<2, double> aabbtree_lines; + bool empty() const { return this->lines.empty(); } + }; + std::vector layer_collision_cache; + layer_collision_cache.reserve(1024); + const SlicingParameters &slicing_params = print_object.slicing_parameters(); + for (const std::pair& element : elements_with_link_down) { + LayerIndex layer_idx = element.first->state.layer_idx; + if (size_t num_layers = layer_idx + 1; num_layers > layer_collision_cache.size()) { + if (num_layers > layer_collision_cache.capacity()) + layer_collision_cache.reserve(next_highest_power_of_2(num_layers)); + layer_collision_cache.resize(num_layers, {}); + } + auto& l = layer_collision_cache[layer_idx]; + l.min_element_radius = std::min(l.min_element_radius, support_element_radius(config, *element.first)); + } + + throw_on_cancel(); + + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(layer_collision_cache.size()); ++layer_idx) + if (LayerCollisionCache& l = layer_collision_cache[layer_idx]; !l.min_element_radius_known()) + l.min_element_radius = 0; + else { + //FIXME + l.min_element_radius = 0; + std::optional>> res = volumes.get_collision_lower_bound_area(layer_idx, l.min_element_radius); + assert(res.has_value()); + l.collision_radius = res->first; + Lines alines = to_lines(res->second.get()); + l.lines.reserve(alines.size()); + for (const Line &line : alines) + l.lines.push_back({ unscaled(line.a), unscaled(line.b) }); + l.aabbtree_lines = AABBTreeLines::build_aabb_tree_over_indexed_lines(l.lines); + throw_on_cancel(); + } + + struct CollisionSphere { + const SupportElement& element; + int element_below_id; + const bool locked; + float radius; + // Current position, when nudged away from the collision. + Vec3f position; + // Previous position, for Laplacian smoothing. + Vec3f prev_position; + // + Vec3f last_collision; + double last_collision_depth; + // Minimum Z for which the sphere collision will be evaluated. + // Limited by the minimum sloping angle and by the bottom of the tree. + float min_z{ -std::numeric_limits::max() }; + // Maximum Z for which the sphere collision will be evaluated. + // Limited by the minimum sloping angle and by the tip of the current branch. + float max_z{ std::numeric_limits::max() }; + uint32_t layer_begin; + uint32_t layer_end; + }; + + std::vector collision_spheres; + collision_spheres.reserve(elements_with_link_down.size()); + for (const std::pair &element_with_link : elements_with_link_down) { + const SupportElement &element = *element_with_link.first; + const int link_down = element_with_link.second; + collision_spheres.push_back({ + element, + link_down, + // locked + element.parents.empty() || (link_down == -1 && element.state.layer_idx > 0), + unscaled(support_element_radius(config, element)), + // 3D position + to_3d(unscaled(element.state.result_on_layer), float(layer_z(slicing_params, config, element.state.layer_idx))) + }); + // Update min_z coordinate to min_z of the tree below. + CollisionSphere &collision_sphere = collision_spheres.back(); + if (link_down != -1) { + const size_t offset_below = linear_data_layers[element.state.layer_idx - 1]; + collision_sphere.min_z = collision_spheres[offset_below + link_down].min_z; + } else + collision_sphere.min_z = collision_sphere.position.z(); + } + // Update max_z by propagating max_z from the tips of the branches. + for (int collision_sphere_id = int(collision_spheres.size()) - 1; collision_sphere_id >= 0; -- collision_sphere_id) { + CollisionSphere &collision_sphere = collision_spheres[collision_sphere_id]; + if (collision_sphere.element.parents.empty()) + // Tip + collision_sphere.max_z = collision_sphere.position.z(); + else { + // Below tip + const size_t offset_above = linear_data_layers[collision_sphere.element.state.layer_idx + 1]; + for (auto iparent : collision_sphere.element.parents) { + float parent_z = collision_spheres[offset_above + iparent].max_z; +// collision_sphere.max_z = collision_sphere.max_z == std::numeric_limits::max() ? parent_z : std::max(collision_sphere.max_z, parent_z); + collision_sphere.max_z = std::min(collision_sphere.max_z, parent_z); + } + } + } + // Update min_z / max_z to limit the search Z span of a given sphere for collision detection. + for (CollisionSphere &collision_sphere : collision_spheres) { + //FIXME limit the collision span by the tree slope. + collision_sphere.min_z = std::max(collision_sphere.min_z, collision_sphere.position.z() - collision_sphere.radius); + collision_sphere.max_z = std::min(collision_sphere.max_z, collision_sphere.position.z() + collision_sphere.radius); + collision_sphere.layer_begin = std::min(collision_sphere.element.state.layer_idx, layer_idx_ceil(slicing_params, config, collision_sphere.min_z)); + assert(collision_sphere.layer_begin < layer_collision_cache.size()); + collision_sphere.layer_end = std::min(LayerIndex(layer_collision_cache.size()), std::max(collision_sphere.element.state.layer_idx, layer_idx_floor(slicing_params, config, collision_sphere.max_z)) + 1); + } + + throw_on_cancel(); + + static constexpr const double collision_extra_gap = 0.1; + static constexpr const double max_nudge_collision_avoidance = 0.5; + static constexpr const double max_nudge_smoothing = 0.2; + static constexpr const size_t num_iter = 100; // 1000; + for (size_t iter = 0; iter < num_iter; ++ iter) { + // Back up prev position before Laplacian smoothing. + for (CollisionSphere &collision_sphere : collision_spheres) + collision_sphere.prev_position = collision_sphere.position; + std::atomic num_moved{ 0 }; + tbb::parallel_for(tbb::blocked_range(0, collision_spheres.size()), + [&collision_spheres, &layer_collision_cache, &slicing_params, &config, &linear_data_layers, &num_moved, &throw_on_cancel](const tbb::blocked_range range) { + for (size_t collision_sphere_id = range.begin(); collision_sphere_id < range.end(); ++ collision_sphere_id) + if (CollisionSphere &collision_sphere = collision_spheres[collision_sphere_id]; ! collision_sphere.locked) { + // Calculate collision of multiple 2D layers against a collision sphere. + collision_sphere.last_collision_depth = - std::numeric_limits::max(); + for (uint32_t layer_id = collision_sphere.layer_begin; layer_id != collision_sphere.layer_end; ++ layer_id) { + if(layer_id>= layer_collision_cache.size()) + continue; + double dz = (layer_id - collision_sphere.element.state.layer_idx) * slicing_params.layer_height; + if (double r2 = sqr(collision_sphere.radius) - sqr(dz); r2 > 0) { + if (const LayerCollisionCache &layer_collision_cache_item = layer_collision_cache[layer_id]; ! layer_collision_cache_item.empty()) { + size_t hit_idx_out; + Vec2d hit_point_out; + if (double dist = sqrt(AABBTreeLines::squared_distance_to_indexed_lines( + layer_collision_cache_item.lines, layer_collision_cache_item.aabbtree_lines, Vec2d(to_2d(collision_sphere.position).cast()), + hit_idx_out, hit_point_out, r2)); dist >= 0.) { + double collision_depth = sqrt(r2) - dist; + if (collision_depth > collision_sphere.last_collision_depth) { + collision_sphere.last_collision_depth = collision_depth; + collision_sphere.last_collision = to_3d(hit_point_out.cast(), float(layer_z(slicing_params, config, layer_id))); + } + } + } + } + } + if (collision_sphere.last_collision_depth > 0) { + // Collision detected to be removed. + // Nudge the circle center away from the collision. + if (collision_sphere.last_collision_depth > EPSILON) + // a little bit of hysteresis to detect end of + ++ num_moved; + // Shift by maximum 2mm. + double nudge_dist = std::min(std::max(0., collision_sphere.last_collision_depth + collision_extra_gap), max_nudge_collision_avoidance); + Vec2d nudge_vector = (to_2d(collision_sphere.position) - to_2d(collision_sphere.last_collision)).cast().normalized() * nudge_dist; + collision_sphere.position.head<2>() += (nudge_vector * nudge_dist).cast(); + } + // Laplacian smoothing + Vec2d avg{ 0, 0 }; + const size_t offset_above = linear_data_layers[collision_sphere.element.state.layer_idx + 1]; + double weight = 0.; + for (auto iparent : collision_sphere.element.parents) { + double w = collision_sphere.radius; + avg += w * to_2d(collision_spheres[offset_above + iparent].prev_position.cast()); + weight += w; + } + if (collision_sphere.element_below_id != -1) { + const size_t offset_below = linear_data_layers[collision_sphere.element.state.layer_idx - 1]; + const double w = weight; + avg += w * to_2d(collision_spheres[offset_below + collision_sphere.element_below_id].prev_position.cast()); + weight += w; + } + avg /= weight; + static constexpr const double smoothing_factor = 0.5; + Vec2d old_pos = to_2d(collision_sphere.position).cast(); + Vec2d new_pos = (1. - smoothing_factor) * old_pos + smoothing_factor * avg; + Vec2d shift = new_pos - old_pos; + double nudge_dist_max = shift.norm(); + // Shift by maximum 1mm, less than the collision avoidance factor. + double nudge_dist = std::min(std::max(0., nudge_dist_max), max_nudge_smoothing); + collision_sphere.position.head<2>() += (shift.normalized() * nudge_dist).cast(); + + throw_on_cancel(); + } + }); +#if 0 + std::vector stat; + for (CollisionSphere& collision_sphere : collision_spheres) + if (!collision_sphere.locked) + stat.emplace_back(collision_sphere.last_collision_depth); + std::sort(stat.begin(), stat.end()); + printf("iteration: %d, moved: %d, collision depth: min %lf, max %lf, median %lf\n", int(iter), int(num_moved), stat.front(), stat.back(), stat[stat.size() / 2]); +#endif + if (num_moved == 0) + break; + } + + for (size_t i = 0; i < collision_spheres.size(); ++ i) + elements_with_link_down[i].first->state.result_on_layer = scaled(to_2d(collision_spheres[i].position)); +} +#else // TREE_SUPPORT_ORGANIC_NUDGE_NEW +// Old version using OpenVDB, works but it is extremely slow for complex meshes. +static void organic_smooth_branches_avoid_collisions( + const PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + std::vector &move_bounds, + const std::vector> &elements_with_link_down, + const std::vector &linear_data_layers, + std::function throw_on_cancel) +{ + TriangleMesh mesh = print_object.model_object()->raw_mesh(); + mesh.transform(print_object.trafo_centered()); + double scale = 10.; + openvdb::FloatGrid::Ptr grid = mesh_to_grid(mesh.its, openvdb::math::Transform{}, scale, 0., 0.); + std::unique_ptr> closest_surface_point = openvdb::tools::ClosestSurfacePoint::create(*grid); + std::vector pts, prev, projections; + std::vector distances; + for (const std::pair& element : elements_with_link_down) { + Vec3d pt = to_3d(unscaled(element.first->state.result_on_layer), layer_z(print_object.slicing_parameters(), config, element.first->state.layer_idx)) * scale; + pts.push_back({ pt.x(), pt.y(), pt.z() }); + } + + const double collision_extra_gap = 1. * scale; + const double max_nudge_collision_avoidance = 2. * scale; + const double max_nudge_smoothing = 1. * scale; + + static constexpr const size_t num_iter = 100; // 1000; + for (size_t iter = 0; iter < num_iter; ++ iter) { + prev = pts; + projections = pts; + distances.assign(pts.size(), std::numeric_limits::max()); + closest_surface_point->searchAndReplace(projections, distances); + size_t num_moved = 0; + for (size_t i = 0; i < projections.size(); ++ i) { + const SupportElement &element = *elements_with_link_down[i].first; + const int below = elements_with_link_down[i].second; + const bool locked = (below == -1 && element.state.layer_idx > 0) || element.state.locked(); + if (! locked && pts[i] != projections[i]) { + // Nudge the circle center away from the collision. + Vec3d v{ projections[i].x() - pts[i].x(), projections[i].y() - pts[i].y(), projections[i].z() - pts[i].z() }; + double depth = v.norm(); + assert(std::abs(distances[i] - depth) < EPSILON); + double radius = unscaled(support_element_radius(config, element)) * scale; + if (depth < radius) { + // Collision detected to be removed. + ++ num_moved; + double dxy = sqrt(sqr(radius) - sqr(v.z())); + double nudge_dist_max = dxy - std::hypot(v.x(), v.y()) + //FIXME 1mm gap + + collision_extra_gap; + // Shift by maximum 2mm. + double nudge_dist = std::min(std::max(0., nudge_dist_max), max_nudge_collision_avoidance); + Vec2d nudge_v = to_2d(v).normalized() * (- nudge_dist); + pts[i].x() += nudge_v.x(); + pts[i].y() += nudge_v.y(); + } + } + // Laplacian smoothing + if (! locked && ! element.parents.empty()) { + Vec2d avg{ 0, 0 }; + const SupportElements &above = move_bounds[element.state.layer_idx + 1]; + const size_t offset_above = linear_data_layers[element.state.layer_idx + 1]; + double weight = 0.; + for (auto iparent : element.parents) { + double w = support_element_radius(config, above[iparent]); + avg.x() += w * prev[offset_above + iparent].x(); + avg.y() += w * prev[offset_above + iparent].y(); + weight += w; + } + size_t cnt = element.parents.size(); + if (below != -1) { + const size_t offset_below = linear_data_layers[element.state.layer_idx - 1]; + const double w = weight; // config.getRadius(move_bounds[element.state.layer_idx - 1][below].state); + avg.x() += w * prev[offset_below + below].x(); + avg.y() += w * prev[offset_below + below].y(); + ++ cnt; + weight += w; + } + //avg /= double(cnt); + avg /= weight; + static constexpr const double smoothing_factor = 0.5; + Vec2d old_pos{ pts[i].x(), pts[i].y() }; + Vec2d new_pos = (1. - smoothing_factor) * old_pos + smoothing_factor * avg; + Vec2d shift = new_pos - old_pos; + double nudge_dist_max = shift.norm(); + // Shift by maximum 1mm, less than the collision avoidance factor. + double nudge_dist = std::min(std::max(0., nudge_dist_max), max_nudge_smoothing); + Vec2d nudge_v = shift.normalized() * nudge_dist; + pts[i].x() += nudge_v.x(); + pts[i].y() += nudge_v.y(); + } + } +// printf("iteration: %d, moved: %d\n", int(iter), int(num_moved)); + if (num_moved == 0) + break; + } + + for (size_t i = 0; i < projections.size(); ++ i) { + elements_with_link_down[i].first->state.result_on_layer.x() = scaled(pts[i].x()) / scale; + elements_with_link_down[i].first->state.result_on_layer.y() = scaled(pts[i].y()) / scale; + } +} +#endif // TREE_SUPPORT_ORGANIC_NUDGE_NEW + +// Organic specific: Smooth branches and produce one cummulative mesh to be sliced. +indexed_triangle_set draw_branches( + PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + std::vector &move_bounds, + std::function throw_on_cancel) +{ + static int irun = 0; + + // All SupportElements are put into a layer independent storage to improve parallelization. + std::vector> elements_with_link_down; + std::vector linear_data_layers; + { + std::vector> map_downwards_old; + std::vector> map_downwards_new; + linear_data_layers.emplace_back(0); + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()); ++ layer_idx) { + SupportElements *layer_above = layer_idx + 1 < move_bounds.size() ? &move_bounds[layer_idx + 1] : nullptr; + map_downwards_new.clear(); + std::sort(map_downwards_old.begin(), map_downwards_old.end(), [](auto& l, auto& r) { return l.first < r.first; }); + SupportElements &layer = move_bounds[layer_idx]; + for (size_t elem_idx = 0; elem_idx < layer.size(); ++ elem_idx) { + SupportElement &elem = layer[elem_idx]; + int child = -1; + if (layer_idx > 0) { + auto it = std::lower_bound(map_downwards_old.begin(), map_downwards_old.end(), &elem, [](auto& l, const SupportElement* r) { return l.first < r; }); + if (it != map_downwards_old.end() && it->first == &elem) { + child = it->second; + // Only one link points to a node above from below. + assert(!(++it != map_downwards_old.end() && it->first == &elem)); + } + const SupportElement *pchild = child == -1 ? nullptr : &move_bounds[layer_idx - 1][child]; + assert(pchild ? pchild->state.result_on_layer_is_set() : elem.state.target_height > layer_idx); + } + for (int32_t parent_idx : elem.parents) { + SupportElement &parent = (*layer_above)[parent_idx]; + if (parent.state.result_on_layer_is_set()) + map_downwards_new.emplace_back(&parent, elem_idx); + } + + elements_with_link_down.push_back({ &elem, int(child) }); + } + std::swap(map_downwards_old, map_downwards_new); + linear_data_layers.emplace_back(elements_with_link_down.size()); + } + } + + throw_on_cancel(); + + organic_smooth_branches_avoid_collisions(print_object, volumes, config, elements_with_link_down, linear_data_layers, throw_on_cancel); + + // Unmark all nodes. + for (SupportElements &elements : move_bounds) + for (SupportElement &element : elements) + element.state.marked = false; + + // Traverse all nodes, generate tubes. + // Traversal stack with nodes and thier current parent + const SlicingParameters &slicing_params = print_object.slicing_parameters(); + std::vector path; + indexed_triangle_set cummulative_mesh; + indexed_triangle_set partial_mesh; + indexed_triangle_set temp_mesh; + for (LayerIndex layer_idx = 0; layer_idx + 1 < LayerIndex(move_bounds.size()); ++ layer_idx) { + SupportElements &layer = move_bounds[layer_idx]; + SupportElements &layer_above = move_bounds[layer_idx + 1]; + + for (SupportElement &start_element : layer) + if (! start_element.state.marked && ! start_element.parents.empty()) { + // Collect elements up to a bifurcation above. + start_element.state.marked = true; + for (size_t parent_idx = 0; parent_idx < start_element.parents.size(); ++ parent_idx) { + path.clear(); + path.emplace_back(&start_element); + // Traverse each branch until it branches again. + SupportElement &first_parent = layer_above[start_element.parents[parent_idx]]; + assert(path.back()->state.layer_idx + 1 == first_parent.state.layer_idx); + path.emplace_back(&first_parent); + if (first_parent.parents.size() < 2) + first_parent.state.marked = true; + if (first_parent.parents.size() == 1) { + for (SupportElement *parent = &first_parent;;) { + SupportElement &next_parent = move_bounds[parent->state.layer_idx + 1][parent->parents.front()]; + assert(path.back()->state.layer_idx + 1 == next_parent.state.layer_idx); + path.emplace_back(&next_parent); + if (next_parent.parents.size() > 1) + break; + next_parent.state.marked = true; + if (next_parent.parents.size() == 0) + break; + parent = &next_parent; + } + } + // Triangulate the tube. + partial_mesh.clear(); + extrude_branch(path, config, slicing_params, move_bounds, partial_mesh); +#if 1 + char fname[2048]; + sprintf(fname, "SVG\\tree-raw-%d.obj", ++ irun); + its_write_obj(partial_mesh, fname); +#if 0 + temp_mesh.clear(); + cut_mesh(partial_mesh, layer_z(slicing_params, path.back()->state.layer_idx) + EPSILON, nullptr, &temp_mesh, false); + sprintf(fname, "d:\\temp\\meshes\\tree-trimmed1-%d.obj", irun); + its_write_obj(temp_mesh, fname); + partial_mesh.clear(); + cut_mesh(temp_mesh, layer_z(slicing_params, path.front()->state.layer_idx) - EPSILON, &partial_mesh, nullptr, false); + sprintf(fname, "d:\\temp\\meshes\\tree-trimmed2-%d.obj", irun); + its_write_obj(partial_mesh, fname); +#endif +#endif + its_merge(cummulative_mesh, partial_mesh); + } + throw_on_cancel(); + } + } + return cummulative_mesh; +} + +// Organic specific: Slice the cummulative mesh produced by draw_branches(). +void slice_branches( + PrintObject &print_object, + const TreeModelVolumes &volumes, + const TreeSupportSettings &config, + const std::vector &overhangs, + std::vector &move_bounds, + const indexed_triangle_set &cummulative_mesh, + + SupportGeneratorLayersPtr &bottom_contacts, + SupportGeneratorLayersPtr &top_contacts, + SupportGeneratorLayersPtr &intermediate_layers, + SupportGeneratorLayerStorage &layer_storage, + + std::function throw_on_cancel) +{ + const SlicingParameters &slicing_params = print_object.slicing_parameters(); + std::vector slice_z; + for (size_t layer_idx = 0; layer_idx < move_bounds.size(); ++ layer_idx) { + double print_z = slicing_params.object_print_z_min + slicing_params.first_object_layer_height + layer_idx * slicing_params.layer_height; + double layer_height = layer_idx == 0 ? slicing_params.first_object_layer_height : slicing_params.layer_height; + slice_z.emplace_back(float(print_z - layer_height * 0.5)); + } + // Remove the trailing slices. + while (! slice_z.empty()) + if (move_bounds[slice_z.size() - 1].empty()) + slice_z.pop_back(); + else + break; + +#if 0 + its_write_obj(cummulative_mesh, "d:\\temp\\meshes\\tree.obj"); +#endif + + MeshSlicingParamsEx params; + params.closing_radius = float(print_object.config().slice_closing_radius.value); + params.mode = MeshSlicingParams::SlicingMode::Positive; + std::vector slices = slice_mesh_ex(cummulative_mesh, slice_z, params, throw_on_cancel); + for (size_t layer_idx = 0; layer_idx < slice_z.size(); ++ layer_idx) + if (! slices[layer_idx].empty()) { + SupportGeneratorLayer *&l = intermediate_layers[layer_idx]; + if (l == nullptr) + l = &layer_allocate(layer_storage, SupporLayerType::sltBase, slicing_params, layer_idx); + append(l->polygons, to_polygons(std::move(slices[layer_idx]))); + } + + // Trim the slices. + tbb::parallel_for(tbb::blocked_range(0, intermediate_layers.size()), + [&](const tbb::blocked_range &range) { + for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) + if (SupportGeneratorLayer *layer = intermediate_layers[layer_idx]; layer) { + Polygons &poly = intermediate_layers[layer_idx]->polygons; + poly = diff_clipped(poly, volumes.getCollision(0, layer_idx, true)); + poly = intersection(poly, volumes.m_bed_area); + } + }); + + std::vector support_layer_storage(move_bounds.size()); + std::vector support_roof_storage(move_bounds.size()); + finalize_interface_and_support_areas(print_object, volumes, config, overhangs, support_layer_storage, support_roof_storage, + bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel); +} + +/*! + * \brief Create the areas that need support. + * + * These areas are stored inside the given SliceDataStorage object. + * \param storage The data storage where the mesh data is gotten from and + * where the resulting support areas are stored. + */ +static void generate_support_areas(Print &print, TreeSupport* tree_support, const BuildVolume &build_volume, const std::vector &print_object_ids, std::function throw_on_cancel) +{ + // Settings with the indexes of meshes that use these settings. + std::vector>> grouped_meshes = group_meshes(print, print_object_ids); + if (grouped_meshes.empty()) + return; + + size_t counter = 0; + + // Process every mesh group. These groups can not be processed parallel, as the processing in each group is parallelized, and nested parallelization is disables and slow. + for (std::pair> &processing : grouped_meshes) + { + // process each combination of meshes + // this struct is used to easy retrieve setting. No other function except those in TreeModelVolumes and generate_initial_areas() have knowledge of the existence of multiple meshes being processed. + //FIXME this is a copy + // Contains config settings to avoid loading them in every function. This was done to improve readability of the code. + TreeSupportSettings &config = processing.first; + BOOST_LOG_TRIVIAL(info) << "Processing support tree mesh group " << counter + 1 << " of " << grouped_meshes.size() << " containing " << grouped_meshes[counter].second.size() << " meshes."; + auto t_start = std::chrono::high_resolution_clock::now(); + +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + m_progress_multiplier = 1.0 / double(grouped_meshes.size()); + m_progress_offset = counter == 0 ? 0 : TREE_PROGRESS_TOTAL * (double(counter) * m_progress_multiplier); +#endif // SLIC3R_TREESUPPORT_PROGRESS + PrintObject &print_object = *print.get_object(processing.second.front()); + // Generator for model collision, avoidance and internal guide volumes. + TreeModelVolumes volumes{ print_object, build_volume, config.maximum_move_distance, config.maximum_move_distance_slow, processing.second.front(), +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + m_progress_multiplier, m_progress_offset, +#endif // SLIC3R_TREESUPPORTS_PROGRESS + /* additional_excluded_areas */{} }; + + //FIXME generating overhangs just for the first mesh of the group. + assert(processing.second.size() == 1); + + print.set_status(55, _L("Support: detect overhangs")); +#if 0 + std::vector overhangs; + tree_support->detect_overhangs(); + const int num_raft_layers = int(config.raft_layers.size()); + const int num_layers = int(print_object.layer_count()) + num_raft_layers; + overhangs.resize(num_layers); + for (size_t i = 0; i < print_object.layer_count(); i++) + { + overhangs[i + num_raft_layers] = to_polygons(print_object.get_support_layer(i)->overhang_areas); + } + print_object.clear_support_layers(); +#else + std::vector overhangs = generate_overhangs(config, *print.get_object(processing.second.front()), throw_on_cancel); +#endif + // ### Precalculate avoidances, collision etc. + size_t num_support_layers = precalculate(print, overhangs, processing.first, processing.second, volumes, throw_on_cancel); + + bool has_support = num_support_layers > 0; + bool has_raft = config.raft_layers.size() > 0; + num_support_layers = std::max(num_support_layers, config.raft_layers.size()); + + if (num_support_layers == 0) + continue; + + SupportParameters support_params(print_object); + support_params.with_sheath = true; + // organic support default pattern is none. + if (config.support_pattern == smpDefault) { + config.support_pattern = smpNone; + support_params.support_density = 0; + } + + SupportGeneratorLayerStorage layer_storage; + SupportGeneratorLayersPtr top_contacts; + SupportGeneratorLayersPtr bottom_contacts; + SupportGeneratorLayersPtr interface_layers; + SupportGeneratorLayersPtr base_interface_layers; + SupportGeneratorLayersPtr intermediate_layers(num_support_layers, nullptr); + if (support_params.has_top_contacts || has_raft) + top_contacts.assign(num_support_layers, nullptr); + if (support_params.has_bottom_contacts) + bottom_contacts.assign(num_support_layers, nullptr); + if (support_params.has_interfaces() || has_raft) + interface_layers.assign(num_support_layers, nullptr); + if (support_params.has_base_interfaces() || has_raft) + base_interface_layers.assign(num_support_layers, nullptr); + + auto remove_undefined_layers = [&bottom_contacts, &top_contacts, &interface_layers, &base_interface_layers, &intermediate_layers]() { + auto doit = [](SupportGeneratorLayersPtr& layers) { + layers.erase(std::remove_if(layers.begin(), layers.end(), [](const SupportGeneratorLayer* ptr) { return ptr == nullptr; }), layers.end()); + }; + doit(bottom_contacts); + doit(top_contacts); + doit(interface_layers); + doit(base_interface_layers); + doit(intermediate_layers); + }; + + InterfacePlacer interface_placer{ + print_object.slicing_parameters(), support_params, config, + // Outputs + layer_storage, top_contacts, interface_layers, base_interface_layers }; + + + if (has_support) { + auto t_precalc = std::chrono::high_resolution_clock::now(); + // value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in draw_areas + std::vector move_bounds(num_support_layers); + + + for (size_t mesh_idx : processing.second) + generate_initial_areas(*print.get_object(mesh_idx), volumes, config, overhangs, + move_bounds, interface_placer, throw_on_cancel); + auto t_gen = std::chrono::high_resolution_clock::now(); + + // save num of points to log + for (size_t i = 0; i < move_bounds.size(); i++) + BOOST_LOG_TRIVIAL(info) << "Number of points in move_bound: " << move_bounds[i].size() << " in layer " << i; + +#ifdef TREESUPPORT_DEBUG_SVG + for (size_t layer_idx = 0; layer_idx < move_bounds.size(); ++layer_idx) { + Polygons polys; + for (auto& area : move_bounds[layer_idx]) + append(polys, area.influence_area); + if (auto begin = move_bounds[layer_idx].begin(); begin != move_bounds[layer_idx].end()) + SVG::export_expolygons(debug_out_path("treesupport-initial_areas-%d.svg", layer_idx), + { { { union_ex(volumes.getWallRestriction(support_element_collision_radius(config, begin->state), layer_idx, begin->state.use_min_xy_dist)) }, + { "wall_restricrictions", "gray", 0.5f } }, + { { union_ex(polys) }, { "parent", "red", "black", "", scaled(0.1f), 0.5f } } }); + } +#endif // TREESUPPORT_DEBUG_SVG + + // ### Propagate the influence areas downwards. This is an inherently serial operation. + print.set_status(60, _L("Support: propagate branches")); + create_layer_pathing(volumes, config, move_bounds, throw_on_cancel); + auto t_path = std::chrono::high_resolution_clock::now(); + + // ### Set a point in each influence area + create_nodes_from_area(volumes, config, move_bounds, throw_on_cancel); + auto t_place = std::chrono::high_resolution_clock::now(); + + // ### draw these points as circles + indexed_triangle_set branches = draw_branches(*print.get_object(processing.second.front()), volumes, config, move_bounds, throw_on_cancel); + // Reduce memory footprint. After this point only slice_branches() will use volumes and from that only collisions with zero radius will be used. + volumes.clear_all_but_object_collision(); + slice_branches(*print.get_object(processing.second.front()), volumes, config, overhangs, move_bounds, branches, + bottom_contacts, top_contacts, intermediate_layers, layer_storage, throw_on_cancel); + + // this new function may cause bad_function_call exception + //organic_draw_branches( + // *print.get_object(processing.second.front()), volumes, config, move_bounds, + // bottom_contacts, top_contacts, interface_placer, intermediate_layers, layer_storage, + // throw_on_cancel); + + + remove_undefined_layers(); + + std::tie(interface_layers, base_interface_layers) = generate_interface_layers(print_object.config(), support_params, + bottom_contacts, top_contacts, interface_layers, base_interface_layers, intermediate_layers, layer_storage); + + auto t_draw = std::chrono::high_resolution_clock::now(); + auto dur_pre_gen = 0.001 * std::chrono::duration_cast(t_precalc - t_start).count(); + auto dur_gen = 0.001 * std::chrono::duration_cast(t_gen - t_precalc).count(); + auto dur_path = 0.001 * std::chrono::duration_cast(t_path - t_gen).count(); + auto dur_place = 0.001 * std::chrono::duration_cast(t_place - t_path).count(); + auto dur_draw = 0.001 * std::chrono::duration_cast(t_draw - t_place).count(); + auto dur_total = 0.001 * std::chrono::duration_cast(t_draw - t_start).count(); + BOOST_LOG_TRIVIAL(info) << + "Total time used creating Tree support for the currently grouped meshes: " << dur_total << " ms. " + "Different subtasks:\nCalculating Avoidance: " << dur_pre_gen << " ms " + "Creating inital influence areas: " << dur_gen << " ms " + "Influence area creation: " << dur_path << "ms " + "Placement of Points in InfluenceAreas: " << dur_place << "ms " + "Drawing result as support " << dur_draw << " ms"; + + move_bounds.clear(); + } + else if (generate_raft_contact(print_object, config, interface_placer) >= 0) { + remove_undefined_layers(); + } + else + // No raft. + continue; + + // Produce the support G-code. + SupportGeneratorLayersPtr raft_layers = generate_raft_base(print_object, support_params, print_object.slicing_parameters(), top_contacts, interface_layers, base_interface_layers, intermediate_layers, layer_storage); + SupportGeneratorLayersPtr layers_sorted = generate_support_layers(print_object, raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers); + + // Don't fill in the tree supports, make them hollow with just a single sheath line. + print.set_status(69, _L("Support: generate toolpath")); + generate_support_toolpaths(print_object, print_object.support_layers(), print_object.config(), support_params, print_object.slicing_parameters(), + raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers); + + #if 0 +//#ifdef SLIC3R_DEBUG + { + static int iRun = 0; + ++ iRun; + size_t layer_id = 0; + for (int i = 0; i < int(layers_sorted.size());) { + // Find the last layer with roughly the same print_z, find the minimum layer height of all. + // Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should. + int j = i + 1; + coordf_t zmax = layers_sorted[i]->print_z + EPSILON; + bool empty = layers_sorted[i]->polygons.empty(); + for (; j < layers_sorted.size() && layers_sorted[j]->print_z <= zmax; ++j) + if (!layers_sorted[j]->polygons.empty()) + empty = false; + if (!empty) { + export_print_z_polygons_to_svg( + debug_out_path("support-%d-%lf.svg", iRun, layers_sorted[i]->print_z).c_str(), + layers_sorted.data() + i, j - i); + export_print_z_polygons_and_extrusions_to_svg( + debug_out_path("support-w-fills-%d-%lf.svg", iRun, layers_sorted[i]->print_z).c_str(), + layers_sorted.data() + i, j - i, + *print_object.support_layers()[layer_id]); + ++layer_id; + } + i = j; + } + } +#endif /* SLIC3R_DEBUG */ + + ++ counter; + } + +// storage.support.generated = true; +} + +// Organic specific: Smooth branches and produce one cummulative mesh to be sliced. +void organic_draw_branches( + PrintObject& print_object, + TreeModelVolumes& volumes, + const TreeSupportSettings& config, + std::vector& move_bounds, + + // I/O: + SupportGeneratorLayersPtr& bottom_contacts, + SupportGeneratorLayersPtr& top_contacts, + InterfacePlacer& interface_placer, + + // Output: + SupportGeneratorLayersPtr& intermediate_layers, + SupportGeneratorLayerStorage& layer_storage, + + std::function throw_on_cancel) +{ + // All SupportElements are put into a layer independent storage to improve parallelization. + std::vector> elements_with_link_down; + std::vector linear_data_layers; + { + std::vector> map_downwards_old; + std::vector> map_downwards_new; + linear_data_layers.emplace_back(0); + for (LayerIndex layer_idx = 0; layer_idx < LayerIndex(move_bounds.size()); ++layer_idx) { + SupportElements* layer_above = layer_idx + 1 < LayerIndex(move_bounds.size()) ? &move_bounds[layer_idx + 1] : nullptr; + map_downwards_new.clear(); + std::sort(map_downwards_old.begin(), map_downwards_old.end(), [](auto& l, auto& r) { return l.first < r.first; }); + SupportElements& layer = move_bounds[layer_idx]; + for (size_t elem_idx = 0; elem_idx < layer.size(); ++elem_idx) { + SupportElement& elem = layer[elem_idx]; + int child = -1; + if (layer_idx > 0) { + auto it = std::lower_bound(map_downwards_old.begin(), map_downwards_old.end(), &elem, [](auto& l, const SupportElement* r) { return l.first < r; }); + if (it != map_downwards_old.end() && it->first == &elem) { + child = it->second; + // Only one link points to a node above from below. + assert(!(++it != map_downwards_old.end() && it->first == &elem)); + } +#ifndef NDEBUG + { + const SupportElement* pchild = child == -1 ? nullptr : &move_bounds[layer_idx - 1][child]; + assert(pchild ? pchild->state.result_on_layer_is_set() : elem.state.target_height > layer_idx); + } +#endif // NDEBUG + } + for (int32_t parent_idx : elem.parents) { + SupportElement& parent = (*layer_above)[parent_idx]; + if (parent.state.result_on_layer_is_set()) + map_downwards_new.emplace_back(&parent, elem_idx); + } + + elements_with_link_down.push_back({ &elem, int(child) }); + } + std::swap(map_downwards_old, map_downwards_new); + linear_data_layers.emplace_back(elements_with_link_down.size()); + } + } + + throw_on_cancel(); + + organic_smooth_branches_avoid_collisions(print_object, volumes, config, elements_with_link_down, linear_data_layers, throw_on_cancel); + + // Reduce memory footprint. After this point only finalize_interface_and_support_areas() will use volumes and from that only collisions with zero radius will be used. + volumes.clear_all_but_object_collision(); + + // Unmark all nodes. + for (SupportElements& elements : move_bounds) + for (SupportElement& element : elements) + element.state.marked = false; + + // Traverse all nodes, generate tubes. + // Traversal stack with nodes and their current parent + + struct Branch { + std::vector path; + bool has_root{ false }; + bool has_tip{ false }; + }; + + struct Slice { + Polygons polygons; + Polygons bottom_contacts; + size_t num_branches{ 0 }; + }; + + struct Tree { + std::vector branches; + + std::vector slices; + LayerIndex first_layer_id{ -1 }; + }; + + std::vector trees; + + struct TreeVisitor { + static void visit_recursive(std::vector& move_bounds, SupportElement& start_element, Tree& out) { + assert(!start_element.state.marked && !start_element.parents.empty()); + // Collect elements up to a bifurcation above. + start_element.state.marked = true; + // For each branch bifurcating from this point: + //SupportElements &layer = move_bounds[start_element.state.layer_idx]; + SupportElements& layer_above = move_bounds[start_element.state.layer_idx + 1]; + bool root = out.branches.empty(); + for (size_t parent_idx = 0; parent_idx < start_element.parents.size(); ++parent_idx) { + Branch branch; + branch.path.emplace_back(&start_element); + // Traverse each branch until it branches again. + SupportElement& first_parent = layer_above[start_element.parents[parent_idx]]; + assert(!first_parent.state.marked); + assert(branch.path.back()->state.layer_idx + 1 == first_parent.state.layer_idx); + branch.path.emplace_back(&first_parent); + if (first_parent.parents.size() < 2) + first_parent.state.marked = true; + SupportElement* next_branch = nullptr; + if (first_parent.parents.size() == 1) { + for (SupportElement* parent = &first_parent;;) { + assert(parent->state.marked); + SupportElement& next_parent = move_bounds[parent->state.layer_idx + 1][parent->parents.front()]; + assert(!next_parent.state.marked); + assert(branch.path.back()->state.layer_idx + 1 == next_parent.state.layer_idx); + branch.path.emplace_back(&next_parent); + if (next_parent.parents.size() > 1) { + // Branching point was reached. + next_branch = &next_parent; + break; + } + next_parent.state.marked = true; + if (next_parent.parents.size() == 0) + // Tip is reached. + break; + parent = &next_parent; + } + } + else if (first_parent.parents.size() > 1) + // Branching point was reached. + next_branch = &first_parent; + assert(branch.path.size() >= 2); + assert(next_branch == nullptr || !next_branch->state.marked); + branch.has_root = root; + branch.has_tip = !next_branch; + out.branches.emplace_back(std::move(branch)); + if (next_branch) + visit_recursive(move_bounds, *next_branch, out); + } + } + }; + + for (LayerIndex layer_idx = 0; layer_idx + 1 < LayerIndex(move_bounds.size()); ++layer_idx) { + // int ielement; + for (SupportElement& start_element : move_bounds[layer_idx]) { + if (!start_element.state.marked && !start_element.parents.empty()) { +#if 0 + int found = 0; + if (layer_idx > 0) { + for (auto& el : move_bounds[layer_idx - 1]) { + for (auto iparent : el.parents) + if (iparent == ielement) + ++found; + } + if (found != 0) + printf("Found: %d\n", found); + } +#endif + trees.push_back({}); + TreeVisitor::visit_recursive(move_bounds, start_element, trees.back()); + assert(!trees.back().branches.empty()); + //FIXME debugging +#if 0 + if (start_element.state.lost) { + } + else if (start_element.state.verylost) { + } + else + trees.pop_back(); +#endif + } + // ++ ielement; + } + } + + const SlicingParameters& slicing_params = print_object.slicing_parameters(); + MeshSlicingParams mesh_slicing_params; + mesh_slicing_params.mode = MeshSlicingParams::SlicingMode::Positive; + + tbb::parallel_for(tbb::blocked_range(0, trees.size(), trees.size()), + [&trees, &volumes, &config, &slicing_params, &move_bounds, &mesh_slicing_params, &throw_on_cancel](const tbb::blocked_range& range) { + indexed_triangle_set partial_mesh; + std::vector slice_z; + std::vector bottom_contacts; + for (size_t tree_id = range.begin(); tree_id < range.end(); ++tree_id) { + Tree& tree = trees[tree_id]; + for (const Branch& branch : tree.branches) { + // Triangulate the tube. + partial_mesh.clear(); + std::pair zspan = extrude_branch(branch.path, config, slicing_params, move_bounds, partial_mesh); + LayerIndex layer_begin = branch.has_root ? + branch.path.front()->state.layer_idx : + std::min(branch.path.front()->state.layer_idx, layer_idx_ceil(slicing_params, config, zspan.first)); + LayerIndex layer_end = (branch.has_tip ? + branch.path.back()->state.layer_idx : + std::max(branch.path.back()->state.layer_idx, layer_idx_floor(slicing_params, config, zspan.second))) + 1; + slice_z.clear(); + for (LayerIndex layer_idx = layer_begin; layer_idx < layer_end; ++layer_idx) { + const double print_z = layer_z(slicing_params, config, layer_idx); + const double bottom_z = layer_idx > 0 ? layer_z(slicing_params, config, layer_idx - 1) : 0.; + slice_z.emplace_back(float(0.5 * (bottom_z + print_z))); + } + std::vector slices = slice_mesh(partial_mesh, slice_z, mesh_slicing_params, throw_on_cancel); + bottom_contacts.clear(); + //FIXME parallelize? + for (LayerIndex i = 0; i < LayerIndex(slices.size()); ++i) + slices[i] = diff_clipped(slices[i], volumes.getCollision(0, layer_begin + i, true)); //FIXME parent_uses_min || draw_area.element->state.use_min_xy_dist); + + size_t num_empty = 0; + if (slices.front().empty()) { + // Some of the initial layers are empty. + num_empty = std::find_if(slices.begin(), slices.end(), [](auto& s) { return !s.empty(); }) - slices.begin(); + } + else { + if (branch.has_root) { + if (branch.path.front()->state.to_model_gracious) { + if (config.settings.support_floor_layers > 0) + //FIXME one may just take the whole tree slice as bottom interface. + bottom_contacts.emplace_back(intersection_clipped(slices.front(), volumes.getPlaceableAreas(0, layer_begin, [] {}))); + } + else if (layer_begin > 0) { + // Drop down areas that do rest non - gracefully on the model to ensure the branch actually rests on something. + struct BottomExtraSlice { + Polygons polygons; + double area; + }; + std::vector bottom_extra_slices; + Polygons rest_support; + coord_t bottom_radius = support_element_radius(config, *branch.path.front()); + // Don't propagate further than 1.5 * bottom radius. + //LayerIndex layers_propagate_max = 2 * bottom_radius / config.layer_height; + LayerIndex layers_propagate_max = 5 * bottom_radius / config.layer_height; + LayerIndex layer_bottommost = branch.path.front()->state.verylost ? + // If the tree bottom is hanging in the air, bring it down to some surface. + 0 : + //FIXME the "verylost" branches should stop when crossing another support. + std::max(0, layer_begin - layers_propagate_max); + double support_area_min_radius = M_PI * sqr(double(config.branch_radius)); + double support_area_stop = std::max(0.2 * M_PI * sqr(double(bottom_radius)), 0.5 * support_area_min_radius); + // Only propagate until the rest area is smaller than this threshold. + //double support_area_min = 0.1 * support_area_min_radius; + for (LayerIndex layer_idx = layer_begin - 1; layer_idx >= layer_bottommost; --layer_idx) { + rest_support = diff_clipped(rest_support.empty() ? slices.front() : rest_support, volumes.getCollision(0, layer_idx, false)); + double rest_support_area = area(rest_support); + if (rest_support_area < support_area_stop) + // Don't propagate a fraction of the tree contact surface. + break; + bottom_extra_slices.push_back({ rest_support, rest_support_area }); + } + // Now remove those bottom slices that are not supported at all. +#if 0 + while (!bottom_extra_slices.empty()) { + Polygons this_bottom_contacts = intersection_clipped( + bottom_extra_slices.back().polygons, volumes.getPlaceableAreas(0, layer_begin - LayerIndex(bottom_extra_slices.size()), [] {})); + if (area(this_bottom_contacts) < support_area_min) + bottom_extra_slices.pop_back(); + else { + // At least a fraction of the tree bottom is considered to be supported. + if (config.settings.support_floor_layers > 0) + // Turn this fraction of the tree bottom into a contact layer. + bottom_contacts.emplace_back(std::move(this_bottom_contacts)); + break; + } + } +#endif + if (config.settings.support_floor_layers > 0) + for (int i = int(bottom_extra_slices.size()) - 2; i >= 0; --i) + bottom_contacts.emplace_back( + intersection_clipped(bottom_extra_slices[i].polygons, volumes.getPlaceableAreas(0, layer_begin - i - 1, [] {}))); + layer_begin -= LayerIndex(bottom_extra_slices.size()); + slices.insert(slices.begin(), bottom_extra_slices.size(), {}); + auto it_dst = slices.begin(); + for (auto it_src = bottom_extra_slices.rbegin(); it_src != bottom_extra_slices.rend(); ++it_src) + *it_dst++ = std::move(it_src->polygons); + } + } + +#if 0 + //FIXME branch.has_tip seems to not be reliable. + if (branch.has_tip && interface_placer.support_parameters.has_top_contacts) + // Add top slices to top contacts / interfaces / base interfaces. + for (int i = int(branch.path.size()) - 1; i >= 0; --i) { + const SupportElement& el = *branch.path[i]; + if (el.state.missing_roof_layers == 0) + break; + //FIXME Move or not? + interface_placer.add_roof(std::move(slices[int(slices.size()) - i - 1]), el.state.layer_idx, + interface_placer.support_parameters.num_top_interface_layers + 1 - el.state.missing_roof_layers); + } +#endif + } + + layer_begin += LayerIndex(num_empty); + while (!slices.empty() && slices.back().empty()) { + slices.pop_back(); + --layer_end; + } + if (layer_begin < layer_end) { + LayerIndex new_begin = tree.first_layer_id == -1 ? layer_begin : std::min(tree.first_layer_id, layer_begin); + LayerIndex new_end = tree.first_layer_id == -1 ? layer_end : std::max(tree.first_layer_id + LayerIndex(tree.slices.size()), layer_end); + size_t new_size = size_t(new_end - new_begin); + if (tree.first_layer_id == -1) { + } + else if (tree.slices.capacity() < new_size) { + std::vector new_slices; + new_slices.reserve(new_size); + if (LayerIndex dif = tree.first_layer_id - new_begin; dif > 0) + new_slices.insert(new_slices.end(), dif, {}); + append(new_slices, std::move(tree.slices)); + tree.slices.swap(new_slices); + } + else if (LayerIndex dif = tree.first_layer_id - new_begin; dif > 0) + tree.slices.insert(tree.slices.begin(), tree.first_layer_id - new_begin, {}); + tree.slices.insert(tree.slices.end(), new_size - tree.slices.size(), {}); + layer_begin -= LayerIndex(num_empty); + for (LayerIndex i = layer_begin; i != layer_end; ++i) { + int j = i - layer_begin; + if (Polygons& src = slices[j]; !src.empty()) { + Slice& dst = tree.slices[i - new_begin]; + if (++dst.num_branches > 1) { + append(dst.polygons, std::move(src)); + if (j < int(bottom_contacts.size())) + append(dst.bottom_contacts, std::move(bottom_contacts[j])); + } + else { + dst.polygons = std::move(std::move(src)); + if (j < int(bottom_contacts.size())) + dst.bottom_contacts = std::move(bottom_contacts[j]); + } + } + } + tree.first_layer_id = new_begin; + } + } + } + }, tbb::simple_partitioner()); + + tbb::parallel_for(tbb::blocked_range(0, trees.size(), 1), + [&trees, &throw_on_cancel](const tbb::blocked_range& range) { + for (size_t tree_id = range.begin(); tree_id < range.end(); ++tree_id) { + Tree& tree = trees[tree_id]; + for (Slice& slice : tree.slices) + if (slice.num_branches > 1) { + slice.polygons = union_(slice.polygons); + slice.bottom_contacts = union_(slice.bottom_contacts); + slice.num_branches = 1; + } + throw_on_cancel(); + } + }, tbb::simple_partitioner()); + + size_t num_layers = 0; + for (Tree& tree : trees) + if (tree.first_layer_id >= 0) + num_layers = std::max(num_layers, size_t(tree.first_layer_id + tree.slices.size())); + + std::vector slices(num_layers, Slice{}); + for (Tree& tree : trees) + if (tree.first_layer_id >= 0) { + for (LayerIndex i = tree.first_layer_id; i != tree.first_layer_id + LayerIndex(tree.slices.size()); ++i) + if (Slice& src = tree.slices[i - tree.first_layer_id]; !src.polygons.empty()) { + Slice& dst = slices[i]; + if (++dst.num_branches > 1) { + append(dst.polygons, std::move(src.polygons)); + append(dst.bottom_contacts, std::move(src.bottom_contacts)); + } + else { + dst.polygons = std::move(src.polygons); + dst.bottom_contacts = std::move(src.bottom_contacts); + } + } + } + + tbb::parallel_for(tbb::blocked_range(0, std::min(move_bounds.size(), slices.size()), 1), + [&print_object, &config, &slices, &bottom_contacts, &top_contacts, &intermediate_layers, &layer_storage, &throw_on_cancel](const tbb::blocked_range& range) { + for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + Slice& slice = slices[layer_idx]; + assert(intermediate_layers[layer_idx] == nullptr); + Polygons base_layer_polygons = slice.num_branches > 1 ? union_(slice.polygons) : std::move(slice.polygons); + Polygons bottom_contact_polygons = slice.num_branches > 1 ? union_(slice.bottom_contacts) : std::move(slice.bottom_contacts); + + if (!base_layer_polygons.empty()) { + // Most of the time in this function is this union call. Can take 300+ ms when a lot of areas are to be unioned. + base_layer_polygons = smooth_outward(union_(base_layer_polygons), config.support_line_width); //FIXME was .smooth(50); + //smooth_outward(closing(std::move(bottom), closing_distance + minimum_island_radius, closing_distance, SUPPORT_SURFACES_OFFSET_PARAMETERS), smoothing_distance) : + // simplify a bit, to ensure the output does not contain outrageous amounts of vertices. Should not be necessary, just a precaution. + base_layer_polygons = polygons_simplify(base_layer_polygons, std::min(scaled(0.03), double(config.resolution))); + } + + // Subtract top contact layer polygons from support base. + SupportGeneratorLayer* top_contact_layer = top_contacts.empty() ? nullptr : top_contacts[layer_idx]; + if (top_contact_layer && !top_contact_layer->polygons.empty() && !base_layer_polygons.empty()) { + base_layer_polygons = diff(base_layer_polygons, top_contact_layer->polygons); + if (!bottom_contact_polygons.empty()) + //FIXME it may be better to clip bottom contacts with top contacts first after they are propagated to produce interface layers. + bottom_contact_polygons = diff(bottom_contact_polygons, top_contact_layer->polygons); + } + if (!bottom_contact_polygons.empty()) { + base_layer_polygons = diff(base_layer_polygons, bottom_contact_polygons); + SupportGeneratorLayer* bottom_contact_layer = bottom_contacts[layer_idx] = &layer_allocate( + layer_storage, SupporLayerType::sltBottomContact, print_object.slicing_parameters(), config, layer_idx); + bottom_contact_layer->polygons = std::move(bottom_contact_polygons); + } + if (!base_layer_polygons.empty()) { + SupportGeneratorLayer* base_layer = intermediate_layers[layer_idx] = &layer_allocate( + layer_storage, SupporLayerType::sltBase, print_object.slicing_parameters(), config, layer_idx); + base_layer->polygons = union_(base_layer_polygons); + } + + throw_on_cancel(); + } + }, tbb::simple_partitioner()); +} + + +} // namespace TreeSupport3D + +void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_support, std::function throw_on_cancel) +{ + size_t idx = 0; + for (const PrintObject *po : print_object.print()->objects()) { + if (po == &print_object) + break; + ++idx; + } + + Points bedpts = tree_support->m_machine_border.contour.points; + BuildVolume build_volume{ Pointfs{ unscaled(bedpts[0]), unscaled(bedpts[1]),unscaled(bedpts[2]),unscaled(bedpts[3])}, tree_support->m_print_config->printable_height }; + + TreeSupport3D::generate_support_areas(*print_object.print(), tree_support, build_volume, { idx }, throw_on_cancel); +} + +} // namespace Slic3r diff --git a/src/libslic3r/Support/TreeSupport3D.hpp b/src/libslic3r/Support/TreeSupport3D.hpp new file mode 100644 index 00000000000..7a6d342ff3e --- /dev/null +++ b/src/libslic3r/Support/TreeSupport3D.hpp @@ -0,0 +1,332 @@ +// Tree supports by Thomas Rahm, losely based on Tree Supports by CuraEngine. +// Original source of Thomas Rahm's tree supports: +// https://github.com/ThomasRahm/CuraEngine +// +// Original CuraEngine copyright: +// Copyright (c) 2021 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#ifndef slic3r_TreeSupport_hpp +#define slic3r_TreeSupport_hpp + +#include +#include "../Point.hpp" +#include "../BoundingBox.hpp" +#include "../Utils.hpp" +#include "TreeModelVolumes.hpp" +#include "TreeSupportCommon.hpp" + +// #define TREE_SUPPORT_SHOW_ERRORS + +#ifdef SLIC3R_TREESUPPORTS_PROGRESS + // The various stages of the process can be weighted differently in the progress bar. + // These weights are obtained experimentally using a small sample size. Sensible weights can differ drastically based on the assumed default settings and model. + #define TREE_PROGRESS_TOTAL 10000 + #define TREE_PROGRESS_PRECALC_COLL TREE_PROGRESS_TOTAL * 0.1 + #define TREE_PROGRESS_PRECALC_AVO TREE_PROGRESS_TOTAL * 0.4 + #define TREE_PROGRESS_GENERATE_NODES TREE_PROGRESS_TOTAL * 0.1 + #define TREE_PROGRESS_AREA_CALC TREE_PROGRESS_TOTAL * 0.3 + #define TREE_PROGRESS_DRAW_AREAS TREE_PROGRESS_TOTAL * 0.1 + #define TREE_PROGRESS_GENERATE_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3 + #define TREE_PROGRESS_SMOOTH_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3 + #define TREE_PROGRESS_FINALIZE_BRANCH_AREAS TREE_PROGRESS_DRAW_AREAS / 3 +#endif // SLIC3R_TREESUPPORTS_PROGRESS + +namespace Slic3r +{ + +// Forward declarations +class TreeSupport; +class Print; +class PrintObject; +class SupportGeneratorLayer; +using SupportGeneratorLayersPtr = std::vector; + +namespace TreeSupport3D +{ + +// The number of vertices in each circle. +static constexpr const size_t SUPPORT_TREE_CIRCLE_RESOLUTION = 25; + +struct AreaIncreaseSettings +{ + AreaIncreaseSettings( + TreeModelVolumes::AvoidanceType type = TreeModelVolumes::AvoidanceType::Fast, coord_t increase_speed = 0, + bool increase_radius = false, bool no_error = false, bool use_min_distance = false, bool move = false) : + increase_speed{ increase_speed }, type{ type }, increase_radius{ increase_radius }, no_error{ no_error }, use_min_distance{ use_min_distance }, move{ move } {} + + coord_t increase_speed; + // Packing for smaller memory footprint of SupportElementState && SupportElementMerging + TreeModelVolumes::AvoidanceType type; + bool increase_radius : 1; + bool no_error : 1; + bool use_min_distance : 1; + bool move : 1; + bool operator==(const AreaIncreaseSettings& other) const + { + return type == other.type && + increase_speed == other.increase_speed && + increase_radius == other.increase_radius && + no_error == other.no_error && + use_min_distance == other.use_min_distance && + move == other.move; + } +}; + +#define TREE_SUPPORTS_TRACK_LOST + +// C++17 does not support in place initializers of bit values, thus a constructor zeroing the bits is provided. +struct SupportElementStateBits { + SupportElementStateBits() : + to_buildplate(false), + to_model_gracious(false), + use_min_xy_dist(false), + supports_roof(false), + can_use_safe_radius(false), + skip_ovalisation(false), +#ifdef TREE_SUPPORTS_TRACK_LOST + lost(false), + verylost(false), +#endif // TREE_SUPPORTS_TRACK_LOST + deleted(false), + marked(false) + {} + + /*! + * \brief The element trys to reach the buildplate + */ + bool to_buildplate : 1; + + /*! + * \brief Will the branch be able to rest completely on a flat surface, be it buildplate or model ? + */ + bool to_model_gracious : 1; + + /*! + * \brief Whether the min_xy_distance can be used to get avoidance or similar. Will only be true if support_xy_overrides_z=Z overrides X/Y. + */ + bool use_min_xy_dist : 1; + + /*! + * \brief True if this Element or any parent provides support to a support roof. + */ + bool supports_roof : 1; + + /*! + * \brief An influence area is considered safe when it can use the holefree avoidance <=> It will not have to encounter holes on its way downward. + */ + bool can_use_safe_radius : 1; + + /*! + * \brief Skip the ovalisation to parent and children when generating the final circles. + */ + bool skip_ovalisation : 1; + +#ifdef TREE_SUPPORTS_TRACK_LOST + // Likely a lost branch, debugging information. + bool lost : 1; + bool verylost : 1; +#endif // TREE_SUPPORTS_TRACK_LOST + + // Not valid anymore, to be deleted. + bool deleted : 1; + + // General purpose flag marking a visited element. + bool marked : 1; +}; + +struct SupportElementState : public SupportElementStateBits +{ + int type = 0; + coordf_t radius = 0; + float print_z = 0; + + /*! + * \brief The layer this support elements wants reach + */ + LayerIndex target_height; + + /*! + * \brief The position this support elements wants to support on layer=target_height + */ + Point target_position; + + /*! + * \brief The next position this support elements wants to reach. NOTE: This is mainly a suggestion regarding direction inside the influence area. + */ + Point next_position; + + /*! + * \brief The next height this support elements wants to reach + */ + LayerIndex layer_idx; + + /*! + * \brief The Effective distance to top of this element regarding radius increases and collision calculations. + */ + uint32_t effective_radius_height; + + /*! + * \brief The amount of layers this element is below the topmost layer of this branch. + */ + uint32_t distance_to_top; + + /*! + * \brief The resulting center point around which a circle will be drawn later. + * Will be set by setPointsOnAreas + */ + Point result_on_layer{ std::numeric_limits::max(), std::numeric_limits::max() }; + bool result_on_layer_is_set() const { return this->result_on_layer != Point{ std::numeric_limits::max(), std::numeric_limits::max() }; } + void result_on_layer_reset() { this->result_on_layer = Point{ std::numeric_limits::max(), std::numeric_limits::max() }; } + /*! + * \brief The amount of extra radius we got from merging branches that could have reached the buildplate, but merged with ones that can not. + */ + coord_t increased_to_model_radius; // how much to model we increased only relevant for merging + + /*! + * \brief Counter about the times the elephant foot was increased. Can be fractions for merge reasons. + */ + double elephant_foot_increases; + + /*! + * \brief The element trys not to move until this dtt is reached, is set to 0 if the element had to move. + */ + uint32_t dont_move_until; + + /*! + * \brief Settings used to increase the influence area to its current state. + */ + AreaIncreaseSettings last_area_increase; + + /*! + * \brief Amount of roof layers that were not yet added, because the branch needed to move. + */ + uint32_t missing_roof_layers; + + // called by increase_single_area() and increaseAreas() + [[nodiscard]] static SupportElementState propagate_down(const SupportElementState& src) + { + SupportElementState dst{ src }; + ++dst.distance_to_top; + --dst.layer_idx; + // set to invalid as we are a new node on a new layer + dst.result_on_layer_reset(); + dst.skip_ovalisation = false; + return dst; + } +}; + + +/*! + * \brief Get the Distance to top regarding the real radius this part will have. This is different from distance_to_top, which is can be used to calculate the top most layer of the branch. + * \param elem[in] The SupportElement one wants to know the effectiveDTT + * \return The Effective DTT. + */ +[[nodiscard]] inline size_t getEffectiveDTT(const TreeSupportSettings &settings, const SupportElementState &elem) +{ + return elem.effective_radius_height < settings.increase_radius_until_layer ? + (elem.distance_to_top < settings.increase_radius_until_layer ? elem.distance_to_top : settings.increase_radius_until_layer) : + elem.effective_radius_height; +} + +/*! + * \brief Get the Radius, that this element will have. + * \param elem[in] The Element. + * \return The radius the element has. + */ +[[nodiscard]] inline coord_t support_element_radius(const TreeSupportSettings &settings, const SupportElementState &elem) +{ + return settings.getRadius(getEffectiveDTT(settings, elem), elem.elephant_foot_increases); +} + +/*! + * \brief Get the collision Radius of this Element. This can be smaller then the actual radius, as the drawAreas will cut off areas that may collide with the model. + * \param elem[in] The Element. + * \return The collision radius the element has. + */ +[[nodiscard]] inline coord_t support_element_collision_radius(const TreeSupportSettings &settings, const SupportElementState &elem) +{ + return settings.getRadius(elem.effective_radius_height, elem.elephant_foot_increases); +} + +struct SupportElement +{ + using ParentIndices = +#ifdef NDEBUG + // To reduce memory allocation in release mode. + boost::container::small_vector; +#else // NDEBUG + // To ease debugging. + std::vector; +#endif // NDEBUG + +// SupportElement(const SupportElementState &state) : SupportElementState(state) {} + SupportElement(const SupportElementState &state, Polygons &&influence_area) : state(state), influence_area(std::move(influence_area)) {} + SupportElement(const SupportElementState &state, ParentIndices &&parents, Polygons &&influence_area) : + state(state), parents(std::move(parents)), influence_area(std::move(influence_area)) {} + + SupportElementState state; + + /*! + * \brief All elements in the layer above the current one that are supported by this element + */ + ParentIndices parents; + + /*! + * \brief The resulting influence area. + * Will only be set in the results of createLayerPathing, and will be nullptr inside! + */ + Polygons influence_area; +}; + +void tree_supports_show_error(std::string_view message, bool critical); + +using SupportElements = std::deque; + +[[nodiscard]] inline coord_t support_element_radius(const TreeSupportSettings &settings, const SupportElement &elem) +{ + return support_element_radius(settings, elem.state); +} + +[[nodiscard]] inline coord_t support_element_collision_radius(const TreeSupportSettings &settings, const SupportElement &elem) +{ + return support_element_collision_radius(settings, elem.state); +} + +void create_layer_pathing(const TreeModelVolumes& volumes, const TreeSupportSettings& config, std::vector& move_bounds, std::function throw_on_cancel); + +void create_nodes_from_area(const TreeModelVolumes& volumes, const TreeSupportSettings& config, std::vector& move_bounds, std::function throw_on_cancel); + +void organic_smooth_branches_avoid_collisions(const PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector>& elements_with_link_down, const std::vector& linear_data_layers, std::function throw_on_cancel); + +indexed_triangle_set draw_branches(PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, std::vector& move_bounds, std::function throw_on_cancel); + +void slice_branches(PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector& overhangs, std::vector& move_bounds, const indexed_triangle_set& cummulative_mesh, SupportGeneratorLayersPtr& bottom_contacts, SupportGeneratorLayersPtr& top_contacts, SupportGeneratorLayersPtr& intermediate_layers, SupportGeneratorLayerStorage& layer_storage, std::function throw_on_cancel); + +void generate_initial_areas(const PrintObject& print_object, const TreeModelVolumes& volumes, const TreeSupportSettings& config, const std::vector& overhangs, std::vector& move_bounds, InterfacePlacer& interface_placer, std::function throw_on_cancel); + +// Organic specific: Smooth branches and produce one cummulative mesh to be sliced. +void organic_draw_branches( + PrintObject& print_object, + TreeModelVolumes& volumes, + const TreeSupportSettings& config, + std::vector& move_bounds, + + // I/O: + SupportGeneratorLayersPtr& bottom_contacts, + SupportGeneratorLayersPtr& top_contacts, + InterfacePlacer& interface_placer, + + // Output: + SupportGeneratorLayersPtr& intermediate_layers, + SupportGeneratorLayerStorage& layer_storage, + + std::function throw_on_cancel); + +} // namespace TreeSupport3D + +void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_support, std::function throw_on_cancel = []{}); + +} // namespace Slic3r + +#endif /* slic3r_TreeSupport_hpp */ diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 92557dfdb5e..973d6c6d337 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -23,6 +23,7 @@ #include "Point.hpp" #include "Execution/ExecutionTBB.hpp" #include "Execution/ExecutionSeq.hpp" +#include "CutUtils.hpp" #include "Utils.hpp" #include "Format/STL.hpp" #include diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 12002cc5357..fb6951c1df0 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -26,7 +26,7 @@ namespace Slic3r { class TriangleMesh; class TriangleMeshSlicer; - +struct Groove; struct RepairedMeshErrors { // How many edges were united by merging their end points with some other end points in epsilon neighborhood? int edges_fixed = 0; @@ -353,6 +353,7 @@ indexed_triangle_set its_make_frustum_dowel(double r, double h, int sectorCou indexed_triangle_set its_make_pyramid(float base, float height); indexed_triangle_set its_make_sphere(double radius, double fa); indexed_triangle_set its_make_snap(double r, double h, float space_proportion = 0.25f, float bulge_proportion = 0.125f); +indexed_triangle_set its_make_groove_plane(const Groove &cur_groove, float rotate_radius, std::vector &cur_groove_vertices); indexed_triangle_set its_convex_hull(const std::vector &pts); inline indexed_triangle_set its_convex_hull(const indexed_triangle_set &its) { return its_convex_hull(its.vertices); } diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 204b267c22f..ea99f13eb92 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -51,9 +51,12 @@ bool is_equal(float lh, float rh) return abs(lh - rh) <= epson; } -bool is_less(float lh, float rh) -{ - return lh + epson < rh; +bool is_equal_for_sort(float lh, float rh) { + return abs(lh - rh) <= 1e-8; +} + +bool is_equal(const Vec3f &lh, const Vec3f &rh) { + return is_equal(lh[0], rh[0]) && is_equal(lh[1], rh[1]) && is_equal(lh[2], rh[2]); } class IntersectionReference @@ -174,7 +177,7 @@ static FacetSliceType slice_facet( // (external on the right of the line) for (int j = 0; j < 3; ++ j) { // loop through facet edges int edge_id; - const stl_vertex *a, *b; + const stl_vertex *a, *b, *c; int a_id, b_id; { int k = (idx_vertex_lowest + j) % 3; @@ -184,6 +187,7 @@ static FacetSliceType slice_facet( a = vertices + k; b_id = indices[l]; b = vertices + l; + c = vertices + (k + 2) % 3; } // Is edge or face aligned with the cutting plane? @@ -319,6 +323,159 @@ static FacetSliceType slice_facet( return FacetSliceType::NoSlice; } +// Return true, if the facet has been sliced and line_out has been filled. +static FacetSliceType slice_facet_for_cut_mesh( + // Z height of the slice in XY plane. Scaled or unscaled (same as vertices[].z()). + float slice_z, + // 3 vertices of the triangle, XY scaled. Z scaled or unscaled (same as slice_z). + const stl_vertex * vertices, + const stl_triangle_vertex_indices &indices, + const Vec3i & edge_ids, + const int idx_vertex_lowest, + const bool horizontal, + IntersectionLine & line_out) +{ + IntersectionPoint points[3]; + size_t num_points = 0; + auto point_on_layer = size_t(-1); + + // Reorder vertices so that the first one is the one with lowest Z. + // This is needed to get all intersection lines in a consistent order + // (external on the right of the line) + for (int j = 0; j < 3; ++j) { // loop through facet edges + int edge_id; + const stl_vertex *a, *b, *c; + int a_id, b_id; + { + int k = (idx_vertex_lowest + j) % 3; + int l = (k + 1) % 3; + edge_id = edge_ids(k); + a_id = indices[k]; + a = vertices + k; + b_id = indices[l]; + b = vertices + l; + c = vertices + (k + 2) % 3; + } + + // Is edge or face aligned with the cutting plane? + if (is_equal(a->z(), slice_z) && is_equal(b->z(), slice_z)) { + // Edge is horizontal and belongs to the current layer. + // The following rotation of the three vertices may not be efficient, but this branch happens rarely. + const stl_vertex &v0 = vertices[0]; + const stl_vertex &v1 = vertices[1]; + const stl_vertex &v2 = vertices[2]; + // We may ignore this edge for slicing purposes, but we may still use it for object cutting. + FacetSliceType result = FacetSliceType::Slicing; + if (horizontal) { + // All three vertices are aligned with slice_z. + line_out.edge_type = IntersectionLine::FacetEdgeType::Horizontal; + result = FacetSliceType::Cutting; + double normal = (v1.x() - v0.x()) * (v2.y() - v1.y()) - (v1.y() - v0.y()) * (v2.x() - v1.x()); + if (normal < 0) { + // If normal points downwards this is a bottom horizontal facet so we reverse its point order. + std::swap(a, b); + std::swap(a_id, b_id); + } + } else { + // Two vertices are aligned with the cutting plane, the third vertex is below or above the cutting plane. + // Is the third vertex below the cutting plane? + bool third_below = c->z() < slice_z; + // Two vertices on the cutting plane, the third vertex is below the plane. Consider the edge to be part of the slice + // only if it is the upper edge. + // (the bottom most edge resp. vertex of a triangle is not owned by the triangle, but the top most edge resp. vertex is part of the triangle + // in respect to the cutting plane). + result = third_below ? FacetSliceType::Slicing : FacetSliceType::Cutting; + if (third_below) { + line_out.edge_type = IntersectionLine::FacetEdgeType::Top; + std::swap(a, b); + std::swap(a_id, b_id); + } else + line_out.edge_type = IntersectionLine::FacetEdgeType::Bottom; + } + line_out.a.x() = a->x(); + line_out.a.y() = a->y(); + line_out.b.x() = b->x(); + line_out.b.y() = b->y(); + line_out.a_id = a_id; + line_out.b_id = b_id; + assert(line_out.a != line_out.b); + return result; + } + + if (is_equal(a->z(), slice_z)) { + // Only point a alings with the cutting plane. + if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != a_id) { + point_on_layer = num_points; + IntersectionPoint &point = points[num_points++]; + point.x() = a->x(); + point.y() = a->y(); + point.point_id = a_id; + } + } else if (is_equal(b->z(), slice_z)) { + // Only point b alings with the cutting plane. + if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != b_id) { + point_on_layer = num_points; + IntersectionPoint &point = points[num_points++]; + point.x() = b->x(); + point.y() = b->y(); + point.point_id = b_id; + } + } else if ((a->z() < slice_z && b->z() > slice_z) || (b->z() < slice_z && a->z() > slice_z)) { + // A general case. The face edge intersects the cutting plane. Calculate the intersection point. + assert(a_id != b_id); + // Sort the edge to give a consistent answer. + if (a_id > b_id) { + std::swap(a_id, b_id); + std::swap(a, b); + } + IntersectionPoint &point = points[num_points]; + double t = (double(slice_z) - double(b->z())) / (double(a->z()) - double(b->z())); + if (t <= 0.) { + if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != a_id) { + point.x() = a->x(); + point.y() = a->y(); + point_on_layer = num_points++; + point.point_id = a_id; + } + } else if (t >= 1.) { + if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != b_id) { + point.x() = b->x(); + point.y() = b->y(); + point_on_layer = num_points++; + point.point_id = b_id; + } + } else { + point.x() = coord_t(floor(double(b->x()) + (double(a->x()) - double(b->x())) * t + 0.5)); + point.y() = coord_t(floor(double(b->y()) + (double(a->y()) - double(b->y())) * t + 0.5)); + point.edge_id = edge_id; + ++num_points; + } + } + } + + // Facets must intersect each plane 0 or 2 times, or it may touch the plane at a single vertex only. + assert(num_points < 3); + if (num_points == 2) { + line_out.edge_type = IntersectionLine::FacetEdgeType::General; + line_out.a = static_cast(points[1]); + line_out.b = static_cast(points[0]); + line_out.a_id = points[1].point_id; + line_out.b_id = points[0].point_id; + line_out.edge_a_id = points[1].edge_id; + line_out.edge_b_id = points[0].edge_id; + // Not a zero lenght edge. + // FIXME slice_facet() may create zero length edges due to rounding of doubles into coord_t. + // assert(line_out.a != line_out.b); + // The plane cuts at least one edge in a general position. + assert(line_out.a_id == -1 || line_out.b_id == -1); + assert(line_out.edge_a_id != -1 || line_out.edge_b_id != -1); + // General slicing position, use the segment for both slicing and object cutting. + + return FacetSliceType::Slicing; + } + return FacetSliceType::NoSlice; +} + template void slice_facet_at_zs( // Scaled or unscaled vertices. transform_vertex_fn may scale zs. @@ -336,12 +493,12 @@ void slice_facet_at_zs( // find facet extents const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z())); const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z())); - + // find layer extents auto min_layer = std::lower_bound(zs.begin(), zs.end(), min_z); // first layer whose slice_z is >= min_z auto max_layer = std::upper_bound(min_layer, zs.end(), max_z); // first layer whose slice_z is > max_z int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0); - + for (auto it = min_layer; it != max_layer; ++ it) { IntersectionLine il; // Ignore horizontal triangles. Any valid horizontal triangle must have a vertical triangle connected, otherwise the part has zero volume. @@ -396,7 +553,7 @@ static inline IntersectionLines slice_make_lines( const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z())); const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z())); assert(min_z <= plane_z && max_z >= plane_z); - int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0); + int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0); IntersectionLine il; // Ignore horizontal triangles. Any valid horizontal triangle must have a vertical triangle connected, otherwise the part has zero volume. if (min_z != max_z && slice_facet(plane_z, vertices, indices, face_edge_ids[face_idx], idx_vertex_lowest, false, il) == FacetSliceType::Slicing) { @@ -452,7 +609,7 @@ void slice_facet_with_slabs( const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z())); const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z())); const bool horizontal = min_z == max_z; - + // find layer extents auto min_layer = std::lower_bound(zs.begin(), zs.end(), min_z); // first layer whose slice_z is >= min_z auto max_layer = std::upper_bound(min_layer, zs.end(), max_z); // first layer whose slice_z is > max_z @@ -2001,15 +2158,16 @@ void slice_mesh_slabs( // Remove duplicates of slice_vertices, optionally triangulate the cut. static void triangulate_slice( - indexed_triangle_set &its, - IntersectionLines &lines, + indexed_triangle_set &its, + IntersectionLines &lines, std::vector &slice_vertices, // Vertices of the original (unsliced) mesh. Newly added vertices are those on the slice. int num_original_vertices, // Z height of the slice. - float z, - bool triangulate, - bool normals_down) + float z, + bool triangulate, + bool normals_down, + const std::map §ion_vertices_map) { sort_remove_duplicates(slice_vertices); @@ -2019,11 +2177,12 @@ static void triangulate_slice( map_vertex_to_index.reserve(slice_vertices.size()); for (int i : slice_vertices) map_vertex_to_index.emplace_back(to_2d(its.vertices[i]), i); - std::sort(map_vertex_to_index.begin(), map_vertex_to_index.end(), - [](const std::pair &l, const std::pair &r) { - return is_less(l.first.x(), r.first.x()) || - (is_equal(l.first.x(), r.first.x()) && (is_less(l.first.y(), r.first.y()) || - (is_equal(l.first.y(), r.first.y()) && l.second < r.second))); }); + std::sort(map_vertex_to_index.begin(), map_vertex_to_index.end(), + [](const std::pair &l, const std::pair &r) { + return l.first.x() < r.first.x() || + (is_equal_for_sort(l.first.x(), r.first.x()) && (l.first.y()< r.first.y() || + (is_equal_for_sort(l.first.y(), r.first.y()) && l.second < r.second))); + }); // 2) Discover duplicate points on the slice. Remap duplicate vertices to a vertex with a lowest index. // Remove denegerate triangles, if they happen to be created by merging duplicate vertices. @@ -2072,14 +2231,40 @@ static void triangulate_slice( stl_triangle_vertex_indices facet; for (size_t j = 0; j < 3; ++ j) { Vec3f v = triangles[i ++].cast(); - auto it = lower_bound_by_predicate(map_vertex_to_index.begin(), map_vertex_to_index.end(), + auto it = lower_bound_by_predicate(map_vertex_to_index.begin(), map_vertex_to_index.end(), [&v](const std::pair &l) { - return is_less(l.first.x(), v.x()) || (is_equal(l.first.x(), v.x()) && is_less(l.first.y(), v.y())); + return l.first.x() < v.x() || (is_equal_for_sort(l.first.x(), v.x()) && l.first.y() < v.y()); }); int idx = -1; - if (it != map_vertex_to_index.end() && is_equal(it->first.x(), v.x()) && is_equal(it->first.y(), v.y())) - idx = it->second; - else { + bool exist = false; + for (auto iter = section_vertices_map.begin(); iter != section_vertices_map.end(); iter++) { + if (is_equal(v, *iter->second)) { + idx = iter->first; + exist = true; + break; + } + } + // go on finding + if (!exist) { + for (; it != map_vertex_to_index.end(); it++) { + if (is_equal(it->first.x(), v.x()) && is_equal(it->first.y(), v.y())) { + idx = it->second; + exist = true; + break; + } + } + } + // go on finding + if (!exist) { + for (; it != map_vertex_to_index.begin(); it--) { + if (is_equal(it->first.x(), v.x()) && is_equal(it->first.y(), v.y())) { + idx = it->second; + exist = true; + break; + } + } + } + if (!exist){ // Try to find the vertex in the list of newly added vertices. Those vertices are not matched on the cut and they shall be rare. for (size_t k = idx_vertex_new_first; k < its.vertices.size(); ++ k) if (its.vertices[k] == v) { @@ -2160,16 +2345,22 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u IntersectionLines upper_lines, lower_lines; std::vector upper_slice_vertices, lower_slice_vertices; std::vector facets_edge_ids = its_face_edge_ids(mesh); + std::map section_vertices_map; for (int facet_idx = 0; facet_idx < int(mesh.indices.size()); ++ facet_idx) { const stl_triangle_vertex_indices &facet = mesh.indices[facet_idx]; Vec3f vertices[3] { mesh.vertices[facet(0)], mesh.vertices[facet(1)], mesh.vertices[facet(2)] }; float min_z = std::min(vertices[0].z(), std::min(vertices[1].z(), vertices[2].z())); float max_z = std::max(vertices[0].z(), std::max(vertices[1].z(), vertices[2].z())); - + + for (size_t i = 0; i < 3; i++) { + if (is_equal(z, vertices[i].z()) && section_vertices_map[facet(i)] == nullptr) { + section_vertices_map[facet(i)] = new Vec3f(vertices[i].x(), vertices[i].y(), vertices[i].z()); + } + } // intersect facet with cutting plane IntersectionLine line; - int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0); + int idx_vertex_lowest = is_equal(vertices[1].z(), min_z) ? 1 : (is_equal(vertices[2].z() , min_z) ? 2 : 0); FacetSliceType slice_type = FacetSliceType::NoSlice; if (z > min_z - EPSILON && z < max_z + EPSILON) { Vec3f vertices_scaled[3]; @@ -2180,7 +2371,7 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u dst.y() = scale_(src.y()); dst.z() = src.z(); } - slice_type = slice_facet(z, vertices_scaled, mesh.indices[facet_idx], facets_edge_ids[facet_idx], idx_vertex_lowest, min_z == max_z, line); + slice_type = slice_facet_for_cut_mesh(z, vertices_scaled, mesh.indices[facet_idx], facets_edge_ids[facet_idx], idx_vertex_lowest, is_equal(min_z, max_z), line); } if (slice_type != FacetSliceType::NoSlice) { @@ -2198,12 +2389,12 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u upper_lines.emplace_back(line); } } - - if (min_z > z || (min_z == z && max_z > z)) { + + if (min_z > z || (is_equal(min_z , z) && max_z > z)) { // facet is above the cut plane and does not belong to it if (upper != nullptr) upper->indices.emplace_back(facet); - } else if (max_z < z || (max_z == z && min_z < z)) { + } else if (max_z < z || (is_equal(max_z, z) && min_z < z)) { // facet is below the cut plane and does not belong to it if (lower != nullptr) lower->indices.emplace_back(facet); @@ -2215,21 +2406,56 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u assert(line.edge_b_id != -1); // look for the vertex on whose side of the slicing plane there are no other vertices - int isolated_vertex = - (vertices[0].z() > z) == (vertices[1].z() > z) ? 2 : - (vertices[1].z() > z) == (vertices[2].z() > z) ? 0 : 1; - + int isolated_vertex, isolated_vertex_option = -1; + std::vector list{0, 1, 2}; + auto get_third = [&list](int isolated_vertex, int temp) {// not use vertex data + for (size_t i = 0; i < list.size(); i++) { + if (list[i] != isolated_vertex && list[i] != temp) { + return list[i]; + } + } + return -1; + }; + if (is_equal(vertices[0].z(), z)) { + isolated_vertex = vertices[1].z() > z ? 1 : 2; + isolated_vertex_option = get_third(isolated_vertex, 0); + } else if (is_equal(vertices[1].z(), z)) { + isolated_vertex = vertices[2].z() > z ? 2 : 0; + isolated_vertex_option = get_third(isolated_vertex, 1); + } else if (is_equal(vertices[2].z(), z)) { + isolated_vertex = vertices[0].z() > z ? 0 : 1; + isolated_vertex_option = get_third(isolated_vertex, 2); + } else { + isolated_vertex = (vertices[0].z() > z) == (vertices[1].z() > z) ? 2 : (vertices[1].z() > z) == (vertices[2].z() > z) ? 0 : 1; + } // get vertices starting from the isolated one - int iv = isolated_vertex; stl_vertex v0v1, v2v0; - assert(facets_edge_ids[facet_idx](iv) == line.edge_a_id || facets_edge_ids[facet_idx](iv) == line.edge_b_id); - if (facets_edge_ids[facet_idx](iv) == line.edge_a_id) { - // Unscale to doubles first, then to floats to reach the same accuracy as triangulate_expolygons_2d(). - v0v1 = to_3d(unscaled(line.a).cast().eval(), z); - v2v0 = to_3d(unscaled(line.b).cast().eval(), z); + auto calc_isolated_vertex = [&v0v1, &v2v0, &line, &facet_idx, &facets_edge_ids, &z](int iv, bool &is_find) { + assert(facets_edge_ids[facet_idx](iv) == line.edge_a_id || facets_edge_ids[facet_idx](iv) == line.edge_b_id); + is_find = true; + if (facets_edge_ids[facet_idx](iv) == line.edge_a_id) { + // Unscale to doubles first, then to floats to reach the same accuracy as triangulate_expolygons_2d(). + v0v1 = to_3d(unscaled(line.a).cast().eval(), z); + v2v0 = to_3d(unscaled(line.b).cast().eval(), z); + } else if (facets_edge_ids[facet_idx](iv) == line.edge_b_id) { + v0v1 = to_3d(unscaled(line.b).cast().eval(), z); + v2v0 = to_3d(unscaled(line.a).cast().eval(), z); + } else { + is_find = false; + } + }; + bool find_isolated_vertex; + int iv; + calc_isolated_vertex(isolated_vertex, find_isolated_vertex); + if (!find_isolated_vertex && isolated_vertex_option != -1) { + calc_isolated_vertex(isolated_vertex_option, find_isolated_vertex); + if (!find_isolated_vertex) { + BOOST_LOG_TRIVIAL(trace) << "cut_mesh:error:could not find isolated_vertex"; + continue; + } + iv = isolated_vertex_option; } else { - v0v1 = to_3d(unscaled(line.b).cast().eval(), z); - v2v0 = to_3d(unscaled(line.a).cast().eval(), z); + iv = isolated_vertex; } const stl_vertex &v0 = vertices[iv]; const int iv0 = facet[iv]; @@ -2243,48 +2469,71 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u const int iv2 = facet[iv]; // intersect v0-v1 and v2-v0 with cutting plane and make new vertices - auto new_vertex = [upper, lower, &upper_slice_vertices, &lower_slice_vertices](const Vec3f &a, const int ia, const Vec3f &b, const int ib, const Vec3f &c) { + auto new_vertex = [upper, lower, &upper_slice_vertices, &lower_slice_vertices](const Vec3f &a, const int ia, const Vec3f &b, const int ib, const Vec3f &c, + const int ic, const Vec3f &new_pt, bool &is_new_vertex) { int iupper, ilower; - if (c == a) + is_new_vertex = false; + if (is_equal(new_pt, a)) iupper = ilower = ia; - else if (c == b) + else if (is_equal(new_pt, b)) iupper = ilower = ib; + else if (is_equal(new_pt, c)) + iupper = ilower = ic; else { // Insert a new vertex into upper / lower. + is_new_vertex = true; if (upper) { iupper = int(upper->vertices.size()); - upper->vertices.emplace_back(c); + upper->vertices.emplace_back(new_pt); upper_slice_vertices.emplace_back(iupper); } if (lower) { ilower = int(lower->vertices.size()); - lower->vertices.emplace_back(c); + lower->vertices.emplace_back(new_pt); lower_slice_vertices.emplace_back(ilower); } } return std::make_pair(iupper, ilower); }; - auto [iv0v1_upper, iv0v1_lower] = new_vertex(v1, iv1, v0, iv0, v0v1); - auto [iv2v0_upper, iv2v0_lower] = new_vertex(v2, iv2, v0, iv0, v2v0); - auto new_face = [](indexed_triangle_set *its, int i, int j, int k) { - if (its != nullptr && i != j && i != k && j != k) - its->indices.emplace_back(i, j, k); + bool is_new_vertex_v0v1; + bool is_new_vertex_v2v0; + auto [iv0v1_upper, iv0v1_lower] = new_vertex(v1, iv1, v0, iv0, v2, iv2, v0v1, is_new_vertex_v0v1); + auto [iv2v0_upper, iv2v0_lower] = new_vertex(v2, iv2, v0, iv0, v1, iv1, v2v0, is_new_vertex_v2v0); + auto new_face = [](indexed_triangle_set *its, int i, int j, int k) { + if (its != nullptr && i != j && i != k && j != k) its->indices.emplace_back(i, j, k); }; - - if (v0.z() > z) { - new_face(upper, iv0, iv0v1_upper, iv2v0_upper); - new_face(lower, iv1, iv2, iv0v1_lower); - new_face(lower, iv2, iv2v0_lower, iv0v1_lower); - } else { - new_face(upper, iv1, iv2, iv0v1_upper); - new_face(upper, iv2, iv2v0_upper, iv0v1_upper); - new_face(lower, iv0, iv0v1_lower, iv2v0_lower); + if (is_new_vertex_v0v1 && is_new_vertex_v2v0) { + if (v0.z() > z) { + new_face(upper, iv0, iv0v1_upper, iv2v0_upper); + new_face(lower, iv1, iv2, iv0v1_lower); + new_face(lower, iv2, iv2v0_lower, iv0v1_lower); + } else { + new_face(upper, iv1, iv2, iv0v1_upper); + new_face(upper, iv2, iv2v0_upper, iv0v1_upper); + new_face(lower, iv0, iv0v1_lower, iv2v0_lower); + } + } else if (is_new_vertex_v0v1) { + if (v0.z() > z) { + new_face(upper, iv0, iv0v1_upper, iv2); + new_face(lower, iv1, iv2, iv0v1_lower); + } else { + new_face(lower, iv0, iv0v1_lower, iv2); + new_face(upper, iv1, iv2, iv0v1_upper); + } + } else if (is_new_vertex_v2v0) { + if (v0.z() > z) { + new_face(upper, iv0, iv1, iv2v0_upper); + new_face(lower, iv1, iv2, iv2v0_lower); + } else { + new_face(lower, iv0, iv1, iv2v0_lower); + new_face(upper, iv1, iv2, iv2v0_upper); + } } } } - + if (upper != nullptr) { - triangulate_slice(*upper, upper_lines, upper_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_DOWN); + triangulate_slice(*upper, upper_lines, upper_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_DOWN, section_vertices_map); #ifndef NDEBUG if (triangulate_caps) { size_t num_open_edges_new = its_num_open_edges(*upper); @@ -2294,7 +2543,7 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u } if (lower != nullptr) { - triangulate_slice(*lower, lower_lines, lower_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_UP); + triangulate_slice(*lower, lower_lines, lower_slice_vertices, int(mesh.vertices.size()), z, triangulate_caps, NORMALS_UP, section_vertices_map); #ifndef NDEBUG if (triangulate_caps) { size_t num_open_edges_new = its_num_open_edges(*lower); @@ -2302,6 +2551,7 @@ void cut_mesh(const indexed_triangle_set& mesh, float z, indexed_triangle_set* u } #endif // NDEBUG } + std::map().swap(section_vertices_map); } } // namespace Slic3r diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index ef3ccf46f90..6499215b2fb 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -1703,7 +1703,12 @@ void TriangleSelector::deserialize(const std::pair= int(m_triangles.size())) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "array bound:error:triangle_id >= int(m_triangles.size())"; + return; + } + } // Reserve number of triangles as if each triangle was saved with 4 bits. // With MMU painting this estimate may be somehow low, but better than nothing. m_triangles.reserve(std::max(m_mesh.its.indices.size(), data.second.size() / 4)); diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index ce12a334863..8687a503e6b 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -48,6 +48,7 @@ #define CLI_PRINTABLE_SIZE_REDUCED -20 #define CLI_OBJECT_ARRANGE_FAILED -21 #define CLI_OBJECT_ORIENT_FAILED -22 +#define CLI_MODIFIED_PARAMS_TO_PRINTER -23 #define CLI_NO_SUITABLE_OBJECTS -50 @@ -124,8 +125,11 @@ inline std::string convert_to_full_version(std::string short_version) } return result; } - - +template +inline DataType round_divide(DataType dividend, DataType divisor) //!< Return dividend divided by divisor rounded to the nearest integer +{ + return (dividend + divisor / 2) / divisor; +} // Set a path with GUI localization files. void set_local_dir(const std::string &path); diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index fa59415d4f4..d54f581c1d3 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -67,7 +67,7 @@ static constexpr double RESOLUTION = 0.0125; static constexpr double SPARSE_INFILL_RESOLUTION = 0.04; #define SCALED_SPARSE_INFILL_RESOLUTION (SPARSE_INFILL_RESOLUTION / SCALING_FACTOR) -static constexpr double SUPPORT_RESOLUTION = 0.05; +static constexpr double SUPPORT_RESOLUTION = 0.1; #define SCALED_SUPPORT_RESOLUTION (SUPPORT_RESOLUTION / SCALING_FACTOR) // Maximum perimeter length for the loop to apply the small perimeter speed. #define SMALL_PERIMETER_LENGTH(LENGTH) (((LENGTH) / SCALING_FACTOR) * 2 * PI) @@ -76,6 +76,7 @@ static constexpr double INSET_OVERLAP_TOLERANCE = 0.4; //FIXME This is quite a lot. static constexpr double EXTERNAL_INFILL_MARGIN = 3; static constexpr double BRIDGE_INFILL_MARGIN = 1; +static constexpr double WIPE_TOWER_MARGIN = 15.; //FIXME Better to use an inline function with an explicit return type. //inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); } #define scale_(val) ((val) / SCALING_FACTOR) diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 8b1f86a3ac7..ececd0b15b0 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -208,6 +208,11 @@ const std::string& var_dir() std::string var(const std::string &file_name) { + boost::system::error_code ec; + if (boost::filesystem::exists(file_name, ec)) { + return file_name; + } + auto file = (boost::filesystem::path(g_var_dir) / file_name).make_preferred(); return file.string(); } diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 173b0ce0127..71a4334ab9b 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -91,6 +91,8 @@ set(SLIC3R_GUI_SOURCES GUI/AuxiliaryDialog.hpp GUI/Auxiliary.cpp GUI/Auxiliary.hpp + GUI/DailyTips.cpp + GUI/DailyTips.hpp GUI/Project.cpp GUI/Project.hpp GUI/BackgroundSlicingProcess.cpp @@ -114,6 +116,8 @@ set(SLIC3R_GUI_SOURCES GUI/OpenGLManager.cpp GUI/Selection.hpp GUI/Selection.cpp + GUI/SlicingProgressNotification.cpp + GUI/SlicingProgressNotification.hpp GUI/Gizmos/GLGizmosManager.cpp GUI/Gizmos/GLGizmosManager.hpp GUI/Gizmos/GLGizmosCommon.cpp @@ -288,7 +292,7 @@ set(SLIC3R_GUI_SOURCES GUI/3DBed.hpp GUI/Camera.cpp GUI/Camera.hpp - GUI/CameraUtils.cpp + GUI/CameraUtils.cpp GUI/CameraUtils.hpp GUI/wxExtensions.cpp GUI/wxExtensions.hpp @@ -391,7 +395,7 @@ set(SLIC3R_GUI_SOURCES GUI/DragCanvas.hpp GUI/PublishDialog.cpp GUI/PublishDialog.hpp - GUI/RecenterDialog.cpp + GUI/RecenterDialog.cpp GUI/RecenterDialog.hpp GUI/PrivacyUpdateDialog.cpp GUI/PrivacyUpdateDialog.hpp @@ -419,13 +423,13 @@ set(SLIC3R_GUI_SOURCES GUI/CalibrationWizard.cpp GUI/CalibrationWizardPage.cpp GUI/CalibrationWizardPage.hpp - GUI/CalibrationWizardStartPage.cpp + GUI/CalibrationWizardStartPage.cpp GUI/CalibrationWizardStartPage.hpp - GUI/CalibrationWizardPresetPage.cpp + GUI/CalibrationWizardPresetPage.cpp GUI/CalibrationWizardPresetPage.hpp - GUI/CalibrationWizardCaliPage.cpp + GUI/CalibrationWizardCaliPage.cpp GUI/CalibrationWizardCaliPage.hpp - GUI/CalibrationWizardSavePage.cpp + GUI/CalibrationWizardSavePage.cpp GUI/CalibrationWizardSavePage.hpp GUI/Calibration.hpp GUI/Calibration.cpp @@ -435,6 +439,8 @@ set(SLIC3R_GUI_SOURCES GUI/BonjourDialog.cpp GUI/BedShapeDialog.hpp GUI/BedShapeDialog.cpp + GUI/CreatePresetsDialog.hpp + GUI/CreatePresetsDialog.cpp Utils/json_diff.hpp Utils/json_diff.cpp GUI/KBShortcutsDialog.hpp @@ -445,6 +451,8 @@ set(SLIC3R_GUI_SOURCES Utils/FixModelByWin10.hpp Utils/Bonjour.cpp Utils/Bonjour.hpp + Utils/FileHelp.cpp + Utils/FileHelp.hpp Utils/PresetUpdater.cpp Utils/PresetUpdater.hpp Utils/Process.cpp diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 88c61ac8b12..2dee760cbca 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -645,8 +645,12 @@ void Bed3D::update_bed_triangles() (*model_offset_ptr)(1) = m_build_volume.bounding_volume2d().min.y() - bed_ext.min.y(); (*model_offset_ptr)(2) = -0.41 + GROUND_Z; - std::vector new_bed_shape; - for (auto point: m_bed_shape) { + std::vector origin_bed_shape; + for (size_t i = 0; i < m_bed_shape.size(); i++) { + origin_bed_shape.push_back(m_bed_shape[i] - m_bed_shape[0]); + } + std::vector new_bed_shape; // offset to correct origin + for (auto point : origin_bed_shape) { Vec2d new_point(point.x() + model_offset_ptr->x(), point.y() + model_offset_ptr->y()); new_bed_shape.push_back(new_point); } diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 7325941ed01..f407a999a6c 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -612,30 +612,38 @@ bool GLWipeTowerVolume::IsTransparent() { } std::vector GLVolumeCollection::load_object( - const ModelObject* model_object, - int obj_idx, - const std::vector& instance_idxs) + const ModelObject *model_object, + int obj_idx, + const std::vector &instance_idxs, + const std::string &color_by, + bool opengl_initialized) { std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int instance_idx : instance_idxs) - volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx)); + volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized)); return volumes_idx; } + int GLVolumeCollection::load_object_volume( - const ModelObject* model_object, + const ModelObject *model_object, int obj_idx, int volume_idx, int instance_idx, + const std::string &color_by, + bool opengl_initialized, bool in_assemble_view, bool use_loaded_id) { const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); const ModelInstance *instance = model_object->instances[instance_idx]; + auto color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4]; + color.a(model_volume->is_model_part() ? 0.7f : 0.4f); + std::shared_ptr mesh = model_volume->mesh_ptr(); - this->volumes.emplace_back(new GLVolume()); + this->volumes.emplace_back(new GLVolume(color)); GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); v.name = model_volume->name; @@ -647,7 +655,9 @@ int GLVolumeCollection::load_object_volume( v.mesh_raycaster = std::make_unique(mesh); #endif // ENABLE_SMOOTH_NORMALS v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); - if (model_volume->is_model_part()) { + + if (model_volume->is_model_part()) + { // GLVolume will reference a convex hull from model_volume! v.set_convex_hull(model_volume->get_convex_hull_shared_ptr()); if (extruder_id != -1) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index ce10a463f2f..c3f0d95b2fc 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -440,18 +440,21 @@ class GLVolumeCollection ~GLVolumeCollection() { clear(); } std::vector load_object( - const ModelObject* model_object, + const ModelObject *model_object, int obj_idx, - const std::vector& instance_idxs); + const std::vector &instance_idxs, + const std::string &color_by, + bool opengl_initialized); int load_object_volume( - const ModelObject* model_object, + const ModelObject *model_object, int obj_idx, int volume_idx, int instance_idx, + const std::string &color_by, + bool opengl_initialized, bool in_assemble_view = false, bool use_loaded_id = false); - // Load SLA auxiliary GLVolumes (for support trees or pad). void load_object_auxiliary( const SLAPrintObject *print_object, diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 197b2329570..6e89a04d46b 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -323,12 +323,6 @@ void AMSMaterialsSetting::create_panel_kn(wxWindow* parent) m_n_param->Hide(); m_input_n_val->Hide(); - // hide n (P1P old logic) - //if (!this->obj || !this->obj->is_high_printer_type()) { - // m_n_param->Hide(); - // m_input_n_val->Hide(); - //} - sizer->Add(0, 0, 0, wxTOP, FromDIP(10)); sizer->Add(m_ratio_text, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(20)); sizer->Add(0, 0, 0, wxTOP, FromDIP(16)); @@ -447,7 +441,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { } // set k / n value - if (!obj->is_high_printer_type()) { + if (obj->get_printer_series() != PrinterSeries::SERIES_X1) { // set extrusion cali ratio int cali_tray_id = ams_id * 4 + tray_id; @@ -490,7 +484,9 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (preset_bundle) { for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { - if (it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) { + auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()]; + std::string filament_id = filament_item.filament_id; + if (it->filament_id.compare(filament_id) == 0) { //check is it in the filament blacklist @@ -501,9 +497,12 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) std::string filamnt_type; it->get_filament_type(filamnt_type); - if (it->vendor) { - DeviceManager::check_filaments_in_blacklist(it->vendor->name, filamnt_type, in_blacklist, action, info); + auto vendor = dynamic_cast (it->config.option("filament_vendor")); + if (vendor && (vendor->values.size() > 0)) { + std::string vendor_name = vendor->values[0]; + DeviceManager::check_filaments_in_blacklist(vendor_name, filamnt_type, in_blacklist, action, info); } + if (in_blacklist) { if (action == "prohibition") { @@ -545,12 +544,6 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) return; } - if (ams_filament_id.empty() || nozzle_temp_min.empty() || nozzle_temp_max.empty() || m_filament_type.empty()) { - BOOST_LOG_TRIVIAL(trace) << "Invalid Setting id"; - MessageDialog msg_dlg(nullptr, _L("You need to select the material type and color first."), wxEmptyString, wxICON_WARNING | wxOK); - msg_dlg.ShowModal(); - return; - } // set filament if (m_is_third) { @@ -566,9 +559,9 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) wxString k_text = m_input_k_val->GetTextCtrl()->GetValue(); wxString n_text = m_input_n_val->GetTextCtrl()->GetValue(); - if (!obj->is_high_printer_type() && !ExtrusionCalibration::check_k_validation(k_text)) { - wxString k_tips = _L("Please input a valid value (K in 0~0.5)"); - wxString kn_tips = _L("Please input a valid value (K in 0~0.5, N in 0.6~2.0)"); + if ((obj->get_printer_series() != PrinterSeries::SERIES_X1) && !ExtrusionCalibration::check_k_validation(k_text)) { + wxString k_tips = _L("Please input a valid value (K in 0~0.3)"); + wxString kn_tips = _L("Please input a valid value (K in 0~0.3, N in 0.6~2.0)"); MessageDialog msg_dlg(nullptr, k_tips, wxEmptyString, wxICON_WARNING | wxOK); msg_dlg.ShowModal(); return; @@ -591,7 +584,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) ; } - if (obj->is_high_printer_type()) { + if (obj->get_printer_series() == PrinterSeries::SERIES_X1) { PACalibIndexInfo select_index_info; select_index_info.tray_id = tray_id; select_index_info.nozzle_diameter = obj->nozzle_diameter; @@ -630,7 +623,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) ; } - if (obj->is_high_printer_type()) { + if (obj->get_printer_series() == PrinterSeries::SERIES_X1) { PACalibIndexInfo select_index_info; select_index_info.tray_id = cali_tray_id; select_index_info.nozzle_diameter = obj->nozzle_diameter; @@ -729,7 +722,7 @@ void AMSMaterialsSetting::update_widgets() else m_panel_normal->Hide(); m_panel_kn->Show(); - } else if (obj && (obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_TYAY) || obj->is_high_printer_type())) { + } else if (obj && (obj->ams_support_virtual_tray || (obj->get_printer_series() == PrinterSeries::SERIES_X1))) { m_panel_normal->Show(); m_panel_kn->Show(); } else { @@ -759,6 +752,7 @@ bool AMSMaterialsSetting::Show(bool show) void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_min, wxString temp_max, wxString k, wxString n) { + if (!obj) return; update_widgets(); // set default value if (k.IsEmpty()) @@ -771,14 +765,22 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi int selection_idx = -1, idx = 0; wxArrayString filament_items; + + std::set filament_id_set; PresetBundle* preset_bundle = wxGetApp().preset_bundle; if (preset_bundle) { BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size(); for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) { - // filter by system preset - if (!filament_it->is_system) continue; + //filter by system preset + Preset& preset = *filament_it; + /*The situation where the user preset is not displayed is as follows: + 1. Not a root preset + 2. Not system preset and the printer firmware does not support user preset */ + if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) { + continue; + } for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) { // filter by system preset @@ -786,7 +788,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi // get printer_model ConfigOption* printer_model_opt = printer_it->config.option("printer_model"); ConfigOptionString* printer_model_str = dynamic_cast(printer_model_opt); - if (!printer_model_str || !obj) + if (!printer_model_str ) continue; // use printer_model as printer type @@ -802,7 +804,30 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi else { filament_id_set.insert(filament_it->filament_id); // name matched - filament_items.push_back(filament_it->alias); + if (filament_it->is_system) { + filament_items.push_back(filament_it->alias); + FilamentInfos filament_infos; + filament_infos.filament_id = filament_it->filament_id; + filament_infos.setting_id = filament_it->setting_id; + map_filament_items[filament_it->alias] = filament_infos; + } + else { + char target = '@'; + size_t pos = filament_it->name.find(target); + if (pos != std::string::npos) { + std::string user_preset_alias = filament_it->name.substr(0, pos-1); + wxString wx_user_preset_alias = wxString(user_preset_alias.c_str(), wxConvUTF8); + user_preset_alias = wx_user_preset_alias.ToStdString(); + + filament_items.push_back(user_preset_alias); + FilamentInfos filament_infos; + filament_infos.filament_id = filament_it->filament_id; + filament_infos.setting_id = filament_it->setting_id; + map_filament_items[user_preset_alias] = filament_infos; + } + + } + if (filament_it->filament_id == ams_filament_id) { selection_idx = idx; @@ -853,7 +878,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi m_readonly_filament->Hide(); } - if (obj->is_high_printer_type()) { + if (obj->get_printer_series() == PrinterSeries::SERIES_X1) { m_title_pa_profile->Show(); m_comboBox_cali_result->Show(); m_input_k_val->Disable(); @@ -913,40 +938,44 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) PresetBundle* preset_bundle = wxGetApp().preset_bundle; if (preset_bundle) { for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { - if (!m_comboBox_filament->GetValue().IsEmpty() && it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) { - - // ) if nozzle_temperature_range is found - ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low"); - if (opt_min) { - ConfigOptionInts* opt_min_ints = dynamic_cast(opt_min); - if (opt_min_ints) { - wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0)); - m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min); + if (!m_comboBox_filament->GetValue().IsEmpty()) { + auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()]; + std::string filament_id = filament_item.filament_id; + if (it->filament_id.compare(filament_id) == 0) { + + // ) if nozzle_temperature_range is found + ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low"); + if (opt_min) { + ConfigOptionInts* opt_min_ints = dynamic_cast(opt_min); + if (opt_min_ints) { + wxString text_nozzle_temp_min = wxString::Format("%d", opt_min_ints->get_at(0)); + m_input_nozzle_min->GetTextCtrl()->SetValue(text_nozzle_temp_min); + } } - } - ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high"); - if (opt_max) { - ConfigOptionInts* opt_max_ints = dynamic_cast(opt_max); - if (opt_max_ints) { - wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0)); - m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max); + ConfigOption* opt_max = it->config.option("nozzle_temperature_range_high"); + if (opt_max) { + ConfigOptionInts* opt_max_ints = dynamic_cast(opt_max); + if (opt_max_ints) { + wxString text_nozzle_temp_max = wxString::Format("%d", opt_max_ints->get_at(0)); + m_input_nozzle_max->GetTextCtrl()->SetValue(text_nozzle_temp_max); + } } - } - ConfigOption* opt_type = it->config.option("filament_type"); - bool found_filament_type = false; - if (opt_type) { - ConfigOptionStrings* opt_type_strs = dynamic_cast(opt_type); - if (opt_type_strs) { - found_filament_type = true; - //m_filament_type = opt_type_strs->get_at(0); - std::string display_filament_type; - m_filament_type = it->config.get_filament_type(display_filament_type); + ConfigOption* opt_type = it->config.option("filament_type"); + bool found_filament_type = false; + if (opt_type) { + ConfigOptionStrings* opt_type_strs = dynamic_cast(opt_type); + if (opt_type_strs) { + found_filament_type = true; + //m_filament_type = opt_type_strs->get_at(0); + std::string display_filament_type; + m_filament_type = it->config.get_filament_type(display_filament_type); + } } - } - if (!found_filament_type) - m_filament_type = ""; + if (!found_filament_type) + m_filament_type = ""; - break; + break; + } } } } @@ -985,6 +1014,13 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) if (preset_bundle) { for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { + auto itor = map_filament_items.find(m_comboBox_filament->GetValue().ToStdString()); + if ( itor != map_filament_items.end()) { + ams_filament_id = itor->second.filament_id; + ams_setting_id = itor->second.setting_id; + break; + } + if (it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) { ams_filament_id = it->filament_id; ams_setting_id = it->setting_id; @@ -997,7 +1033,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) m_pa_profile_items.clear(); m_comboBox_cali_result->SetValue(wxEmptyString); - if (this->obj->is_high_printer_type()) { + if (obj->get_printer_series() == PrinterSeries::SERIES_X1) { m_input_k_val->GetTextCtrl()->SetValue(wxEmptyString); std::vector cali_history = this->obj->pa_calib_tab; for (auto cali_item : cali_history) { diff --git a/src/slic3r/GUI/AMSMaterialsSetting.hpp b/src/slic3r/GUI/AMSMaterialsSetting.hpp index ee5eca9c46a..847bc834038 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.hpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.hpp @@ -180,6 +180,12 @@ class AMSMaterialsSetting : public DPIDialog #endif ComboBox * m_comboBox_cali_result; TextInput* m_readonly_filament; + + struct FilamentInfos { + std::string filament_id; + std::string setting_id; + }; + std::map map_filament_items; }; wxDECLARE_EVENT(EVT_SELECTED_COLOR, wxCommandEvent); diff --git a/src/slic3r/GUI/AMSSetting.cpp b/src/slic3r/GUI/AMSSetting.cpp index cad793ea4d4..ac62d1ebaf8 100644 --- a/src/slic3r/GUI/AMSSetting.cpp +++ b/src/slic3r/GUI/AMSSetting.cpp @@ -192,8 +192,8 @@ void AMSSetting::create() wxPanel* m_panel_img = new wxPanel(m_panel_body, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_panel_img->SetBackgroundColour(AMS_SETTING_GREY200); wxBoxSizer *m_sizer_img = new wxBoxSizer(wxVERTICAL); - ams_img = new wxStaticBitmap(m_panel_img, wxID_ANY, create_scaled_bitmap("ams_icon", nullptr, 126), wxDefaultPosition, wxDefaultSize); - m_sizer_img->Add(ams_img, 0, wxALIGN_CENTER | wxTOP, 26); + m_am_img = new wxStaticBitmap(m_panel_img, wxID_ANY, create_scaled_bitmap("ams_icon", nullptr, 126), wxDefaultPosition, wxDefaultSize); + m_sizer_img->Add(m_am_img, 0, wxALIGN_CENTER | wxTOP, 26); m_sizer_img->Add(0, 0, 0, wxTOP, 18); m_panel_img->SetSizer(m_sizer_img); m_panel_img->Layout(); @@ -262,17 +262,9 @@ void AMSSetting::update_insert_material_read_mode(bool selected) Fit(); } -void AMSSetting::update_image(std::string ams_type) +void AMSSetting::update_ams_img(std::string ams_icon_str) { - if (ams_type == m_current_ams_type) return; - if (ams_type == "generic") { - ams_img->SetBitmap(create_scaled_bitmap("monitor_upgrade_f1", nullptr, 126)); - } - else { - ams_img->SetBitmap(create_scaled_bitmap("ams_icon", nullptr, 126)); - } - m_current_ams_type = ams_type; - Layout(); + m_am_img->SetBitmap(create_scaled_bitmap(ams_icon_str, nullptr, 126)); } void AMSSetting::update_starting_read_mode(bool selected) @@ -292,12 +284,24 @@ void AMSSetting::update_starting_read_mode(bool selected) void AMSSetting::update_remain_mode(bool selected) { + if (obj->is_support_update_remain) { + m_checkbox_remain->Show(); + m_title_remain->Show(); + m_tip_remain_line1->Show(); + Layout(); + } + else { + m_checkbox_remain->Hide(); + m_title_remain->Hide(); + m_tip_remain_line1->Hide(); + Layout(); + } m_checkbox_remain->SetValue(selected); } void AMSSetting::update_switch_filament(bool selected) { - if (obj->is_function_supported(PrinterFunction::FUNC_AUTO_SWITCH_FILAMENT)) { + if (obj->is_support_filament_backup) { m_checkbox_switch_filament->Show(); m_title_switch_filament->Show(); m_tip_switch_filament_line1->Show(); diff --git a/src/slic3r/GUI/AMSSetting.hpp b/src/slic3r/GUI/AMSSetting.hpp index 6afaea68e5c..4fddf47660c 100644 --- a/src/slic3r/GUI/AMSSetting.hpp +++ b/src/slic3r/GUI/AMSSetting.hpp @@ -27,8 +27,8 @@ class AMSSetting : public DPIDialog ~AMSSetting(); void create(); - void update_insert_material_read_mode(bool selected); - void update_image(std::string ams_type); + void update_insert_material_read_mode(bool selected); + void update_ams_img(std::string ams_icon_str); void update_starting_read_mode(bool selected); void update_remain_mode(bool selected); void update_switch_filament(bool selected); @@ -41,13 +41,13 @@ class AMSSetting : public DPIDialog wxStaticText *append_text(wxString text); MachineObject *obj{nullptr}; bool ams_support_remain{false}; + wxStaticBitmap* m_am_img; int ams_id { 0 }; protected: void on_dpi_changed(const wxRect &suggested_rect) override; protected: - std::string m_current_ams_type; wxPanel * m_panel_body; CheckBox * m_checkbox_Insert_material_auto_read; wxStaticText *m_title_Insert_material_auto_read; @@ -70,7 +70,7 @@ class AMSSetting : public DPIDialog wxStaticText *m_tip_ams_img; Button * m_button_auto_demarcate; - wxStaticBitmap* ams_img; + wxBoxSizer *m_sizer_Insert_material_tip_inline; wxBoxSizer *m_sizer_starting_tip_inline; wxBoxSizer *m_sizer_remain_inline; diff --git a/src/slic3r/GUI/AmsMappingPopup.cpp b/src/slic3r/GUI/AmsMappingPopup.cpp index 28c3010e7f9..1c4c1868160 100644 --- a/src/slic3r/GUI/AmsMappingPopup.cpp +++ b/src/slic3r/GUI/AmsMappingPopup.cpp @@ -186,7 +186,7 @@ void MaterialItem::doRender(wxDC &dc) auto mcolor = m_material_coloul; auto acolor = m_ams_coloul; - if (mcolor.Alpha() == 0) { + if (mcolor.Alpha() == 0 || acolor.Alpha() == 0) { dc.DrawBitmap(m_transparent_mitem.bmp(), FromDIP(1), FromDIP(1)); } @@ -1332,7 +1332,7 @@ void AmsReplaceMaterialDialog::update_machine_obj(MachineObject* obj) m_scrollview_groups->SetMinSize(wxSize(FromDIP(400), height)); m_scrollview_groups->SetMaxSize(wxSize(FromDIP(400), height)); } else { - if (!obj->is_function_supported(PrinterFunction::FUNC_FILAMENT_BACKUP)) { + if (!obj->is_support_filament_backup) { label_txt->SetLabel(_L("The printer does not currently support auto refill.")); } else if (!obj->ams_auto_switch_filament_flag) { @@ -1340,11 +1340,12 @@ void AmsReplaceMaterialDialog::update_machine_obj(MachineObject* obj) } else { label_txt->SetLabelText(_L("If there are two identical filaments in AMS, AMS filament backup will be enabled. \n(Currently supporting automatic supply of consumables with the same brand, material type, and color)")); - } + } label_txt->SetMinSize(wxSize(FromDIP(380), -1)); label_txt->SetMaxSize(wxSize(FromDIP(380), -1)); label_txt->Wrap(FromDIP(380)); + } m_scrollview_groups->Layout(); @@ -1548,10 +1549,13 @@ void AmsRMGroup::doRender(wxDC& dc) dc.SetFont(::Label::Body_12); auto text_size = dc.GetTextExtent(tray_name); dc.SetTextForeground(tray_color.GetLuminance() < 0.6 ? *wxWHITE : wxColour(0x262E30)); + if (tray_color.Alpha() == 0) {dc.SetTextForeground(wxColour(0x262E30));} + dc.DrawText(tray_name, x_center - text_size.x / 2, size.y - y_center - text_size.y / 2); //draw split line dc.SetPen(wxPen(*wxWHITE, 2)); + if (tray_color.Alpha() == 0) {dc.SetPen(wxPen(wxColour(0xCECECE), 2));} dc.SetBrush(*wxTRANSPARENT_BRUSH); auto pos_sp_start = CalculateEndpoint(wxPoint(x, y), (360 - startAngle), size.x / 2 - FromDIP(3)); dc.DrawLine(wxPoint(x, y), pos_sp_start); diff --git a/src/slic3r/GUI/BBLTopbar.cpp b/src/slic3r/GUI/BBLTopbar.cpp index be5656c8282..386dfea00f0 100644 --- a/src/slic3r/GUI/BBLTopbar.cpp +++ b/src/slic3r/GUI/BBLTopbar.cpp @@ -577,7 +577,7 @@ void BBLTopbar::OnFileToolItem(wxAuiToolBarEvent& evt) tb->SetToolSticky(evt.GetId(), true); if (!m_skip_popup_file_menu) { - this->PopupMenu(m_file_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2)); + GetParent()->PopupMenu(m_file_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2)); } else { m_skip_popup_file_menu = false; @@ -594,7 +594,7 @@ void BBLTopbar::OnDropdownToolItem(wxAuiToolBarEvent& evt) tb->SetToolSticky(evt.GetId(), true); if (!m_skip_popup_dropdown_menu) { - PopupMenu(&m_top_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2)); + GetParent()->PopupMenu(&m_top_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2)); } else { m_skip_popup_dropdown_menu = false; @@ -612,7 +612,7 @@ void BBLTopbar::OnCalibToolItem(wxAuiToolBarEvent &evt) if (!m_skip_popup_calib_menu) { auto rec = this->GetToolRect(ID_CALIB); - PopupMenu(&m_calib_menu, wxPoint(rec.GetLeft(), this->GetSize().GetHeight() - 2)); + GetParent()->PopupMenu(&m_calib_menu, wxPoint(rec.GetLeft(), this->GetSize().GetHeight() - 2)); } else { m_skip_popup_calib_menu = false; } diff --git a/src/slic3r/GUI/BindDialog.cpp b/src/slic3r/GUI/BindDialog.cpp index fae5731dd67..ca0d4fd7022 100644 --- a/src/slic3r/GUI/BindDialog.cpp +++ b/src/slic3r/GUI/BindDialog.cpp @@ -59,6 +59,8 @@ wxString get_fail_reason(int code) SetDoubleBuffered(true); #endif //__WINDOWS__ + m_tocken.reset(new int(0)); + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); @@ -296,8 +298,7 @@ wxString get_fail_reason(int code) wxBoxSizer* m_sizer_bind_failed_info = new wxBoxSizer(wxVERTICAL); m_sw_bind_failed_info->SetSizer( m_sizer_bind_failed_info ); - m_link_network_state = new Label(m_sw_bind_failed_info, _L("Check the status of current system services")); - m_link_network_state->SetForegroundColour(0x009688); + m_link_network_state = new wxHyperlinkCtrl(m_sw_bind_failed_info, wxID_ANY,_L("Check the status of current system services"),""); m_link_network_state->SetFont(::Label::Body_12); m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); }); m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND); }); @@ -433,26 +434,6 @@ wxString get_fail_reason(int code) Bind(wxEVT_SHOW, &BindMachineDialog::on_show, this); Bind(wxEVT_CLOSE_WINDOW, &BindMachineDialog::on_close, this); - Bind(wxEVT_WEBREQUEST_STATE, [this](wxWebRequestEvent& evt) { - switch (evt.GetState()) { - // Request completed - case wxWebRequest::State_Completed: { - wxImage avatar_stream = *evt.GetResponse().GetStream(); - if (avatar_stream.IsOk()) { - avatar_stream.Rescale(FromDIP(60), FromDIP(60)); - auto bitmap = new wxBitmap(avatar_stream); - //bitmap->SetSize(wxSize(FromDIP(60), FromDIP(60))); - m_avatar->SetBitmap(*bitmap); - Layout(); - } - break; - } - // Request failed - case wxWebRequest::State_Failed: { - break; - } - } - }); m_button_bind->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BindMachineDialog::on_bind_printer), NULL, this); m_button_cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BindMachineDialog::on_cancel), NULL, this); @@ -536,10 +517,6 @@ wxString get_fail_reason(int code) m_bind_job->cancel(); m_bind_job->join(); } - - if (web_request.IsOk()) { - web_request.Cancel(); - } } void BindMachineDialog::on_close(wxCloseEvent &event) @@ -597,7 +574,7 @@ wxString get_fail_reason(int code) m_simplebook->SetSelection(0); m_bind_job = std::make_shared(m_status_bar, wxGetApp().plater(), m_machine_info->dev_id, m_machine_info->dev_ip, m_machine_info->bind_sec_link); - if (m_machine_info && (m_machine_info->printer_type == "BL-P001" || m_machine_info->printer_type == "BL-P002")) { + if (m_machine_info && (m_machine_info->get_printer_series() == PrinterSeries::SERIES_X1)) { m_bind_job->set_improved(false); } else { @@ -617,7 +594,7 @@ void BindMachineDialog::on_dpi_changed(const wxRect &suggested_rect) void BindMachineDialog::update_machine_info(MachineObject* info) { m_machine_info = info; - if (m_machine_info && (m_machine_info->printer_type == "BL-P001" || m_machine_info->printer_type == "BL-P002")) { + if (m_machine_info && (m_machine_info->get_printer_series() == PrinterSeries::SERIES_X1)) { m_button_bind->Enable(true); m_panel_agreement->Hide(); } @@ -650,14 +627,30 @@ void BindMachineDialog::on_show(wxShowEvent &event) if (wxGetApp().is_user_login()) { wxString username_text = from_u8(wxGetApp().getAgent()->get_user_nickanme()); m_user_name->SetLabelText(username_text); - web_request = wxWebSession::GetDefault().CreateRequest(this, wxGetApp().getAgent()->get_user_avatar()); - if (!web_request.IsOk()) { - // todo request fail - } - // Start the request - web_request.Start(); - } + std::string avatar_url = wxGetApp().getAgent()->get_user_avatar(); + Slic3r::Http http = Slic3r::Http::get(avatar_url); + std::string suffix = avatar_url.substr(avatar_url.find_last_of(".") + 1); + http.header("accept", "image/" + suffix) + .on_complete([this, time = std::weak_ptr(m_tocken)](std::string body, unsigned int status) { + if (time.expired()) return; + wxMemoryInputStream stream(body.data(), body.size()); + wxImage avatar_image; + if (avatar_image.LoadFile(stream, wxBITMAP_TYPE_ANY)) { + if (avatar_image.IsOk() && m_avatar) { + avatar_image.Rescale(this->FromDIP(60), this->FromDIP(60)); + CallAfter([this, avatar_image]() { + auto bitmap = new wxBitmap(avatar_image); + m_avatar->SetBitmap(*bitmap); + Layout(); + }); + } + } + }) + .on_error([this](std::string body, std::string error, unsigned status) { + //BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error; + }).perform(); + } Layout(); event.Skip(); } @@ -667,7 +660,8 @@ void BindMachineDialog::on_show(wxShowEvent &event) UnBindMachineDialog::UnBindMachineDialog(Plater *plater /*= nullptr*/) : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, _L("Log out printer"), wxDefaultPosition, wxDefaultSize, wxCAPTION) { - std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + m_tocken.reset(new int(0)); +std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); SetBackgroundColour(*wxWHITE); @@ -779,33 +773,12 @@ UnBindMachineDialog::UnBindMachineDialog(Plater *plater /*= nullptr*/) m_button_unbind->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(UnBindMachineDialog::on_unbind_printer), NULL, this); m_button_cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(UnBindMachineDialog::on_cancel), NULL, this); - Bind(wxEVT_WEBREQUEST_STATE, [this](wxWebRequestEvent& evt) { - switch (evt.GetState()) { - // Request completed - case wxWebRequest::State_Completed: { - wxImage avatar_stream = *evt.GetResponse().GetStream(); - if (avatar_stream.IsOk()) { - avatar_stream.Rescale(FromDIP(60), FromDIP(60)); - auto bitmap = new wxBitmap(avatar_stream); - //bitmap->SetSize(wxSize(FromDIP(60), FromDIP(60))); - m_avatar->SetBitmap(*bitmap); - Layout(); - } - break; - } - // Request failed - case wxWebRequest::State_Failed: { - break; - } - } - }); wxGetApp().UpdateDlgDarkUI(this); } UnBindMachineDialog::~UnBindMachineDialog() { - web_request.Cancel(); m_button_unbind->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(UnBindMachineDialog::on_unbind_printer), NULL, this); m_button_cancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(UnBindMachineDialog::on_cancel), NULL, this); } @@ -874,12 +847,30 @@ void UnBindMachineDialog::on_show(wxShowEvent &event) if (wxGetApp().is_user_login()) { wxString username_text = from_u8(wxGetApp().getAgent()->get_user_name()); m_user_name->SetLabelText(username_text); - wxString avatar_url = wxGetApp().getAgent()->get_user_avatar(); - web_request = wxWebSession::GetDefault().CreateRequest(this, avatar_url); - if (!web_request.IsOk()) { - // todo request fail - } - web_request.Start(); + + std::string avatar_url = wxGetApp().getAgent()->get_user_avatar(); + Slic3r::Http http = Slic3r::Http::get(avatar_url); + std::string suffix = avatar_url.substr(avatar_url.find_last_of(".") + 1); + http.header("accept", "image/" + suffix) + .on_complete([this, time = std::weak_ptr(m_tocken)](std::string body, unsigned int status) { + if (time.expired()) return; + wxMemoryInputStream stream(body.data(), body.size()); + wxImage avatar_image; + if (avatar_image.LoadFile(stream, wxBITMAP_TYPE_ANY)) { + if (avatar_image.IsOk() && m_avatar) { + avatar_image.Rescale(this->FromDIP(60), this->FromDIP(60)); + CallAfter([this, avatar_image]() { + auto bitmap = new wxBitmap(avatar_image); + m_avatar->SetBitmap(*bitmap); + Layout(); + }); + } + } + }) + .on_error([this](std::string body, std::string error, unsigned status) { + //BOOST_LOG_TRIVIAL(info) << "load oss picture failed, oss path: " << oss_path << " status:" << status << " error:" << error; + }).perform(); + } Layout(); diff --git a/src/slic3r/GUI/BindDialog.hpp b/src/slic3r/GUI/BindDialog.hpp index 6df98875a10..8a8b878e36a 100644 --- a/src/slic3r/GUI/BindDialog.hpp +++ b/src/slic3r/GUI/BindDialog.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "wxExtensions.hpp" #include "Plater.hpp" #include "Widgets/StepCtrl.hpp" @@ -61,19 +62,19 @@ class BindMachineDialog : public DPIDialog wxStaticBitmap *m_static_bitmap_show_error; wxBitmap m_bitmap_show_error_close; wxBitmap m_bitmap_show_error_open; - wxWebRequest web_request; wxScrolledWindow* m_sw_bind_failed_info; Label* m_bind_failed_info; Label* m_st_txt_error_code{ nullptr }; Label* m_st_txt_error_desc{ nullptr }; Label* m_st_txt_extra_info{ nullptr }; - Label* m_link_network_state{ nullptr }; + wxHyperlinkCtrl* m_link_network_state{ nullptr }; wxString m_result_info; wxString m_result_extra; bool m_show_error_info_state = true; bool m_allow_privacy{false}; bool m_allow_notice{false}; int m_result_code; + std::shared_ptr m_tocken; MachineObject * m_machine_info{nullptr}; std::shared_ptr m_bind_job; @@ -108,7 +109,7 @@ class UnBindMachineDialog : public DPIDialog MachineObject *m_machine_info{nullptr}; wxStaticBitmap *m_avatar; wxStaticBitmap *m_printer_img; - wxWebRequest web_request; + std::shared_ptr m_tocken; public: UnBindMachineDialog(Plater *plater = nullptr); diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index a0edea0711a..080a0f7db60 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -316,13 +316,13 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_ + (grayscale ? "-gs" : "") + new_color; - /*auto it = m_map.find(bitmap_key); + auto it = m_map.find(bitmap_key); if (it != m_map.end()) - return it->second;*/ + return it->second; // map of color replaces std::map replaces; - replaces["\"#0x00AE42\""] = "\"#009688\""; +replaces["\"#0x00AE42\""] = "\"#009688\""; replaces["\"#00FF00\""] = "\"#52c7b8\""; if (dark_mode) { replaces["\"#262E30\""] = "\"#EFEFF0\""; @@ -333,7 +333,7 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_ replaces["\"#6B6B6B\""] = "\"#818182\""; replaces["\"#909090\""] = "\"#FFFFFF\""; replaces["\"#00FF00\""] = "\"#FF0000\""; - replaces["\"#009688\""] = "\"#00675b\""; +replaces["\"#009688\""] = "\"#00675b\""; } //if (!new_color.empty()) // replaces["\"#ED6B21\""] = "\"" + new_color + "\""; @@ -431,5 +431,46 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi return wxImage_to_wxBitmap_with_alpha(std::move(image), scale); } +bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out) +{ + if (scolor.size() == 9) { + unsigned char rgba[4]; + parse_color4(scolor, rgba); + rgb_out[0] = rgba[0]; + rgb_out[1] = rgba[1]; + rgb_out[2] = rgba[2]; + return true; + } + rgb_out[0] = rgb_out[1] = rgb_out[2] = 0; + if (scolor.size() != 7 || scolor.front() != '#') + return false; + const char* c = scolor.data() + 1; + for (size_t i = 0; i < 3; ++i) { + int digit1 = hex_digit_to_int(*c++); + int digit2 = hex_digit_to_int(*c++); + if (digit1 == -1 || digit2 == -1) + return false; + rgb_out[i] = (unsigned char)(digit1 * 16 + digit2); + } + + return true; +} + +bool BitmapCache::parse_color4(const std::string& scolor, unsigned char* rgba_out) +{ + rgba_out[0] = rgba_out[1] = rgba_out[2] = 0; rgba_out[3] = 255; + if ((scolor.size() != 7 && scolor.size() != 9) || scolor.front() != '#') + return false; + const char* c = scolor.data() + 1; + for (size_t i = 0; i < scolor.size() / 2; ++i) { + int digit1 = hex_digit_to_int(*c++); + int digit2 = hex_digit_to_int(*c++); + if (digit1 == -1 || digit2 == -1) + return false; + rgba_out[i] = (unsigned char)(digit1 * 16 + digit2); + } + return true; +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp index a5748acac21..ab9e4572406 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -12,8 +12,7 @@ #include "libslic3r/Color.hpp" struct NSVGimage; -namespace Slic3r { -namespace GUI { +namespace Slic3r { namespace GUI { class BitmapCache { @@ -46,9 +45,13 @@ class BitmapCache wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false, const bool dark_mode = false, const std::string& new_color = "", const float scale_in_center = 0.f); wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false); + wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE, suppress_scaling, border_width, dark_mode); } wxBitmap mksolid(size_t width, size_t height, const ColorRGB& rgb, bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false) { return mksolid(width, height, rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar(), wxALPHA_OPAQUE, suppress_scaling, border_width, dark_mode); } wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); } + static bool parse_color(const std::string& scolor, unsigned char* rgb_out); + static bool parse_color4(const std::string& scolor, unsigned char* rgba_out); + private: std::map m_map; double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs) diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index eeef068a456..520b2d1a3ae 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -15,6 +15,7 @@ namespace GUI { #define HISTORY_WINDOW_SIZE wxSize(FromDIP(700), FromDIP(600)) #define EDIT_HISTORY_DIALOG_INPUT_SIZE wxSize(FromDIP(160), FromDIP(24)) #define HISTORY_WINDOW_ITEMS_COUNT 5 +static const wxString k_tips = "Please input a valid value (K in 0~0.3)"; static wxString get_preset_name_by_filament_id(std::string filament_id) { @@ -351,18 +352,10 @@ EditCalibrationHistoryDialog::EditCalibrationHistoryDialog(wxWindow* parent, con flex_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); Label* name_title = new Label(top_panel, _L("Name")); - TextInput* name_value = new TextInput(top_panel, from_u8(m_new_result.name), "", "", wxDefaultPosition, EDIT_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER); - name_value->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this, name_value](auto& e) { - if (!name_value->GetTextCtrl()->GetValue().IsEmpty()) - m_new_result.name = name_value->GetTextCtrl()->GetValue().ToUTF8().data(); - }); - name_value->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this, name_value](auto& e) { - if (!name_value->GetTextCtrl()->GetValue().IsEmpty()) - m_new_result.name = name_value->GetTextCtrl()->GetValue().ToUTF8().data(); - e.Skip(); - }); + m_name_value = new TextInput(top_panel, from_u8(m_new_result.name), "", "", wxDefaultPosition, EDIT_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER); + flex_sizer->Add(name_title); - flex_sizer->Add(name_value); + flex_sizer->Add(m_name_value); Label* preset_name_title = new Label(top_panel, _L("Filament")); wxString preset_name = get_preset_name_by_filament_id(result.filament_id); @@ -372,30 +365,9 @@ EditCalibrationHistoryDialog::EditCalibrationHistoryDialog(wxWindow* parent, con Label* k_title = new Label(top_panel, _L("Factor K")); auto k_str = wxString::Format("%.3f", m_new_result.k_value); - TextInput* k_value = new TextInput(top_panel, k_str, "", "", wxDefaultPosition, EDIT_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER); - k_value->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this, k_value](auto& e) { - float k = 0.0f; - if (!CalibUtils::validate_input_k_value(k_value->GetTextCtrl()->GetValue(), &k)) { - MessageDialog msg_dlg(nullptr, _L("Please input a valid value (K in 0~0.5)"), wxEmptyString, wxICON_WARNING | wxOK); - msg_dlg.ShowModal(); - } - wxString k_str = wxString::Format("%.3f", k); - k_value->GetTextCtrl()->SetValue(k_str); - m_new_result.k_value = k; - }); - k_value->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this, k_value](auto& e) { - float k = 0.0f; - if (!CalibUtils::validate_input_k_value(k_value->GetTextCtrl()->GetValue(), &k)) { - MessageDialog msg_dlg(nullptr, _L("Please input a valid value (K in 0~0.5)"), wxEmptyString, wxICON_WARNING | wxOK); - msg_dlg.ShowModal(); - } - wxString k_str = wxString::Format("%.3f", k); - k_value->GetTextCtrl()->SetValue(k_str); - m_new_result.k_value = k; - e.Skip(); - }); + m_k_value = new TextInput(top_panel, k_str, "", "", wxDefaultPosition, EDIT_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER); flex_sizer->Add(k_title); - flex_sizer->Add(k_value); + flex_sizer->Add(m_k_value); // Hide: //Label* n_title = new Label(top_panel, _L("Factor N")); @@ -449,6 +421,27 @@ PACalibResult EditCalibrationHistoryDialog::get_result() { } void EditCalibrationHistoryDialog::on_save(wxCommandEvent& event) { + wxString name = m_name_value->GetTextCtrl()->GetValue(); + if (name.IsEmpty()) + return; + if (name.Length() > 40) { + MessageDialog msg_dlg(nullptr, _L("The name cannot exceed 40 characters."), wxEmptyString, wxICON_WARNING | wxOK); + msg_dlg.ShowModal(); + return; + } + m_new_result.name = m_name_value->GetTextCtrl()->GetValue().ToUTF8().data(); + + float k = 0.0f; + if (!CalibUtils::validate_input_k_value(m_k_value->GetTextCtrl()->GetValue(), &k)) { + MessageDialog msg_dlg(nullptr, _L(k_tips), wxEmptyString, wxICON_WARNING | wxOK); + msg_dlg.ShowModal(); + return; + } + wxString k_str = wxString::Format("%.3f", k); + m_k_value->GetTextCtrl()->SetValue(k_str); + m_new_result.k_value = k; + + EndModal(wxID_OK); } diff --git a/src/slic3r/GUI/CaliHistoryDialog.hpp b/src/slic3r/GUI/CaliHistoryDialog.hpp index 38576fcba0a..c44d4399e59 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.hpp +++ b/src/slic3r/GUI/CaliHistoryDialog.hpp @@ -50,6 +50,9 @@ class EditCalibrationHistoryDialog : public DPIDialog protected: PACalibResult m_new_result; + + TextInput* m_name_value{ nullptr }; + TextInput* m_k_value{ nullptr }; }; } // namespace GUI diff --git a/src/slic3r/GUI/Calibration.cpp b/src/slic3r/GUI/Calibration.cpp index ab0b2b2a39b..34ffd6f15b9 100644 --- a/src/slic3r/GUI/Calibration.cpp +++ b/src/slic3r/GUI/Calibration.cpp @@ -215,36 +215,27 @@ wxWindow* CalibrationDialog::create_check_option(wxString title, wxWindow* paren void CalibrationDialog::update_cali(MachineObject *obj) { if (!obj) return; - if (obj->is_function_supported(PrinterFunction::FUNC_AI_MONITORING) - && obj->is_function_supported(PrinterFunction::FUNC_LIDAR_CALIBRATION)) { + if (obj->is_support_ai_monitoring && obj->is_support_lidar_calibration) { select_xcam_cali->Show(); } else { select_xcam_cali->Hide(); m_checkbox_list["xcam_cali"]->SetValue(false); } - if(obj->is_function_supported(PrinterFunction::FUNC_AUTO_LEVELING)){ + if(obj->is_support_auto_leveling){ select_bed_leveling->Show(); }else{ select_bed_leveling->Hide(); m_checkbox_list["bed_leveling"]->SetValue(false); } - if (obj->is_function_supported(PrinterFunction::FUNC_MOTOR_NOISE_CALI)) { + if (obj->is_support_motor_noise_cali) { select_motor_noise->Show(); } else { select_motor_noise->Hide(); m_checkbox_list["motor_noise"]->SetValue(false); } - if (!m_checkbox_list["vibration"]->GetValue() && !m_checkbox_list["bed_leveling"]->GetValue() && !m_checkbox_list["xcam_cali"]->GetValue() && - !m_checkbox_list["motor_noise"]->GetValue()) { - m_calibration_btn->Disable(); - m_calibration_btn->SetLabel(_L("No step selected")); - return ; - } else { - m_calibration_btn->Enable(); - } if (obj->is_calibration_running() || obj->is_calibration_done()) { if (obj->is_calibration_done()) { @@ -282,6 +273,14 @@ void CalibrationDialog::update_cali(MachineObject *obj) m_calibration_flow->DeleteAllItems(); m_calibration_btn->SetLabel(_L("Start Calibration")); } + if (!obj->is_calibration_running() && !m_checkbox_list["vibration"]->GetValue() && !m_checkbox_list["bed_leveling"]->GetValue() && + !m_checkbox_list["xcam_cali"]->GetValue() && !m_checkbox_list["motor_noise"]->GetValue()) { + m_calibration_btn->Disable(); + m_calibration_btn->SetLabel(_L("No step selected")); + } + else if(!obj->is_calibration_running()){ + m_calibration_btn->Enable(); + } } bool CalibrationDialog::is_stage_list_info_changed(MachineObject *obj) diff --git a/src/slic3r/GUI/CalibrationPanel.cpp b/src/slic3r/GUI/CalibrationPanel.cpp index dfe27ec132d..88e107da84c 100644 --- a/src/slic3r/GUI/CalibrationPanel.cpp +++ b/src/slic3r/GUI/CalibrationPanel.cpp @@ -242,21 +242,26 @@ void SelectMObjectPopup::Popup(wxWindow* WXUNUSED(focus)) if (wxGetApp().is_user_login()) { if (!get_print_info_thread) { - get_print_info_thread = new boost::thread(Slic3r::create_thread([&] { + get_print_info_thread = new boost::thread(Slic3r::create_thread([this, token = std::weak_ptr(m_token)] { NetworkAgent* agent = wxGetApp().getAgent(); unsigned int http_code; std::string body; int result = agent->get_user_print_info(&http_code, &body); - if (result == 0) { - m_print_info = body; - } - else { - m_print_info = ""; - } - wxCommandEvent event(EVT_UPDATE_USER_MLIST); - event.SetEventObject(this); - wxPostEvent(this, event); - })); + + wxGetApp().CallAfter([token, this, result, body]() { + if (token.expired()) {return;} + if (result == 0) { + m_print_info = body; + } + else { + m_print_info = ""; + } + + wxCommandEvent event(EVT_UPDATE_USER_MLIST); + event.SetEventObject(this); + wxPostEvent(this, event); + }); + })); } } @@ -510,10 +515,15 @@ void CalibrationPanel::update_print_error_info(int code, std::string msg, std::s if (curr_selected >= 0 && curr_selected < CALI_MODE_COUNT) { if (m_cali_panels[curr_selected]) { auto page = m_cali_panels[curr_selected]->get_curr_step()->page; - if(page && page->get_page_type() == CaliPageType::CALI_PAGE_PRESET){ - auto preset_page = static_cast(page); - if (preset_page->get_page_status() == CaliPresetPageStatus::CaliPresetStatusSending) + if (page) { + if (page->get_page_type() == CaliPageType::CALI_PAGE_PRESET) { + auto preset_page = static_cast(page); preset_page->update_print_error_info(code, msg, extra); + } + if (page->get_page_type() == CaliPageType::CALI_PAGE_COARSE_SAVE) { + auto corase_page = static_cast(page); + corase_page->update_print_error_info(code, msg, extra); + } } } } diff --git a/src/slic3r/GUI/CalibrationPanel.hpp b/src/slic3r/GUI/CalibrationPanel.hpp index d13e643726f..a993ff28869 100644 --- a/src/slic3r/GUI/CalibrationPanel.hpp +++ b/src/slic3r/GUI/CalibrationPanel.hpp @@ -89,6 +89,7 @@ class SelectMObjectPopup : public PopupWindow std::vector m_user_list_machine_panel; boost::thread* get_print_info_thread{ nullptr }; std::string m_print_info; + std::shared_ptr m_token = std::make_shared(0); std::map m_bind_machine_list; private: diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index f05cde89fca..a96cc93f1d1 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -16,7 +16,7 @@ wxDEFINE_EVENT(EVT_CALIBRATION_JOB_FINISHED, wxCommandEvent); static const wxString NA_STR = _L("N/A"); static const float MIN_PA_K_VALUE = 0.0; -static const float MAX_PA_K_VALUE = 0.5; +static const float MAX_PA_K_VALUE = 0.3; static const float MIN_PA_K_VALUE_STEP = 0.001; bool check_preset_name_valid(const wxString& name) { @@ -185,17 +185,17 @@ void CalibrationWizard::set_cali_method(CalibrationMethod method) } } -bool CalibrationWizard::save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map &key_values, std::string& message) +bool CalibrationWizard::save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map &key_values, wxString& message) { if (new_preset_name.empty()) { - message = _u8L("The name cannot be empty."); + message = _L("The name cannot be empty."); return false; } PresetCollection *filament_presets = &wxGetApp().preset_bundle->filaments; Preset* preset = filament_presets->find_preset(old_preset_name); if (!preset) { - message = (boost::format(_u8L("The selected preset: %1% is not found.")) % old_preset_name).str(); + message = wxString::Format(_L("The selected preset: %s is not found."), old_preset_name); return false; } @@ -207,12 +207,12 @@ bool CalibrationWizard::save_preset(const std::string &old_preset_name, const st Preset *new_preset = filament_presets->find_preset(new_name); if (new_preset) { if (new_preset->is_system) { - message = _u8L("The name cannot be the same as the system preset name."); + message = _L("The name cannot be the same as the system preset name."); return false; } if (new_preset != preset) { - message = _u8L("The name is the same as another existing preset name"); + message = _L("The name is the same as another existing preset name"); return false; } if (new_preset != &filament_presets->get_edited_preset()) new_preset = &temp_preset; @@ -233,7 +233,7 @@ bool CalibrationWizard::save_preset(const std::string &old_preset_name, const st // Preset* preset = &m_presets.preset(it - m_presets.begin(), true); if (!new_preset) { BOOST_LOG_TRIVIAL(info) << "create new preset failed"; - message = _u8L("create new preset failed."); + message = _L("create new preset failed."); return false; } @@ -299,14 +299,14 @@ void CalibrationWizard::recover_preset_info(MachineObject *obj) } } -void CalibrationWizard::back_preset_info(MachineObject *obj, bool cali_finish) +void CalibrationWizard::back_preset_info(MachineObject *obj, bool cali_finish, bool back_cali_flag) { PrinterCaliInfo printer_cali_info; printer_cali_info.dev_id = obj->dev_id; printer_cali_info.cali_finished = cali_finish; printer_cali_info.cache_flow_ratio = obj->cache_flow_ratio; printer_cali_info.selected_presets = obj->selected_cali_preset; - wxGetApp().app_config->save_printer_cali_infos(printer_cali_info); + wxGetApp().app_config->save_printer_cali_infos(printer_cali_info, back_cali_flag); } void CalibrationWizard::msw_rescale() @@ -361,7 +361,7 @@ void CalibrationWizard::on_cali_go_home() go_home_dialog->on_show(); } else { if (!m_page_steps.empty()) { - back_preset_info(curr_obj, true); + back_preset_info(curr_obj, true, obj_cali_mode == m_mode); show_step(m_page_steps.front()); } } @@ -951,6 +951,7 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow cali_page->clear_last_job_status(); } else if (m_cali_method == CalibrationMethod::CALI_METHOD_MANUAL) { + CalibrationFlowCoarseSavePage* coarse_page = (static_cast(coarse_save_step->page)); CalibInfo calib_info; calib_info.dev_id = curr_obj->dev_id; Preset* temp_filament_preset = nullptr; @@ -979,17 +980,23 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow temp_filament_preset->config = preset->config; calib_info.bed_type = plate_type; - calib_info.process_bar = preset_page->get_sending_progress_bar(); calib_info.printer_prest = preset_page->get_printer_preset(curr_obj, nozzle_dia); calib_info.print_prest = preset_page->get_print_preset(); calib_info.params.mode = CalibMode::Calib_Flow_Rate; if (stage == CaliPresetStage::CALI_MANUAL_STAGE_1) { cali_stage = 1; + calib_info.process_bar = preset_page->get_sending_progress_bar(); } else if (stage == CaliPresetStage::CALI_MANUAL_STAGE_2) { cali_stage = 2; temp_filament_preset->config.set_key_value("filament_flow_ratio", new ConfigOptionFloats{ cali_value }); + if (from_page == FlowRatioCaliSource::FROM_PRESET_PAGE) { + calib_info.process_bar = preset_page->get_sending_progress_bar(); + } + else if (from_page == FlowRatioCaliSource::FROM_COARSE_PAGE) { + calib_info.process_bar = coarse_page->get_sending_progress_bar(); + } } calib_info.filament_prest = temp_filament_preset; @@ -1008,17 +1015,23 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow msg_dlg.ShowModal(); return; } - preset_page->on_cali_start_job(); if (temp_filament_preset) delete temp_filament_preset; if (cali_stage == 1) { CalibrationCaliPage *cali_coarse_page = (static_cast(cali_coarse_step->page)); cali_coarse_page->clear_last_job_status(); + preset_page->on_cali_start_job(); } else if (cali_stage == 2) { CalibrationCaliPage *cali_fine_page = (static_cast(cali_fine_step->page)); cali_fine_page->clear_last_job_status(); + if (from_page == FlowRatioCaliSource::FROM_PRESET_PAGE) { + preset_page->on_cali_start_job(); + } + else if (from_page == FlowRatioCaliSource::FROM_COARSE_PAGE) { + coarse_page->on_cali_start_job(); + } } } else { assert(false); @@ -1050,7 +1063,7 @@ void FlowRateWizard::on_cali_save() for (int i = 0; i < new_results.size(); i++) { std::map key_value_map; key_value_map.insert(std::make_pair("filament_flow_ratio", new ConfigOptionFloats{ new_results[i].second })); - std::string message; + wxString message; if (!save_preset(old_preset_name, into_u8(new_results[i].first), key_value_map, message)) { MessageDialog error_msg_dlg(nullptr, message, wxEmptyString, wxICON_WARNING | wxOK); error_msg_dlg.ShowModal(); @@ -1097,9 +1110,9 @@ void FlowRateWizard::on_cali_save() std::map key_value_map; key_value_map.insert(std::make_pair("filament_flow_ratio", new ConfigOptionFloats{ new_flow_ratio })); - std::string message; + wxString message; if (!save_preset(old_preset_name, into_u8(new_preset_name), key_value_map, message)) { - MessageDialog error_msg_dlg(nullptr, from_u8(message), wxEmptyString, wxICON_WARNING | wxOK); + MessageDialog error_msg_dlg(nullptr, message, wxEmptyString, wxICON_WARNING | wxOK); error_msg_dlg.ShowModal(); return; } @@ -1197,17 +1210,20 @@ void FlowRateWizard::on_cali_job_finished(wxString evt_data) if (cali_stage == 1) { if (m_curr_step != cali_coarse_step) show_step(cali_coarse_step); + // change ui, hide + static_cast(preset_step->page)->on_cali_finished_job(); } else if (cali_stage == 2) { if (m_curr_step != cali_fine_step) { show_step(cali_fine_step); } + // change ui, hide + static_cast(preset_step->page)->on_cali_finished_job(); + static_cast(coarse_save_step->page)->on_cali_finished_job(); } else show_step(cali_coarse_step); } - // change ui, hide - static_cast(preset_step->page)->on_cali_finished_job(); } void FlowRateWizard::cache_coarse_info(MachineObject *obj) @@ -1375,9 +1391,9 @@ void MaxVolumetricSpeedWizard::on_cali_save() std::map key_value_map; key_value_map.insert(std::make_pair("filament_max_volumetric_speed", new ConfigOptionFloats{ value })); - std::string message; + wxString message; if (!save_preset(old_preset_name, new_preset_name, key_value_map, message)) { - MessageDialog error_msg_dlg(nullptr, from_u8(message), wxEmptyString, wxICON_WARNING | wxOK); + MessageDialog error_msg_dlg(nullptr, message, wxEmptyString, wxICON_WARNING | wxOK); error_msg_dlg.ShowModal(); return; } diff --git a/src/slic3r/GUI/CalibrationWizard.hpp b/src/slic3r/GUI/CalibrationWizard.hpp index 158d42eeaf1..14cfd50a957 100644 --- a/src/slic3r/GUI/CalibrationWizard.hpp +++ b/src/slic3r/GUI/CalibrationWizard.hpp @@ -60,11 +60,11 @@ class CalibrationWizard : public wxPanel { CalibMode get_calibration_mode() { return m_mode; } - bool save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map &key_values, std::string& message); + bool save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map &key_values, wxString& message); virtual void cache_preset_info(MachineObject* obj, float nozzle_dia); virtual void recover_preset_info(MachineObject *obj); - virtual void back_preset_info(MachineObject *obj, bool cali_finish); + virtual void back_preset_info(MachineObject *obj, bool cali_finish, bool back_cali_flag = true); void msw_rescale(); void on_sys_color_changed(); diff --git a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp index 2c59f80fddd..6279cc60485 100644 --- a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp @@ -101,27 +101,27 @@ void CalibrationCaliPage::set_cali_img() { if (m_cali_mode == CalibMode::Calib_PA_Line) { if (m_cali_method == CalibrationMethod::CALI_METHOD_MANUAL) { - m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual", 400)); } else if (m_cali_method == CalibrationMethod::CALI_METHOD_AUTO) { - m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_auto", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_auto", 400)); } } else if (m_cali_mode == CalibMode::Calib_Flow_Rate) { if (m_cali_method == CalibrationMethod::CALI_METHOD_MANUAL) { if (m_page_type == CaliPageType::CALI_PAGE_CALI) - m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_coarse", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse", 400)); if (m_page_type == CaliPageType::CALI_PAGE_FINE_CALI) - m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_fine", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_fine", 400)); else - m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_coarse", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse", 400)); } else if (m_cali_method == CalibrationMethod::CALI_METHOD_AUTO) { - m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_auto", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_auto", 400)); } } else if (m_cali_mode == CalibMode::Calib_Vol_speed_Tower) { - m_picture_panel->set_img(create_scaled_bitmap("max_volumetric_speed_calibration", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "max_volumetric_speed_calibration", 400)); } } @@ -129,9 +129,9 @@ void CalibrationCaliPage::set_pa_cali_image(int stage) { if (m_cali_mode == CalibMode::Calib_PA_Line && m_cali_method == CALI_METHOD_MANUAL) { if (stage == 0) { - m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual", 400)); } else if (stage == 1) { - m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual", nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual", 400)); } } } @@ -428,7 +428,7 @@ void CalibrationCaliPage::reset_printing_values() void CalibrationCaliPage::on_device_connected(MachineObject* obj) { - ; + reset_printing_values(); } void CalibrationCaliPage::set_cali_method(CalibrationMethod method) @@ -473,6 +473,20 @@ void CalibrationCaliPage::set_cali_method(CalibrationMethod method) } } +bool CalibrationCaliPage::Show(bool show /*= true*/) +{ + if (true) { + reset_printing_values(); + } + return wxPanel::Show(show); +} + +void CalibrationCaliPage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); + m_picture_panel->msw_rescale(); +} + float CalibrationCaliPage::get_selected_calibration_nozzle_dia(MachineObject* obj) { // return selected if this is set diff --git a/src/slic3r/GUI/CalibrationWizardCaliPage.hpp b/src/slic3r/GUI/CalibrationWizardCaliPage.hpp index 59a07aad382..6d102501a02 100644 --- a/src/slic3r/GUI/CalibrationWizardCaliPage.hpp +++ b/src/slic3r/GUI/CalibrationWizardCaliPage.hpp @@ -32,6 +32,8 @@ class CalibrationCaliPage : public CalibrationWizardPage void on_device_connected(MachineObject* obj) override; void set_cali_method(CalibrationMethod method) override; + virtual bool Show(bool show = true) override; + void msw_rescale() override; protected: float get_selected_calibration_nozzle_dia(MachineObject* obj); diff --git a/src/slic3r/GUI/CalibrationWizardPage.cpp b/src/slic3r/GUI/CalibrationWizardPage.cpp index aa57d160af2..f3ff77313b5 100644 --- a/src/slic3r/GUI/CalibrationWizardPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPage.cpp @@ -249,6 +249,13 @@ CaliPageButton::CaliPageButton(wxWindow* parent, CaliPageActionType type, wxStri SetCornerRadius(FromDIP(12)); } +void CaliPageButton::msw_rescale() +{ + SetMinSize(wxSize(-1, FromDIP(24))); + SetCornerRadius(FromDIP(12)); + Rescale(); +} + FilamentComboBox::FilamentComboBox(wxWindow* parent, const wxPoint& pos, const wxSize& size) : wxPanel(parent, wxID_ANY, pos, size, wxTAB_TRAVERSAL) @@ -343,6 +350,14 @@ void FilamentComboBox::SetValue(bool value, bool send_event) { m_checkBox->SetValue(value); } +void FilamentComboBox::msw_rescale() +{ + //m_checkBox->Rescale(); + m_comboBox->SetSize(CALIBRATION_FILAMENT_COMBOX_SIZE); + m_comboBox->SetMinSize(CALIBRATION_FILAMENT_COMBOX_SIZE); + m_comboBox->msw_rescale(); +} + CaliPageCaption::CaliPageCaption(wxWindow* parent, CalibMode cali_mode, @@ -460,6 +475,11 @@ void CaliPageCaption::on_sys_color_changed() m_prev_btn->msw_rescale(); } +void CaliPageCaption::msw_rescale() +{ + m_prev_btn->msw_rescale(); +} + CaliPageStepGuide::CaliPageStepGuide(wxWindow* parent, wxArrayString steps, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxPanel(parent, id, pos, size, style), @@ -541,9 +561,16 @@ CaliPagePicture::CaliPagePicture(wxWindow* parent, wxWindowID id, const wxPoint& top_sizer->Fit(this); } -void CaliPagePicture::set_img(const wxBitmap& bmp) +void CaliPagePicture::set_bmp(const ScalableBitmap& bmp) +{ + m_bmp = bmp; + m_img->SetBitmap(m_bmp.bmp()); +} + +void CaliPagePicture::msw_rescale() { - m_img->SetBitmap(bmp); + m_bmp.msw_rescale(); + m_img->SetBitmap(m_bmp.bmp()); } @@ -582,6 +609,13 @@ PAPageHelpPanel::PAPageHelpPanel(wxWindow* parent, bool ground_panel, wxWindowID top_sizer->Fit(this); } +void PAPageHelpPanel::msw_rescale() +{ + m_help_btn->msw_rescale(); + m_bmp.msw_rescale(); + m_img->SetBitmap(m_bmp.bmp()); +} + void PAPageHelpPanel::create_pop_window() { m_pop_win = new PopupWindow(this); @@ -589,13 +623,10 @@ void PAPageHelpPanel::create_pop_window() wxBoxSizer* pop_sizer = new wxBoxSizer(wxVERTICAL); m_pop_win->SetSizer(pop_sizer); - wxStaticBitmap* img = new wxStaticBitmap(m_pop_win, wxID_ANY, wxNullBitmap); - if (wxGetApp().app_config->get_language_code() == "zh-cn") { - img->SetBitmap(ScalableBitmap(this, "cali_fdc_editing_diagram_CN", 206).bmp()); - } else { - img->SetBitmap(ScalableBitmap(this, "cali_fdc_editing_diagram", 206).bmp()); - } - pop_sizer->Add(img, 1, wxEXPAND | wxALL, FromDIP(20)); + m_img = new wxStaticBitmap(m_pop_win, wxID_ANY, wxNullBitmap); + m_bmp = ScalableBitmap(this, "cali_fdc_editing_diagram", 206); + m_img->SetBitmap(m_bmp.bmp()); + pop_sizer->Add(m_img, 1, wxEXPAND | wxALL, FromDIP(20)); m_pop_win->Layout(); m_pop_win->Fit(); @@ -754,6 +785,163 @@ void CaliPageActionPanel::enable_button(CaliPageActionType action_type, bool ena } } +void CaliPageActionPanel::msw_rescale() +{ + for (int i = 0; i < m_action_btns.size(); i++) { + m_action_btns[i]->msw_rescale(); + } +} + +CaliPageSendingPanel::CaliPageSendingPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) + : wxPanel(parent, id, pos, size, style) +{ + SetBackgroundColour(*wxWHITE); + SetMinSize({ FromDIP(475), FromDIP(200) }); + SetMaxSize({ FromDIP(475), FromDIP(200) }); + + create(this); + + Layout(); + Fit(); + + Bind(EVT_SHOW_ERROR_INFO, [this](auto& e) { + show_send_failed_info(true); + }); +} + +void CaliPageSendingPanel::create(wxWindow* parent) +{ + auto panel_sizer = new wxBoxSizer(wxVERTICAL); + parent->SetSizer(panel_sizer); + + m_send_progress_bar = std::shared_ptr(new BBLStatusBarSend(parent)); + panel_sizer->Add(m_send_progress_bar->get_panel(), 0, wxEXPAND); + + m_sw_print_failed_info = new wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(380), FromDIP(125)), wxVSCROLL); + m_sw_print_failed_info->SetBackgroundColour(*wxWHITE); + m_sw_print_failed_info->SetScrollRate(0, 5); + m_sw_print_failed_info->SetMinSize(wxSize(FromDIP(380), FromDIP(125))); + m_sw_print_failed_info->SetMaxSize(wxSize(FromDIP(380), FromDIP(125))); + + m_sw_print_failed_info->Hide(); + + panel_sizer->Add(m_sw_print_failed_info, 0, wxEXPAND); + + // create error info panel + wxBoxSizer* sizer_print_failed_info = new wxBoxSizer(wxVERTICAL); + m_sw_print_failed_info->SetSizer(sizer_print_failed_info); + + wxBoxSizer* sizer_error_code = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_error_desc = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_extra_info = new wxBoxSizer(wxHORIZONTAL); + + auto st_title_error_code = new Label(m_sw_print_failed_info, _L("Error code")); + auto st_title_error_code_doc = new Label(m_sw_print_failed_info, ": "); + m_st_txt_error_code = new Label(m_sw_print_failed_info, wxEmptyString); + st_title_error_code->SetForegroundColour(0x909090); + st_title_error_code_doc->SetForegroundColour(0x909090); + m_st_txt_error_code->SetForegroundColour(0x909090); + st_title_error_code->SetFont(::Label::Body_13); + st_title_error_code_doc->SetFont(::Label::Body_13); + m_st_txt_error_code->SetFont(::Label::Body_13); + st_title_error_code->SetMinSize(wxSize(FromDIP(74), -1)); + st_title_error_code->SetMaxSize(wxSize(FromDIP(74), -1)); + m_st_txt_error_code->SetMinSize(wxSize(FromDIP(260), -1)); + m_st_txt_error_code->SetMaxSize(wxSize(FromDIP(260), -1)); + sizer_error_code->Add(st_title_error_code, 0, wxALL, 0); + sizer_error_code->Add(st_title_error_code_doc, 0, wxALL, 0); + sizer_error_code->Add(m_st_txt_error_code, 0, wxALL, 0); + + auto st_title_error_desc = new Label(m_sw_print_failed_info, _L("Error desc")); + auto st_title_error_desc_doc = new Label(m_sw_print_failed_info, ": "); + m_st_txt_error_desc = new Label(m_sw_print_failed_info, wxEmptyString); + st_title_error_desc->SetForegroundColour(0x909090); + st_title_error_desc_doc->SetForegroundColour(0x909090); + m_st_txt_error_desc->SetForegroundColour(0x909090); + st_title_error_desc->SetFont(::Label::Body_13); + st_title_error_desc_doc->SetFont(::Label::Body_13); + m_st_txt_error_desc->SetFont(::Label::Body_13); + st_title_error_desc->SetMinSize(wxSize(FromDIP(74), -1)); + st_title_error_desc->SetMaxSize(wxSize(FromDIP(74), -1)); + m_st_txt_error_desc->SetMinSize(wxSize(FromDIP(260), -1)); + m_st_txt_error_desc->SetMaxSize(wxSize(FromDIP(260), -1)); + sizer_error_desc->Add(st_title_error_desc, 0, wxALL, 0); + sizer_error_desc->Add(st_title_error_desc_doc, 0, wxALL, 0); + sizer_error_desc->Add(m_st_txt_error_desc, 0, wxALL, 0); + + auto st_title_extra_info = new Label(m_sw_print_failed_info, _L("Extra info")); + auto st_title_extra_info_doc = new Label(m_sw_print_failed_info, ": "); + m_st_txt_extra_info = new Label(m_sw_print_failed_info, wxEmptyString); + st_title_extra_info->SetForegroundColour(0x909090); + st_title_extra_info_doc->SetForegroundColour(0x909090); + m_st_txt_extra_info->SetForegroundColour(0x909090); + st_title_extra_info->SetFont(::Label::Body_13); + st_title_extra_info_doc->SetFont(::Label::Body_13); + m_st_txt_extra_info->SetFont(::Label::Body_13); + st_title_extra_info->SetMinSize(wxSize(FromDIP(74), -1)); + st_title_extra_info->SetMaxSize(wxSize(FromDIP(74), -1)); + m_st_txt_extra_info->SetMinSize(wxSize(FromDIP(260), -1)); + m_st_txt_extra_info->SetMaxSize(wxSize(FromDIP(260), -1)); + sizer_extra_info->Add(st_title_extra_info, 0, wxALL, 0); + sizer_extra_info->Add(st_title_extra_info_doc, 0, wxALL, 0); + sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0); + + sizer_print_failed_info->Add(sizer_error_code, 0, wxLEFT, 5); + sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3)); + sizer_print_failed_info->Add(sizer_error_desc, 0, wxLEFT, 5); + sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3)); + sizer_print_failed_info->Add(sizer_extra_info, 0, wxLEFT, 5); +} + +void CaliPageSendingPanel::update_print_error_info(int code, const std::string& msg, const std::string& extra) +{ + m_print_error_code = code; + m_print_error_msg = msg; + m_print_error_extra = extra; +} + +void CaliPageSendingPanel::show_send_failed_info(bool show, int code, wxString description, wxString extra) +{ + if (show) { + if (!m_sw_print_failed_info->IsShown()) { + m_sw_print_failed_info->Show(true); + + m_st_txt_error_code->SetLabelText(wxString::Format("%d", m_print_error_code)); + m_st_txt_error_desc->SetLabelText(wxGetApp().filter_string(m_print_error_msg)); + m_st_txt_extra_info->SetLabelText(wxGetApp().filter_string(m_print_error_extra)); + + m_st_txt_error_code->Wrap(FromDIP(260)); + m_st_txt_error_desc->Wrap(FromDIP(260)); + m_st_txt_extra_info->Wrap(FromDIP(260)); + } + else { + m_sw_print_failed_info->Show(false); + } + Layout(); + Fit(); + } + else { + if (!m_sw_print_failed_info->IsShown()) { return; } + m_sw_print_failed_info->Show(false); + m_st_txt_error_code->SetLabelText(wxEmptyString); + m_st_txt_error_desc->SetLabelText(wxEmptyString); + m_st_txt_extra_info->SetLabelText(wxEmptyString); + Layout(); + Fit(); + } +} + +std::shared_ptr CaliPageSendingPanel::get_sending_progress_bar() +{ + return m_send_progress_bar; +} + +void CaliPageSendingPanel::reset() +{ + m_send_progress_bar->reset(); + m_sw_print_failed_info->Show(false); +} + CalibrationWizardPage::CalibrationWizardPage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxPanel(parent, id, pos, size, style) , m_parent(parent) @@ -764,6 +952,8 @@ CalibrationWizardPage::CalibrationWizardPage(wxWindow* parent, wxWindowID id, co void CalibrationWizardPage::msw_rescale() { + m_page_caption->msw_rescale(); + m_action_panel->msw_rescale(); } void CalibrationWizardPage::on_sys_color_changed() @@ -771,4 +961,5 @@ void CalibrationWizardPage::on_sys_color_changed() m_page_caption->on_sys_color_changed(); } -}} +} +} diff --git a/src/slic3r/GUI/CalibrationWizardPage.hpp b/src/slic3r/GUI/CalibrationWizardPage.hpp index 75522a6df75..a046c629ec5 100644 --- a/src/slic3r/GUI/CalibrationWizardPage.hpp +++ b/src/slic3r/GUI/CalibrationWizardPage.hpp @@ -96,6 +96,7 @@ class FilamentComboBox : public wxPanel virtual bool Show(bool show = true); virtual bool Enable(bool enable); virtual void SetValue(bool value, bool send_event = true); + void msw_rescale(); protected: int m_tray_id { -1 }; @@ -123,6 +124,7 @@ class CaliPageCaption : public wxPanel void show_prev_btn(bool show = true); void show_help_icon(bool show = true); void on_sys_color_changed(); + void msw_rescale(); protected: ScalableButton* m_prev_btn; @@ -167,9 +169,12 @@ class CaliPagePicture : public wxPanel const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL); - void set_img(const wxBitmap& bmp); + void set_bmp(const ScalableBitmap& bmp); void paint_on_img(); + void msw_rescale(); + protected: + ScalableBitmap m_bmp; wxStaticBitmap* m_img; }; @@ -182,12 +187,14 @@ class PAPageHelpPanel : public wxPanel const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL); - + void msw_rescale(); + protected: void create_pop_window(); ScalableButton* m_help_btn; PopupWindow* m_pop_win; + ScalableBitmap m_bmp; wxStaticBitmap* m_img; }; @@ -218,10 +225,38 @@ class CaliPageButton : public Button CaliPageButton(wxWindow* parent, CaliPageActionType type, wxString text = wxEmptyString); CaliPageActionType get_action_type() { return m_action_type; } + + void msw_rescale(); + private: CaliPageActionType m_action_type; }; +class CaliPageSendingPanel : public wxPanel +{ +public: + CaliPageSendingPanel(wxWindow* parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL); + void create(wxWindow* parent); + void update_print_error_info(int code, const std::string& msg, const std::string& extra); + void show_send_failed_info(bool show, int code = 0, wxString description = wxEmptyString, wxString extra = wxEmptyString); + std::shared_ptr get_sending_progress_bar(); + void reset(); + +private: + std::shared_ptr m_send_progress_bar; + wxScrolledWindow* m_sw_print_failed_info{ nullptr }; + Label* m_st_txt_error_code{ nullptr }; + Label* m_st_txt_error_desc{ nullptr }; + Label* m_st_txt_extra_info{ nullptr }; + int m_print_error_code; + std::string m_print_error_msg; + std::string m_print_error_extra; +}; + class CaliPageActionPanel : public wxPanel { public: @@ -236,6 +271,7 @@ class CaliPageActionPanel : public wxPanel void bind_button(CaliPageActionType action_type, bool is_block); void show_button(CaliPageActionType action_type, bool show = true); void enable_button(CaliPageActionType action_type, bool enable = true); + void msw_rescale(); protected: std::vector m_action_btns; @@ -277,8 +313,8 @@ class CalibrationWizardPage : public wxPanel } } - void msw_rescale(); - void on_sys_color_changed(); + virtual void msw_rescale(); + virtual void on_sys_color_changed(); protected: CalibMode m_cali_mode; diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index f889fc38abe..9e72a211aea 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -445,6 +445,22 @@ CalibrationPresetPage::CalibrationPresetPage( m_top_sizer->Fit(this); } +void CalibrationPresetPage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); + m_ams_sync_button->msw_rescale(); + m_virtual_tray_comboBox->msw_rescale(); + for (auto& comboBox : m_filament_comboBox_list) { + comboBox->msw_rescale(); + } +} + +void CalibrationPresetPage::on_sys_color_changed() +{ + CalibrationWizardPage::on_sys_color_changed(); + m_ams_sync_button->msw_rescale(); +} + void CalibrationPresetPage::create_selection_panel(wxWindow* parent) { auto panel_sizer = new wxBoxSizer(wxVERTICAL); @@ -633,108 +649,6 @@ void CalibrationPresetPage::create_ext_spool_panel(wxWindow* parent) }); } -void CalibrationPresetPage::create_sending_panel(wxWindow* parent) -{ - parent->SetMinSize({ FromDIP(475), FromDIP(200) }); - parent->SetMaxSize({ FromDIP(475), FromDIP(200) }); - - auto panel_sizer = new wxBoxSizer(wxVERTICAL); - parent->SetSizer(panel_sizer); - - m_send_progress_bar = std::shared_ptr(new BBLStatusBarSend(parent)); - m_send_progress_bar->set_cancel_callback_fina([this]() { - BOOST_LOG_TRIVIAL(info) << "CalibrationWizard::print_job: enter canceled"; - if (CalibUtils::print_job) { - if (CalibUtils::print_job->is_running()) { - BOOST_LOG_TRIVIAL(info) << "calibration_print_job: canceled"; - CalibUtils::print_job->cancel(); - } - CalibUtils::print_job->join(); - } - show_status(CaliPresetStatusNormal); - }); - panel_sizer->Add(m_send_progress_bar->get_panel(), 0, wxEXPAND); - - m_sw_print_failed_info = new wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(380), FromDIP(125)), wxVSCROLL); - m_sw_print_failed_info->SetBackgroundColour(*wxWHITE); - m_sw_print_failed_info->SetScrollRate(0, 5); - m_sw_print_failed_info->SetMinSize(wxSize(FromDIP(380), FromDIP(125))); - m_sw_print_failed_info->SetMaxSize(wxSize(FromDIP(380), FromDIP(125))); - - m_sw_print_failed_info->Hide(); - - panel_sizer->Add(m_sw_print_failed_info, 0, wxEXPAND); - - // create error info panel - wxBoxSizer* sizer_print_failed_info = new wxBoxSizer(wxVERTICAL); - m_sw_print_failed_info->SetSizer(sizer_print_failed_info); - - wxBoxSizer* sizer_error_code = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_error_desc = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sizer_extra_info = new wxBoxSizer(wxHORIZONTAL); - - auto st_title_error_code = new Label(m_sw_print_failed_info, _L("Error code")); - auto st_title_error_code_doc = new Label(m_sw_print_failed_info, ": "); - m_st_txt_error_code = new Label(m_sw_print_failed_info, wxEmptyString); - st_title_error_code->SetForegroundColour(0x909090); - st_title_error_code_doc->SetForegroundColour(0x909090); - m_st_txt_error_code->SetForegroundColour(0x909090); - st_title_error_code->SetFont(::Label::Body_13); - st_title_error_code_doc->SetFont(::Label::Body_13); - m_st_txt_error_code->SetFont(::Label::Body_13); - st_title_error_code->SetMinSize(wxSize(FromDIP(74), -1)); - st_title_error_code->SetMaxSize(wxSize(FromDIP(74), -1)); - m_st_txt_error_code->SetMinSize(wxSize(FromDIP(260), -1)); - m_st_txt_error_code->SetMaxSize(wxSize(FromDIP(260), -1)); - sizer_error_code->Add(st_title_error_code, 0, wxALL, 0); - sizer_error_code->Add(st_title_error_code_doc, 0, wxALL, 0); - sizer_error_code->Add(m_st_txt_error_code, 0, wxALL, 0); - - auto st_title_error_desc = new Label(m_sw_print_failed_info, _L("Error desc")); - auto st_title_error_desc_doc = new Label(m_sw_print_failed_info, ": "); - m_st_txt_error_desc = new Label(m_sw_print_failed_info, wxEmptyString); - st_title_error_desc->SetForegroundColour(0x909090); - st_title_error_desc_doc->SetForegroundColour(0x909090); - m_st_txt_error_desc->SetForegroundColour(0x909090); - st_title_error_desc->SetFont(::Label::Body_13); - st_title_error_desc_doc->SetFont(::Label::Body_13); - m_st_txt_error_desc->SetFont(::Label::Body_13); - st_title_error_desc->SetMinSize(wxSize(FromDIP(74), -1)); - st_title_error_desc->SetMaxSize(wxSize(FromDIP(74), -1)); - m_st_txt_error_desc->SetMinSize(wxSize(FromDIP(260), -1)); - m_st_txt_error_desc->SetMaxSize(wxSize(FromDIP(260), -1)); - sizer_error_desc->Add(st_title_error_desc, 0, wxALL, 0); - sizer_error_desc->Add(st_title_error_desc_doc, 0, wxALL, 0); - sizer_error_desc->Add(m_st_txt_error_desc, 0, wxALL, 0); - - auto st_title_extra_info = new Label(m_sw_print_failed_info, _L("Extra info")); - auto st_title_extra_info_doc = new Label(m_sw_print_failed_info, ": "); - m_st_txt_extra_info = new Label(m_sw_print_failed_info, wxEmptyString); - st_title_extra_info->SetForegroundColour(0x909090); - st_title_extra_info_doc->SetForegroundColour(0x909090); - m_st_txt_extra_info->SetForegroundColour(0x909090); - st_title_extra_info->SetFont(::Label::Body_13); - st_title_extra_info_doc->SetFont(::Label::Body_13); - m_st_txt_extra_info->SetFont(::Label::Body_13); - st_title_extra_info->SetMinSize(wxSize(FromDIP(74), -1)); - st_title_extra_info->SetMaxSize(wxSize(FromDIP(74), -1)); - m_st_txt_extra_info->SetMinSize(wxSize(FromDIP(260), -1)); - m_st_txt_extra_info->SetMaxSize(wxSize(FromDIP(260), -1)); - sizer_extra_info->Add(st_title_extra_info, 0, wxALL, 0); - sizer_extra_info->Add(st_title_extra_info_doc, 0, wxALL, 0); - sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0); - - sizer_print_failed_info->Add(sizer_error_code, 0, wxLEFT, 5); - sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3)); - sizer_print_failed_info->Add(sizer_error_desc, 0, wxLEFT, 5); - sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3)); - sizer_print_failed_info->Add(sizer_extra_info, 0, wxLEFT, 5); - - Bind(EVT_SHOW_ERROR_INFO, [this](auto& e) { - show_send_failed_info(true); - }); -} - void CalibrationPresetPage::create_page(wxWindow* parent) { m_page_caption = new CaliPageCaption(parent, m_cali_mode); @@ -788,10 +702,10 @@ void CalibrationPresetPage::create_page(wxWindow* parent) m_tips_panel = new CaliPresetTipsPanel(parent); - m_sending_panel = new wxPanel(parent); - m_sending_panel->SetBackgroundColour(*wxWHITE); - create_sending_panel(m_sending_panel); - + m_sending_panel = new CaliPageSendingPanel(parent); + m_sending_panel->get_sending_progress_bar()->set_cancel_callback_fina([this]() { + on_cali_cancel_job(); + }); m_sending_panel->Hide(); m_custom_range_panel = new CaliPresetCustomRangePanel(parent); @@ -1038,8 +952,10 @@ bool CalibrationPresetPage::is_filament_in_blacklist(Preset* preset, std::string std::string filamnt_type; preset->get_filament_type(filamnt_type); - if (preset->vendor) { - DeviceManager::check_filaments_in_blacklist(preset->vendor->name, filamnt_type, in_blacklist, action, info); + auto vendor = dynamic_cast (preset->config.option("filament_vendor")); + if (vendor && (vendor->values.size() > 0)) { + std::string vendor_name = vendor->values[0]; + DeviceManager::check_filaments_in_blacklist(vendor_name, filamnt_type, in_blacklist, action, info); } if (in_blacklist) { @@ -1189,12 +1105,6 @@ bool CalibrationPresetPage::is_blocking_printing() void CalibrationPresetPage::update_show_status() { - if (get_status() == CaliPresetPageStatus::CaliPresetStatusSending) - return; - - if (get_status() == CaliPresetPageStatus::CaliPresetStatusSendingCanceled) - return; - NetworkAgent* agent = Slic3r::GUI::wxGetApp().getAgent(); DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!agent) {return;} @@ -1307,12 +1217,8 @@ bool CalibrationPresetPage::need_check_sdcard(MachineObject* obj) void CalibrationPresetPage::show_status(CaliPresetPageStatus status) { - if (status == CaliPresetPageStatus::CaliPresetStatusSending) { - sending_mode(); - } - else { - prepare_mode(); - } + if (m_stop_update_page_status) + return; if (m_page_status != status) //BOOST_LOG_TRIVIAL(info) << "CalibrationPresetPage: show_status = " << status << "(" << get_print_status_info(status) << ")"; @@ -1324,7 +1230,6 @@ void CalibrationPresetPage::show_status(CaliPresetPageStatus status) Enable_Send_Button(false); } else if (status == CaliPresetPageStatus::CaliPresetStatusNormal) { - m_sending_panel->Show(false); update_print_status_msg(wxEmptyString, false); Enable_Send_Button(true); Layout(); @@ -1359,15 +1264,6 @@ void CalibrationPresetPage::show_status(CaliPresetPageStatus status) update_print_status_msg(msg_text, true); Enable_Send_Button(false); } - else if (status == CaliPresetPageStatus::CaliPresetStatusSending) { - m_sending_panel->Show(); - Enable_Send_Button(false); - Layout(); - Fit(); - } - else if (status == CaliPresetPageStatus::CaliPresetStatusSendingCanceled) { - Enable_Send_Button(true); - } else if (status == CaliPresetPageStatus::CaliPresetStatusLanModeNoSdcard) { wxString msg_text = _L("An SD card needs to be inserted before printing via LAN."); update_print_status_msg(msg_text, true); @@ -1406,19 +1302,6 @@ void CalibrationPresetPage::Enable_Send_Button(bool enable) m_action_panel->enable_button(CaliPageActionType::CALI_ACTION_CALI, enable); } -void CalibrationPresetPage::prepare_mode() -{ - Enable_Send_Button(true); - m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, true); -} - -void CalibrationPresetPage::sending_mode() -{ - Enable_Send_Button(false); - m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, false); -} - - float CalibrationPresetPage::get_nozzle_value() { double nozzle_value = 0.0; @@ -1448,44 +1331,6 @@ void CalibrationPresetPage::on_device_connected(MachineObject* obj) update_combobox_filaments(obj); } -void CalibrationPresetPage::update_print_error_info(int code, const std::string& msg, const std::string& extra) -{ - m_print_error_code = code; - m_print_error_msg = msg; - m_print_error_extra = extra; -} - -void CalibrationPresetPage::show_send_failed_info(bool show, int code, wxString description, wxString extra) -{ - if (show) { - if (!m_sw_print_failed_info->IsShown()) { - m_sw_print_failed_info->Show(true); - - m_st_txt_error_code->SetLabelText(wxString::Format("%d", m_print_error_code)); - m_st_txt_error_desc->SetLabelText(wxGetApp().filter_string(m_print_error_msg)); - m_st_txt_extra_info->SetLabelText(wxGetApp().filter_string(m_print_error_extra)); - - m_st_txt_error_code->Wrap(FromDIP(260)); - m_st_txt_error_desc->Wrap(FromDIP(260)); - m_st_txt_extra_info->Wrap(FromDIP(260)); - } - else { - m_sw_print_failed_info->Show(false); - } - Layout(); - Fit(); - } - else { - if (!m_sw_print_failed_info->IsShown()) { return; } - m_sw_print_failed_info->Show(false); - m_st_txt_error_code->SetLabelText(wxEmptyString); - m_st_txt_error_desc->SetLabelText(wxEmptyString); - m_st_txt_extra_info->SetLabelText(wxEmptyString); - Layout(); - Fit(); - } -} - void CalibrationPresetPage::set_cali_filament_mode(CalibrationFilamentMode mode) { CalibrationWizardPage::set_cali_filament_mode(mode); @@ -1539,9 +1384,9 @@ void CalibrationPresetPage::set_cali_method(CalibrationMethod method) wxArrayString values; values.push_back(_L("0")); - values.push_back(_L("0.5")); + values.push_back(_L("0.5")); values.push_back(_L("0.005")); - m_custom_range_panel->set_values(values); + m_custom_range_panel->set_values(values); m_custom_range_panel->set_unit(""); m_custom_range_panel->Show(); @@ -1566,14 +1411,49 @@ void CalibrationPresetPage::set_cali_method(CalibrationMethod method) void CalibrationPresetPage::on_cali_start_job() { - m_send_progress_bar->reset(); - m_sw_print_failed_info->Show(false); - show_status(CaliPresetPageStatus::CaliPresetStatusSending); + m_sending_panel->reset(); + m_sending_panel->Show(); + Enable_Send_Button(false); + m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, false); + Layout(); + Fit(); + + m_stop_update_page_status = true; } void CalibrationPresetPage::on_cali_finished_job() { - show_status(CaliPresetPageStatus::CaliPresetStatusNormal); + m_sending_panel->reset(); + m_sending_panel->Show(false); + update_print_status_msg(wxEmptyString, false); + Enable_Send_Button(true); + m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, true); + Layout(); + Fit(); + + m_stop_update_page_status = false; +} + +void CalibrationPresetPage::on_cali_cancel_job() +{ + BOOST_LOG_TRIVIAL(info) << "CalibrationWizard::print_job: enter canceled"; + if (CalibUtils::print_job) { + if (CalibUtils::print_job->is_running()) { + BOOST_LOG_TRIVIAL(info) << "calibration_print_job: canceled"; + CalibUtils::print_job->cancel(); + } + CalibUtils::print_job->join(); + } + + m_sending_panel->reset(); + m_sending_panel->Show(false); + update_print_status_msg(wxEmptyString, false); + Enable_Send_Button(true); + m_action_panel->show_button(CaliPageActionType::CALI_ACTION_CALI, true); + Layout(); + Fit(); + + m_stop_update_page_status = false; } void CalibrationPresetPage::init_with_machine(MachineObject* obj) @@ -1986,7 +1866,7 @@ MaxVolumetricSpeedPresetPage::MaxVolumetricSpeedPresetPage( wxArrayString titles; titles.push_back(_L("From Volumetric Speed")); titles.push_back(_L("To Volumetric Speed")); - titles.push_back(_L("Step value")); + titles.push_back(_L("Step")); m_custom_range_panel->set_titles(titles); m_custom_range_panel->set_unit(_L("mm\u00B3/s")); diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.hpp b/src/slic3r/GUI/CalibrationWizardPresetPage.hpp index 9327527587d..9096c7a34aa 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.hpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.hpp @@ -129,14 +129,12 @@ enum CaliPresetPageStatus { CaliPresetStatusInit = 0, CaliPresetStatusNormal, - CaliPresetStatusSending, CaliPresetStatusNoUserLogin, CaliPresetStatusInvalidPrinter, CaliPresetStatusConnectingServer, CaliPresetStatusInUpgrading, CaliPresetStatusInSystemPrinting, CaliPresetStatusInPrinting, - CaliPresetStatusSendingCanceled, CaliPresetStatusLanModeNoSdcard, CaliPresetStatusNoSdcard, CaliPresetStatusNeedForceUpgrading, @@ -167,9 +165,7 @@ class CalibrationPresetPage : public CalibrationWizardPage void on_device_connected(MachineObject* obj) override; - void update_print_error_info(int code, const std::string& msg, const std::string& extra); - - void show_send_failed_info(bool show, int code = 0, wxString description = wxEmptyString, wxString extra = wxEmptyString); + void update_print_error_info(int code, const std::string& msg, const std::string& extra) { m_sending_panel->update_print_error_info(code, msg, extra); } void set_cali_filament_mode(CalibrationFilamentMode mode) override; @@ -179,6 +175,8 @@ class CalibrationPresetPage : public CalibrationWizardPage void on_cali_finished_job(); + void on_cali_cancel_job(); + void init_with_machine(MachineObject* obj); void sync_ams_info(MachineObject* obj); @@ -197,7 +195,7 @@ class CalibrationPresetPage : public CalibrationWizardPage void get_cali_stage(CaliPresetStage& stage, float& value); std::shared_ptr get_sending_progress_bar() { - return m_send_progress_bar; + return m_sending_panel->get_sending_progress_bar(); } Preset* get_printer_preset(MachineObject* obj, float nozzle_value); @@ -208,11 +206,14 @@ class CalibrationPresetPage : public CalibrationWizardPage CalibMode get_pa_cali_method(); CaliPresetPageStatus get_page_status() { return m_page_status; } + + void msw_rescale() override; + void on_sys_color_changed() override; + protected: void create_selection_panel(wxWindow* parent); void create_filament_list_panel(wxWindow* parent); void create_ext_spool_panel(wxWindow* parent); - void create_sending_panel(wxWindow* parent); void init_selection_values(); void update_filament_combobox(std::string ams_id = ""); @@ -244,8 +245,6 @@ class CalibrationPresetPage : public CalibrationWizardPage void update_show_status(); void show_status(CaliPresetPageStatus status); void Enable_Send_Button(bool enable); - void prepare_mode(); - void sending_mode(); bool is_blocking_printing(); bool need_check_sdcard(MachineObject* obj); @@ -263,7 +262,7 @@ class CalibrationPresetPage : public CalibrationWizardPage CaliPresetWarningPanel* m_warning_panel { nullptr }; CaliPresetCustomRangePanel* m_custom_range_panel { nullptr }; CaliPresetTipsPanel* m_tips_panel { nullptr }; - wxPanel* m_sending_panel { nullptr }; + CaliPageSendingPanel* m_sending_panel { nullptr }; wxBoxSizer* m_top_sizer; @@ -279,15 +278,6 @@ class CalibrationPresetPage : public CalibrationWizardPage FilamentComboBoxList m_filament_comboBox_list; FilamentComboBox* m_virtual_tray_comboBox; - // m_sending panel widgets - std::shared_ptr m_send_progress_bar; - wxScrolledWindow* m_sw_print_failed_info { nullptr }; - Label* m_st_txt_error_code { nullptr }; - Label* m_st_txt_error_desc { nullptr }; - Label* m_st_txt_extra_info { nullptr }; - int m_print_error_code; - std::string m_print_error_msg; - std::string m_print_error_extra; std::vector m_ams_item_list; @@ -295,6 +285,7 @@ class CalibrationPresetPage : public CalibrationWizardPage std::map filament_ams_list; CaliPresetPageStatus m_page_status { CaliPresetPageStatus::CaliPresetStatusInit }; + bool m_stop_update_page_status{ false }; bool m_show_custom_range { false }; bool m_has_filament_incompatible { false }; diff --git a/src/slic3r/GUI/CalibrationWizardSavePage.cpp b/src/slic3r/GUI/CalibrationWizardSavePage.cpp index b399673682b..42828fb902a 100644 --- a/src/slic3r/GUI/CalibrationWizardSavePage.cpp +++ b/src/slic3r/GUI/CalibrationWizardSavePage.cpp @@ -8,6 +8,7 @@ namespace Slic3r { namespace GUI { #define CALIBRATION_SAVE_INPUT_SIZE wxSize(FromDIP(240), FromDIP(24)) #define FLOW_RATE_MAX_VALUE 1.15 +static const wxString k_tips = "Please input a valid value (K in 0~0.3)"; static wxString get_default_name(wxString filament_name, CalibMode mode){ PresetBundle* preset_bundle = wxGetApp().preset_bundle; @@ -363,10 +364,11 @@ void CaliPASaveAutoPanel::save_to_result_from_widgets(wxWindow* window, bool* ou if (input->get_type() == GridTextInputType::K) { float k = 0.0f; if (!CalibUtils::validate_input_k_value(input->GetTextCtrl()->GetValue(), &k)) { - *out_msg = _L("Please input a valid value (K in 0~0.5)"); + *out_msg = _L("Please input a valid value (K in 0~0.3)"); *out_is_valid = false; } - m_calib_results[tray_id].k_value = k; + else + m_calib_results[tray_id].k_value = k; } else if (input->get_type() == GridTextInputType::N) { } @@ -517,9 +519,9 @@ void CaliPASaveManualPanel::create_panel(wxWindow* parent) void CaliPASaveManualPanel::set_save_img() { if (wxGetApp().app_config->get_language_code() == "zh-cn") { - m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual_result_CN", nullptr, 330)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result_CN", 330)); } else { - m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual_result", nullptr, 330)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result", 330)); } } @@ -531,9 +533,9 @@ void CaliPASaveManualPanel::set_pa_cali_method(ManualPaCaliMethod method) } else if (method == ManualPaCaliMethod::PA_PATTERN) { m_complete_text->SetLabel(_L("Please find the cornor with perfect degree of extrusion")); if (wxGetApp().app_config->get_language_code() == "zh-cn") { - m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual_result_CN", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual_result_CN", 350)); } else { - m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual_result", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual_result", 350)); } } } @@ -546,7 +548,7 @@ bool CaliPASaveManualPanel::get_result(PACalibResult& out_result) { // Check if the value is valid float k; if (!CalibUtils::validate_input_k_value(m_k_val->GetTextCtrl()->GetValue(), &k)) { - MessageDialog msg_dlg(nullptr, _L("Please input a valid value (K in 0~0.5)"), wxEmptyString, wxICON_WARNING | wxOK); + MessageDialog msg_dlg(nullptr, _L(k_tips), wxEmptyString, wxICON_WARNING | wxOK); msg_dlg.ShowModal(); return false; } @@ -593,6 +595,8 @@ bool CaliPASaveManualPanel::Show(bool show) { if (!m_obj->selected_cali_preset.empty()) { wxString default_name = get_default_name(m_obj->selected_cali_preset[0].name, CalibMode::Calib_PA_Line); set_default_name(default_name); + m_k_val->GetTextCtrl()->SetLabel(""); + m_n_val->GetTextCtrl()->SetLabel(""); } } else { @@ -602,6 +606,11 @@ bool CaliPASaveManualPanel::Show(bool show) { return wxPanel::Show(show); } +void CaliPASaveManualPanel::msw_rescale() +{ + m_picture_panel->msw_rescale(); +} + CaliPASaveP1PPanel::CaliPASaveP1PPanel( wxWindow* parent, wxWindowID id, @@ -671,9 +680,9 @@ void CaliPASaveP1PPanel::create_panel(wxWindow* parent) void CaliPASaveP1PPanel::set_save_img() { if (wxGetApp().app_config->get_language_code() == "zh-cn") { - m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual_result_CN", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result_CN", 350)); } else { - m_picture_panel->set_img(create_scaled_bitmap("fd_calibration_manual_result", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result", 350)); } } @@ -686,9 +695,9 @@ void CaliPASaveP1PPanel::set_pa_cali_method(ManualPaCaliMethod method) else if (method == ManualPaCaliMethod::PA_PATTERN) { m_complete_text->SetLabel(_L("Please find the cornor with perfect degree of extrusion")); if (wxGetApp().app_config->get_language_code() == "zh-cn") { - m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual_result_CN", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual_result_CN", 350)); } else { - m_picture_panel->set_img(create_scaled_bitmap("fd_pattern_manual_result", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "fd_pattern_manual_result", 350)); } } } @@ -696,13 +705,26 @@ void CaliPASaveP1PPanel::set_pa_cali_method(ManualPaCaliMethod method) bool CaliPASaveP1PPanel::get_result(float* out_k, float* out_n){ // Check if the value is valid if (!CalibUtils::validate_input_k_value(m_k_val->GetTextCtrl()->GetValue(), out_k)) { - MessageDialog msg_dlg(nullptr, _L("Please input a valid value (K in 0~0.5)"), wxEmptyString, wxICON_WARNING | wxOK); + MessageDialog msg_dlg(nullptr, _L(k_tips), wxEmptyString, wxICON_WARNING | wxOK); msg_dlg.ShowModal(); return false; } return true; } +bool CaliPASaveP1PPanel::Show(bool show) { + if (show) { + m_k_val->GetTextCtrl()->SetLabel(""); + m_n_val->GetTextCtrl()->SetLabel(""); + } + return wxPanel::Show(show); +} + +void CaliPASaveP1PPanel::msw_rescale() +{ + m_picture_panel->msw_rescale(); +} + CaliSavePresetValuePanel::CaliSavePresetValuePanel( wxWindow *parent, wxWindowID id, @@ -751,7 +773,7 @@ void CaliSavePresetValuePanel::create_panel(wxWindow *parent) void CaliSavePresetValuePanel::set_img(const std::string& bmp_name_in) { - m_picture_panel->set_img(create_scaled_bitmap(bmp_name_in, nullptr, 400)); + m_picture_panel->set_bmp(ScalableBitmap(this, bmp_name_in, 400)); } void CaliSavePresetValuePanel::set_value_title(const wxString& title) { @@ -777,6 +799,11 @@ void CaliSavePresetValuePanel::set_save_name(const std::string& name) m_input_name->GetTextCtrl()->SetValue(name); } +void CaliSavePresetValuePanel::msw_rescale() +{ + m_picture_panel->msw_rescale(); +} + CalibrationPASavePage::CalibrationPASavePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : CalibrationCommonSavePage(parent, id, pos, size, style) { @@ -875,6 +902,8 @@ void CalibrationPASavePage::set_cali_method(CalibrationMethod method) void CalibrationPASavePage::on_device_connected(MachineObject* obj) { curr_obj = obj; + m_auto_panel->set_machine_obj(curr_obj); + m_manual_panel->set_machine_obj(curr_obj); if (curr_obj) show_panels(m_cali_method, curr_obj->get_printer_series()); } @@ -899,6 +928,14 @@ bool CalibrationPASavePage::Show(bool show) { return wxPanel::Show(show); } +void CalibrationPASavePage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); + m_manual_panel->msw_rescale(); + m_p1p_panel->msw_rescale(); + m_help_panel->msw_rescale(); +} + CalibrationFlowX1SavePage::CalibrationFlowX1SavePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : CalibrationCommonSavePage(parent, id, pos, size, style) { @@ -1138,6 +1175,11 @@ bool CalibrationFlowX1SavePage::Show(bool show) { return wxPanel::Show(show); } +void CalibrationFlowX1SavePage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); +} + CalibrationFlowCoarseSavePage::CalibrationFlowCoarseSavePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : CalibrationCommonSavePage(parent, id, pos, size, style) { @@ -1258,6 +1300,13 @@ void CalibrationFlowCoarseSavePage::create_page(wxWindow* parent) m_coarse_calc_result_text->SetLabel(wxString::Format(_L("flow ratio : %s "), std::to_string(m_coarse_flow_ratio))); }); + m_sending_panel = new CaliPageSendingPanel(parent); + m_sending_panel->get_sending_progress_bar()->set_cancel_callback_fina([this]() { + on_cali_cancel_job(); + }); + m_sending_panel->Hide(); + m_top_sizer->Add(m_sending_panel, 0, wxALIGN_CENTER); + m_action_panel = new CaliPageActionPanel(parent, m_cali_mode, CaliPageType::CALI_PAGE_COARSE_SAVE); m_action_panel->show_button(CaliPageActionType::CALI_ACTION_FLOW_COARSE_SAVE, false); m_top_sizer->Add(m_action_panel, 0, wxEXPAND, 0); @@ -1265,9 +1314,9 @@ void CalibrationFlowCoarseSavePage::create_page(wxWindow* parent) void CalibrationFlowCoarseSavePage::set_save_img() { if (wxGetApp().app_config->get_language_code() == "zh-cn") { - m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_coarse_result_CN", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse_result_CN", 350)); } else { - m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_coarse_result", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse_result", 350)); } } @@ -1324,6 +1373,51 @@ bool CalibrationFlowCoarseSavePage::Show(bool show) { return wxPanel::Show(show); } +void CalibrationFlowCoarseSavePage::on_cali_start_job() +{ + m_sending_panel->reset(); + m_sending_panel->Show(); + m_action_panel->enable_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, false); + m_action_panel->show_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, false); + Layout(); + Fit(); +} + +void CalibrationFlowCoarseSavePage::on_cali_finished_job() +{ + m_sending_panel->reset(); + m_sending_panel->Show(false); + m_action_panel->enable_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, true); + m_action_panel->show_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, true); + Layout(); + Fit(); +} + +void CalibrationFlowCoarseSavePage::on_cali_cancel_job() +{ + BOOST_LOG_TRIVIAL(info) << "CalibrationWizard::print_job: enter canceled"; + if (CalibUtils::print_job) { + if (CalibUtils::print_job->is_running()) { + BOOST_LOG_TRIVIAL(info) << "calibration_print_job: canceled"; + CalibUtils::print_job->cancel(); + } + CalibUtils::print_job->join(); + } + + m_sending_panel->reset(); + m_sending_panel->Show(false); + m_action_panel->enable_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, true); + m_action_panel->show_button(CaliPageActionType::CALI_ACTION_FLOW_CALI_STAGE_2, true); + Layout(); + Fit(); +} + +void CalibrationFlowCoarseSavePage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); + m_picture_panel->msw_rescale(); +} + CalibrationFlowFineSavePage::CalibrationFlowFineSavePage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : CalibrationCommonSavePage(parent, id, pos, size, style) { @@ -1406,9 +1500,9 @@ void CalibrationFlowFineSavePage::create_page(wxWindow* parent) void CalibrationFlowFineSavePage::set_save_img() { if (wxGetApp().app_config->get_language_code() == "zh-cn") { - m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_fine_result_CN", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_fine_result_CN", 350)); } else { - m_picture_panel->set_img(create_scaled_bitmap("flow_rate_calibration_fine_result", nullptr, 350)); + m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_fine_result", 350)); } } @@ -1456,6 +1550,12 @@ bool CalibrationFlowFineSavePage::Show(bool show) { return wxPanel::Show(show); } +void CalibrationFlowFineSavePage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); + m_picture_panel->msw_rescale(); +} + CalibrationMaxVolumetricSpeedSavePage::CalibrationMaxVolumetricSpeedSavePage( wxWindow *parent, wxWindowID id, diff --git a/src/slic3r/GUI/CalibrationWizardSavePage.hpp b/src/slic3r/GUI/CalibrationWizardSavePage.hpp index 6396d12e786..6b76b22acb3 100644 --- a/src/slic3r/GUI/CalibrationWizardSavePage.hpp +++ b/src/slic3r/GUI/CalibrationWizardSavePage.hpp @@ -74,6 +74,7 @@ class CaliSavePresetValuePanel : public wxPanel void get_value(double& value); void get_save_name(std::string& name); void set_save_name(const std::string& name); + void msw_rescale(); }; @@ -129,6 +130,8 @@ class CaliPASaveManualPanel : public wxPanel virtual bool Show(bool show = true) override; + void msw_rescale(); + protected: wxBoxSizer* m_top_sizer; Label * m_complete_text; @@ -155,6 +158,10 @@ class CaliPASaveP1PPanel : public wxPanel bool get_result(float* out_k, float* out_n); + virtual bool Show(bool show = true) override; + + void msw_rescale(); + protected: wxBoxSizer* m_top_sizer; Label * m_complete_text; @@ -185,12 +192,14 @@ class CalibrationPASavePage : public CalibrationCommonSavePage virtual bool Show(bool show = true) override; + void msw_rescale() override; + protected: CaliPageStepGuide* m_step_panel { nullptr }; CaliPASaveAutoPanel* m_auto_panel { nullptr }; CaliPASaveManualPanel* m_manual_panel { nullptr }; CaliPASaveP1PPanel* m_p1p_panel{ nullptr }; - PAPageHelpPanel* m_help_panel; + PAPageHelpPanel* m_help_panel{ nullptr }; CaliSaveStyle m_save_style; }; @@ -209,6 +218,8 @@ class CalibrationFlowX1SavePage : public CalibrationCommonSavePage bool is_all_failed() { return m_is_all_failed; } virtual bool Show(bool show = true) override; + + void msw_rescale() override; protected: CaliPageStepGuide* m_step_panel{ nullptr }; @@ -237,6 +248,20 @@ class CalibrationFlowCoarseSavePage : public CalibrationCommonSavePage virtual bool Show(bool show = true) override; + void update_print_error_info(int code, const std::string& msg, const std::string& extra) { m_sending_panel->update_print_error_info(code, msg, extra); } + + void on_cali_start_job(); + + void on_cali_finished_job(); + + void on_cali_cancel_job(); + + std::shared_ptr get_sending_progress_bar() { + return m_sending_panel->get_sending_progress_bar(); + } + + void msw_rescale() override; + protected: CaliPageStepGuide* m_step_panel{ nullptr }; CaliPagePicture* m_picture_panel; @@ -249,6 +274,8 @@ class CalibrationFlowCoarseSavePage : public CalibrationCommonSavePage bool m_skip_fine_calibration = false; float m_curr_flow_ratio; float m_coarse_flow_ratio; + + CaliPageSendingPanel* m_sending_panel{ nullptr }; }; class CalibrationFlowFineSavePage : public CalibrationCommonSavePage @@ -267,6 +294,8 @@ class CalibrationFlowFineSavePage : public CalibrationCommonSavePage virtual bool Show(bool show = true) override; + void msw_rescale() override; + protected: CaliPageStepGuide* m_step_panel{ nullptr }; CaliPagePicture* m_picture_panel; diff --git a/src/slic3r/GUI/CalibrationWizardStartPage.cpp b/src/slic3r/GUI/CalibrationWizardStartPage.cpp index 551cd6c5be4..3857d0983ea 100644 --- a/src/slic3r/GUI/CalibrationWizardStartPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardStartPage.cpp @@ -35,30 +35,37 @@ void CalibrationStartPage::create_about(wxWindow* parent, wxString title, wxStri void CalibrationStartPage::create_bitmap(wxWindow* parent, const wxBitmap& before_img, const wxBitmap& after_img) { - m_images_sizer = new wxBoxSizer(wxHORIZONTAL); - m_before_bmp = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0); + if (!m_before_bmp) + m_before_bmp = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0); m_before_bmp->SetBitmap(before_img); - m_images_sizer->Add(m_before_bmp, 0, wxALL, 0); - m_images_sizer->AddSpacer(FromDIP(20)); - m_after_bmp = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0); + if (!m_after_bmp) + m_after_bmp = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0); m_after_bmp->SetBitmap(after_img); - m_images_sizer->Add(m_after_bmp, 0, wxALL, 0); + if (!m_images_sizer) { + m_images_sizer = new wxBoxSizer(wxHORIZONTAL); + m_images_sizer->Add(m_before_bmp, 0, wxALL, 0); + m_images_sizer->AddSpacer(FromDIP(20)); + m_images_sizer->Add(m_after_bmp, 0, wxALL, 0); + } } void CalibrationStartPage::create_bitmap(wxWindow* parent, std::string before_img, std::string after_img) { - wxBitmap before_bmp = create_scaled_bitmap(before_img, nullptr, 350); - wxBitmap after_bmp = create_scaled_bitmap(after_img, nullptr, 350); + wxBitmap before_bmp = create_scaled_bitmap(before_img, this, 350); + wxBitmap after_bmp = create_scaled_bitmap(after_img, this, 350); create_bitmap(parent, before_bmp, after_bmp); } void CalibrationStartPage::create_bitmap(wxWindow* parent, std::string img) { - wxBitmap before_bmp = create_scaled_bitmap(img, nullptr, 350); - m_images_sizer = new wxBoxSizer(wxHORIZONTAL); - m_bmp_intro = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0); + wxBitmap before_bmp = create_scaled_bitmap(img, this, 350); + if (!m_bmp_intro) + m_bmp_intro = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0); m_bmp_intro->SetBitmap(before_bmp); - m_images_sizer->Add(m_bmp_intro, 0, wxALL, 0); + if (!m_images_sizer) { + m_images_sizer = new wxBoxSizer(wxHORIZONTAL); + m_images_sizer->Add(m_bmp_intro, 0, wxALL, 0); + } } CalibrationPAStartPage::CalibrationPAStartPage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) @@ -97,7 +104,7 @@ void CalibrationPAStartPage::create_page(wxWindow* parent) m_top_sizer->Add(m_images_sizer, 0, wxALL, 0); m_top_sizer->AddSpacer(PRESET_GAP); - PAPageHelpPanel* m_help_panel = new PAPageHelpPanel(parent, false); + m_help_panel = new PAPageHelpPanel(parent, false); m_top_sizer->Add(m_help_panel, 0, wxALL, 0); m_top_sizer->AddSpacer(PRESET_GAP); @@ -169,6 +176,17 @@ void CalibrationPAStartPage::on_device_connected(MachineObject* obj) } } +void CalibrationPAStartPage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); + m_help_panel->msw_rescale(); + if (wxGetApp().app_config->get_language_code() == "zh-cn") { + create_bitmap(this, "cali_page_before_pa_CN", "cali_page_after_pa_CN"); + } else { + create_bitmap(this, "cali_page_before_pa", "cali_page_after_pa"); + } +} + CalibrationFlowRateStartPage::CalibrationFlowRateStartPage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : CalibrationStartPage(parent, id, pos, size, style) { @@ -291,6 +309,16 @@ void CalibrationFlowRateStartPage::on_device_connected(MachineObject* obj) } } +void CalibrationFlowRateStartPage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); + if (wxGetApp().app_config->get_language_code() == "zh-cn") { + create_bitmap(this, "cali_page_flow_introduction_CN"); + } else { + create_bitmap(this, "cali_page_flow_introduction"); + } +} + CalibrationMaxVolumetricSpeedStartPage::CalibrationMaxVolumetricSpeedStartPage(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : CalibrationStartPage(parent, id, pos, size, style) { @@ -343,4 +371,14 @@ void CalibrationMaxVolumetricSpeedStartPage::create_page(wxWindow* parent) m_top_sizer->Add(m_action_panel, 0, wxEXPAND, 0); } +void CalibrationMaxVolumetricSpeedStartPage::msw_rescale() +{ + CalibrationWizardPage::msw_rescale(); + if (wxGetApp().app_config->get_language_code() == "zh-cn") { + create_bitmap(this, "cali_page_before_pa_CN", "cali_page_after_pa_CN"); + } else { + create_bitmap(this, "cali_page_before_pa", "cali_page_after_pa"); + } +} + }} \ No newline at end of file diff --git a/src/slic3r/GUI/CalibrationWizardStartPage.hpp b/src/slic3r/GUI/CalibrationWizardStartPage.hpp index 41bead8318f..0e893bce108 100644 --- a/src/slic3r/GUI/CalibrationWizardStartPage.hpp +++ b/src/slic3r/GUI/CalibrationWizardStartPage.hpp @@ -19,15 +19,16 @@ class CalibrationStartPage : public CalibrationWizardPage protected: CalibMode m_cali_mode; - wxBoxSizer* m_top_sizer; - wxBoxSizer* m_images_sizer; - Label* m_when_title; - Label* m_when_content; - Label* m_about_title; - Label* m_about_content; + wxBoxSizer* m_top_sizer{ nullptr }; + wxBoxSizer* m_images_sizer{ nullptr }; + Label* m_when_title{ nullptr }; + Label* m_when_content{ nullptr }; + Label* m_about_title{ nullptr }; + Label* m_about_content{ nullptr }; wxStaticBitmap* m_before_bmp{ nullptr }; wxStaticBitmap* m_after_bmp{ nullptr }; wxStaticBitmap* m_bmp_intro{ nullptr }; + PAPageHelpPanel* m_help_panel{ nullptr }; void create_when(wxWindow* parent, wxString title, wxString content); void create_about(wxWindow* parent, wxString title, wxString content); @@ -49,6 +50,7 @@ class CalibrationPAStartPage : public CalibrationStartPage void on_reset_page(); void on_device_connected(MachineObject* obj); + void msw_rescale() override; }; class CalibrationFlowRateStartPage : public CalibrationStartPage @@ -63,6 +65,7 @@ class CalibrationFlowRateStartPage : public CalibrationStartPage void create_page(wxWindow* parent); void on_reset_page(); void on_device_connected(MachineObject* obj); + void msw_rescale() override; }; class CalibrationMaxVolumetricSpeedStartPage : public CalibrationStartPage @@ -75,6 +78,7 @@ class CalibrationMaxVolumetricSpeedStartPage : public CalibrationStartPage long style = wxTAB_TRAVERSAL); void create_page(wxWindow* parent); + void msw_rescale() override; }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/CameraPopup.cpp b/src/slic3r/GUI/CameraPopup.cpp index b21c37878b2..e7b5cf68dd5 100644 --- a/src/slic3r/GUI/CameraPopup.cpp +++ b/src/slic3r/GUI/CameraPopup.cpp @@ -260,7 +260,7 @@ void CameraPopup::check_func_supported(MachineObject *obj2) if (m_obj == nullptr) return; // function supported - if (m_obj->is_function_supported(PrinterFunction::FUNC_RECORDING) && m_obj->has_ipcam) { + if (m_obj->has_ipcam) { m_text_recording->Show(); m_switch_recording->Show(); } else { @@ -268,7 +268,7 @@ void CameraPopup::check_func_supported(MachineObject *obj2) m_switch_recording->Hide(); } - if (m_obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_CAMERA) && m_obj->has_ipcam) { + if (m_obj->virtual_camera && m_obj->has_ipcam) { m_text_vcamera->Show(); m_switch_vcamera->Show(); if (is_vcamera_show) { @@ -282,7 +282,7 @@ void CameraPopup::check_func_supported(MachineObject *obj2) link_underline->Hide(); } - allow_alter_resolution = (m_obj->is_function_supported(PrinterFunction::FUNC_ALTER_RESOLUTION) && m_obj->has_ipcam); + allow_alter_resolution = ( (m_obj->camera_resolution_supported.size() > 1?true:false) && m_obj->has_ipcam); //check u2 version DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 069eb4fb36d..9964b37df97 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -409,8 +409,8 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con if (config->opt_bool("enable_support")) { auto support_type = config->opt_enum("support_type"); auto support_style = config->opt_enum("support_style"); - std::set enum_set_normal = {0, 1, 2}; - std::set enum_set_tree = {0, 3, 4, 5, 6}; + std::set enum_set_normal = { smsDefault, smsGrid, smsSnug }; + std::set enum_set_tree = { smsDefault, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsOrganic }; auto & set = is_tree(support_type) ? enum_set_tree : enum_set_normal; if (set.find(support_style) == set.end()) { DynamicPrintConfig new_conf = *config; @@ -490,7 +490,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool have_perimeters = config->opt_int("wall_loops") > 0; for (auto el : { "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall", - "seam_position", "staggered_inner_seams", "wall_infill_order", "outer_wall_line_width", + "seam_position", "staggered_inner_seams", "wall_sequence", "outer_wall_line_width", "inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" }) toggle_field(el, have_perimeters); @@ -571,8 +571,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co "support_base_pattern_spacing", "support_expansion", "support_angle", "support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers", "bridge_no_support", "max_bridge_length", "support_top_z_distance", "support_bottom_z_distance", - //BBS: add more support params to dependent of enable_support - "support_type", "support_on_build_plate_only", "support_critical_regions_only", + "support_type", "support_on_build_plate_only", "support_critical_regions_only","support_interface_not_for_body", "support_object_xy_distance"/*, "independent_support_layer_height"*/}) toggle_field(el, have_support_material); toggle_field("support_threshold_angle", have_support_material && is_auto(support_type)); @@ -663,7 +662,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("slowdown_for_curled_perimeters",!has_overhang_speed_classic && has_overhang_speed); toggle_line("flush_into_objects", !is_global_config); - + + toggle_line("support_interface_not_for_body",config->opt_int("support_interface_filament")&&!config->opt_int("support_filament")); + bool has_fuzzy_skin = (config->opt_enum("fuzzy_skin") != FuzzySkinType::None); for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer"}) toggle_line(el, has_fuzzy_skin); diff --git a/src/slic3r/GUI/ConnectPrinter.cpp b/src/slic3r/GUI/ConnectPrinter.cpp index cabda0afbef..932c60bfd5a 100644 --- a/src/slic3r/GUI/ConnectPrinter.cpp +++ b/src/slic3r/GUI/ConnectPrinter.cpp @@ -118,32 +118,22 @@ void ConnectPrinterDialog::init_bitmap() std::string language = config->get("language"); if (m_obj) { - if (m_obj->printer_type == "C11" || m_obj->printer_type == "C12") { - m_diagram_bmp = create_scaled_bitmap("input_accesscode_help2", nullptr, 190); - } - else if (m_obj->printer_type == "BL-P001" || m_obj->printer_type == "BL-P002" || m_obj->printer_type == "C13") { - if (language == "zh_CN") { - m_diagram_bmp = create_scaled_bitmap("input_access_code_cn", nullptr, 190); - } - else { - m_diagram_bmp = create_scaled_bitmap("input_access_code_en", nullptr, 190); - } + std::string img_str = DeviceManager::get_printer_diagram_img(m_obj->printer_type); + if(img_str.empty()){img_str = "input_access_code_x1"; } + + if (language == "zh_CN") { + m_diagram_bmp = create_scaled_bitmap(img_str+"_cn", nullptr, 190); } - else if (m_obj->printer_type == "N1") { - if (language == "zh_CN") { - m_diagram_bmp = create_scaled_bitmap("input_access_code_n1_cn", nullptr, 250); - } - else { - m_diagram_bmp = create_scaled_bitmap("input_access_code_n1_en", nullptr, 250); - } + else { + m_diagram_bmp = create_scaled_bitmap(img_str+"_en", nullptr, 190); } } - else { + else{ if (language == "zh_CN") { - m_diagram_bmp = create_scaled_bitmap("input_access_code_cn", nullptr, 190); + m_diagram_bmp = create_scaled_bitmap("input_access_code_x1_cn", nullptr, 190); } else { - m_diagram_bmp = create_scaled_bitmap("input_access_code_en", nullptr, 190); + m_diagram_bmp = create_scaled_bitmap("input_access_code_x1_en", nullptr, 190); } } m_diagram_img = m_diagram_bmp.ConvertToImage(); diff --git a/src/slic3r/GUI/CreatePresetsDialog.cpp b/src/slic3r/GUI/CreatePresetsDialog.cpp new file mode 100644 index 00000000000..bc545e2a3f4 --- /dev/null +++ b/src/slic3r/GUI/CreatePresetsDialog.cpp @@ -0,0 +1,4993 @@ +#include "CreatePresetsDialog.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "libslic3r/PresetBundle.hpp" +#include "I18N.hpp" +#include "GUI_App.hpp" +#include "MsgDialog.hpp" +#include "FileHelp.hpp" +#include "Tab.hpp" +#include "MainFrame.hpp" + +#define NAME_OPTION_COMBOBOX_SIZE wxSize(FromDIP(200), FromDIP(24)) +#define FILAMENT_PRESET_COMBOBOX_SIZE wxSize(FromDIP(300), FromDIP(24)) +#define OPTION_SIZE wxSize(FromDIP(100), FromDIP(24)) +#define PRINTER_LIST_SIZE wxSize(-1, FromDIP(100)) +#define FILAMENT_LIST_SIZE wxSize(FromDIP(560), FromDIP(100)) +#define FILAMENT_OPTION_SIZE wxSize(FromDIP(-1), FromDIP(30)) +#define PRESET_TEMPLATE_SIZE wxSize(FromDIP(-1), FromDIP(100)) +#define PRINTER_SPACE_SIZE wxSize(FromDIP(80), FromDIP(24)) +#define ORIGIN_TEXT_SIZE wxSize(FromDIP(10), FromDIP(24)) +#define PRINTER_PRESET_VENDOR_SIZE wxSize(FromDIP(150), FromDIP(24)) +#define PRINTER_PRESET_MODEL_SIZE wxSize(FromDIP(280), FromDIP(24)) +#define STATIC_TEXT_COLOUR wxColour("#363636") +#define PRINTER_LIST_COLOUR wxColour("#EEEEEE") +#define FILAMENT_OPTION_COLOUR wxColour("#D9D9D9") +#define SELECT_ALL_OPTION_COLOUR wxColour("#009688") +#define DEFAULT_PROMPT_TEXT_COLOUR wxColour("#ACACAC") + +namespace Slic3r { +namespace GUI { + +static const std::vector filament_vendors = {"Polymaker", "OVERTURE", "Kexcelled", "HATCHBOX", "eSUN", "SUNLU", "Prusament", "Creality", "Protopasta", + "Anycubic", "Basf", "ELEGOO", "INLAND", "FLASHFORGE", "AMOLEN", "MIKA3D", "3DXTECH", "Duramic", + "Priline", "Eryone", "3Dgunius", "Novamaker", "Justmaker", "Giantarm", "iProspect"}; + +static const std::vector filament_types = {"PLA", "PLA+", "PLA Tough", "PETG", "ABS", "ASA", "FLEX", "HIPS", "PA", "PACF", + "NYLON", "PVA", "PC", "PCABS", "PCTG", "PCCF", "PP", "PEI", "PET", "PETG", + "PETGCF", "PTBA", "PTBA90A", "PEEK", "TPU93A", "TPU75D", "TPU", "TPU92A", "TPU98A", "Misc", + "TPE", "GLAZE", "Nylon", "CPE", "METAL", "ABST", "Carbon Fiber"}; + +static const std::vector system_filament_types = {"PLA", "ABS", "TPU", "PC", "ASA", "PA-CF", "PA6-CF", "PET-CF", "PETG", "PETG-CF", + "PLA Aero", "PLA-CF", "PPA-CF", "PPA-GF", "PA", "HIPS", "PPS", "PPS-CF", "PVA"}; + +static std::unordered_map system_filament_types_map = {{"PLA", "PLA"}, {"ABS", "ABS"}, {"TPU", "TPU"}, + {"PC", "PC"}, {"ASA", "ASA"}, {"PA-CF", "PA-CF"}, + {"PA6-CF", "PA6-CF"}, {"PET-CF", "PET-CF"}, {"PETG", "PETG"}, + {"PETG-CF", "PETG-CF"}, {"PLA Aero", "PLA-AERO"}, {"PLA-CF", "PLA-CF"}, + {"PPA-CF", "PPA-CF"}, {"PPA-GF", "PPA-GF"}, {"PA", "PA"}, + {"HIPS", "HIPS"}, {"PPS", "PPS"}, {"PPS-CF", "PPS-CF"}, + {"PVA", "PVA"}}; + +static const std::vector printer_vendors = {"Anycubic", "Artillery", "BIBO", "BIQU", "Creality ENDER", "Creality CR", "Creality SERMOON", + "FLSun", "gCreate", "Geeetech", "INAT", "Infinity3D", "Jubilee", "LNL3D", + "LulzBot", "MakerGear", "Original Prusa", "Papapiu", "Print4Taste", "RatRig", "Rigid3D", + "Snapmaker", "Sovol", "TriLAB", "Trimaker", "Ultimaker", "Voron", "Zonestar"}; + +static const std::unordered_map> printer_model_map = + {{"Anycubic", {"Kossel Linear Plus", "Kossel Pulley(Linear)", "Mega Zero", "i3 Mega", "Predator"}}, + {"Artillery", {"sidewinder X1", "Genius", "Hornet"}}, + {"BIBO", {"BIBO2 Touch"}}, + {"BIQU", {"BX"}}, + {"Creality ENDER", {"Ender-3", "Ender-3 BLTouch", "Ender-3 Pro", "Ender-3 Neo", + "Ender-3 V2 Neo", "Ender-3 S1 Plus", "Ender-3 Max", "Ender-3 Max Neo", + "Ender-4", "Ender-5 Pro", "Ender-5 Pro", + "Ender-7", "Ender-2", "Ender-2 Pro"}}, + {"Creality CR", {"CR-5 Pro", "CR-5 Pro H", "CR-10 SMART", "CR-10 SMART Pro", "CR-10 Mini", + "CR-10", "CR-10 v3", "CR-10 S", "CR-10 v2", "CR-10 v2", + "CR-10 S Pro", "CR-10 S Pro v2", "CR-10 S4", "CR-10 S5", "CR-20", "CR-20 Pro", "CR-200B", + "CR-8"}}, + {"Creality SERMOON",{"Sermoon-D1", "Sermoon-V1", "Sermoon-V1 Pro"}}, + {"FLSun", {"FLSun QQs Pro", "FLSun Q5"}}, + {"gCreate", {"gMax 1.5XT Plus", "gMax 2", "gMax 2 Pro", "gMax 2 Dual 2in1", "gMax 2 Dual Chimera"}}, + {"Geeetech", {"Thunder", "Thunder Pro", "Mizar s", "Mizar Pro", "Mizar", "Mizar Max", + "Mizar M", "A10 Pro", "A10 M", "A10 T", "A20", "A20 M", + "A20T", "A30 Pro", "A30 M", "A30 T", "E180", "Me Ducer", + "Me creator", "Me Creator2", "GiantArmD200", "l3 ProB", "l3 Prow", "l3 ProC"}}, + {"INAT", {"Proton X Rail", "Proton x Rod", "Proton XE-750"}}, + {"Infinity3D", {"DEV-200", "DEV-350"}}, + {"Jubilee", {"Jubilee"}}, + {"LNL3D", {"D3 v2", "D3 Vulcan", "D5", "D6"}}, + {"LulzBot", {"Mini Aero", "Taz6 Aero"}}, + {"MakerGear", {"Micro", "M2(V4 Hotend)", "M2 Dual", "M3-single Extruder", "M3-Independent Dual Rev.0", "M3-Independent Dual Rev.0(Duplication Mode)", + "M3-Independent Dual Rev.1", "M3-Independent Dual Rev.1(Duplication Mode)", "ultra One", "Ultra One (DuplicationMode)"}}, + {"Original Prusa", {"MK4", "SL1S SPEED", "MMU3"}}, + {"Papapiu", {"N1s"}}, + {"Print4Taste", {"mycusini 2.0"}}, + {"RatRig", {"V-core-3 300mm", "V-Core-3 400mm", "V-Core-3 500mm", "V-Minion"}}, + {"Rigid3D", {"Zero2", "Zero3"}}, + {"Snapmaker", {"A250", "A350"}}, + {"Sovol", {"SV06", "SV06 PLUS", "SV05", "SV04", "SV03 / SV03 BLTOUCH", "SVO2 / SV02 BLTOUCH", "SVO1 / SV01 BLToUCH", "SV01 PRO"}}, + {"TriLAB", {"AzteQ Industrial","AzteQ Dynamic", "DeltiQ 2", "DeltiQ 2 Plus", "DeltiQ 2 + FlexPrint 2", "DeltiQ 2 Plus + FlexPrint 2", "DeltiQ 2 +FlexPrint", + "DeltiQ 2 Plus + FlexPrint", "DeltiQ M", "DeltiQ L", "DeltiQ XL"}}, + {"Trimaker", {"Nebula cloud", "Nebula", "Cosmos ll"}}, + {"Ultimaker", {"Ultimaker 2"}}, + {"Voron", {"v2 250mm3", "v2 300mm3", "v2 350mm3", "v1 250mm3", "v1 300mm3", "v1 350mm3", + "Zero 120mm3", "Switchwire"}}, + {"Zonestar", {"Z5", "Z6", "Z5x", "Z8", "Z9"}}}; + +static std::vector nozzle_diameter_vec = {"0.4", "0.2", "0.25", "0.3", "0.35", "0.5", "0.6", "0.75", "0.8", "1.0", "1.2"}; +static std::unordered_map nozzle_diameter_map = {{"0.2", 0.2}, {"0.25", 0.25}, {"0.3", 0.3}, {"0.35", 0.35}, + {"0.4", 0.4}, {"0.5", 0.5}, {"0.6", 0.6}, {"0.75", 0.75}, + {"0.8", 0.8}, {"1.0", 1.0}, {"1.2", 1.2}}; + +static std::set cannot_input_key = {9, 10, 13, 33, 35, 36, 37, 38, 40, 41, 42, 44, 46, 47, 59, 60, 62, 63, 64, 92, 94, 95, 124, 126}; + +static std::set special_key = {'\n', '\t', '\r', '\v', '@', ';'}; + +static std::string remove_special_key(const std::string &str) +{ + std::string res_str; + for (char c : str) { + if (special_key.find(c) == special_key.end()) { + res_str.push_back(c); + } + } + return res_str; +} + +static bool delete_filament_preset_by_name(std::string delete_preset_name, std::string &selected_preset_name) +{ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("select preset, name %1%") % delete_preset_name; + if (delete_preset_name.empty()) return false; + + // Find an alternate preset to be selected after the current preset is deleted. + PresetCollection &m_presets = wxGetApp().preset_bundle->filaments; + if (delete_preset_name == selected_preset_name) { + const std::deque &presets = m_presets.get_presets(); + size_t idx_current = m_presets.get_idx_selected(); + + // Find the visible preset. + size_t idx_new = idx_current; + if (idx_current > presets.size()) idx_current = presets.size(); + if (idx_current < 0) idx_current = 0; + if (idx_new < presets.size()) + for (; idx_new < presets.size() && (presets[idx_new].name == delete_preset_name || !presets[idx_new].is_visible); ++idx_new) + ; + if (idx_new == presets.size()) + for (idx_new = idx_current - 1; idx_new > 0 && (presets[idx_new].name == delete_preset_name || !presets[idx_new].is_visible); --idx_new) + ; + selected_preset_name = presets[idx_new].name; + BOOST_LOG_TRIVIAL(info) << boost::format("cause by delete current ,choose the next visible, idx %1%, name %2%") % idx_new % selected_preset_name; + } + + try { + // BBS delete preset + Preset *need_delete_preset = m_presets.find_preset(delete_preset_name); + if (!need_delete_preset) BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" can't find delete preset and name: %1%") % delete_preset_name; + if (!need_delete_preset->setting_id.empty()) { + BOOST_LOG_TRIVIAL(info) << "delete preset = " << need_delete_preset->name << ", setting_id = " << need_delete_preset->setting_id; + m_presets.set_sync_info_and_save(need_delete_preset->name, need_delete_preset->setting_id, "delete", 0); + wxGetApp().delete_preset_from_cloud(need_delete_preset->setting_id); + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" can't preset setting id is empty and name: %1%") % delete_preset_name; + } + if (m_presets.get_edited_preset().name == delete_preset_name) { + m_presets.discard_current_changes(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("delete preset dirty and cancelled"); + } + m_presets.delete_preset(need_delete_preset->name); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " preset has been delete from filaments, and preset name is: " << delete_preset_name; + } catch (const std::exception &ex) { + // FIXME add some error reporting! + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("found exception when delete: %1% and preset name: %%") % ex.what() % delete_preset_name; + return false; + } + + return true; +} + +static std::string get_curr_time() +{ + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + + std::time_t time = std::chrono::system_clock::to_time_t(now); + + std::tm local_time = *std::localtime(&time); + std::ostringstream time_stream; + time_stream << std::put_time(&local_time, "%Y_%m_%d_%H_%M_%S"); + + std::string current_time = time_stream.str(); + return current_time; +} + +static std::string get_curr_timestmp() +{ + std::time_t currentTime = std::time(nullptr); + std::ostringstream oss; + oss << currentTime; + std::string timestampString = oss.str(); + return timestampString; +} + +static void get_filament_compatible_printer(Preset* preset, vector& printers) +{ + auto compatible_printers = dynamic_cast(preset->config.option("compatible_printers")); + if (compatible_printers == nullptr) return; + for (const std::string &printer_name : compatible_printers->values) { + printers.push_back(printer_name); + } +} + +static wxBoxSizer* create_checkbox(wxWindow* parent, Preset* preset, wxString& preset_name, std::vector>& preset_checkbox) +{ + wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); + ::CheckBox * checkbox = new ::CheckBox(parent); + sizer->Add(checkbox, 0, 0, 0); + preset_checkbox.push_back(std::make_pair(checkbox, preset)); + wxStaticText *preset_name_str = new wxStaticText(parent, wxID_ANY, preset_name); + wxToolTip * toolTip = new wxToolTip(preset_name); + preset_name_str->SetToolTip(toolTip); + sizer->Add(preset_name_str, 0, wxLEFT, 5); + return sizer; +} + +static wxBoxSizer *create_checkbox(wxWindow *parent, std::string &compatible_printer, Preset* preset, std::unordered_map<::CheckBox *, std::pair> &ptinter_compatible_filament_preset) +{ + wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); + ::CheckBox *checkbox = new ::CheckBox(parent); + sizer->Add(checkbox, 0, 0, 0); + ptinter_compatible_filament_preset[checkbox] = std::make_pair(compatible_printer, preset); + wxStaticText *preset_name_str = new wxStaticText(parent, wxID_ANY, wxString::FromUTF8(compatible_printer)); + sizer->Add(preset_name_str, 0, wxLEFT, 5); + return sizer; +} + +static wxBoxSizer *create_checkbox(wxWindow *parent, wxString &preset_name, std::vector> &preset_checkbox) +{ + wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); + ::CheckBox *checkbox = new ::CheckBox(parent); + sizer->Add(checkbox, 0, 0, 0); + preset_checkbox.push_back(std::make_pair(checkbox, into_u8(preset_name))); + wxStaticText *preset_name_str = new wxStaticText(parent, wxID_ANY, preset_name); + sizer->Add(preset_name_str, 0, wxLEFT, 5); + return sizer; +} + +static wxArrayString get_exist_vendor_choices(VendorMap& vendors) +{ + wxArrayString choices; + PresetBundle temp_preset_bundle; + temp_preset_bundle.load_system_models_from_json(ForwardCompatibilitySubstitutionRule::EnableSystemSilent); + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + + VendorProfile users_models = preset_bundle->get_custom_vendor_models(); + + vendors = temp_preset_bundle.vendors; + + if (!users_models.models.empty()) { + vendors[users_models.name] = users_models; + } + + for (const pair &vendor : vendors) { + if (vendor.second.models.empty() || vendor.second.id.empty()) continue; + choices.Add(vendor.first); + } + return choices; +} + +static std::string get_machine_name(const std::string &preset_name) +{ + size_t index_at = preset_name.find_last_of("@"); + if (std::string::npos == index_at) { + return ""; + } else { + return preset_name.substr(index_at + 1); + } +} + +static std::string get_filament_name(std::string &preset_name) +{ + size_t index_at = preset_name.find_last_of("@"); + if (std::string::npos == index_at) { + return preset_name; + } else { + return preset_name.substr(0, index_at - 1); + } +} + +static wxBoxSizer *create_preset_tree(wxWindow *parent, std::pair>> printer_and_preset) +{ + wxTreeCtrl *treeCtrl = new wxTreeCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE | wxNO_BORDER); + wxColour backgroundColor = parent->GetBackgroundColour(); + treeCtrl->SetBackgroundColour(backgroundColor); + + wxString printer_name = wxString::FromUTF8(printer_and_preset.first); + wxTreeItemId rootId = treeCtrl->AddRoot(printer_name); + int row = 1; + for (std::shared_ptr preset : printer_and_preset.second) { + wxString preset_name = wxString::FromUTF8(preset->name); + wxTreeItemId childId1 = treeCtrl->AppendItem(rootId, preset_name); + row++; + } + + treeCtrl->Expand(rootId); + wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL); + treeCtrl->SetMinSize(wxSize(-1, row * 22)); + treeCtrl->SetMaxSize(wxSize(-1, row * 22)); + sizer->Add(treeCtrl, 0, wxEXPAND | wxALL, 0); + + return sizer; +} + +static std::string get_vendor_name(std::string& preset_name) +{ + if (preset_name.empty()) return ""; + std::string vendor_name = preset_name.substr(preset_name.find_first_not_of(' ')); //remove the name prefix space + size_t index_at = vendor_name.find(" "); + if (std::string::npos == index_at) { + return vendor_name; + } else { + vendor_name = vendor_name.substr(0, index_at); + return vendor_name; + } +} + +static wxBoxSizer *create_select_filament_preset_checkbox(wxWindow * parent, + std::string & compatible_printer, + std::vector presets, + std::unordered_map<::CheckBox *, std::pair> &machine_filament_preset) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer *checkbox_sizer = new wxBoxSizer(wxVERTICAL); + ::CheckBox *checkbox = new ::CheckBox(parent); + checkbox_sizer->Add(checkbox, 0, wxEXPAND | wxRIGHT, 5); + + wxBoxSizer *combobox_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *machine_name_str = new wxStaticText(parent, wxID_ANY, wxString::FromUTF8(compatible_printer)); + ComboBox * combobox = new ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, 24), 0, nullptr, wxCB_READONLY); + combobox->SetBackgroundColor(PRINTER_LIST_COLOUR); + combobox->SetBorderColor(*wxWHITE); + combobox->SetLabel(_L("Select filament preset")); + combobox->Bind(wxEVT_COMBOBOX, [combobox, checkbox, presets, &machine_filament_preset, compatible_printer](wxCommandEvent &e) { + combobox->SetLabelColor(*wxBLACK); + wxString preset_name = combobox->GetStringSelection(); + checkbox->SetValue(true); + for (Preset *preset : presets) { + if (preset_name == wxString::FromUTF8(preset->name)) { + machine_filament_preset[checkbox] = std::make_pair(compatible_printer, preset); + } + } + e.Skip(); + }); + combobox_sizer->Add(machine_name_str, 0, wxEXPAND, 0); + combobox_sizer->Add(combobox, 0, wxEXPAND | wxTOP, 5); + + wxArrayString choices; + for (Preset *preset : presets) { + choices.Add(wxString::FromUTF8(preset->name)); + } + combobox->Set(choices); + + horizontal_sizer->Add(checkbox_sizer); + horizontal_sizer->Add(combobox_sizer); + return horizontal_sizer; +} + +static wxString get_curr_radio_type(std::vector> &radio_btns) +{ + for (std::pair radio_string : radio_btns) { + if (radio_string.first->GetValue()) { + return radio_string.second; + } + } + return ""; +} + +static std::string calculate_md5(const std::string &input) +{ + unsigned char digest[MD5_DIGEST_LENGTH]; + std::string md5; + + EVP_MD_CTX *mdContext = EVP_MD_CTX_new(); + EVP_DigestInit(mdContext, EVP_md5()); + EVP_DigestUpdate(mdContext, input.c_str(), input.length()); + EVP_DigestFinal(mdContext, digest, nullptr); + EVP_MD_CTX_free(mdContext); + + char hexDigest[MD5_DIGEST_LENGTH * 2 + 1]; + for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { sprintf(hexDigest + (i * 2), "%02x", digest[i]); } + hexDigest[MD5_DIGEST_LENGTH * 2] = '\0'; + + md5 = std::string(hexDigest); + return md5; +} + +static std::string get_filament_id(std::string vendor_typr_serial) +{ + std::unordered_map> filament_id_to_filament_name; + + // temp filament presets + PresetBundle temp_preset_bundle; + temp_preset_bundle.load_system_filaments_json(Slic3r::ForwardCompatibilitySubstitutionRule::EnableSilent); + std::string dir_user_presets = wxGetApp().app_config->get("preset_folder"); + if (dir_user_presets.empty()) { + temp_preset_bundle.load_user_presets(DEFAULT_USER_FOLDER_NAME, ForwardCompatibilitySubstitutionRule::EnableSilent); + } else { + temp_preset_bundle.load_user_presets(dir_user_presets, ForwardCompatibilitySubstitutionRule::EnableSilent); + } + const std::deque &filament_presets = temp_preset_bundle.filaments.get_presets(); + + for (const Preset &preset : filament_presets) { + std::string preset_name = preset.name; + size_t index_at = preset_name.find_first_of('@'); + if (index_at == std::string::npos) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " filament preset name has no @ and name is: " << preset_name; + continue; + } + std::string filament_name = preset_name.substr(0, index_at - 1); + if (filament_name == vendor_typr_serial) + return preset.filament_id; + filament_id_to_filament_name[preset.filament_id].insert(filament_name); + } + // global filament presets + PresetBundle * preset_bundle = wxGetApp().preset_bundle; + std::map> temp_filament_id_to_presets = preset_bundle->filaments.get_filament_presets(); + for (std::pair> filament_id_to_presets : temp_filament_id_to_presets) { + if (filament_id_to_presets.first.empty()) continue; + for (const Preset *preset : filament_id_to_presets.second) { + std::string preset_name = preset->name; + size_t index_at = preset_name.find_first_of('@'); + if (index_at == std::string::npos) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " filament preset name has no @ and name is: " << preset_name; + continue; + } + std::string filament_name = preset_name.substr(0, index_at - 1); + if (filament_name == vendor_typr_serial) + return preset->filament_id; + filament_id_to_filament_name[preset->filament_id].insert(filament_name); + } + } + + std::string user_filament_id = "P" + calculate_md5(vendor_typr_serial).substr(0, 7); + + while (filament_id_to_filament_name.find(user_filament_id) != filament_id_to_filament_name.end()) {//find same filament id + bool have_same_filament_name = false; + for (const std::string &name : filament_id_to_filament_name.find(user_filament_id)->second) { + if (name == vendor_typr_serial) { + have_same_filament_name = true; + break; + } + } + if (have_same_filament_name) { + break; + } + else { //Different names correspond to the same filament id + user_filament_id = "P" + calculate_md5(vendor_typr_serial + get_curr_time()).substr(0, 7); + } + } + return user_filament_id; +} + +static json get_config_json(const Preset* preset) { + json j; + // record the headers + j[BBL_JSON_KEY_VERSION] = preset->version.to_string(); + j[BBL_JSON_KEY_NAME] = preset->name; + j[BBL_JSON_KEY_FROM] = ""; + + DynamicPrintConfig config = preset->config; + + // record all the key-values + for (const std::string &opt_key : config.keys()) { + const ConfigOption *opt = config.option(opt_key); + if (opt->is_scalar()) { + if (opt->type() == coString) + // keep \n, \r, \t + j[opt_key] = (dynamic_cast(opt))->value; + else + j[opt_key] = opt->serialize(); + } else { + const ConfigOptionVectorBase *vec = static_cast(opt); + std::vector string_values = vec->vserialize(); + + json j_array(string_values); + j[opt_key] = j_array; + } + } + + return j; +} + +static char* read_json_file(const std::string &preset_path) +{ + FILE *json_file = boost::nowide::fopen(boost::filesystem::path(preset_path).make_preferred().string().c_str(), "rb"); + if (json_file == NULL) { + BOOST_LOG_TRIVIAL(info) << "Failed to open JSON file: " << preset_path; + return NULL; + } + fseek(json_file, 0, SEEK_END); // seek to end + long file_size = ftell(json_file); // get file size + fseek(json_file, 0, SEEK_SET); // seek to start + + char * json_contents = (char *) malloc(file_size); + if (json_contents == NULL) { + BOOST_LOG_TRIVIAL(info) << "Failed to allocate memory for JSON file "; + fclose(json_file); + return NULL; + } + + fread(json_contents, 1, file_size, json_file); + fclose(json_file); + + return json_contents; +} + +static void adjust_dialog_in_screen(DPIDialog* dialog) { + wxSize screen_size = wxGetDisplaySize(); + int pos_x, pos_y, size_x, size_y, screen_width, screen_height, dialog_x, dialog_y; + pos_x = dialog->GetPosition().x; + pos_y = dialog->GetPosition().y; + size_x = dialog->GetSize().x; + size_y = dialog->GetSize().y; + screen_width = screen_size.GetWidth(); + screen_height = screen_size.GetHeight(); + dialog_x = pos_x; + dialog_y = pos_y; + if (pos_x + size_x > screen_width) { + int exceed_x = pos_x + size_x - screen_width; + dialog_x -= exceed_x; + } + if (pos_y + size_y > screen_height - 50) { + int exceed_y = pos_y + size_y - screen_height + 50; + dialog_y -= exceed_y; + } + if (pos_x != dialog_x || pos_y != dialog_y) { dialog->SetPosition(wxPoint(dialog_x, dialog_y)); } +} + +CreateFilamentPresetDialog::CreateFilamentPresetDialog(wxWindow *parent) + : DPIDialog(parent ? parent : nullptr, wxID_ANY, _L("Create Filament"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxCENTRE) +{ + m_create_type.base_filament = _L("Create Based on Current Filament"); + m_create_type.base_filament_preset = _L("Copy Current Filament Preset "); + + this->SetBackgroundColour(*wxWHITE); + this->SetSize(wxSize(FromDIP(600), FromDIP(480))); + + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + wxBoxSizer *m_main_sizer = new wxBoxSizer(wxVERTICAL); + // top line + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + m_main_sizer->Add(m_line_top, 0, wxEXPAND, 0); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + + wxStaticText *basic_infomation = new wxStaticText(this, wxID_ANY, _L("Basic Information")); + basic_infomation->SetFont(Label::Head_16); + m_main_sizer->Add(basic_infomation, 0, wxLEFT, FromDIP(10)); + + m_main_sizer->Add(create_item(FilamentOptionType::VENDOR), 0, wxEXPAND | wxALL, FromDIP(5)); + m_main_sizer->Add(create_item(FilamentOptionType::TYPE), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_main_sizer->Add(create_item(FilamentOptionType::SERIAL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + + // divider line + auto line_divider = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + line_divider->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + m_main_sizer->Add(line_divider, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10)); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + + wxStaticText *presets_infomation = new wxStaticText(this, wxID_ANY, _L("Add Filament Preset under this filament")); + presets_infomation->SetFont(Label::Head_16); + m_main_sizer->Add(presets_infomation, 0, wxLEFT | wxRIGHT, FromDIP(15)); + + m_main_sizer->Add(create_item(FilamentOptionType::FILAMENT_PRESET), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + + m_filament_preset_text = new wxStaticText(this, wxID_ANY, _L("We could create the filament presets for your following printer:"), wxDefaultPosition, wxDefaultSize); + m_main_sizer->Add(m_filament_preset_text, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(15)); + + m_scrolled_preset_panel = new wxScrolledWindow(this, wxID_ANY); + m_scrolled_preset_panel->SetMaxSize(wxSize(-1, FromDIP(350))); + m_scrolled_preset_panel->SetBackgroundColour(*wxWHITE); + m_scrolled_preset_panel->SetScrollRate(5, 5); + m_scrolled_sizer = new wxBoxSizer(wxVERTICAL); + m_scrolled_sizer->Add(create_item(FilamentOptionType::PRESET_FOR_PRINTER), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_scrolled_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + m_scrolled_preset_panel->SetSizerAndFit(m_scrolled_sizer); + m_main_sizer->Add(m_scrolled_preset_panel, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10)); + m_main_sizer->Add(create_button_item(), 0, wxEXPAND | wxALL, FromDIP(10)); + + get_all_filament_presets(); + get_all_visible_printer_name(); + select_curr_radiobox(m_create_type_btns, 0); + + this->SetSizer(m_main_sizer); + + Layout(); + Fit(); + + wxGetApp().UpdateDlgDarkUI(this); +} + +CreateFilamentPresetDialog::~CreateFilamentPresetDialog() +{ + for (std::pair preset : m_all_presets_map) { + Preset *p = preset.second; + if (p) { + delete p; + p = nullptr; + } + } +} + +void CreateFilamentPresetDialog::on_dpi_changed(const wxRect &suggested_rect) { + + m_button_create->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_create->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_create->SetCornerRadius(FromDIP(12)); + m_button_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetCornerRadius(FromDIP(12)); + + Layout(); +} + +bool CreateFilamentPresetDialog::is_check_box_selected() +{ + for (const std::pair<::CheckBox *, std::pair> &checkbox_preset : m_filament_preset) { + if (checkbox_preset.first->GetValue()) { return true; } + } + + for (const std::pair<::CheckBox *, std::pair> &checkbox_preset : m_machint_filament_preset) { + if (checkbox_preset.first->GetValue()) { return true; } + } + + return false; +} + +wxBoxSizer *CreateFilamentPresetDialog::create_item(FilamentOptionType option_type) +{ + + wxSizer *item = nullptr; + switch (option_type) { + case VENDOR: return create_vendor_item(); + case TYPE: return create_type_item(); + case SERIAL: return create_serial_item(); + case FILAMENT_PRESET: return create_filament_preset_item(); + case PRESET_FOR_PRINTER: return create_filament_preset_for_printer_item(); + default: return nullptr; + } +} +wxBoxSizer *CreateFilamentPresetDialog::create_vendor_item() +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_vendor_text = new wxStaticText(this, wxID_ANY, _L("Vendor"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_vendor_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + wxArrayString choices; + for (const wxString &vendor : filament_vendors) { + choices.push_back(vendor); + } + + wxBoxSizer *vendor_sizer = new wxBoxSizer(wxHORIZONTAL); + m_filament_vendor_combobox = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE, 0, nullptr, wxCB_READONLY); + m_filament_vendor_combobox->SetLabel(_L("Select Vendor")); + m_filament_vendor_combobox->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + m_filament_vendor_combobox->Set(choices); + m_filament_vendor_combobox->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) { + m_filament_vendor_combobox->SetLabelColor(*wxBLACK); + e.Skip(); + }); + vendor_sizer->Add(m_filament_vendor_combobox, 0, wxEXPAND | wxALL, 0); + wxBoxSizer *textInputSizer = new wxBoxSizer(wxVERTICAL); + m_filament_custom_vendor_input = new TextInput(this, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE, wxTE_PROCESS_ENTER); + m_filament_custom_vendor_input->GetTextCtrl()->SetMaxLength(50); + m_filament_custom_vendor_input->SetSize(NAME_OPTION_COMBOBOX_SIZE); + textInputSizer->Add(m_filament_custom_vendor_input, 0, wxEXPAND | wxALL, 0); + m_filament_custom_vendor_input->GetTextCtrl()->SetHint(_L("Input Custom Vendor")); + m_filament_custom_vendor_input->GetTextCtrl()->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + int key = event.GetKeyCode(); + if (cannot_input_key.find(key) != cannot_input_key.end()) { + event.Skip(false); + return; + } + event.Skip(); + }); + m_filament_custom_vendor_input->Hide(); + vendor_sizer->Add(textInputSizer, 0, wxEXPAND | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *comboBoxSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *checkbox_sizer = new wxBoxSizer(wxHORIZONTAL); + m_can_not_find_vendor_checkbox = new ::CheckBox(this); + + checkbox_sizer->Add(m_can_not_find_vendor_checkbox, 0, wxALIGN_CENTER, 0); + checkbox_sizer->Add(0, 0, 0, wxEXPAND | wxRIGHT, FromDIP(5)); + + wxStaticText *m_can_not_find_vendor_text = new wxStaticText(this, wxID_ANY, _L("Can't find vendor I want"), wxDefaultPosition, wxDefaultSize, 0); + m_can_not_find_vendor_text->SetFont(::Label::Body_13); + + wxSize size = m_can_not_find_vendor_text->GetTextExtent(_L("Can't find vendor I want")); + m_can_not_find_vendor_text->SetMinSize(wxSize(size.x + FromDIP(4), -1)); + m_can_not_find_vendor_text->Wrap(-1); + checkbox_sizer->Add(m_can_not_find_vendor_text, 0, wxALIGN_CENTER, 0); + + m_can_not_find_vendor_checkbox->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent &e) { + bool value = m_can_not_find_vendor_checkbox->GetValue(); + if (value) { + m_can_not_find_vendor_checkbox->SetValue(true); + m_filament_vendor_combobox->Hide(); + m_filament_custom_vendor_input->Show(); + } else { + m_can_not_find_vendor_checkbox->SetValue(false); + m_filament_vendor_combobox->Show(); + m_filament_custom_vendor_input->Hide(); + } + Refresh(); + Layout(); + Fit(); + }); + + comboBoxSizer->Add(vendor_sizer, 0, wxEXPAND | wxTOP, FromDIP(5)); + comboBoxSizer->Add(checkbox_sizer, 0, wxEXPAND | wxTOP, FromDIP(5)); + horizontal_sizer->Add(comboBoxSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + return horizontal_sizer; + +} + +wxBoxSizer *CreateFilamentPresetDialog::create_type_item() +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(this, wxID_ANY, _L("Type"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + wxArrayString filament_type; + for (const wxString &filament : system_filament_types) { + filament_type.Add(filament); + } + + wxBoxSizer *comboBoxSizer = new wxBoxSizer(wxVERTICAL); + m_filament_type_combobox = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE, 0, nullptr, wxCB_READONLY); + m_filament_type_combobox->SetLabel(_L("Select Type")); + m_filament_type_combobox->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + m_filament_type_combobox->Set(filament_type); + comboBoxSizer->Add(m_filament_type_combobox, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(comboBoxSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + m_filament_type_combobox->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) { + m_filament_type_combobox->SetLabelColor(*wxBLACK); + const wxString &curr_create_type = curr_create_filament_type(); + clear_filament_preset_map(); + if (curr_create_type == m_create_type.base_filament) { + wxArrayString filament_preset_choice = get_filament_preset_choices(); + m_filament_preset_combobox->Set(filament_preset_choice); + m_filament_preset_combobox->SetLabel(_L("Select Filament Preset")); + m_filament_preset_combobox->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + + } else if (curr_create_type == m_create_type.base_filament_preset) { + get_filament_presets_by_machine(); + } + m_scrolled_preset_panel->SetSizerAndFit(m_scrolled_sizer); + + update_dialog_size(); + e.Skip(); + }); + + return horizontal_sizer; +} + +wxBoxSizer *CreateFilamentPresetDialog::create_serial_item() +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_serial_text = new wxStaticText(this, wxID_ANY, _L("Serial"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_serial_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + wxBoxSizer *comboBoxSizer = new wxBoxSizer(wxVERTICAL); + m_filament_serial_input = new TextInput(this, "", "", "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE, wxTE_PROCESS_ENTER); + m_filament_serial_input->GetTextCtrl()->SetMaxLength(50); + comboBoxSizer->Add(m_filament_serial_input, 0, wxEXPAND | wxALL, 0); + m_filament_serial_input->GetTextCtrl()->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + int key = event.GetKeyCode(); + if (cannot_input_key.find(key) != cannot_input_key.end()) { + event.Skip(false); + return; + } + event.Skip(); + }); + + wxStaticText *static_eg_text = new wxStaticText(this, wxID_ANY, _L("e.g. Basic, Matte, Silk, Marble"), wxDefaultPosition, wxDefaultSize); + static_eg_text->SetForegroundColour(wxColour("#6B6B6B")); + static_eg_text->SetFont(::Label::Body_12); + comboBoxSizer->Add(static_eg_text, 0, wxEXPAND | wxTOP, FromDIP(5)); + horizontal_sizer->Add(comboBoxSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + return horizontal_sizer; +} + +wxBoxSizer *CreateFilamentPresetDialog::create_filament_preset_item() +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_filament_preset_text = new wxStaticText(this, wxID_ANY, _L("Filament Preset"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_filament_preset_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer * comboBoxSizer = new wxBoxSizer(wxVERTICAL); + comboBoxSizer->Add(create_radio_item(m_create_type.base_filament, this, wxEmptyString, m_create_type_btns), 0, wxEXPAND | wxALL, 0); + + m_filament_preset_combobox = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, FILAMENT_PRESET_COMBOBOX_SIZE, 0, nullptr, wxCB_READONLY); + m_filament_preset_combobox->SetLabel(_L("Select Filament Preset")); + m_filament_preset_combobox->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + + + m_filament_preset_combobox->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) { + m_filament_preset_combobox->SetLabelColor(*wxBLACK); + wxString filament_type = m_filament_preset_combobox->GetStringSelection(); + std::unordered_map>::iterator iter = m_filament_choice_map.find(m_public_name_to_filament_id_map[filament_type]); + + m_scrolled_preset_panel->Freeze(); + m_filament_presets_sizer->Clear(true); + m_filament_preset.clear(); + + std::vector> printer_name_to_filament_preset; + if (iter != m_filament_choice_map.end()) { + std::unordered_map nozzle_diameter = nozzle_diameter_map; + for (Preset* preset : iter->second) { + auto compatible_printers = preset->config.option("compatible_printers", true); + if (!compatible_printers || compatible_printers->values.empty()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "there is a preset has no compatible printers and the preset name is: " << preset->name; + continue; + } + for (std::string &compatible_printer_name : compatible_printers->values) { + if (m_visible_printers.find(compatible_printer_name) == m_visible_printers.end()) continue; + size_t index = compatible_printer_name.find("nozzle"); + if (index < 4) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " compatible printer name encounter exception and name is: " << compatible_printer_name; + continue; + } + if (nozzle_diameter[compatible_printer_name.substr(index - 4, 3)] == 0) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " compatible printer nozzle encounter exception and name is: " << compatible_printer_name; + continue; + } + printer_name_to_filament_preset.push_back(std::make_pair(compatible_printer_name,preset)); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "show compatible printer name: " << compatible_printer_name << "and preset name is: " << preset; + } + } + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " not find filament id corresponding to the type: and the type is" << filament_type; + } + sort_printer_by_nozzle(printer_name_to_filament_preset); + for (std::pair printer_to_preset : printer_name_to_filament_preset) + m_filament_presets_sizer->Add(create_checkbox(m_filament_preset_panel, printer_to_preset.first, printer_to_preset.second, m_filament_preset), 0, + wxEXPAND | wxTOP | wxLEFT, FromDIP(5)); + m_scrolled_preset_panel->SetSizerAndFit(m_scrolled_sizer); + m_scrolled_preset_panel->Thaw(); + + update_dialog_size(); + e.Skip(); + }); + + comboBoxSizer->Add(m_filament_preset_combobox, 0, wxEXPAND | wxTOP, FromDIP(5)); + + comboBoxSizer->Add(create_radio_item(m_create_type.base_filament_preset, this, wxEmptyString, m_create_type_btns), 0, wxEXPAND | wxTOP, FromDIP(10)); + + horizontal_sizer->Add(comboBoxSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + horizontal_sizer->Add(0, 0, 0, wxLEFT, FromDIP(30)); + + return horizontal_sizer; + +} + +wxBoxSizer *CreateFilamentPresetDialog::create_filament_preset_for_printer_item() +{ + wxBoxSizer *vertical_sizer = new wxBoxSizer(wxVERTICAL); + m_filament_preset_panel = new wxPanel(m_scrolled_preset_panel, wxID_ANY); + m_filament_preset_panel->SetBackgroundColour(PRINTER_LIST_COLOUR); + m_filament_preset_panel->SetSize(PRINTER_LIST_SIZE); + m_filament_presets_sizer = new wxGridSizer(3, FromDIP(5), FromDIP(5)); + m_filament_preset_panel->SetSizer(m_filament_presets_sizer); + vertical_sizer->Add(m_filament_preset_panel, 0, wxEXPAND | wxTOP | wxALIGN_CENTER_HORIZONTAL, FromDIP(5)); + + return vertical_sizer; +} + +wxBoxSizer *CreateFilamentPresetDialog::create_button_item() +{ + wxBoxSizer *bSizer_button = new wxBoxSizer(wxHORIZONTAL); + bSizer_button->Add(0, 0, 1, wxEXPAND, 0); + + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + + m_button_create = new Button(this, _L("Create")); + m_button_create->SetBackgroundColor(btn_bg_green); + m_button_create->SetBorderColor(*wxWHITE); + m_button_create->SetTextColor(wxColour(0xFFFFFE)); + m_button_create->SetFont(Label::Body_12); + m_button_create->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_create->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_create->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_create, 0, wxRIGHT, FromDIP(10)); + + m_button_create->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + //get vendor name + wxString vendor_str = m_filament_vendor_combobox->GetLabel(); + std::string vendor_name; + + if (!m_can_not_find_vendor_checkbox->GetValue()) { + if (_L("Select Vendor") == vendor_str) { + MessageDialog dlg(this, _L("Vendor is not selected, please reselect vendor."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } else { + vendor_name = into_u8(vendor_str); + } + } else { + if (m_filament_custom_vendor_input->GetTextCtrl()->GetValue().empty()) { + MessageDialog dlg(this, _L("Custom vendor is not input, please input custom vendor."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } else { + vendor_name = into_u8(m_filament_custom_vendor_input->GetTextCtrl()->GetValue()); + if (vendor_name == "Bambu" || vendor_name == "Generic") { + MessageDialog dlg(this, _L("\"Bambu\" or \"Generic\" can not be used as a Vendor for custom filaments."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + } + } + + //get fialment type name + wxString type_str = m_filament_type_combobox->GetLabel(); + std::string type_name; + if (_L("Select Type") == type_str) { + MessageDialog dlg(this, _L("Filament type is not selected, please reselect type."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } else { + type_name = into_u8(type_str); + } + //get filament serial + wxString serial_str = m_filament_serial_input->GetTextCtrl()->GetValue(); + std::string serial_name; + if (serial_str.empty()) { + MessageDialog dlg(this, _L("Filament serial is not inputed, please input serial."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } else { + serial_name = into_u8(serial_str); + } + vendor_name = remove_special_key(vendor_name); + serial_name = remove_special_key(serial_name); + + if (vendor_name.empty() || serial_name.empty()) { + MessageDialog dlg(this, _L("There may be escape characters in the vendor or serial input of filament. Please delete and re-enter."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + boost::algorithm::trim(vendor_name); + boost::algorithm::trim(serial_name); + if (vendor_name.empty() || serial_name.empty()) { + MessageDialog dlg(this, _L("All inputs in the custom vendor or serial are spaces. Please re-enter."), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + if (m_can_not_find_vendor_checkbox->GetValue() && vendor_name[0] >= '0' && vendor_name[0] <= '9') { + MessageDialog dlg(this, _L("The beginning of the vendor can not be a number. Please re-enter."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + + if (!is_check_box_selected()) { + MessageDialog dlg(this, _L("You have not selected a printer or preset yet. Please select at least one."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + + std::string filament_preset_name = vendor_name + " " + type_name + " " + serial_name; + std::string user_filament_id = get_filament_id(filament_preset_name); + + const wxString &curr_create_type = curr_create_filament_type(); + PresetBundle * preset_bundle = wxGetApp().preset_bundle; + if (curr_create_type == m_create_type.base_filament) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":clone filament create type filament "; + for (const std::pair<::CheckBox *, std::pair> &checkbox_preset : m_filament_preset) { + if (checkbox_preset.first->GetValue()) { + std::string compatible_printer_name = checkbox_preset.second.first; + std::vector failures; + Preset const *const checked_preset = checkbox_preset.second.second; + DynamicConfig dynamic_config; + dynamic_config.set_key_value("filament_vendor", new ConfigOptionStrings({vendor_name})); + dynamic_config.set_key_value("compatible_printers", new ConfigOptionStrings({compatible_printer_name})); + dynamic_config.set_key_value("filament_type", new ConfigOptionStrings({type_name})); + bool res = preset_bundle->filaments.clone_presets_for_filament(checked_preset, failures, filament_preset_name, user_filament_id, dynamic_config, + compatible_printer_name); + if (!res) { + std::string failure_names; + for (std::string &failure : failures) { failure_names += failure + "\n"; } + MessageDialog dlg(this, _L("Some existing presets have failed to be created, as follows:\n") + from_u8(failure_names) + _L("\nDo you want to rewrite it?"), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + if (dlg.ShowModal() == wxID_YES) { + res = preset_bundle->filaments.clone_presets_for_filament(checked_preset, failures, filament_preset_name, user_filament_id, dynamic_config, + compatible_printer_name, true); + BOOST_LOG_TRIVIAL(info) << "clone filament have failures rewritten is successful? " << res; + } + } + BOOST_LOG_TRIVIAL(info) << "clone filament no failures is successful? " << res; + } + } + } else if (curr_create_type == m_create_type.base_filament_preset) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":clone filament presets create type filament preset"; + for (const std::pair<::CheckBox *, std::pair> &checkbox_preset : m_machint_filament_preset) { + if (checkbox_preset.first->GetValue()) { + std::string compatible_printer_name = checkbox_preset.second.first; + std::vector failures; + Preset const *const checked_preset = checkbox_preset.second.second; + DynamicConfig dynamic_config; + dynamic_config.set_key_value("filament_vendor", new ConfigOptionStrings({vendor_name})); + dynamic_config.set_key_value("compatible_printers", new ConfigOptionStrings({compatible_printer_name})); + dynamic_config.set_key_value("filament_type", new ConfigOptionStrings({type_name})); + bool res = preset_bundle->filaments.clone_presets_for_filament(checked_preset, failures, filament_preset_name, user_filament_id, dynamic_config, + compatible_printer_name); + if (!res) { + std::string failure_names; + for (std::string &failure : failures) { failure_names += failure + "\n"; } + MessageDialog dlg(this, _L("Some existing presets have failed to be created, as follows:\n") + from_u8(failure_names) + _L("\nDo you want to rewrite it?"), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + if (wxID_YES == dlg.ShowModal()) { + res = preset_bundle->filaments.clone_presets_for_filament(checked_preset, failures, filament_preset_name, user_filament_id, dynamic_config, + compatible_printer_name, true); + BOOST_LOG_TRIVIAL(info) << "clone filament presets have failures rewritten is successful? " << res; + } + } + BOOST_LOG_TRIVIAL(info) << "clone filament presets no failures is successful? " << res << " old preset is: " << checked_preset->name + << " compatible_printer_name is: " << compatible_printer_name; + } + } + } + preset_bundle->update_compatible(PresetSelectCompatibleType::Always); + EndModal(wxID_OK); + }); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + m_button_cancel = new Button(this, _L("Cancel")); + m_button_cancel->SetBackgroundColor(btn_bg_white); + m_button_cancel->SetBorderColor(wxColour(38, 46, 48)); + m_button_cancel->SetFont(Label::Body_12); + m_button_cancel->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_cancel, 0, wxRIGHT, FromDIP(10)); + + m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + EndModal(wxID_CANCEL); + }); + + return bSizer_button; +} + +wxArrayString CreateFilamentPresetDialog::get_filament_preset_choices() +{ + wxArrayString choices; + // get fialment type name + wxString type_str = m_filament_type_combobox->GetLabel(); + std::string type_name; + if (_L("Select Type") == type_str) { + /*MessageDialog dlg(this, _L("Filament type is not selected, please reselect type."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal();*/ + return choices; + } else { + type_name = into_u8(type_str); + } + + for (std::pair filament_presets : m_all_presets_map) { + Preset *preset = filament_presets.second; + auto inherit = preset->config.option("inherits"); + if (inherit && !inherit->value.empty()) continue; + if (std::string::npos == filament_presets.first.find(type_name)) continue; + m_filament_choice_map[preset->filament_id].push_back(preset); + } + + int suffix = 0; + for (const pair> &preset : m_filament_choice_map) { + if (preset.second.empty()) continue; + std::set preset_name_set; + for (Preset* filament_preset : preset.second) { + std::string preset_name = filament_preset->name; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " filament id: " << filament_preset->filament_id << " preset name: " << filament_preset->name; + size_t index_at = preset_name.find("@"); + if (std::string::npos != index_at) { + std::string cur_preset_name = preset_name.substr(0, index_at - 1); + preset_name_set.insert(wxString::FromUTF8(cur_preset_name)); + } + } + assert(1 == preset_name_set.size()); + if (preset_name_set.size() > 1) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " the same filament has different filament(vendor type serial)"; + } + for (const wxString& public_name : preset_name_set) { + if (m_public_name_to_filament_id_map.find(public_name) != m_public_name_to_filament_id_map.end()) { + suffix++; + m_public_name_to_filament_id_map[public_name + "_" + std::to_string(suffix)] = preset.first; + choices.Add(public_name + "_" + std::to_string(suffix)); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " add filament choice: " << choices.back(); + } else { + m_public_name_to_filament_id_map[public_name] = preset.first; + choices.Add(public_name); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " add filament choice: " << choices.back(); + } + } + } + + return choices; +} + +wxBoxSizer *CreateFilamentPresetDialog::create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector> &radiobox_list) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + RadioBox * radiobox = new RadioBox(parent); + horizontal_sizer->Add(radiobox, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(5)); + radiobox_list.push_back(std::make_pair(radiobox, title)); + int btn_idx = radiobox_list.size() - 1; + radiobox->Bind(wxEVT_LEFT_DOWN, [this, &radiobox_list, btn_idx](wxMouseEvent &e) { select_curr_radiobox(radiobox_list, btn_idx); }); + + wxStaticText *text = new wxStaticText(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize); + text->Bind(wxEVT_LEFT_DOWN, [this, &radiobox_list, btn_idx](wxMouseEvent &e) { select_curr_radiobox(radiobox_list, btn_idx); }); + horizontal_sizer->Add(text, 0, wxEXPAND | wxLEFT, 0); + + radiobox->SetToolTip(tooltip); + text->SetToolTip(tooltip); + return horizontal_sizer; +} + +void CreateFilamentPresetDialog::select_curr_radiobox(std::vector> &radiobox_list, int btn_idx) +{ + int len = radiobox_list.size(); + for (int i = 0; i < len; ++i) { + if (i == btn_idx) { + radiobox_list[i].first->SetValue(true); + const wxString &curr_selected_type = radiobox_list[i].second; + this->Freeze(); + if (curr_selected_type == m_create_type.base_filament) { + m_filament_preset_text->SetLabel(_L("We could create the filament presets for your following printer:")); + m_filament_preset_combobox->Show(); + if (_L("Select Type") != m_filament_type_combobox->GetLabel()) { + clear_filament_preset_map(); + wxArrayString filament_preset_choice = get_filament_preset_choices(); + m_filament_preset_combobox->Set(filament_preset_choice); + m_filament_preset_combobox->SetLabel(_L("Select Filament Preset")); + m_filament_preset_combobox->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + } + } else if (curr_selected_type == m_create_type.base_filament_preset) { + m_filament_preset_text->SetLabel(_L("We would rename the presets as \"Vendor Type Serial @printer you selected\". \nTo add preset for more prinetrs, Please go to printer selection")); + m_filament_preset_combobox->Hide(); + if (_L("Select Type") != m_filament_type_combobox->GetLabel()) { + + clear_filament_preset_map(); + get_filament_presets_by_machine(); + + } + } + m_scrolled_preset_panel->SetSizerAndFit(m_scrolled_sizer); + this->Thaw(); + } else { + radiobox_list[i].first->SetValue(false); + } + } + update_dialog_size(); +} + +wxString CreateFilamentPresetDialog::curr_create_filament_type() +{ + wxString curr_filament_type; + for (const std::pair &printer_radio : m_create_type_btns) { + if (printer_radio.first->GetValue()) { + curr_filament_type = printer_radio.second; + } + } + return curr_filament_type; +} + +void CreateFilamentPresetDialog::get_filament_presets_by_machine() +{ + wxArrayString choices; + // get fialment type name + wxString type_str = m_filament_type_combobox->GetLabel(); + std::string type_name; + if (_L("Select Type") == type_str) { + /*MessageDialog dlg(this, _L("Filament type is not selected, please reselect type."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | + wxCENTRE); dlg.ShowModal();*/ + return; + } else { + type_name = into_u8(type_str); + } + + std::unordered_map nozzle_diameter = nozzle_diameter_map; + std::unordered_map> machine_name_to_presets; + PresetBundle * preset_bundle = wxGetApp().preset_bundle; + for (std::pair filament_preset : m_all_presets_map) { + Preset * preset = filament_preset.second; + auto compatible_printers = preset->config.option("compatible_printers", true); + if (!compatible_printers || compatible_printers->values.empty()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "there is a preset has no compatible printers and the preset name is: " << preset->name; + continue; + } + for (std::string &compatible_printer_name : compatible_printers->values) { + if (m_visible_printers.find(compatible_printer_name) == m_visible_printers.end()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " compatable printer is not visible and preset name is: " << preset->name; + continue; + } + Preset * inherit_preset = nullptr; + auto inherit = dynamic_cast(preset->config.option(BBL_JSON_KEY_INHERITS,false)); + if (inherit && !inherit->value.empty()) { + std::string inherits_value = inherit->value; + inherit_preset = preset_bundle->filaments.find_preset(inherits_value, false, true); + } + ConfigOptionStrings *filament_types; + if (!inherit_preset) { + filament_types = dynamic_cast(preset->config.option("filament_type")); + } else { + filament_types = dynamic_cast(inherit_preset->config.option("filament_type")); + } + + if (filament_types && filament_types->values.empty()) continue; + const std::string filament_type = filament_types->values[0]; + if (filament_type != type_name) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " preset type is not selected type and preset name is: " << preset->name; + continue; + } + size_t index = compatible_printer_name.find("nozzle"); + if (index < 4) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " compatible printer name encounter exception and name is: " << compatible_printer_name; + continue; + } + if (nozzle_diameter[compatible_printer_name.substr(index - 4, 3)] == 0) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " compatible printer nozzle encounter exception and name is: " << compatible_printer_name; + continue; + } + machine_name_to_presets[compatible_printer_name].push_back(preset); + } + } + std::vector>> printer_name_to_filament_presets; + for (std::pair> machine_filament_presets : machine_name_to_presets) { + printer_name_to_filament_presets.push_back(machine_filament_presets); + } + sort_printer_by_nozzle(printer_name_to_filament_presets); + m_filament_preset_panel->Freeze(); + for (std::pair> machine_filament_presets : printer_name_to_filament_presets) { + std::string compatible_printer = machine_filament_presets.first; + std::vector &presets = machine_filament_presets.second; + m_filament_presets_sizer->Add(create_select_filament_preset_checkbox(m_filament_preset_panel, compatible_printer, presets, m_machint_filament_preset), 0, wxEXPAND | wxALL, FromDIP(5)); + } + m_filament_preset_panel->Thaw(); +} + +void CreateFilamentPresetDialog::get_all_filament_presets() +{ + // temp filament presets + PresetBundle temp_preset_bundle; + std::string dir_user_presets = wxGetApp().app_config->get("preset_folder"); + if (dir_user_presets.empty()) { + temp_preset_bundle.load_user_presets(DEFAULT_USER_FOLDER_NAME, ForwardCompatibilitySubstitutionRule::EnableSilent); + } else { + temp_preset_bundle.load_user_presets(dir_user_presets, ForwardCompatibilitySubstitutionRule::EnableSilent); + } + const std::deque &filament_presets = temp_preset_bundle.filaments.get_presets(); + + for (const Preset &preset : filament_presets) { + if (preset.filament_id.empty() || "null" == preset.filament_id) continue; + std::string filament_preset_name = preset.name; + Preset *filament_preset = new Preset(preset); + m_all_presets_map[filament_preset_name] = filament_preset; + } + // global filament presets + PresetBundle * preset_bundle = wxGetApp().preset_bundle; + const std::deque &temp_filament_presets = preset_bundle->filaments.get_presets(); + for (const Preset& preset : temp_filament_presets) { + if (preset.filament_id.empty() || "null" == preset.filament_id) continue; + std::string filament_preset_name = preset.name; + if (!preset.is_visible) continue; + Preset *filament_preset = new Preset(preset); + m_all_presets_map[filament_preset_name] = filament_preset; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " loaded preset name is: " << filament_preset->name; + } +} + +void CreateFilamentPresetDialog::get_all_visible_printer_name() +{ + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + for (const Preset &printer_preset : preset_bundle->printers.get_presets()) { + if (!printer_preset.is_visible) continue; + assert(m_visible_printers.find(printer_preset.name) == m_visible_printers.end()); + m_visible_printers.insert(printer_preset.name); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry, and visible printer is: " << printer_preset.name; + } + +} + +void CreateFilamentPresetDialog::update_dialog_size() +{ + this->Freeze(); + m_filament_preset_panel->SetSizerAndFit(m_filament_presets_sizer); + int width = m_filament_preset_panel->GetSize().GetWidth(); + int height = m_filament_preset_panel->GetSize().GetHeight(); + m_scrolled_preset_panel->SetMinSize(wxSize(std::min(1400, width + FromDIP(26)), std::min(600, height + FromDIP(18)))); + m_scrolled_preset_panel->SetMaxSize(wxSize(std::min(1400, width + FromDIP(26)), std::min(600, height + FromDIP(18)))); + m_scrolled_preset_panel->SetSize(wxSize(std::min(1500, width + FromDIP(26)), std::min(600, height + FromDIP(18)))); + Layout(); + Fit(); + Refresh(); + adjust_dialog_in_screen(this); + this->Thaw(); +} + +template +void CreateFilamentPresetDialog::sort_printer_by_nozzle(std::vector> &printer_name_to_filament_preset) +{ + std::unordered_map nozzle_diameter = nozzle_diameter_map; + std::sort(printer_name_to_filament_preset.begin(), printer_name_to_filament_preset.end(), + [&nozzle_diameter](const std::pair &a, const std::pair &b) { + size_t nozzle_index_a = a.first.find("nozzle"); + size_t nozzle_index_b = b.first.find("nozzle"); + if (nozzle_index_a == std::string::npos || nozzle_index_b == std::string::npos) return a.first < b.first; + std::string nozzle_str_a; + std::string nozzle_str_b; + try { + nozzle_str_a = a.first.substr(nozzle_index_a - 4, 3); + nozzle_str_b = b.first.substr(nozzle_index_b - 4, 3); + } catch (...) { + BOOST_LOG_TRIVIAL(info) << "substr filed, and printer name is: " << a.first << " and " << b.first; + return a.first < b.first; + } + float nozzle_a, nozzle_b; + try { + nozzle_a = nozzle_diameter[nozzle_str_a]; + nozzle_b = nozzle_diameter[nozzle_str_b]; + assert(nozzle_a != 0 && nozzle_b != 0); + } catch (...) { + BOOST_LOG_TRIVIAL(info) << "find nozzle filed, and nozzle is: " << nozzle_str_a << "mm and " << nozzle_str_b << "mm"; + return a.first < b.first; + } + float diff_nozzle_a = std::abs(nozzle_a - 0.4); + float diff_nozzle_b = std::abs(nozzle_b - 0.4); + if (nozzle_a == nozzle_b) return a.first < b.first; + if (diff_nozzle_a == diff_nozzle_b) return nozzle_a < nozzle_b; + + return diff_nozzle_a < diff_nozzle_b; + }); +} + +void CreateFilamentPresetDialog::clear_filament_preset_map() +{ + m_filament_choice_map.clear(); + m_filament_preset.clear(); + m_machint_filament_preset.clear(); + m_public_name_to_filament_id_map.clear(); + m_filament_preset_panel->Freeze(); + m_filament_presets_sizer->Clear(true); + m_filament_preset_panel->Thaw(); +} + +CreatePrinterPresetDialog::CreatePrinterPresetDialog(wxWindow *parent) +: DPIDialog(parent ? parent : nullptr, wxID_ANY, _L("Create Printer/Nozzle"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxCENTER) +{ + m_create_type.create_printer = _L("Create Printer"); + m_create_type.create_nozzle = _L("Create Nozzle for Existing Printer"); + m_create_type.base_template = _L("Create from Template"); + m_create_type.base_curr_printer = _L("Create Based on Current Printer"); + this->SetBackgroundColour(*wxWHITE); + SetSizeHints(wxDefaultSize, wxDefaultSize); + + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + wxBoxSizer *m_main_sizer = new wxBoxSizer(wxVERTICAL); + // top line + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 2), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + m_main_sizer->Add(m_line_top, 0, wxEXPAND, 0); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + m_main_sizer->Add(create_step_switch_item(), 0, wxEXPAND | wxALL, FromDIP(5)); + + wxBoxSizer *page_sizer = new wxBoxSizer(wxHORIZONTAL); + + m_page1 = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize); + m_page1->SetBackgroundColour(*wxWHITE); + m_page1->SetScrollRate(5, 5); + m_page2 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);\ + m_page2->SetBackgroundColour(*wxWHITE); + + create_printer_page1(m_page1); + create_printer_page2(m_page2); + m_page2->Hide(); + + page_sizer->Add(m_page1, 1, wxEXPAND, 0); + page_sizer->Add(m_page2, 1, wxEXPAND, 0); + m_main_sizer->Add(page_sizer, 0, wxEXPAND | wxRIGHT, FromDIP(10)); + select_curr_radiobox(m_create_type_btns, 0); + select_curr_radiobox(m_create_presets_btns, 0); + + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(10)); + + this->SetSizer(m_main_sizer); + + Layout(); + Fit(); + + wxSize screen_size = wxGetDisplaySize(); + int dialogX = (screen_size.GetWidth() - GetSize().GetWidth()) / 2; + int dialogY = (screen_size.GetHeight() - GetSize().GetHeight()) / 2; + SetPosition(wxPoint(dialogX, dialogY)); + + wxGetApp().UpdateDlgDarkUI(this); +} + +CreatePrinterPresetDialog::~CreatePrinterPresetDialog() +{ + clear_preset_combobox(); + if (m_printer_preset) { + delete m_printer_preset; + m_printer_preset = nullptr; + } +} + +void CreatePrinterPresetDialog::on_dpi_changed(const wxRect &suggested_rect) { + m_button_OK->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_OK->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_OK->SetCornerRadius(FromDIP(12)); + m_button_create->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_create->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_create->SetCornerRadius(FromDIP(12)); + m_button_page1_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page1_cancel->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page1_cancel->SetCornerRadius(FromDIP(12)); + m_button_page2_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page2_cancel->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page2_cancel->SetCornerRadius(FromDIP(12)); + m_button_page2_back->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page2_back->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page2_back->SetCornerRadius(FromDIP(12)); + Layout(); +} + +wxBoxSizer *CreatePrinterPresetDialog::create_step_switch_item() +{ + wxBoxSizer *step_switch_sizer = new wxBoxSizer(wxVERTICAL); + + std::string wiki_url = "https://wiki.bambulab.com/en/software/bambu-studio/3rd-party-printer-profile"; + wxHyperlinkCtrl *m_download_hyperlink = new wxHyperlinkCtrl(this, wxID_ANY, _L("wiki"), wiki_url, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE); + step_switch_sizer->Add(m_download_hyperlink, 0, wxRIGHT | wxALIGN_RIGHT, FromDIP(5)); + + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + wxPanel * step_switch_panel = new wxPanel(this); + step_switch_panel->SetBackgroundColour(*wxWHITE); + horizontal_sizer->Add(0, 0, 1, wxEXPAND,0); + m_step_1 = new wxStaticBitmap(step_switch_panel, wxID_ANY, create_scaled_bitmap("step_1", nullptr, FromDIP(20)), wxDefaultPosition, wxDefaultSize); + horizontal_sizer->Add(m_step_1, 0, wxEXPAND | wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(3)); + wxStaticText *static_create_printer_text = new wxStaticText(step_switch_panel, wxID_ANY, m_create_type.create_printer, wxDefaultPosition, wxDefaultSize); + horizontal_sizer->Add(static_create_printer_text, 0, wxEXPAND | wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(3)); + auto divider_line = new wxPanel(step_switch_panel, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(50), 1)); + divider_line->SetBackgroundColour(PRINTER_LIST_COLOUR); + horizontal_sizer->Add(divider_line, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(3)); + m_step_2 = new wxStaticBitmap(step_switch_panel, wxID_ANY, create_scaled_bitmap("step_2_ready", nullptr, FromDIP(20)), wxDefaultPosition, wxDefaultSize); + horizontal_sizer->Add(m_step_2, 0, wxEXPAND | wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(3)); + wxStaticText *static_improt_presets_text = new wxStaticText(step_switch_panel, wxID_ANY, _L("Improt Preset"), wxDefaultPosition, wxDefaultSize); + horizontal_sizer->Add(static_improt_presets_text, 0, wxEXPAND | wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(3)); + horizontal_sizer->Add(0, 0, 1, wxEXPAND, 0); + + step_switch_panel->SetSizer(horizontal_sizer); + + step_switch_sizer->Add(step_switch_panel, 0, wxBOTTOM | wxALIGN_CENTER_HORIZONTAL, FromDIP(10)); + + auto line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + line_top->SetBackgroundColour(PRINTER_LIST_COLOUR); + + step_switch_sizer->Add(line_top, 0, wxEXPAND | wxALL, FromDIP(10)); + + return step_switch_sizer; +} + +void CreatePrinterPresetDialog::create_printer_page1(wxWindow *parent) +{ + this->SetBackgroundColour(*wxWHITE); + + m_page1_sizer = new wxBoxSizer(wxVERTICAL); + + m_page1_sizer->Add(create_type_item(parent), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_page1_sizer->Add(create_printer_item(parent), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_page1_sizer->Add(create_nozzle_diameter_item(parent), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_printer_info_panel = new wxPanel(parent); + m_printer_info_panel->SetBackgroundColour(*wxWHITE); + m_printer_info_sizer = new wxBoxSizer(wxVERTICAL); + m_printer_info_sizer->Add(create_bed_shape_item(m_printer_info_panel), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_printer_info_sizer->Add(create_bed_size_item(m_printer_info_panel), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_printer_info_sizer->Add(create_origin_item(m_printer_info_panel), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_printer_info_sizer->Add(create_hot_bed_stl_item(m_printer_info_panel), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_printer_info_sizer->Add(create_hot_bed_svg_item(m_printer_info_panel), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_printer_info_sizer->Add(create_max_print_height_item(m_printer_info_panel), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_printer_info_panel->SetSizer(m_printer_info_sizer); + m_page1_sizer->Add(m_printer_info_panel, 0, wxEXPAND, 0); + m_page1_sizer->Add(create_page1_btns_item(parent), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + + parent->SetSizerAndFit(m_page1_sizer); + Layout(); + + wxGetApp().UpdateDlgDarkUI(this); +} + +wxBoxSizer *CreatePrinterPresetDialog::create_type_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_serial_text = new wxStaticText(parent, wxID_ANY, _L("Create Type"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_serial_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *radioBoxSizer = new wxBoxSizer(wxVERTICAL); + + radioBoxSizer->Add(create_radio_item(m_create_type.create_printer, parent, wxEmptyString, m_create_type_btns), 0, wxEXPAND | wxALL, 0); + radioBoxSizer->Add(create_radio_item(m_create_type.create_nozzle, parent, wxEmptyString, m_create_type_btns), 0, wxEXPAND | wxTOP, FromDIP(10)); + horizontal_sizer->Add(radioBoxSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return horizontal_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_printer_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_vendor_text = new wxStaticText(parent, wxID_ANY, _L("Printer"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_vendor_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *vertical_sizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *comboBoxSizer = new wxBoxSizer(wxHORIZONTAL); + m_select_vendor = new ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE, 0, nullptr, wxCB_READONLY); + m_select_vendor->SetValue(_L("Select Vendor")); + m_select_vendor->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + wxArrayString printer_vendor; + for (const std::string &vendor : printer_vendors) { + printer_vendor.Add(vendor); + } + m_select_vendor->Set(printer_vendor); + m_select_vendor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent e) { + m_select_vendor->SetLabelColor(*wxBLACK); + std::string curr_selected_vendor = into_u8(m_select_vendor->GetStringSelection()); + std::unordered_map>::const_iterator iter = printer_model_map.find(curr_selected_vendor); + if (iter != printer_model_map.end()) + { + std::vector vendor_model = iter->second; + wxArrayString model_choice; + for (const std::string &model : vendor_model) { + model_choice.Add(model); + } + m_select_model->Set(model_choice); + if (!model_choice.empty()) { + m_select_model->SetSelection(0); + m_select_model->SetLabelColor(*wxBLACK); + } + } else { + MessageDialog dlg(this, _L("The model is not fond, place reselect vendor."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + } + e.Skip(); + }); + + comboBoxSizer->Add(m_select_vendor, 0, wxEXPAND | wxALL, 0); + + m_select_model = new ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE, 0, nullptr, wxCB_READONLY); + comboBoxSizer->Add(m_select_model, 0, wxEXPAND | wxLEFT, FromDIP(5)); + m_select_model->SetValue(_L("Select Model")); + m_select_model->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + m_select_model->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent e) { + m_select_model->SetLabelColor(*wxBLACK); + e.Skip(); + }); + + m_select_printer = new ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, PRINTER_PRESET_MODEL_SIZE, 0, nullptr, wxCB_READONLY); + comboBoxSizer->Add(m_select_printer, 0, wxEXPAND | wxALL, 0); + m_select_printer->SetValue(_L("Select Printer")); + m_select_printer->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + m_select_printer->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent e) { + m_select_printer->SetLabelColor(*wxBLACK); + + e.Skip(); + }); + m_select_printer->Hide(); + + m_custom_vendor_text_ctrl = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE); + m_custom_vendor_text_ctrl->SetHint(_L("Input Custom Vendor")); + m_custom_vendor_text_ctrl->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + int key = event.GetKeyCode(); + if (cannot_input_key.find(key) != cannot_input_key.end()) { // "@" can not be inputed + event.Skip(false); + return; + } + event.Skip(); + }); + comboBoxSizer->Add(m_custom_vendor_text_ctrl, 0, wxEXPAND | wxALL, 0); + m_custom_vendor_text_ctrl->Hide(); + m_custom_model_text_ctrl = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, NAME_OPTION_COMBOBOX_SIZE); + m_custom_model_text_ctrl->SetHint(_L("Input Custom Model")); + m_custom_model_text_ctrl->Bind(wxEVT_CHAR, [this](wxKeyEvent &event) { + int key = event.GetKeyCode(); + if (cannot_input_key.find(key) != cannot_input_key.end()) { // "@" can not be inputed + event.Skip(false); + return; + } + event.Skip(); + }); + comboBoxSizer->Add(m_custom_model_text_ctrl, 0, wxEXPAND | wxLEFT, FromDIP(5)); + m_custom_model_text_ctrl->Hide(); + + vertical_sizer->Add(comboBoxSizer, 0, wxEXPAND, 0); + + wxBoxSizer *checkbox_sizer = new wxBoxSizer(wxHORIZONTAL); + m_can_not_find_vendor_combox = new ::CheckBox(parent); + + checkbox_sizer->Add(m_can_not_find_vendor_combox, 0, wxALIGN_CENTER, 0); + checkbox_sizer->Add(0, 0, 0, wxEXPAND | wxRIGHT, FromDIP(5)); + + m_can_not_find_vendor_text = new wxStaticText(parent, wxID_ANY, _L("Can't find my printer model"), wxDefaultPosition, wxDefaultSize, 0); + m_can_not_find_vendor_text->SetFont(::Label::Body_13); + + wxSize size = m_can_not_find_vendor_text->GetTextExtent(_L("Can't find my printer model")); + m_can_not_find_vendor_text->SetMinSize(wxSize(size.x + FromDIP(4), -1)); + m_can_not_find_vendor_text->Wrap(-1); + checkbox_sizer->Add(m_can_not_find_vendor_text, 0, wxALIGN_CENTER, 0); + + m_can_not_find_vendor_combox->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent &e) { + bool value = m_can_not_find_vendor_combox->GetValue(); + if (value) { + m_can_not_find_vendor_combox->SetValue(true); + m_custom_vendor_text_ctrl->Show(); + m_custom_model_text_ctrl->Show(); + m_select_vendor->Hide(); + m_select_model->Hide(); + } else { + m_can_not_find_vendor_combox->SetValue(false); + m_custom_vendor_text_ctrl->Hide(); + m_custom_model_text_ctrl->Hide(); + m_select_vendor->Show(); + m_select_model->Show(); + } + Refresh(); + Layout(); + m_page1->SetSizerAndFit(m_page1_sizer); + Fit(); + }); + + vertical_sizer->Add(checkbox_sizer, 0, wxEXPAND | wxTOP, FromDIP(5)); + + horizontal_sizer->Add(vertical_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return horizontal_sizer; + +} + +wxBoxSizer *CreatePrinterPresetDialog::create_nozzle_diameter_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(parent, wxID_ANY, _L("Nozzle Diameter"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *comboBoxSizer = new wxBoxSizer(wxVERTICAL); + m_nozzle_diameter = new ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, OPTION_SIZE, 0, nullptr, wxCB_READONLY); + wxArrayString nozzle_diameters; + for (const std::string nozzle : nozzle_diameter_vec) { + nozzle_diameters.Add(nozzle + " mm"); + } + m_nozzle_diameter->Set(nozzle_diameters); + m_nozzle_diameter->SetSelection(0); + comboBoxSizer->Add(m_nozzle_diameter, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(comboBoxSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + horizontal_sizer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(200)); + + return horizontal_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_bed_shape_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(parent, wxID_ANY, _L("Bed Shape"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer * bed_shape_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_bed_shape_text = new wxStaticText(parent, wxID_ANY, _L("Rectangle"), wxDefaultPosition, wxDefaultSize); + bed_shape_sizer->Add(static_bed_shape_text, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(bed_shape_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return horizontal_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_bed_size_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(parent, wxID_ANY, _L("Printable Space"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer * length_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_length_text = new wxStaticText(parent, wxID_ANY, _L("X"), wxDefaultPosition, wxDefaultSize); + static_length_text->SetMinSize(ORIGIN_TEXT_SIZE); + static_length_text->SetSize(ORIGIN_TEXT_SIZE); + length_sizer->Add(static_length_text, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(length_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + wxBoxSizer *length_input_sizer = new wxBoxSizer(wxVERTICAL); + m_bed_size_x_input = new TextInput(parent, "200", "mm", wxEmptyString, wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER); + wxTextValidator validator(wxFILTER_DIGITS); + m_bed_size_x_input->GetTextCtrl()->SetValidator(validator); + length_input_sizer->Add(m_bed_size_x_input, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(length_input_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + wxBoxSizer * width_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_width_text = new wxStaticText(parent, wxID_ANY, _L("Y"), wxDefaultPosition, wxDefaultSize); + static_width_text->SetMinSize(ORIGIN_TEXT_SIZE); + static_width_text->SetSize(ORIGIN_TEXT_SIZE); + width_sizer->Add(static_width_text, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(width_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + wxBoxSizer *width_input_sizer = new wxBoxSizer(wxVERTICAL); + m_bed_size_y_input = new TextInput(parent, "200", "mm", wxEmptyString, wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER); + m_bed_size_y_input->GetTextCtrl()->SetValidator(validator); + width_input_sizer->Add(m_bed_size_y_input, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(width_input_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + return horizontal_sizer; + +} + +wxBoxSizer *CreatePrinterPresetDialog::create_origin_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(parent, wxID_ANY, _L("Origin"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer * length_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_origin_x_text = new wxStaticText(parent, wxID_ANY, _L("X"), wxDefaultPosition, wxDefaultSize); + static_origin_x_text->SetMinSize(ORIGIN_TEXT_SIZE); + static_origin_x_text->SetSize(ORIGIN_TEXT_SIZE); + length_sizer->Add(static_origin_x_text, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(length_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + wxBoxSizer *length_input_sizer = new wxBoxSizer(wxVERTICAL); + m_bed_origin_x_input = new TextInput(parent, "0", "mm", wxEmptyString, wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER); + wxTextValidator validator(wxFILTER_DIGITS); + m_bed_origin_x_input->GetTextCtrl()->SetValidator(validator); + length_input_sizer->Add(m_bed_origin_x_input, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(length_input_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + wxBoxSizer * width_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_origin_y_text = new wxStaticText(parent, wxID_ANY, _L("Y"), wxDefaultPosition, wxDefaultSize); + static_origin_y_text->SetMinSize(ORIGIN_TEXT_SIZE); + static_origin_y_text->SetSize(ORIGIN_TEXT_SIZE); + width_sizer->Add(static_origin_y_text, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(width_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + wxBoxSizer *width_input_sizer = new wxBoxSizer(wxVERTICAL); + m_bed_origin_y_input = new TextInput(parent, "0", "mm", wxEmptyString, wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER); + m_bed_origin_y_input->GetTextCtrl()->SetValidator(validator); + width_input_sizer->Add(m_bed_origin_y_input, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(width_input_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + return horizontal_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_hot_bed_stl_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(parent, wxID_ANY, _L("Hot Bed STL"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *hot_bed_stl_sizer = new wxBoxSizer(wxVERTICAL); + + StateColor flush_bg_col(std::pair(wxColour(219, 253, 231), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(wxColour(238, 238, 238), StateColor::Normal)); + + StateColor flush_bd_col(std::pair(wxColour(0, 150, 136), StateColor::Pressed), std::pair(wxColour(0, 150, 136), StateColor::Hovered), + std::pair(wxColour(172, 172, 172), StateColor::Normal)); + + m_button_bed_stl = new Button(parent, _L("Load stl")); + m_button_bed_stl->Bind(wxEVT_BUTTON, ([this](wxCommandEvent &e) { load_model_stl(); })); + m_button_bed_stl->SetFont(Label::Body_10); + + m_button_bed_stl->SetPaddingSize(wxSize(FromDIP(30), FromDIP(8))); + m_button_bed_stl->SetFont(Label::Body_13); + m_button_bed_stl->SetCornerRadius(FromDIP(8)); + m_button_bed_stl->SetBackgroundColor(flush_bg_col); + m_button_bed_stl->SetBorderColor(flush_bd_col); + hot_bed_stl_sizer->Add(m_button_bed_stl, 0, wxEXPAND | wxALL, 0); + + horizontal_sizer->Add(hot_bed_stl_sizer, 0, wxEXPAND | wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + m_upload_stl_tip_text = new wxStaticText(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize); + m_upload_stl_tip_text->SetLabelText(_L("Empty")); + horizontal_sizer->Add(m_upload_stl_tip_text, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + return horizontal_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_hot_bed_svg_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(parent, wxID_ANY, _L("Hot Bed SVG"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *hot_bed_stl_sizer = new wxBoxSizer(wxVERTICAL); + + StateColor flush_bg_col(std::pair(wxColour(219, 253, 231), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(wxColour(238, 238, 238), StateColor::Normal)); + + StateColor flush_bd_col(std::pair(wxColour(0, 150, 136), StateColor::Pressed), std::pair(wxColour(0, 150, 136), StateColor::Hovered), + std::pair(wxColour(172, 172, 172), StateColor::Normal)); + + m_button_bed_svg = new Button(parent, _L("Load svg")); + m_button_bed_svg->Bind(wxEVT_BUTTON, ([this](wxCommandEvent &e) { load_texture(); })); + m_button_bed_svg->SetFont(Label::Body_10); + + m_button_bed_svg->SetPaddingSize(wxSize(FromDIP(30), FromDIP(8))); + m_button_bed_svg->SetFont(Label::Body_13); + m_button_bed_svg->SetCornerRadius(FromDIP(8)); + m_button_bed_svg->SetBackgroundColor(flush_bg_col); + m_button_bed_svg->SetBorderColor(flush_bd_col); + hot_bed_stl_sizer->Add(m_button_bed_svg, 0, wxEXPAND | wxALL, 0); + + horizontal_sizer->Add(hot_bed_stl_sizer, 0, wxEXPAND | wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + m_upload_svg_tip_text = new wxStaticText(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize); + m_upload_svg_tip_text->SetLabelText(_L("Empty")); + horizontal_sizer->Add(m_upload_svg_tip_text, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + return horizontal_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_max_print_height_item(wxWindow *parent) +{ + wxBoxSizer * horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(parent, wxID_ANY, _L("Max Print Height"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *hight_input_sizer = new wxBoxSizer(wxVERTICAL); + m_print_height_input = new TextInput(parent, "200", "mm", wxEmptyString, wxDefaultPosition, PRINTER_SPACE_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER); + wxTextValidator validator(wxFILTER_DIGITS); + m_print_height_input->GetTextCtrl()->SetValidator(validator); + hight_input_sizer->Add(m_print_height_input, 0, wxEXPAND | wxLEFT, FromDIP(5)); + horizontal_sizer->Add(hight_input_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + + return horizontal_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_page1_btns_item(wxWindow *parent) +{ + wxBoxSizer *bSizer_button = new wxBoxSizer(wxHORIZONTAL); + bSizer_button->Add(0, 0, 1, wxEXPAND, 0); + + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + + m_button_OK = new Button(parent, _L("OK")); + m_button_OK->SetBackgroundColor(btn_bg_green); + m_button_OK->SetBorderColor(*wxWHITE); + m_button_OK->SetTextColor(wxColour(0xFFFFFE)); + m_button_OK->SetFont(Label::Body_12); + m_button_OK->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_OK->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_OK->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_OK, 0, wxRIGHT, FromDIP(10)); + + m_button_OK->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + if (!validate_input_valid()) return; + data_init(); + show_page2(); + }); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + m_button_page1_cancel = new Button(parent, _L("Cancel")); + m_button_page1_cancel->SetBackgroundColor(btn_bg_white); + m_button_page1_cancel->SetBorderColor(wxColour(38, 46, 48)); + m_button_page1_cancel->SetFont(Label::Body_12); + m_button_page1_cancel->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page1_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page1_cancel->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_page1_cancel, 0, wxRIGHT, FromDIP(10)); + + m_button_page1_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { EndModal(wxID_CANCEL); }); + + return bSizer_button; +} +static std::string last_directory = ""; +void CreatePrinterPresetDialog::load_texture() { + wxFileDialog dialog(this, _L("Choose a file to import bed texture from (PNG/SVG):"), last_directory, "", file_wildcards(FT_TEX), wxFD_OPEN | wxFD_FILE_MUST_EXIST); + + if (dialog.ShowModal() != wxID_OK) + return; + + m_custom_texture = ""; + m_upload_svg_tip_text->SetLabelText(_L("Empty")); + last_directory = dialog.GetDirectory().ToUTF8().data(); + std::string file_name = dialog.GetPath().ToUTF8().data(); + if (!boost::algorithm::iends_with(file_name, ".png") && !boost::algorithm::iends_with(file_name, ".svg")) { + show_error(this, _L("Invalid file format.")); + return; + } + bool try_ok; + if (Utils::is_file_too_large(file_name, try_ok)) { + if (try_ok) { + m_upload_svg_tip_text->SetLabelText(wxString::Format(_L("The file exceeds %d MB, please import again."), STL_SVG_MAX_FILE_SIZE_MB)); + } else { + m_upload_svg_tip_text->SetLabelText(_L("Exception in obtaining file size, please import again.")); + } + return; + } + m_custom_texture = file_name; + wxGCDC dc; + auto text = wxControl::Ellipsize(_L(boost::filesystem::path(file_name).filename().string()), dc, wxELLIPSIZE_END, FromDIP(200)); + m_upload_svg_tip_text->SetLabelText(text); +} + +void CreatePrinterPresetDialog::load_model_stl() +{ + wxFileDialog dialog(this, _L("Choose an STL file to import bed model from:"), last_directory, "", file_wildcards(FT_STL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); + + if (dialog.ShowModal() != wxID_OK) + return; + + m_custom_model = ""; + m_upload_stl_tip_text->SetLabelText(_L("Empty")); + last_directory = dialog.GetDirectory().ToUTF8().data(); + std::string file_name = dialog.GetPath().ToUTF8().data(); + if (!boost::algorithm::iends_with(file_name, ".stl")) { + show_error(this, _L("Invalid file format.")); + return; + } + bool try_ok; + if (Utils::is_file_too_large(file_name, try_ok)) { + if (try_ok) { + m_upload_stl_tip_text->SetLabelText(wxString::Format(_L("The file exceeds %d MB, please import again."), STL_SVG_MAX_FILE_SIZE_MB)); + } + else { + m_upload_stl_tip_text->SetLabelText(_L("Exception in obtaining file size, please import again.")); + } + return; + } + m_custom_model = file_name; + wxGCDC dc; + auto text = wxControl::Ellipsize(_L(boost::filesystem::path(file_name).filename().string()), dc, wxELLIPSIZE_END, FromDIP(200)); + m_upload_stl_tip_text->SetLabelText(text); +} + +bool CreatePrinterPresetDialog::load_system_and_user_presets_with_curr_model(PresetBundle &temp_preset_bundle, bool just_template) +{ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " is load template: "<< just_template; + std::string selected_vendor_id; + std::string preset_path; + if (m_printer_preset) { + delete m_printer_preset; + m_printer_preset = nullptr; + } + + std::string curr_selected_model = into_u8(m_printer_model->GetStringSelection()); + int nozzle_index = curr_selected_model.find_first_of("@"); + std::string select_model = curr_selected_model.substr(0, nozzle_index - 1); + for (const Slic3r::VendorProfile::PrinterModel &model : m_printer_preset_vendor_selected.models) { + if (model.name == select_model) { + m_printer_preset_model_selected = model; + break; + } + } + if (m_printer_preset_vendor_selected.id.empty() || m_printer_preset_model_selected.id.empty()) { + BOOST_LOG_TRIVIAL(info) << "selected id is not find"; + MessageDialog dlg(this, _L("Preset path is not find, please reselect vendor."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + + bool is_custom_vendor = false; + if (PRESET_CUSTOM_VENDOR == m_printer_preset_vendor_selected.name || PRESET_CUSTOM_VENDOR == m_printer_preset_vendor_selected.id) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " select custom vendor "; + is_custom_vendor = true; + temp_preset_bundle = *(wxGetApp().preset_bundle); + } else { + selected_vendor_id = m_printer_preset_vendor_selected.id; + + if (boost::filesystem::exists(boost::filesystem::path(Slic3r::data_dir()) / PRESET_SYSTEM_DIR / selected_vendor_id)) { + preset_path = (boost::filesystem::path(Slic3r::data_dir()) / PRESET_SYSTEM_DIR).string(); + } else if (boost::filesystem::exists(boost::filesystem::path(Slic3r::resources_dir()) / "profiles" / selected_vendor_id)) { + preset_path = (boost::filesystem::path(Slic3r::resources_dir()) / "profiles").string(); + } + + if (preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Preset path is not find"; + MessageDialog dlg(this, _L("Preset path is not find, please reselect vendor."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES_NO | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + + try { + temp_preset_bundle.load_vendor_configs_from_json(preset_path, selected_vendor_id, PresetBundle::LoadConfigBundleAttribute::LoadSystem, + ForwardCompatibilitySubstitutionRule::EnableSilent); + } catch (...) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "load vendor fonfigs form json failed"; + MessageDialog dlg(this, _L("The printer model was not found, please reselect."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES_NO | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + + if (!just_template) { + std::string dir_user_presets = wxGetApp().app_config->get("preset_folder"); + if (dir_user_presets.empty()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "default user presets path"; + temp_preset_bundle.load_user_presets(DEFAULT_USER_FOLDER_NAME, ForwardCompatibilitySubstitutionRule::EnableSilent); + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "user presets path"; + temp_preset_bundle.load_user_presets(dir_user_presets, ForwardCompatibilitySubstitutionRule::EnableSilent); + } + } + } + //get model varient + std::string model_varient = into_u8(m_printer_model->GetStringSelection()); + size_t index_at = model_varient.find(" @ "); + size_t index_nozzle = model_varient.find("nozzle"); + std::string varient; + if (index_at != std::string::npos && index_nozzle != std::string::npos) { + varient = model_varient.substr(index_at + 3, index_nozzle - index_at - 4); + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "get nozzle failed"; + MessageDialog dlg(this, _L("The nozzle diameter is not fond, place reselect."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + + const Preset *temp_printer_preset = is_custom_vendor ? temp_preset_bundle.printers.find_custom_preset_by_model_and_variant(m_printer_preset_model_selected.id, varient) : + temp_preset_bundle.printers.find_system_preset_by_model_and_variant(m_printer_preset_model_selected.id, varient); + + if (temp_printer_preset) { + m_printer_preset = new Preset(*temp_printer_preset); + } else { + MessageDialog dlg(this, _L("The printer preset is not fond, place reselect."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + + if (!just_template) { + temp_preset_bundle.printers.select_preset_by_name(m_printer_preset->name, true); + temp_preset_bundle.update_compatible(PresetSelectCompatibleType::Always); + } else { + selected_vendor_id = PRESET_TEMPLATE_DIR; + preset_path.clear(); + if (boost::filesystem::exists(boost::filesystem::path(Slic3r::resources_dir()) / PRESET_PROFILES_TEMOLATE_DIR / selected_vendor_id)) { + preset_path = (boost::filesystem::path(Slic3r::resources_dir()) / PRESET_PROFILES_TEMOLATE_DIR).string(); + } + if (preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Preset path is not find"; + MessageDialog dlg(this, _L("Preset path is not find, please reselect vendor."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES_NO | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + try { + temp_preset_bundle.load_vendor_configs_from_json(preset_path, selected_vendor_id, PresetBundle::LoadConfigBundleAttribute::LoadSystem, + ForwardCompatibilitySubstitutionRule::EnableSilent); + } catch (...) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "load template vendor configs form json failed"; + MessageDialog dlg(this, _L("The printer model was not found, please reselect."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES_NO | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + } + + return true; +} + +void CreatePrinterPresetDialog::generate_process_presets_data(std::vector presets, std::string nozzle) +{ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry, and nozzle is: " << nozzle; + std::unordered_map nozzle_diameter_map_ = nozzle_diameter_map; + for (const Preset *preset : presets) { + float nozzle_dia = nozzle_diameter_map_[nozzle]; + assert(nozzle_dia != 0); + + auto layer_height = dynamic_cast(const_cast(preset)->config.option("layer_height", true)); + if (layer_height) + layer_height->value = nozzle_dia / 2; + else + BOOST_LOG_TRIVIAL(info) << "process template has no layer_height"; + + auto initial_layer_print_height = dynamic_cast(const_cast(preset)->config.option("initial_layer_print_height", true)); + if (initial_layer_print_height) + initial_layer_print_height->value = nozzle_dia / 2; + else + BOOST_LOG_TRIVIAL(info) << "process template has no initial_layer_print_height"; + + auto line_width = dynamic_cast(const_cast(preset)->config.option("line_width", true)); + if (line_width) + line_width->value = nozzle_dia; + else + BOOST_LOG_TRIVIAL(info) << "process template has no line_width"; + + auto initial_layer_line_width = dynamic_cast(const_cast(preset)->config.option("initial_layer_line_width", true)); + if (initial_layer_line_width) + initial_layer_line_width->value = nozzle_dia; + else + BOOST_LOG_TRIVIAL(info) << "process template has no initial_layer_line_width"; + + auto outer_wall_line_width = dynamic_cast(const_cast(preset)->config.option("outer_wall_line_width", true)); + if (outer_wall_line_width) + outer_wall_line_width->value = nozzle_dia; + else + BOOST_LOG_TRIVIAL(info) << "process template has no outer_wall_line_width"; + + auto inner_wall_line_width = dynamic_cast(const_cast(preset)->config.option("inner_wall_line_width", true)); + if (inner_wall_line_width) + inner_wall_line_width->value = nozzle_dia; + else + BOOST_LOG_TRIVIAL(info) << "process template has no inner_wall_line_width"; + + auto top_surface_line_width = dynamic_cast(const_cast(preset)->config.option("top_surface_line_width", true)); + if (top_surface_line_width) + top_surface_line_width->value = nozzle_dia; + else + BOOST_LOG_TRIVIAL(info) << "process template has no top_surface_line_width"; + + auto sparse_infill_line_width = dynamic_cast(const_cast(preset)->config.option("sparse_infill_line_width", true)); + if (sparse_infill_line_width) + sparse_infill_line_width->value = nozzle_dia; + else + BOOST_LOG_TRIVIAL(info) << "process template has no sparse_infill_line_width"; + + auto internal_solid_infill_line_width = dynamic_cast(const_cast(preset)->config.option("internal_solid_infill_line_width", true)); + if (internal_solid_infill_line_width) + internal_solid_infill_line_width->value = nozzle_dia; + else + BOOST_LOG_TRIVIAL(info) << "process template has no internal_solid_infill_line_width"; + + auto support_line_width = dynamic_cast(const_cast(preset)->config.option("support_line_width", true)); + if (support_line_width) + support_line_width->value = nozzle_dia; + else + BOOST_LOG_TRIVIAL(info) << "process template has no support_line_width"; + + auto wall_loops = dynamic_cast(const_cast(preset)->config.option("wall_loops", true)); + if (wall_loops) + wall_loops->value = std::max(2, (int) std::ceil(2 * 0.4 / nozzle_dia)); + else + BOOST_LOG_TRIVIAL(info) << "process template has no wall_loops"; + + auto top_shell_layers = dynamic_cast(const_cast(preset)->config.option("top_shell_layers", true)); + if (top_shell_layers) + top_shell_layers->value = std::max(5, (int) std::ceil(5 * 0.4 / nozzle_dia)); + else + BOOST_LOG_TRIVIAL(info) << "process template has no top_shell_layers"; + + auto bottom_shell_layers = dynamic_cast(const_cast(preset)->config.option("bottom_shell_layers", true)); + if (bottom_shell_layers) + bottom_shell_layers->value = std::max(3, (int) std::ceil(3 * 0.4 / nozzle_dia)); + else + BOOST_LOG_TRIVIAL(info) << "process template has no bottom_shell_layers"; + } +} + +void CreatePrinterPresetDialog::update_preset_list_size() +{ + m_scrolled_preset_window->Freeze(); + m_preset_template_panel->SetSizerAndFit(m_filament_sizer); + m_preset_template_panel->SetMinSize(wxSize(FromDIP(660), -1)); + m_preset_template_panel->SetSize(wxSize(FromDIP(660), -1)); + int width = m_preset_template_panel->GetSize().GetWidth(); + int height = m_preset_template_panel->GetSize().GetHeight(); + m_scrolled_preset_window->SetMinSize(wxSize(std::min(1500, width + FromDIP(26)), std::min(600, height))); + m_scrolled_preset_window->SetMaxSize(wxSize(std::min(1500, width + FromDIP(26)), std::min(600, height))); + m_scrolled_preset_window->SetSize(wxSize(std::min(1500, width + FromDIP(26)), std::min(600, height))); + m_page2->SetSizerAndFit(m_page2_sizer); + Layout(); + Fit(); + Refresh(); + adjust_dialog_in_screen(this); + m_scrolled_preset_window->Thaw(); +} + +wxBoxSizer *CreatePrinterPresetDialog::create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector> &radiobox_list) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + RadioBox * radiobox = new RadioBox(parent); + horizontal_sizer->Add(radiobox, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(5)); + radiobox_list.push_back(std::make_pair(radiobox,title)); + int btn_idx = radiobox_list.size() - 1; + radiobox->Bind(wxEVT_LEFT_DOWN, [this, &radiobox_list, btn_idx](wxMouseEvent &e) { + select_curr_radiobox(radiobox_list, btn_idx); + }); + + wxStaticText *text = new wxStaticText(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize); + text->Bind(wxEVT_LEFT_DOWN, [this, &radiobox_list, btn_idx](wxMouseEvent &e) { + select_curr_radiobox(radiobox_list, btn_idx); + }); + horizontal_sizer->Add(text, 0, wxEXPAND | wxLEFT, 0); + + radiobox->SetToolTip(tooltip); + text->SetToolTip(tooltip); + return horizontal_sizer; + +} + +void CreatePrinterPresetDialog::select_curr_radiobox(std::vector> &radiobox_list, int btn_idx) +{ + int len = radiobox_list.size(); + for (int i = 0; i < len; ++i) { + if (i == btn_idx) { + radiobox_list[i].first->SetValue(true); + wxString curr_selected_type = radiobox_list[i].second; + this->Freeze(); + if (curr_selected_type == m_create_type.base_template) { + if (m_printer_model->GetValue() == _L("Select Model")) { + m_filament_preset_template_sizer->Clear(true); + m_filament_preset.clear(); + m_process_preset_template_sizer->Clear(true); + m_process_preset.clear(); + } else { + update_presets_list(true); + } + m_page2->SetSizerAndFit(m_page2_sizer); + } else if (curr_selected_type == m_create_type.base_curr_printer) { + if (m_printer_model->GetValue() == _L("Select Model")) { + m_filament_preset_template_sizer->Clear(true); + m_filament_preset.clear(); + m_process_preset_template_sizer->Clear(true); + m_process_preset.clear(); + } else { + update_presets_list(); + } + m_page2->SetSizerAndFit(m_page2_sizer); + } else if (curr_selected_type == m_create_type.create_printer) { + m_select_printer->Hide(); + m_can_not_find_vendor_combox->Show(); + m_can_not_find_vendor_text->Show(); + m_printer_info_panel->Show(); + if (m_can_not_find_vendor_combox->GetValue()) { + m_custom_vendor_text_ctrl->Show(); + m_custom_model_text_ctrl->Show(); + m_select_vendor->Hide(); + m_select_model->Hide(); + } else { + m_select_vendor->Show(); + m_select_model->Show(); + } + m_page1->SetSizerAndFit(m_page1_sizer); + } else if (curr_selected_type == m_create_type.create_nozzle) { + set_current_visible_printer(); + m_select_vendor->Hide(); + m_select_model->Hide(); + m_can_not_find_vendor_combox->Hide(); + m_can_not_find_vendor_text->Hide(); + m_custom_vendor_text_ctrl->Hide(); + m_custom_model_text_ctrl->Hide(); + m_printer_info_panel->Hide(); + m_select_printer->Show(); + m_page1->SetSizerAndFit(m_page1_sizer); + } + this->Thaw(); + } else { + radiobox_list[i].first->SetValue(false); + } + } + + update_preset_list_size(); +} + +void CreatePrinterPresetDialog::create_printer_page2(wxWindow *parent) +{ + this->SetBackgroundColour(*wxWHITE); + + m_page2_sizer = new wxBoxSizer(wxVERTICAL); + + m_page2_sizer->Add(create_printer_preset_item(parent), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_page2_sizer->Add(create_presets_item(parent), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_page2_sizer->Add(create_presets_template_item(parent), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_page2_sizer->Add(create_page2_btns_item(parent), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + + parent->SetSizerAndFit(m_page2_sizer); + Layout(); + Fit(); + + wxGetApp().UpdateDlgDarkUI(this); +} + +wxBoxSizer *CreatePrinterPresetDialog::create_printer_preset_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_vendor_text = new wxStaticText(parent, wxID_ANY, _L("Printer Preset"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_vendor_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer * vertical_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *combobox_title = new wxStaticText(parent, wxID_ANY, m_create_type.base_curr_printer, wxDefaultPosition, wxDefaultSize, 0); + combobox_title->SetFont(::Label::Body_13); + auto size = combobox_title->GetTextExtent(m_create_type.base_curr_printer); + combobox_title->SetMinSize(wxSize(size.x + FromDIP(4), -1)); + combobox_title->Wrap(-1); + vertical_sizer->Add(combobox_title, 0, wxEXPAND | wxALL, 0); + + wxBoxSizer *comboBox_sizer = new wxBoxSizer(wxHORIZONTAL); + m_printer_vendor = new ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, PRINTER_PRESET_VENDOR_SIZE, 0, nullptr, wxCB_READONLY); + m_printer_vendor->SetValue(_L("Select Vendor")); + m_printer_vendor->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + comboBox_sizer->Add(m_printer_vendor, 0, wxEXPAND, 0); + m_printer_model = new ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, PRINTER_PRESET_MODEL_SIZE, 0, nullptr, wxCB_READONLY); + m_printer_model->SetLabelColor(DEFAULT_PROMPT_TEXT_COLOUR); + m_printer_model->SetValue(_L("Select Model")); + + comboBox_sizer->Add(m_printer_model, 0, wxEXPAND | wxLEFT, FromDIP(10)); + vertical_sizer->Add(comboBox_sizer, 0, wxEXPAND | wxTOP, FromDIP(5)); + + horizontal_sizer->Add(vertical_sizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return horizontal_sizer; + +} + +wxBoxSizer *CreatePrinterPresetDialog::create_presets_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_serial_text = new wxStaticText(parent, wxID_ANY, _L("Presets"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_serial_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *radioBoxSizer = new wxBoxSizer(wxVERTICAL); + + radioBoxSizer->Add(create_radio_item(m_create_type.base_template, parent, wxEmptyString, m_create_presets_btns), 0, wxEXPAND | wxALL, 0); + radioBoxSizer->Add(create_radio_item(m_create_type.base_curr_printer, parent, wxEmptyString, m_create_presets_btns), 0, wxEXPAND | wxTOP, FromDIP(10)); + horizontal_sizer->Add(radioBoxSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return horizontal_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_presets_template_item(wxWindow *parent) +{ + wxBoxSizer *vertical_sizer = new wxBoxSizer(wxVERTICAL); + + m_scrolled_preset_window = new wxScrolledWindow(parent); + m_scrolled_preset_window->SetScrollRate(5, 5); + m_scrolled_preset_window->SetBackgroundColour(*wxWHITE); + //m_scrolled_preset_window->SetMinSize(wxSize(FromDIP(1500), FromDIP(-1))); + m_scrolled_preset_window->SetMaxSize(wxSize(FromDIP(1500), FromDIP(-1))); + m_scrolled_preset_window->SetSize(wxSize(FromDIP(1500), FromDIP(-1))); + m_scrooled_preset_sizer = new wxBoxSizer(wxHORIZONTAL); + + m_preset_template_panel = new wxPanel(m_scrolled_preset_window); + m_preset_template_panel->SetSize(wxSize(-1, -1)); + m_preset_template_panel->SetBackgroundColour(PRINTER_LIST_COLOUR); + m_preset_template_panel->SetMinSize(wxSize(FromDIP(660), -1)); + m_filament_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_filament_preset_text = new wxStaticText(m_preset_template_panel, wxID_ANY, _L("Filament Preset Template"), wxDefaultPosition, wxDefaultSize); + m_filament_sizer->Add(static_filament_preset_text, 0, wxEXPAND | wxALL, FromDIP(5)); + m_filament_preset_panel = new wxPanel(m_preset_template_panel); + m_filament_preset_template_sizer = new wxGridSizer(3, FromDIP(5), FromDIP(5)); + m_filament_preset_panel->SetSize(PRESET_TEMPLATE_SIZE); + m_filament_preset_panel->SetSizer(m_filament_preset_template_sizer); + m_filament_sizer->Add(m_filament_preset_panel, 0, wxEXPAND | wxALL, FromDIP(5)); + + wxBoxSizer *hori_filament_btn_sizer = new wxBoxSizer(wxHORIZONTAL); + wxPanel * filament_btn_panel = new wxPanel(m_preset_template_panel); + filament_btn_panel->SetBackgroundColour(FILAMENT_OPTION_COLOUR); + wxStaticText *filament_sel_all_text = new wxStaticText(filament_btn_panel, wxID_ANY, _L("Select All"), wxDefaultPosition, wxDefaultSize); + filament_sel_all_text->SetForegroundColour(SELECT_ALL_OPTION_COLOUR); + filament_sel_all_text->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + select_all_preset_template(m_filament_preset); + e.Skip(); + }); + wxStaticText *filament_desel_all_text = new wxStaticText(filament_btn_panel, wxID_ANY, _L("Deselect All"), wxDefaultPosition, wxDefaultSize); + filament_desel_all_text->SetForegroundColour(SELECT_ALL_OPTION_COLOUR); + filament_desel_all_text->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + deselect_all_preset_template(m_filament_preset); + e.Skip(); + }); + hori_filament_btn_sizer->Add(filament_sel_all_text, 0, wxEXPAND | wxALL, FromDIP(5)); + hori_filament_btn_sizer->Add(filament_desel_all_text, 0, wxEXPAND | wxALL, FromDIP(5)); + filament_btn_panel->SetSizer(hori_filament_btn_sizer); + m_filament_sizer->Add(filament_btn_panel, 0, wxEXPAND, 0); + + wxPanel *split_panel = new wxPanel(m_preset_template_panel, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(10))); + split_panel->SetBackgroundColour(wxColour(*wxWHITE)); + m_filament_sizer->Add(split_panel, 0, wxEXPAND, 0); + + wxStaticText *static_process_preset_text = new wxStaticText(m_preset_template_panel, wxID_ANY, _L("Process Preset Template"), wxDefaultPosition, wxDefaultSize); + m_filament_sizer->Add(static_process_preset_text, 0, wxEXPAND | wxALL, FromDIP(5)); + m_process_preset_panel = new wxPanel(m_preset_template_panel); + m_process_preset_panel->SetSize(PRESET_TEMPLATE_SIZE); + m_process_preset_template_sizer = new wxGridSizer(3, FromDIP(5), FromDIP(5)); + m_process_preset_panel->SetSizer(m_process_preset_template_sizer); + m_filament_sizer->Add(m_process_preset_panel, 0, wxEXPAND | wxALL, FromDIP(5)); + + + wxBoxSizer *hori_process_btn_sizer = new wxBoxSizer(wxHORIZONTAL); + wxPanel * process_btn_panel = new wxPanel(m_preset_template_panel); + process_btn_panel->SetBackgroundColour(FILAMENT_OPTION_COLOUR); + wxStaticText *process_sel_all_text = new wxStaticText(process_btn_panel, wxID_ANY, _L("Select All"), wxDefaultPosition, wxDefaultSize); + process_sel_all_text->SetForegroundColour(SELECT_ALL_OPTION_COLOUR); + process_sel_all_text->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + select_all_preset_template(m_process_preset); + e.Skip(); + }); + wxStaticText *process_desel_all_text = new wxStaticText(process_btn_panel, wxID_ANY, _L("Deselect All"), wxDefaultPosition, wxDefaultSize); + process_desel_all_text->SetForegroundColour(SELECT_ALL_OPTION_COLOUR); + process_desel_all_text->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + deselect_all_preset_template(m_process_preset); + e.Skip(); + }); + hori_process_btn_sizer->Add(process_sel_all_text, 0, wxEXPAND | wxALL, FromDIP(5)); + hori_process_btn_sizer->Add(process_desel_all_text, 0, wxEXPAND | wxALL, FromDIP(5)); + process_btn_panel->SetSizer(hori_process_btn_sizer); + m_filament_sizer->Add(process_btn_panel, 0, wxEXPAND, 0); + + m_preset_template_panel->SetSizer(m_filament_sizer); + m_scrooled_preset_sizer->Add(m_preset_template_panel, 0, wxEXPAND | wxALL, 0); + m_scrolled_preset_window->SetSizerAndFit(m_scrooled_preset_sizer); + vertical_sizer->Add(m_scrolled_preset_window, 0, wxEXPAND | wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return vertical_sizer; +} + +wxBoxSizer *CreatePrinterPresetDialog::create_page2_btns_item(wxWindow *parent) +{ + wxBoxSizer *bSizer_button = new wxBoxSizer(wxHORIZONTAL); + bSizer_button->Add(0, 0, 1, wxEXPAND, 0); + + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + m_button_page2_back = new Button(parent, _L("Back Page 1")); + m_button_page2_back->SetBackgroundColor(btn_bg_white); + m_button_page2_back->SetBorderColor(wxColour(38, 46, 48)); + m_button_page2_back->SetFont(Label::Body_12); + m_button_page2_back->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page2_back->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page2_back->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_page2_back, 0, wxRIGHT, FromDIP(10)); + + m_button_page2_back->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { show_page1(); }); + + m_button_create = new Button(parent, _L("Create")); + m_button_create->SetBackgroundColor(btn_bg_green); + m_button_create->SetBorderColor(*wxWHITE); + m_button_create->SetTextColor(wxColour(0xFFFFFE)); + m_button_create->SetFont(Label::Body_12); + m_button_create->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_create->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_create->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_create, 0, wxRIGHT, FromDIP(10)); + + m_button_create->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + const wxString curr_selected_printer_type = curr_create_printer_type(); + const wxString curr_selected_preset_type = curr_create_preset_type(); + + // Confirm if the printer preset exists + if (!m_printer_preset) { + MessageDialog dlg(this, _L("You have not yet chosen which printer preset to create based on. Please choose the vendor and model of the printer"), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + + if (!save_printable_area_config(m_printer_preset)) { + MessageDialog dlg(this, _L("You have entered an illegal input in the printable area section on the first page. Please check before creating it."), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + show_page1(); + return; + } + + // create preset name + std::string printer_preset_name; + std::string printer_model_name; + std::string printer_nozzle_name; + std::string nozzle_diameter = into_u8(m_nozzle_diameter->GetStringSelection()); + size_t index_mm = nozzle_diameter.find("mm"); + if (std::string::npos != index_mm) { + nozzle_diameter.replace(index_mm, 2, "nozzle"); + } + if (curr_selected_printer_type == m_create_type.create_printer) { + if (m_can_not_find_vendor_combox->GetValue()) { + std::string custom_vendor = into_u8(m_custom_vendor_text_ctrl->GetValue()); + std::string custom_model = into_u8(m_custom_model_text_ctrl->GetValue()); + if (custom_vendor.empty() || custom_model.empty()) { + MessageDialog dlg(this, _L("The custom printer or model is not inputed, place input."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + show_page1(); + return; + } + custom_vendor = remove_special_key(custom_vendor); + custom_model = remove_special_key(custom_model); + boost::algorithm::trim(custom_vendor); + boost::algorithm::trim(custom_model); + + printer_preset_name = custom_vendor + " " + custom_model + " " + nozzle_diameter; + printer_model_name = custom_vendor + " " + custom_model; + } else { + std::string vender_name = into_u8(m_select_vendor->GetStringSelection()); + std::string model_name = into_u8(m_select_model->GetStringSelection()); + printer_preset_name = vender_name + " " + model_name + " " + nozzle_diameter; + printer_model_name = vender_name + " " + model_name; + + } + } else if (curr_selected_printer_type == m_create_type.create_nozzle) { + std::string selected_printer_preset_name = into_u8(m_select_printer->GetStringSelection()); + std::unordered_map>::iterator itor = m_printer_name_to_preset.find(selected_printer_preset_name); + assert(m_printer_name_to_preset.end() != itor); + if (m_printer_name_to_preset.end() != itor) { + std::shared_ptr printer_preset = itor->second; + try{ + printer_model_name = printer_preset->config.opt_string("printer_model", true); + printer_preset_name = printer_model_name + " " + nozzle_diameter; + } + catch (...) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " get config printer_model or , and the name is: " << selected_printer_preset_name; + } + + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " don't get printer preset, and the name is: " << selected_printer_preset_name; + } + } + printer_nozzle_name = nozzle_diameter.substr(0, nozzle_diameter.find(" nozzle")); + + // Confirm if the printer preset has a duplicate name + if (!rewritten && preset_bundle->printers.find_preset(printer_preset_name)) { + MessageDialog dlg(this, + _L("The printer preset you created already has a preset with the same name. Do you want to overwrite it?\n\tYes: Overwrite the printer preset with the " + "same name, and filament and process presets with the same preset name will be recreated \nand filament and process presets without the same preset name will be reserve.\n\tCancel: Do not create a preset, return to the " + "creation interface."), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxCANCEL | wxYES_DEFAULT | wxCENTRE); + int res = dlg.ShowModal(); + if (res == wxID_YES) { + rewritten = true; + } else { + return; + } + } + + // Confirm if the filament preset is exist + bool filament_preset_is_exist = false; + std::vector selected_filament_presets; + for (std::pair<::CheckBox *, Preset const *> filament_preset : m_filament_preset) { + if (filament_preset.first->GetValue()) { selected_filament_presets.push_back(filament_preset.second); } + if (!filament_preset_is_exist && preset_bundle->filaments.find_preset(filament_preset.second->alias + " @ " + printer_preset_name) != nullptr) { + filament_preset_is_exist = true; + } + } + if (selected_filament_presets.empty() && !filament_preset_is_exist) { + MessageDialog dlg(this, _L("You need to select at least one filament preset."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + + // Confirm if the process preset is exist + bool process_preset_is_exist = false; + std::vector selected_process_presets; + for (std::pair<::CheckBox *, Preset const *> process_preset : m_process_preset) { + if (process_preset.first->GetValue()) { selected_process_presets.push_back(process_preset.second); } + if (!process_preset_is_exist && preset_bundle->prints.find_preset(process_preset.second->alias + " @" + printer_preset_name) != nullptr) { + process_preset_is_exist = true; + } + } + if (selected_process_presets.empty() && !process_preset_is_exist) { + MessageDialog dlg(this, _L("You need to select at least one process preset."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + + std::vector successful_preset_names; + if (curr_selected_preset_type == m_create_type.base_template) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " base template"; + /****************************** clone filament preset ********************************/ + std::vector failures; + if (!selected_filament_presets.empty()) { + bool create_preset_result = preset_bundle->filaments.create_presets_from_template_for_printer(selected_filament_presets, failures, printer_preset_name, get_filament_id, rewritten); + if (!create_preset_result) { + std::string message; + for (const std::string &failure : failures) { message += "\t" + failure + "\n"; } + MessageDialog dlg(this, _L("Create filament presets failed. As follows:\n") + from_u8(message) + _L("\nDo you want to rewrite it?"), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + int res = dlg.ShowModal(); + if (wxID_YES == res) { + create_preset_result = preset_bundle->filaments.create_presets_from_template_for_printer(selected_filament_presets, failures, printer_preset_name, + get_filament_id, true); + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " printer preset no same preset but filament has same preset, user cancel create the printer preset"; + return; + } + } + // save created successfully preset name + for (Preset const *sucessful_preset : selected_filament_presets) + successful_preset_names.push_back(sucessful_preset->name.substr(0, sucessful_preset->name.find(" @")) + " @" + printer_preset_name); + } + + /****************************** clone process preset ********************************/ + failures.clear(); + if (!selected_process_presets.empty()) { + generate_process_presets_data(selected_process_presets, printer_nozzle_name); + bool create_preset_result = preset_bundle->prints.create_presets_from_template_for_printer(selected_process_presets, failures, printer_preset_name, + get_filament_id, rewritten); + if (!create_preset_result) { + std::string message; + for (const std::string &failure : failures) { message += "\t" + failure + "\n"; } + MessageDialog dlg(this, _L("Create process presets failed. As follows:\n") + from_u8(message) + _L("\nDo you want to rewrite it?"), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + int res = dlg.ShowModal(); + if (wxID_YES == res) { + create_preset_result = preset_bundle->prints.create_presets_from_template_for_printer(selected_process_presets, failures, printer_preset_name, get_filament_id, true); + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " printer preset no same preset but process has same preset, user cancel create the printer preset"; + return; + } + } + } + } else if (curr_selected_preset_type == m_create_type.base_curr_printer) { // create printer and based on printer + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " base curr printer"; + /****************************** clone filament preset ********************************/ + std::vector failures; + if (!selected_filament_presets.empty()) { + bool create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name, rewritten); + if (!create_preset_result) { + std::string message; + for (const std::string& failure : failures) { + message += "\t" + failure + "\n"; + } + MessageDialog dlg(this, _L("Create filament presets failed. As follows:\n") + from_u8(message) + _L("\nDo you want to rewrite it?"), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + int res = dlg.ShowModal(); + if (wxID_YES == res) { + create_preset_result = preset_bundle->filaments.clone_presets_for_printer(selected_filament_presets, failures, printer_preset_name, true); + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " printer preset no same preset but filament has same preset, user cancel create the printer preset"; + return; + } + } + } + + /****************************** clone process preset ********************************/ + failures.clear(); + if (!selected_process_presets.empty()) { + bool create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name, rewritten); + if (!create_preset_result) { + std::string message; + for (const std::string& failure : failures) { + message += "\t" + failure + "\n"; + } + MessageDialog dlg(this, _L("Create process presets failed. As follows:\n") + from_u8(message) + _L("\nDo you want to rewrite it?"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + int res = dlg.ShowModal(); + if (wxID_YES == res) { + create_preset_result = preset_bundle->prints.clone_presets_for_printer(selected_process_presets, failures, printer_preset_name, true); + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " printer preset no same preset but filament has same preset, user cancel create the printer preset"; + return; + } + } + // save created successfully preset name + for (Preset const *sucessful_preset : selected_filament_presets) + successful_preset_names.push_back(sucessful_preset->name.substr(0, sucessful_preset->name.find(" @")) + " @" + printer_preset_name); + } + } + + /****************************** clone printer preset ********************************/ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":creater printer "; + try { + auto printer_model = dynamic_cast(m_printer_preset->config.option("printer_model", true)); + if (printer_model) + printer_model->value = printer_model_name; + + auto printer_variant = dynamic_cast(m_printer_preset->config.option("printer_variant", true)); + if (printer_variant) + printer_variant->value = printer_nozzle_name; + + auto nozzle_diameter = dynamic_cast(m_printer_preset->config.option("nozzle_diameter", true)); + if (nozzle_diameter) { + std::unordered_map::const_iterator iter = nozzle_diameter_map.find(printer_nozzle_name); + if (nozzle_diameter_map.end() != iter) { + nozzle_diameter->values = {iter->second}; + } + } + } + catch (...) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " bisic info is not rewritten, may be printer_model, printer_variant, or nozzle_diameter"; + } + preset_bundle->printers.save_current_preset(printer_preset_name, true, false, m_printer_preset); + preset_bundle->update_compatible(PresetSelectCompatibleType::Always); + EndModal(wxID_OK); + + }); + + m_button_page2_cancel = new Button(parent, _L("Cancel")); + m_button_page2_cancel->SetBackgroundColor(btn_bg_white); + m_button_page2_cancel->SetBorderColor(wxColour(38, 46, 48)); + m_button_page2_cancel->SetFont(Label::Body_12); + m_button_page2_cancel->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page2_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_page2_cancel->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_page2_cancel, 0, wxRIGHT, FromDIP(10)); + + m_button_page2_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { EndModal(wxID_CANCEL); }); + + return bSizer_button; +} + +void CreatePrinterPresetDialog::show_page1() +{ + m_step_1->SetBitmap(create_scaled_bitmap("step_1", nullptr, FromDIP(20))); + m_step_2->SetBitmap(create_scaled_bitmap("step_2_ready", nullptr, FromDIP(20))); + m_page1->Show(); + m_page2->Hide(); + Refresh(); + Layout(); + Fit(); +} + +void CreatePrinterPresetDialog::show_page2() +{ + m_step_1->SetBitmap(create_scaled_bitmap("step_is_ok", nullptr, FromDIP(20))); + m_step_2->SetBitmap(create_scaled_bitmap("step_2", nullptr, FromDIP(20))); + m_page2->Show(); + m_page1->Hide(); + Refresh(); + Layout(); + Fit(); +} + +bool CreatePrinterPresetDialog::data_init() +{ + std::string nozzle_type = into_u8(m_nozzle_diameter->GetStringSelection()); + size_t index_mm = nozzle_type.find(" mm"); + if (std::string::npos != index_mm) { + nozzle_type = nozzle_type.substr(0, index_mm); + } + float nozzle = nozzle_diameter_map[nozzle_type]; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry and nozzle type is: " << nozzle_type << " and nozzle is: " << nozzle; + + VendorMap vendors; + wxArrayString exist_vendor_choice = get_exist_vendor_choices(vendors); + m_printer_vendor->Set(exist_vendor_choice); + + m_printer_model->Bind(wxEVT_COMBOBOX, &CreatePrinterPresetDialog::on_preset_model_value_change, this); + + m_printer_vendor->Bind(wxEVT_COMBOBOX, [this, vendors, nozzle](wxCommandEvent e) { + m_printer_vendor->SetLabelColor(*wxBLACK); + + std::string curr_selected_vendor = into_u8(m_printer_vendor->GetStringSelection()); + auto iterator = vendors.find(curr_selected_vendor); + if (iterator != vendors.end()) { + m_printer_preset_vendor_selected = iterator->second; + } else { + MessageDialog dlg(this, _L("Vendor is not find, please reselect."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + + wxArrayString printer_preset_model = printer_preset_sort_with_nozzle_diameter(m_printer_preset_vendor_selected, nozzle); + if (printer_preset_model.size() == 0) { + MessageDialog dlg(this, _L("Current vendor has no models, please reselect."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + m_printer_model->Set(printer_preset_model); + if (!printer_preset_model.empty()) { + m_printer_model->SetSelection(0); + wxCommandEvent e; + on_preset_model_value_change(e); + update_preset_list_size(); + } + rewritten = false; + e.Skip(); + + }); + return true; + +} + +void CreatePrinterPresetDialog::set_current_visible_printer() +{ + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + const std::deque &printer_presets = preset_bundle->printers.get_presets(); + wxArrayString printer_choice; + m_printer_name_to_preset.clear(); + for (const Preset &printer_preset : printer_presets) { + if (printer_preset.is_system || !printer_preset.is_visible) continue; + if (preset_bundle->printers.get_preset_base(printer_preset)->name != printer_preset.name) continue; + printer_choice.push_back(wxString::FromUTF8(printer_preset.name)); + m_printer_name_to_preset[printer_preset.name] = std::make_shared(printer_preset); + } + m_select_printer->Set(printer_choice); +} + +wxArrayString CreatePrinterPresetDialog::printer_preset_sort_with_nozzle_diameter(const VendorProfile &vendor_profile, float nozzle_diameter) +{ + std::vector> preset_sort; + + for (const Slic3r::VendorProfile::PrinterModel &model : vendor_profile.models) { + std::string model_name = model.name; + for (const Slic3r::VendorProfile::PrinterVariant &variant : model.variants) { + try { + float variant_diameter = std::stof(variant.name); + preset_sort.push_back(std::make_pair(variant_diameter, model_name + " @ " + variant.name + " nozzle")); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "nozzle: " << variant_diameter << "model: " << preset_sort.back().second; + } + catch (...) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " prase varient fialed and the model_name is: " << model_name; + continue; + } + } + } + + std::sort(preset_sort.begin(), preset_sort.end(), [](const std::pair &a, const std::pair &b) { return a.first < b.first; }); + + int index_nearest_nozzle = -1; + float nozzle_diameter_diff = 1; + for (int i = 0; i < preset_sort.size(); ++i) { + float curr_nozzle_diameter_diff = std::abs(nozzle_diameter - preset_sort[i].first); + if (curr_nozzle_diameter_diff < nozzle_diameter_diff) { + index_nearest_nozzle = i; + nozzle_diameter_diff = curr_nozzle_diameter_diff; + if (curr_nozzle_diameter_diff == 0) break; + } + } + wxArrayString printer_preset_model_selection; + int right_index = index_nearest_nozzle + 1; + while (index_nearest_nozzle >= 0 || right_index < preset_sort.size()) { + if (index_nearest_nozzle >= 0 && right_index < preset_sort.size()) { + float left_nozzle_diff = std::abs(nozzle_diameter - preset_sort[index_nearest_nozzle].first); + float right_nozzle_diff = std::abs(nozzle_diameter - preset_sort[right_index].first); + bool left_is_little = left_nozzle_diff < right_nozzle_diff; + if (left_is_little) { + printer_preset_model_selection.Add(from_u8(preset_sort[index_nearest_nozzle].second)); + index_nearest_nozzle--; + } else { + printer_preset_model_selection.Add(from_u8(preset_sort[right_index].second)); + right_index++; + } + } else if (index_nearest_nozzle >= 0) { + printer_preset_model_selection.Add(from_u8(preset_sort[index_nearest_nozzle].second)); + index_nearest_nozzle--; + } else if (right_index < preset_sort.size()) { + printer_preset_model_selection.Add(from_u8(preset_sort[right_index].second)); + right_index++; + } + } + return printer_preset_model_selection; +} + +void CreatePrinterPresetDialog::select_all_preset_template(std::vector> &preset_templates) +{ + for (std::pair<::CheckBox *, Preset const *> filament_preset : preset_templates) { + filament_preset.first->SetValue(true); + } +} + +void CreatePrinterPresetDialog::deselect_all_preset_template(std::vector> &preset_templates) +{ + for (std::pair<::CheckBox *, Preset const *> filament_preset : preset_templates) { + filament_preset.first->SetValue(false); + } +} + +void CreatePrinterPresetDialog::update_presets_list(bool just_template) +{ + PresetBundle temp_preset_bundle; + if (!load_system_and_user_presets_with_curr_model(temp_preset_bundle, just_template)) return; + + const std::deque &filament_presets = temp_preset_bundle.filaments.get_presets(); + const std::deque &process_presets = temp_preset_bundle.prints.get_presets(); + + // clear filament preset window sizer + m_preset_template_panel->Freeze(); + clear_preset_combobox(); + + // update filament preset window sizer + for (const Preset &filament_preset : filament_presets) { + if (filament_preset.is_compatible) { + if (filament_preset.is_default) continue; + Preset *temp_filament = new Preset(filament_preset); + wxString filament_name = wxString::FromUTF8(temp_filament->name); + m_filament_preset_template_sizer->Add(create_checkbox(m_filament_preset_panel, temp_filament, filament_name, m_filament_preset), 0, + wxEXPAND, FromDIP(5)); + } + } + + for (const Preset &process_preset : process_presets) { + if (process_preset.is_compatible) { + if (process_preset.is_default) continue; + + Preset *temp_process = new Preset(process_preset); + wxString process_name = wxString::FromUTF8(temp_process->name); + m_process_preset_template_sizer->Add(create_checkbox(m_process_preset_panel, temp_process, process_name, m_process_preset), 0, wxEXPAND, + FromDIP(5)); + } + } + m_preset_template_panel->Thaw(); +} + +void CreatePrinterPresetDialog::clear_preset_combobox() +{ + for (std::pair<::CheckBox *, Preset *> preset : m_filament_preset) { + if (preset.second) { + delete preset.second; + preset.second = nullptr; + } + } + m_filament_preset.clear(); + m_filament_preset_template_sizer->Clear(true); + + for (std::pair<::CheckBox *, Preset *> preset : m_process_preset) { + if (preset.second) { + delete preset.second; + preset.second = nullptr; + } + } + m_process_preset.clear(); + m_process_preset_template_sizer->Clear(true); +} + +bool CreatePrinterPresetDialog::save_printable_area_config(Preset *preset) +{ + const wxString curr_selected_printer_type = curr_create_printer_type(); + DynamicPrintConfig &config = preset->config; + + if (curr_selected_printer_type == m_create_type.create_printer) { + double x = 0; + m_bed_size_x_input->GetTextCtrl()->GetValue().ToDouble(&x); + double y = 0; + m_bed_size_y_input->GetTextCtrl()->GetValue().ToDouble(&y); + double dx = 0; + m_bed_origin_x_input->GetTextCtrl()->GetValue().ToDouble(&dx); + double dy = 0; + m_bed_origin_y_input->GetTextCtrl()->GetValue().ToDouble(&dy); + // range check begin + if (x == 0 || y == 0) { return false; } + double x0 = 0.0; + double y0 = 0.0; + double x1 = x; + double y1 = y; + if (dx >= x || dy >= y) { return false; } + x0 -= dx; + x1 -= dx; + y0 -= dy; + y1 -= dy; + // range check end + std::vector points = {Vec2d(x0, y0), Vec2d(x1, y0), Vec2d(x1, y1), Vec2d(x0, y1)}; + config.set_key_value("printable_area", new ConfigOptionPoints(points)); + + double max_print_height = 0; + m_print_height_input->GetTextCtrl()->GetValue().ToDouble(&max_print_height); + config.set("printable_height", max_print_height); + + Utils::slash_to_back_slash(m_custom_texture); + Utils::slash_to_back_slash(m_custom_model); + config.set("bed_custom_model", m_custom_model); + config.set("bed_custom_texture", m_custom_texture); + } else if(m_create_type.create_nozzle){ + std::string selected_printer_preset_name = into_u8(m_select_printer->GetStringSelection()); + std::unordered_map>::iterator itor = m_printer_name_to_preset.find(selected_printer_preset_name); + assert(m_printer_name_to_preset.end() != itor); + if (m_printer_name_to_preset.end() != itor) { + std::shared_ptr printer_preset = itor->second; + std::vector keys = {"printable_area", "printable_height", "bed_custom_model", "bed_custom_texture"}; + config.apply_only(printer_preset->config, keys, true); + } + } + return true; +} + +bool CreatePrinterPresetDialog::check_printable_area() { + double x = 0; + m_bed_size_x_input->GetTextCtrl()->GetValue().ToDouble(&x); + double y = 0; + m_bed_size_y_input->GetTextCtrl()->GetValue().ToDouble(&y); + double dx = 0; + m_bed_origin_x_input->GetTextCtrl()->GetValue().ToDouble(&dx); + double dy = 0; + m_bed_origin_y_input->GetTextCtrl()->GetValue().ToDouble(&dy); + // range check begin + if (x == 0 || y == 0) { + return false; + } + double x0 = 0.0; + double y0 = 0.0; + double x1 = x; + double y1 = y; + if (dx >= x || dy >= y) { + return false; + } + return true; +} + +bool CreatePrinterPresetDialog::validate_input_valid() +{ + const wxString curr_selected_printer_type = curr_create_printer_type(); + if (curr_selected_printer_type == m_create_type.create_printer) { + std::string vendor_name, model_name; + if (m_can_not_find_vendor_combox->GetValue()) { + vendor_name = into_u8(m_custom_vendor_text_ctrl->GetValue()); + model_name = into_u8(m_custom_model_text_ctrl->GetValue()); + + } else { + vendor_name = into_u8(m_select_vendor->GetStringSelection()); + model_name = into_u8(m_select_model->GetStringSelection()); + } + if ((vendor_name.empty() || model_name.empty())) { + MessageDialog dlg(this, _L("You have not selected the vendor and model or inputed the custom vendor and model."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + + vendor_name = remove_special_key(vendor_name); + model_name = remove_special_key(model_name); + if (vendor_name.empty() || model_name.empty()) { + MessageDialog dlg(this, _L("There may be escape characters in the custom printer vendor or model. Please delete and re-enter."), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + boost::algorithm::trim(vendor_name); + boost::algorithm::trim(model_name); + if (vendor_name.empty() || model_name.empty()) { + MessageDialog dlg(this, _L("All inputs in the custom printer vendor or model are spaces. Please re-enter."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + + if (check_printable_area() == false) { + MessageDialog dlg(this, _L("Please check bed printable shape and origin input."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + } else if (curr_selected_printer_type == m_create_type.create_nozzle) { + wxString printer_name = m_select_printer->GetStringSelection(); + if (printer_name.empty()) { + MessageDialog dlg(this, _L("You have not yet selected the printer to replace the nozzle, please choose."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return false; + } + } + + return true; +} + +void CreatePrinterPresetDialog::on_preset_model_value_change(wxCommandEvent &e) +{ + m_printer_model->SetLabelColor(*wxBLACK); + if (m_printer_preset_vendor_selected.models.empty()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " selected vendor has no models, and the vendor is: " << m_printer_preset_vendor_selected.id; + return; + } + + wxString curr_selected_preset_type = curr_create_preset_type(); + if (curr_selected_preset_type == m_create_type.base_curr_printer) { + update_presets_list(); + } else if (curr_selected_preset_type == m_create_type.base_template) { + update_presets_list(true); + } + rewritten = false; + + update_preset_list_size(); + + e.Skip(); +} + +wxString CreatePrinterPresetDialog::curr_create_preset_type() +{ + wxString curr_selected_preset_type; + for (const std::pair &presets_radio : m_create_presets_btns) { + if (presets_radio.first->GetValue()) { + curr_selected_preset_type = presets_radio.second; + } + } + return curr_selected_preset_type; +} + +wxString CreatePrinterPresetDialog::curr_create_printer_type() +{ + wxString curr_selected_printer_type; + for (const std::pair &printer_radio : m_create_type_btns) { + if (printer_radio.first->GetValue()) { curr_selected_printer_type = printer_radio.second; } + } + return curr_selected_printer_type; +} + +CreatePresetSuccessfulDialog::CreatePresetSuccessfulDialog(wxWindow *parent, const SuccessType &create_success_type) + : DPIDialog(parent ? parent : nullptr, wxID_ANY, PRINTER == create_success_type ? _L("Create Printer Successful") : _L("Create Filament Successful"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) +{ + this->SetBackgroundColour(*wxWHITE); + this->SetSize(wxSize(FromDIP(450), FromDIP(200))); + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + wxBoxSizer *m_main_sizer = new wxBoxSizer(wxVERTICAL); + // top line + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + m_main_sizer->Add(m_line_top, 0, wxEXPAND, 0); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + horizontal_sizer->Add(0, 0, 0, wxLEFT, FromDIP(30)); + + wxBoxSizer *success_bitmap_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticBitmap *success_bitmap = new wxStaticBitmap(this,wxID_ANY, create_scaled_bitmap("create_success", nullptr, FromDIP(24))); + success_bitmap_sizer->Add(success_bitmap, 0, wxEXPAND, 0); + horizontal_sizer->Add(success_bitmap_sizer, 0, wxEXPAND | wxALL, FromDIP(5)); + + wxBoxSizer *success_text_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *success_text; + wxStaticText *next_step_text; + switch (create_success_type) { + case PRINTER: + success_text = new wxStaticText(this, wxID_ANY, _L("Printer Created")); + next_step_text = new wxStaticText(this, wxID_ANY, _L("Please go to printer settings to edit your presets")); + break; + case FILAMENT: + success_text = new wxStaticText(this, wxID_ANY, _L("Filament Created")); + next_step_text = new wxStaticText(this, wxID_ANY, _L("Please go to filament setting to edit your presets if you need.\nPlease note that nozzle temperature, hot bed temperature, and maximum volumetric speed have a significant impact on printing quality. Please set them carefully.")); + break; + } + success_text->SetFont(Label::Head_18); + //next_step_text->SetFont(Label::Body_14); + success_text_sizer->Add(success_text, 0, wxEXPAND, 0); + success_text_sizer->Add(next_step_text, 0, wxEXPAND | wxTOP, FromDIP(5)); + horizontal_sizer->Add(success_text_sizer, 0, wxEXPAND | wxALL, FromDIP(5)); + horizontal_sizer->Add(0, 0, 0, wxLEFT, FromDIP(60)); + + m_main_sizer->Add(horizontal_sizer, 0, wxALL, FromDIP(5)); + + wxBoxSizer *btn_sizer = new wxBoxSizer(wxHORIZONTAL); + btn_sizer->Add(0, 0, 1, wxEXPAND, 0); + switch (create_success_type) { + case PRINTER: + m_button_ok = new Button(this, _L("Printer Setting")); + break; + case FILAMENT: + m_button_ok = new Button(this, _L("OK")); + break; + } + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + m_button_ok->SetBackgroundColor(btn_bg_green); + m_button_ok->SetBorderColor(wxColour(*wxWHITE)); + m_button_ok->SetTextColor(wxColour(*wxWHITE)); + m_button_ok->SetFont(Label::Body_12); + m_button_ok->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetCornerRadius(FromDIP(12)); + btn_sizer->Add(m_button_ok, 0, wxRIGHT, FromDIP(10)); + + m_button_ok->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { EndModal(wxID_OK); }); + + if (PRINTER == create_success_type) { + m_button_cancel = new Button(this, _L("Cancel")); + m_button_cancel->SetBackgroundColor(btn_bg_white); + m_button_cancel->SetBorderColor(wxColour(38, 46, 48)); + m_button_cancel->SetTextColor(wxColour(38, 46, 48)); + m_button_cancel->SetFont(Label::Body_12); + m_button_cancel->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetCornerRadius(FromDIP(12)); + btn_sizer->Add(m_button_cancel, 0, wxRIGHT, FromDIP(10)); + m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { EndModal(wxID_CANCEL); }); + } + + m_main_sizer->Add(btn_sizer, 0, wxEXPAND | wxALL, FromDIP(15)); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(10)); + + SetSizer(m_main_sizer); + Layout(); + Fit(); + wxGetApp().UpdateDlgDarkUI(this); +} + +CreatePresetSuccessfulDialog::~CreatePresetSuccessfulDialog() {} + +void CreatePresetSuccessfulDialog::on_dpi_changed(const wxRect &suggested_rect) { + m_button_ok->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetCornerRadius(FromDIP(12)); + m_button_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetCornerRadius(FromDIP(12)); + Layout(); +} + +ExportConfigsDialog::ExportConfigsDialog(wxWindow *parent) + : DPIDialog(parent ? parent : nullptr, wxID_ANY, _L("Export Configs"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) +{ + m_exprot_type.preset_bundle = _L("Printer config bundle(.bbscfg)"); + m_exprot_type.filament_bundle = _L("Filament bundle(.bbsflmt)"); + m_exprot_type.printer_preset = _L("Printer presets(.zip)"); + m_exprot_type.filament_preset = _L("Filament presets(.zip)"); + m_exprot_type.process_preset = _L("Process presets(.zip)"); + + this->SetBackgroundColour(*wxWHITE); + this->SetSize(wxSize(FromDIP(600), FromDIP(600))); + + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + m_main_sizer = new wxBoxSizer(wxVERTICAL); + // top line + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + m_main_sizer->Add(m_line_top, 0, wxEXPAND, 0); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + + m_main_sizer->Add(create_export_config_item(this), 0, wxEXPAND | wxALL, FromDIP(5)); + m_main_sizer->Add(create_select_printer(this), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + m_main_sizer->Add(create_button_item(this), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(5)); + + data_init(); + + this->SetSizer(m_main_sizer); + + this->Layout(); + this->Fit(); + + wxGetApp().UpdateDlgDarkUI(this); + +} + +ExportConfigsDialog::~ExportConfigsDialog() +{ + for (std::pair printer_preset : m_printer_presets) { + Preset *preset = printer_preset.second; + if (preset) { + delete preset; + preset = nullptr; + } + } + for (std::pair> filament_presets : m_filament_presets) { + for (Preset* preset : filament_presets.second) { + if (preset) { + delete preset; + preset = nullptr; + } + } + } + for (std::pair> filament_presets : m_process_presets) { + for (Preset *preset : filament_presets.second) { + if (preset) { + delete preset; + preset = nullptr; + } + } + } + for (std::pair>> filament_preset : m_filament_name_to_presets) { + for (std::pair printer_name_preset : filament_preset.second) { + Preset *preset = printer_name_preset.second; + if (preset) { + delete preset; + preset = nullptr; + } + } + } +} + +void ExportConfigsDialog::on_dpi_changed(const wxRect &suggested_rect) { + m_button_ok->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetCornerRadius(FromDIP(12)); + m_button_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetCornerRadius(FromDIP(12)); + Layout(); +} + +void ExportConfigsDialog::show_export_result(const ExportCase &export_case) +{ + MessageDialog *msg_dlg = nullptr; + switch (export_case) { + case ExportCase::INITIALIZE_FAIL: + msg_dlg = new MessageDialog(this, _L("initialize fail"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + break; + case ExportCase::ADD_FILE_FAIL: + msg_dlg = new MessageDialog(this, _L("add file fail"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + break; + case ExportCase::ADD_BUNDLE_STRUCTURE_FAIL: + msg_dlg = new MessageDialog(this, _L("add bundle structure file fail"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + break; + case ExportCase::FINALIZE_FAIL: + msg_dlg = new MessageDialog(this, _L("finalize fail"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + break; + case ExportCase::OPEN_ZIP_WRITTEN_FILE: + msg_dlg = new MessageDialog(this, _L("open zip written fail"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + break; + case ExportCase::EXPORT_SUCCESS: + msg_dlg = new MessageDialog(this, _L("Export successful"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + break; + } + + if (msg_dlg) { + msg_dlg->ShowModal(); + delete msg_dlg; + msg_dlg = nullptr; + } +} + +bool ExportConfigsDialog::has_check_box_selected() +{ + for (std::pair<::CheckBox *, Preset *> checkbox_preset : m_preset) { + if (checkbox_preset.first->GetValue()) return true; + } + for (std::pair<::CheckBox *, std::string> checkbox_filament_name : m_printer_name) { + if (checkbox_filament_name.first->GetValue()) return true; + } + + return false; +} + +bool ExportConfigsDialog::preset_is_not_compatible_bbl_printer(Preset *preset) +{ + if (preset->type != Preset::Type::TYPE_PRINT && preset->type != Preset::Type::TYPE_FILAMENT) return true; + PresetBundle * preset_bundle = wxGetApp().preset_bundle; + vector printers; + get_filament_compatible_printer(preset, printers); + if (printers.empty()) return true; + Preset *printer_preset = preset_bundle->printers.find_preset(printers[0], false); + if (!printer_preset) return true; + if (!preset_bundle->is_bbl_vendor()) return true; + return false; +} + +std::string ExportConfigsDialog::initial_file_path(const wxString &path, const std::string &sub_file_path) +{ + std::string export_path = into_u8(path); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "initial file path and path is:" << export_path << " and sub path is: " << sub_file_path; + boost::filesystem::path printer_export_path = (boost::filesystem::path(export_path) / sub_file_path).make_preferred(); + if (boost::filesystem::exists(printer_export_path)) { + MessageDialog dlg(this, wxString::Format(_L("The '%s' folder already exists in the current directory. Do you want to clear it and rebuild it.\nIf not, a time suffix will be " + "added, and you can modify the name after creation."), sub_file_path), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + int res = dlg.ShowModal(); + if (wxID_YES == res) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "Same path exists, delete and need to rebuild, and path is: " << printer_export_path.string(); + try { + boost::filesystem::remove_all(printer_export_path); + } catch (...) { + MessageDialog dlg(this, _L(wxString::Format("The file: %s \nin the directory may have been opened by another program. \nPlease close it and try again.", + encode_path(printer_export_path.string().c_str()))), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return "initial_failed"; + } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "delete path"; + boost::filesystem::create_directories(printer_export_path); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "create path"; + export_path = printer_export_path.string(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "Same path exists, delete and rebuild, and path is: " << export_path; + } else if (wxID_NO == res) { + export_path = printer_export_path.string(); + std::string export_path_with_time; + boost::filesystem::path *printer_export_path_with_time = nullptr; + do { + if (printer_export_path_with_time) { + delete printer_export_path_with_time; + printer_export_path_with_time = nullptr; + } + export_path_with_time = export_path + " " + get_curr_time(); + printer_export_path_with_time = new boost::filesystem::path(export_path_with_time); + } while (boost::filesystem::exists(*printer_export_path_with_time)); + export_path = export_path_with_time; + boost::filesystem::create_directories(*printer_export_path_with_time); + if (printer_export_path_with_time) { + delete printer_export_path_with_time; + printer_export_path_with_time = nullptr; + } + } else { + return ""; + } + } else { + boost::filesystem::create_directories(printer_export_path); + export_path = printer_export_path.string(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "Same path exists, delete and rebuild, and path is: " << export_path; + } + return export_path; +} + +std::string ExportConfigsDialog::initial_file_name(const wxString &path, const std::string file_name) +{ + std::string export_path = into_u8(path); + boost::filesystem::path printer_export_path = (boost::filesystem::path(export_path) / file_name).make_preferred(); + if (boost::filesystem::exists(printer_export_path)) { + MessageDialog dlg(this, wxString::Format(_L("The '%s' folder already exists in the current directory. Do you want to clear it and rebuild it.\nIf not, a time suffix will be " + "added, and you can modify the name after creation."), file_name), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + int res = dlg.ShowModal(); + if (wxID_YES == res) { + try { + boost::filesystem::remove_all(printer_export_path); + } + catch(...) { + MessageDialog dlg(this, + _L(wxString::Format("The file: %s \nmay have been opened by another program. \nPlease close it and try again.", + encode_path(printer_export_path.string().c_str()))), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return "initial_failed"; + } + export_path = printer_export_path.string(); + } else if (wxID_NO == res) { + export_path = printer_export_path.string(); + export_path = export_path.substr(0, export_path.find(".zip")); + std::string export_path_with_time; + boost::filesystem::path *printer_export_path_with_time = nullptr; + do { + if (printer_export_path_with_time) { + delete printer_export_path_with_time; + printer_export_path_with_time = nullptr; + } + export_path_with_time = export_path + " " + get_curr_time() + ".zip"; + printer_export_path_with_time = new boost::filesystem::path(export_path_with_time); + } while (boost::filesystem::exists(*printer_export_path_with_time)); + export_path = export_path_with_time; + if (printer_export_path_with_time) { + delete printer_export_path_with_time; + printer_export_path_with_time = nullptr; + } + } else { + return ""; + } + } else { + export_path = printer_export_path.string(); + } + return export_path; +} + +wxBoxSizer *ExportConfigsDialog::create_export_config_item(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_serial_text = new wxStaticText(parent, wxID_ANY, _L("Presets"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(static_serial_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *radioBoxSizer = new wxBoxSizer(wxVERTICAL); + + radioBoxSizer->Add(create_radio_item(m_exprot_type.preset_bundle, parent, wxEmptyString, m_export_type_btns), 0, wxEXPAND | wxALL, 0); + radioBoxSizer->Add(0, 0, 0, wxTOP, FromDIP(6)); + wxStaticText *static_export_printer_preset_bundle_text = new wxStaticText(parent, wxID_ANY, _L("Printer and all the filament&process presets that belongs to the printer. \nCan be shared with others."), wxDefaultPosition, wxDefaultSize); + static_export_printer_preset_bundle_text->SetFont(Label::Body_12); + static_export_printer_preset_bundle_text->SetForegroundColour(wxColour("#6B6B6B")); + radioBoxSizer->Add(static_export_printer_preset_bundle_text, 0, wxEXPAND | wxLEFT, FromDIP(22)); + radioBoxSizer->Add(create_radio_item(m_exprot_type.filament_bundle, parent, wxEmptyString, m_export_type_btns), 0, wxEXPAND | wxTOP, FromDIP(10)); + wxStaticText *static_export_filament_preset_bundle_text = new wxStaticText(parent, wxID_ANY, _L("User's fillment preset set. \nCan be shared with others."), wxDefaultPosition, wxDefaultSize); + static_export_filament_preset_bundle_text->SetFont(Label::Body_12); + static_export_filament_preset_bundle_text->SetForegroundColour(wxColour("#6B6B6B")); + radioBoxSizer->Add(static_export_filament_preset_bundle_text, 0, wxEXPAND | wxLEFT, FromDIP(22)); + radioBoxSizer->Add(create_radio_item(m_exprot_type.printer_preset, parent, wxEmptyString, m_export_type_btns), 0, wxEXPAND | wxTOP, FromDIP(10)); + radioBoxSizer->Add(create_radio_item(m_exprot_type.filament_preset, parent, wxEmptyString, m_export_type_btns), 0, wxEXPAND | wxTOP, FromDIP(10)); + radioBoxSizer->Add(create_radio_item(m_exprot_type.process_preset, parent, wxEmptyString, m_export_type_btns), 0, wxEXPAND | wxTOP, FromDIP(10)); + horizontal_sizer->Add(radioBoxSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return horizontal_sizer; +} + +wxBoxSizer *ExportConfigsDialog::create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector> &radiobox_list) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxHORIZONTAL); + RadioBox * radiobox = new RadioBox(parent); + horizontal_sizer->Add(radiobox, 0, wxEXPAND | wxALL, 0); + horizontal_sizer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(5)); + radiobox_list.push_back(std::make_pair(radiobox, title)); + int btn_idx = radiobox_list.size() - 1; + radiobox->Bind(wxEVT_LEFT_DOWN, [this, &radiobox_list, btn_idx](wxMouseEvent &e) { + select_curr_radiobox(radiobox_list, btn_idx); + }); + + wxStaticText *text = new wxStaticText(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize); + text->Bind(wxEVT_LEFT_DOWN, [this, &radiobox_list, btn_idx](wxMouseEvent &e) { + select_curr_radiobox(radiobox_list, btn_idx); + }); + horizontal_sizer->Add(text, 0, wxEXPAND | wxLEFT, 0); + + radiobox->SetToolTip(tooltip); + text->SetToolTip(tooltip); + return horizontal_sizer; +} + +mz_bool ExportConfigsDialog::initial_zip_archive(mz_zip_archive &zip_archive, const std::string &file_path) +{ + mz_zip_zero_struct(&zip_archive); + mz_bool status; + + // Initialize the ZIP file to write to the structure, using memory storage + + std::string export_dir = encode_path(file_path.c_str()); + status = mz_zip_writer_init_file(&zip_archive, export_dir.c_str(), 0); + return status; +} + +ExportConfigsDialog::ExportCase ExportConfigsDialog::save_zip_archive_to_file(mz_zip_archive &zip_archive) +{ + // Complete writing of ZIP file + mz_bool status = mz_zip_writer_finalize_archive(&zip_archive); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << "Failed to finalize ZIP archive"; + mz_zip_writer_end(&zip_archive); + return ExportCase::FINALIZE_FAIL; + } + + // Release ZIP file to write structure and related resources + mz_zip_writer_end(&zip_archive); + + return ExportCase::CASE_COUNT; +} + +ExportConfigsDialog::ExportCase ExportConfigsDialog::save_presets_to_zip(const std::string &export_file, const std::vector> &config_paths) +{ + mz_zip_archive zip_archive; + mz_bool status = initial_zip_archive(zip_archive, export_file); + + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << "Failed to initialize ZIP archive"; + return ExportCase::INITIALIZE_FAIL; + } + + for (std::pair config_path : config_paths) { + std::string preset_name = config_path.first; + + // Add a file to the ZIP file + status = mz_zip_writer_add_file(&zip_archive, (preset_name).c_str(), encode_path(config_path.second.c_str()).c_str(), NULL, 0, MZ_DEFAULT_COMPRESSION); + // status = mz_zip_writer_add_mem(&zip_archive, ("printer/" + printer_preset->name + ".json").c_str(), json_contents, strlen(json_contents), MZ_DEFAULT_COMPRESSION); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << preset_name << " Filament preset failed to add file to ZIP archive"; + mz_zip_writer_end(&zip_archive); + return ExportCase::ADD_FILE_FAIL; + } + BOOST_LOG_TRIVIAL(info) << "Printer preset json add successful: " << preset_name; + } + return save_zip_archive_to_file(zip_archive); +} + +void ExportConfigsDialog::select_curr_radiobox(std::vector> &radiobox_list, int btn_idx) +{ + int len = radiobox_list.size(); + for (int i = 0; i < len; ++i) { + if (i == btn_idx) { + radiobox_list[i].first->SetValue(true); + const wxString &export_type = radiobox_list[i].second; + m_preset_sizer->Clear(true); + m_printer_name.clear(); + m_preset.clear(); + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + this->Freeze(); + if (export_type == m_exprot_type.preset_bundle) { + for (std::pair preset : m_printer_presets) { + std::string preset_name = preset.first; + //printer preset mast have user's filament or process preset or printer preset is user preset + if (m_filament_presets.find(preset_name) == m_filament_presets.end() && m_process_presets.find(preset_name) == m_process_presets.end() && preset.second->is_system) continue; + wxString printer_name = wxString::FromUTF8(preset_name); + m_preset_sizer->Add(create_checkbox(m_presets_window, preset.second, printer_name, m_preset), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(5)); + } + m_serial_text->SetLabel(_L("Only display printer names with changes to printer, filament, and process presets.")); + }else if (export_type == m_exprot_type.filament_bundle) { + for (std::pair>> filament_name_to_preset : m_filament_name_to_presets) { + if (filament_name_to_preset.second.empty()) continue; + bool all_preset_is_compatible_third_printer = true; + for (std::pair filament_preset : filament_name_to_preset.second) { + if (!preset_is_not_compatible_bbl_printer(filament_preset.second)) + all_preset_is_compatible_third_printer = false; + } + if (all_preset_is_compatible_third_printer) continue; + wxString filament_name = wxString::FromUTF8(filament_name_to_preset.first); + m_preset_sizer->Add(create_checkbox(m_presets_window, filament_name, m_printer_name), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(5)); + } + m_serial_text->SetLabel(_L("Only display the filament names with changes to filament presets.")); + } else if (export_type == m_exprot_type.printer_preset) { + for (std::pair preset : m_printer_presets) { + if (preset.second->is_system) continue; + wxString printer_name = wxString::FromUTF8(preset.first); + m_preset_sizer->Add(create_checkbox(m_presets_window, preset.second, printer_name, m_preset), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, + FromDIP(5)); + } + m_serial_text->SetLabel(_L("Only printer names with user printer presets will be displayed, and each preset you choose will be exported as a zip.")); + } else if (export_type == m_exprot_type.filament_preset) { + for (std::pair>> filament_name_to_preset : m_filament_name_to_presets) { + if (filament_name_to_preset.second.empty()) continue; + bool all_preset_is_compatible_third_printer = true; + for (std::pair filament_preset : filament_name_to_preset.second) { + if (!preset_is_not_compatible_bbl_printer(filament_preset.second)) + all_preset_is_compatible_third_printer = false; + } + if (all_preset_is_compatible_third_printer) continue; + wxString filament_name = wxString::FromUTF8(filament_name_to_preset.first); + m_preset_sizer->Add(create_checkbox(m_presets_window, filament_name, m_printer_name), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(5)); + } + m_serial_text->SetLabel(_L("Only the filament names with user filament presets will be displayed, \nand all user filament presets in each filament name you select will be exported as a zip.")); + } else if (export_type == m_exprot_type.process_preset) { + for (std::pair> presets : m_process_presets) { + Preset * printer_preset = preset_bundle->printers.find_preset(presets.first, false); + if (!printer_preset) continue; + if (!printer_preset->is_system) continue; + if (preset_bundle->printers.get_preset_base(*printer_preset) != printer_preset) continue; + for (Preset *preset : presets.second) { + if (!preset->is_system) { + wxString printer_name = wxString::FromUTF8(presets.first); + m_preset_sizer->Add(create_checkbox(m_presets_window, printer_name, m_printer_name), 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(5)); + break; + } + } + + } + m_serial_text->SetLabel(_L("Only printer names with changed process presets will be displayed, \nand all user process presets in each printer name you select will be exported as a zip.")); + } + //m_presets_window->SetSizerAndFit(m_preset_sizer); + m_presets_window->Layout(); + m_presets_window->Fit(); + int width = m_presets_window->GetSize().GetWidth(); + int height = m_presets_window->GetSize().GetHeight(); + m_scrolled_preset_window->SetMinSize(wxSize(std::min(1200, width), std::min(600, height))); + m_scrolled_preset_window->SetMaxSize(wxSize(std::min(1200, width), std::min(600, height))); + m_scrolled_preset_window->SetSize(wxSize(std::min(1200, width), std::min(600, height))); + this->SetSizerAndFit(m_main_sizer); + Layout(); + Fit(); + Refresh(); + adjust_dialog_in_screen(this); + this->Thaw(); + } else { + radiobox_list[i].first->SetValue(false); + } + } +} + +ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_preset_bundle_to_file(const wxString &path) +{ + std::string export_path = initial_file_path(path, "Printer config bundle"); + if (export_path.empty() || "initial_failed" == export_path) return ExportCase::EXPORT_CANCEL; + BOOST_LOG_TRIVIAL(info) << "Export printer preset bundle"; + + for (std::pair<::CheckBox *, Preset *> checkbox_preset : m_preset) { + if (checkbox_preset.first->GetValue()) { + Preset *printer_preset = checkbox_preset.second; + std::string printer_preset_name_ = printer_preset->name; + + json bundle_structure; + NetworkAgent *agent = wxGetApp().getAgent(); + std::string clock = get_curr_timestmp(); + if (agent) { + bundle_structure["user_name"] = agent->get_user_name(); + bundle_structure["user_id"] = agent->get_user_id(); + bundle_structure["version"] = agent->get_version(); + bundle_structure["bundle_id"] = agent->get_user_id() + "_" + printer_preset_name_ + "_" + clock; + } else { + bundle_structure["user_name"] = ""; + bundle_structure["user_id"] = ""; + bundle_structure["version"] = ""; + bundle_structure["bundle_id"] = "offline_" + printer_preset_name_ + "_" + clock; + } + bundle_structure["bundle_type"] = "printer config bundle"; + bundle_structure["printer_preset_name"] = printer_preset_name_; + json printer_config = json::array(); + json filament_configs = json::array(); + json process_configs = json::array(); + + mz_zip_archive zip_archive; + mz_bool status = initial_zip_archive(zip_archive, export_path + "/" + printer_preset->name + ".bbscfg"); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << "Failed to initialize ZIP archive"; + return ExportCase::INITIALIZE_FAIL; + } + + boost::filesystem::path pronter_file_path = boost::filesystem::path(printer_preset->file); + std::string preset_path = pronter_file_path.make_preferred().string(); + if (preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Export printer preset: " << printer_preset->name << " skip because of the preset file path is empty."; + continue; + } + + // Add a file to the ZIP file + std::string printer_config_file_name = "printer/" + pronter_file_path.filename().string(); + status = mz_zip_writer_add_file(&zip_archive, printer_config_file_name.c_str(), encode_path(preset_path.c_str()).c_str(), NULL, 0, MZ_DEFAULT_COMPRESSION); + //status = mz_zip_writer_add_mem(&zip_archive, ("printer/" + printer_preset->name + ".json").c_str(), json_contents, strlen(json_contents), MZ_DEFAULT_COMPRESSION); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << printer_preset->name << " Failed to add file to ZIP archive"; + mz_zip_writer_end(&zip_archive); + return ExportCase::ADD_FILE_FAIL; + } + printer_config.push_back(printer_config_file_name); + BOOST_LOG_TRIVIAL(info) << "Printer preset json add successful: " << printer_preset->name; + + const std::string printer_preset_name = printer_preset->name; + std::unordered_map>::iterator iter = m_filament_presets.find(printer_preset_name); + if (m_filament_presets.end() != iter) { + for (Preset *preset : iter->second) { + boost::filesystem::path filament_file_path = boost::filesystem::path(preset->file); + std::string filament_preset_path = filament_file_path.make_preferred().string(); + if (filament_preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Export filament preset: " << preset->name << " skip because of the preset file path is empty."; + continue; + } + + std::string filament_config_file_name = "filament/" + filament_file_path.filename().string(); + status = mz_zip_writer_add_file(&zip_archive, filament_config_file_name.c_str(), encode_path(filament_preset_path.c_str()).c_str(), NULL, 0, MZ_DEFAULT_COMPRESSION); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << preset->name << " Failed to add file to ZIP archive"; + mz_zip_writer_end(&zip_archive); + return ExportCase::ADD_FILE_FAIL; + } + filament_configs.push_back(filament_config_file_name); + BOOST_LOG_TRIVIAL(info) << "Filament preset json add successful."; + } + } + + iter = m_process_presets.find(printer_preset_name); + if (m_process_presets.end() != iter) { + for (Preset *preset : iter->second) { + boost::filesystem::path process_file_path = boost::filesystem::path(preset->file); + std::string process_preset_path = process_file_path.make_preferred().string(); + if (process_preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Export process preset: " << preset->name << " skip because of the preset file path is empty."; + continue; + } + + std::string process_config_file_name = "process/" + process_file_path.filename().string(); + status = mz_zip_writer_add_file(&zip_archive, process_config_file_name.c_str(), encode_path(process_preset_path.c_str()).c_str(), NULL, 0, MZ_DEFAULT_COMPRESSION); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << preset->name << " Failed to add file to ZIP archive"; + mz_zip_writer_end(&zip_archive); + return ExportCase::ADD_FILE_FAIL; + } + process_configs.push_back(process_config_file_name); + BOOST_LOG_TRIVIAL(info) << "Process preset json add successful: "; + } + } + + bundle_structure["printer_config"] = printer_config; + bundle_structure["filament_config"] = filament_configs; + bundle_structure["process_config"] = process_configs; + + std::string bundle_structure_str = bundle_structure.dump(); + status = mz_zip_writer_add_mem(&zip_archive, BUNDLE_STRUCTURE_JSON_NAME, bundle_structure_str.data(), bundle_structure_str.size(), MZ_DEFAULT_COMPRESSION); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << " Failed to add file: " << BUNDLE_STRUCTURE_JSON_NAME; + mz_zip_writer_end(&zip_archive); + return ExportCase::ADD_BUNDLE_STRUCTURE_FAIL; + } + BOOST_LOG_TRIVIAL(info) << " Success to add file: " << BUNDLE_STRUCTURE_JSON_NAME; + + ExportCase save_result = save_zip_archive_to_file(zip_archive); + if (ExportCase::CASE_COUNT != save_result) return save_result; + } + } + BOOST_LOG_TRIVIAL(info) << "ZIP archive created successfully"; + + return ExportCase::EXPORT_SUCCESS; +} + +ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_filament_bundle_to_file(const wxString &path) +{ + std::string export_path = initial_file_path(path, "Filament bundle"); + if (export_path.empty() || "initial_failed" == export_path) return ExportCase::EXPORT_CANCEL; + BOOST_LOG_TRIVIAL(info) << "Export filament preset bundle"; + + for (std::pair<::CheckBox *, std::string> checkbox_filament_name : m_printer_name) { + if (checkbox_filament_name.first->GetValue()) { + std::string filament_name = checkbox_filament_name.second; + + json bundle_structure; + NetworkAgent *agent = wxGetApp().getAgent(); + std::string clock = get_curr_timestmp(); + if (agent) { + bundle_structure["user_name"] = agent->get_user_name(); + bundle_structure["user_id"] = agent->get_user_id(); + bundle_structure["version"] = agent->get_version(); + bundle_structure["bundle_id"] = agent->get_user_id() + "_" + filament_name + "_" + clock; + } else { + bundle_structure["user_name"] = ""; + bundle_structure["user_id"] = ""; + bundle_structure["version"] = ""; + bundle_structure["bundle_id"] = "offline_" + filament_name + "_" + clock; + } + bundle_structure["bundle_type"] = "filament config bundle"; + bundle_structure["filament_name"] = filament_name; + std::unordered_map vendor_structure; + + mz_zip_archive zip_archive; + mz_bool status = initial_zip_archive(zip_archive, export_path + "/" + filament_name + ".bbsflmt"); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << "Failed to initialize ZIP archive"; + return ExportCase::INITIALIZE_FAIL; + } + + std::unordered_map>>::iterator iter = m_filament_name_to_presets.find(filament_name); + if (m_filament_name_to_presets.end() == iter) { + BOOST_LOG_TRIVIAL(info) << "Filament name do not find, filament name:" << filament_name; + continue; + } + std::set> vendor_to_filament_name; + for (std::pair printer_name_to_preset : iter->second) { + std::string printer_vendor = printer_name_to_preset.first; + if (printer_vendor.empty()) continue; + Preset * filament_preset = printer_name_to_preset.second; + if (preset_is_not_compatible_bbl_printer(filament_preset)) continue; + if (vendor_to_filament_name.find(std::make_pair(printer_vendor, filament_preset->name)) != vendor_to_filament_name.end()) continue; + vendor_to_filament_name.insert(std::make_pair(printer_vendor, filament_preset->name)); + std::string preset_path = boost::filesystem::path(filament_preset->file).make_preferred().string(); + if (preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Export printer preset: " << filament_preset->name << " skip because of the preset file path is empty."; + continue; + } + // Add a file to the ZIP file + std::string file_name = printer_vendor + "/" + filament_preset->name + ".json"; + status = mz_zip_writer_add_file(&zip_archive, file_name.c_str(), encode_path(preset_path.c_str()).c_str(), NULL, 0, MZ_DEFAULT_COMPRESSION); + // status = mz_zip_writer_add_mem(&zip_archive, ("printer/" + printer_preset->name + ".json").c_str(), json_contents, strlen(json_contents), MZ_DEFAULT_COMPRESSION); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << filament_preset->name << " Failed to add file to ZIP archive"; + mz_zip_writer_end(&zip_archive); + return ExportCase::ADD_FILE_FAIL; + } + std::unordered_map::iterator iter = vendor_structure.find(printer_vendor); + if (vendor_structure.end() == iter) { + json j = json::array(); + j.push_back(file_name); + vendor_structure[printer_vendor] = j; + } else { + iter->second.push_back(file_name); + } + BOOST_LOG_TRIVIAL(info) << "Filament preset json add successful: " << filament_preset->name; + } + + for (const std::pair& vendor_name_to_json : vendor_structure) { + json j; + std::string printer_vendor = vendor_name_to_json.first; + j["vendor"] = printer_vendor; + j["filament_path"] = vendor_name_to_json.second; + bundle_structure["printer_vendor"].push_back(j); + } + + std::string bundle_structure_str = bundle_structure.dump(); + status = mz_zip_writer_add_mem(&zip_archive, BUNDLE_STRUCTURE_JSON_NAME, bundle_structure_str.data(), bundle_structure_str.size(), MZ_DEFAULT_COMPRESSION); + if (MZ_FALSE == status) { + BOOST_LOG_TRIVIAL(info) << " Failed to add file: " << BUNDLE_STRUCTURE_JSON_NAME; + mz_zip_writer_end(&zip_archive); + return ExportCase::ADD_BUNDLE_STRUCTURE_FAIL; + } + BOOST_LOG_TRIVIAL(info) << " Success to add file: " << BUNDLE_STRUCTURE_JSON_NAME; + + // Complete writing of ZIP file + ExportCase save_result = save_zip_archive_to_file(zip_archive); + if (ExportCase::CASE_COUNT != save_result) return save_result; + } + } + BOOST_LOG_TRIVIAL(info) << "ZIP archive created successfully"; + + return ExportCase::EXPORT_SUCCESS; +} + +ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_printer_preset_to_file(const wxString &path) +{ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "start exprot printer presets"; + std::string export_file = "Printer presets.zip"; + export_file = initial_file_name(path, export_file); + if (export_file.empty() || "initial_failed" == export_file) return ExportCase::EXPORT_CANCEL; + + std::vector> config_paths; + + for (std::pair<::CheckBox *, Preset *> checkbox_preset : m_preset) { + if (checkbox_preset.first->GetValue()) { + Preset * printer_preset = checkbox_preset.second; + std::string preset_path = boost::filesystem::path(printer_preset->file).make_preferred().string(); + if (preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Export printer preset: " << printer_preset->name << " skip because of the preset file path is empty."; + continue; + } + std::string preset_name = printer_preset->name + ".json"; + config_paths.push_back(std::make_pair(preset_name, preset_path)); + } + } + + ExportCase save_result = save_presets_to_zip(export_file, config_paths); + if (ExportCase::CASE_COUNT != save_result) return save_result; + + BOOST_LOG_TRIVIAL(info) << "ZIP archive created successfully"; + + return ExportCase::EXPORT_SUCCESS; + +} + +ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_filament_preset_to_file(const wxString &path) +{ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "start exprot filament presets"; + std::string export_file = "Filament presets.zip"; + export_file = initial_file_name(path, export_file); + if (export_file.empty() || "initial_failed" == export_file) return ExportCase::EXPORT_CANCEL; + + std::vector> config_paths; + + std::set filament_presets; + for (std::pair<::CheckBox *, std::string> checkbox_preset : m_printer_name) { + if (checkbox_preset.first->GetValue()) { + std::string filament_name = checkbox_preset.second; + + std::unordered_map>>::iterator iter = m_filament_name_to_presets.find(filament_name); + if (m_filament_name_to_presets.end() == iter) { + BOOST_LOG_TRIVIAL(info) << "Filament name do not find, filament name:" << filament_name; + continue; + } + for (std::pair printer_name_preset : iter->second) { + Preset * filament_preset = printer_name_preset.second; + if (preset_is_not_compatible_bbl_printer(filament_preset)) continue; + if (filament_presets.find(filament_preset->name) != filament_presets.end()) continue; + filament_presets.insert(filament_preset->name); + std::string preset_path = boost::filesystem::path(filament_preset->file).make_preferred().string(); + if (preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Export filament preset: " << filament_preset->name << " skip because of the filament file path is empty."; + continue; + } + + std::string preset_name = filament_preset->name + ".json"; + config_paths.push_back(std::make_pair(preset_name, preset_path)); + } + } + } + + ExportCase save_result = save_presets_to_zip(export_file, config_paths); + if (ExportCase::CASE_COUNT != save_result) return save_result; + + BOOST_LOG_TRIVIAL(info) << "ZIP archive created successfully"; + + return ExportCase::EXPORT_SUCCESS; +} + +ExportConfigsDialog::ExportCase ExportConfigsDialog::archive_process_preset_to_file(const wxString &path) +{ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "start exprot process presets"; + std::string export_file = "Process presets.zip"; + export_file = initial_file_name(path, export_file); + if (export_file.empty() || "initial_failed" == export_file) return ExportCase::EXPORT_CANCEL; + + std::vector> config_paths; + + std::set process_presets; + for (std::pair<::CheckBox *, std::string> checkbox_preset : m_printer_name) { + if (checkbox_preset.first->GetValue()) { + std::string printer_name = checkbox_preset.second; + std::unordered_map>::iterator iter = m_process_presets.find(printer_name); + if (m_process_presets.end() != iter) { + for (Preset *process_preset : iter->second) { + if (preset_is_not_compatible_bbl_printer(process_preset)) continue; + if (process_presets.find(process_preset->name) != process_presets.end()) continue; + process_presets.insert(process_preset->name); + std::string preset_path = boost::filesystem::path(process_preset->file).make_preferred().string(); + if (preset_path.empty()) { + BOOST_LOG_TRIVIAL(info) << "Export process preset: " << process_preset->name << " skip because of the preset file path is empty."; + continue; + } + + std::string preset_name = process_preset->name + ".json"; + config_paths.push_back(std::make_pair(preset_name, preset_path)); + } + } + } + } + + ExportCase save_result = save_presets_to_zip(export_file, config_paths); + if (ExportCase::CASE_COUNT != save_result) return save_result; + + BOOST_LOG_TRIVIAL(info) << "ZIP archive created successfully"; + + return ExportCase::EXPORT_SUCCESS; +} + +wxBoxSizer *ExportConfigsDialog::create_button_item(wxWindow* parent) +{ + wxBoxSizer *bSizer_button = new wxBoxSizer(wxHORIZONTAL); + bSizer_button->Add(0, 0, 1, wxEXPAND, 0); + + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + + m_button_ok = new Button(this, _L("OK")); + m_button_ok->SetBackgroundColor(btn_bg_green); + m_button_ok->SetBorderColor(*wxWHITE); + m_button_ok->SetTextColor(wxColour(0xFFFFFE)); + m_button_ok->SetFont(Label::Body_12); + m_button_ok->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_ok, 0, wxRIGHT, FromDIP(10)); + + m_button_ok->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + if (!has_check_box_selected()) { + MessageDialog dlg(this, _L("Please select at least one printer or filament."), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + + wxDirDialog dlg(this, _L("Choose a directory"), from_u8(wxGetApp().app_config->get_last_dir()), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); + wxString path; + if (dlg.ShowModal() == wxID_OK) path = dlg.GetPath(); + ExportCase export_case = ExportCase::EXPORT_CANCEL; + if (!path.IsEmpty()) { + wxGetApp().app_config->update_config_dir(into_u8(path)); + wxGetApp().app_config->save(); + const wxString curr_radio_type = get_curr_radio_type(m_export_type_btns); + + if (curr_radio_type == m_exprot_type.preset_bundle) { + export_case = archive_preset_bundle_to_file(path); + } else if (curr_radio_type == m_exprot_type.filament_bundle) { + export_case = archive_filament_bundle_to_file(path); + } else if (curr_radio_type == m_exprot_type.printer_preset) { + export_case = archive_printer_preset_to_file(path); + } else if (curr_radio_type == m_exprot_type.filament_preset) { + export_case = archive_filament_preset_to_file(path); + } else if (curr_radio_type == m_exprot_type.process_preset) { + export_case = archive_process_preset_to_file(path); + } + } else { + return; + } + show_export_result(export_case); + if (ExportCase::EXPORT_SUCCESS != export_case) return; + + EndModal(wxID_OK); + }); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + m_button_cancel = new Button(this, _L("Cancel")); + m_button_cancel->SetBackgroundColor(btn_bg_white); + m_button_cancel->SetBorderColor(wxColour(38, 46, 48)); + m_button_cancel->SetFont(Label::Body_12); + m_button_cancel->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_button_cancel, 0, wxRIGHT, FromDIP(10)); + + m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { EndModal(wxID_CANCEL); }); + + return bSizer_button; +} + +wxBoxSizer *ExportConfigsDialog::create_select_printer(wxWindow *parent) +{ + wxBoxSizer *horizontal_sizer = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer * optionSizer = new wxBoxSizer(wxVERTICAL); + m_serial_text = new wxStaticText(parent, wxID_ANY, _L("Please select a type you want to export"), wxDefaultPosition, wxDefaultSize); + optionSizer->Add(m_serial_text, 0, wxEXPAND | wxALL, 0); + optionSizer->SetMinSize(OPTION_SIZE); + horizontal_sizer->Add(optionSizer, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + m_scrolled_preset_window = new wxScrolledWindow(parent); + m_scrolled_preset_window->SetScrollRate(5, 5); + m_scrolled_preset_window->SetBackgroundColour(PRINTER_LIST_COLOUR); + m_scrolled_preset_window->SetMaxSize(wxSize(FromDIP(660), FromDIP(400))); + m_scrolled_preset_window->SetSize(wxSize(FromDIP(660), FromDIP(400))); + wxBoxSizer *scrolled_window = new wxBoxSizer(wxHORIZONTAL); + + m_presets_window = new wxPanel(m_scrolled_preset_window, wxID_ANY); + m_presets_window->SetBackgroundColour(PRINTER_LIST_COLOUR); + wxBoxSizer *select_printer_sizer = new wxBoxSizer(wxVERTICAL); + + m_preset_sizer = new wxGridSizer(3, FromDIP(5), FromDIP(5)); + select_printer_sizer->Add(m_preset_sizer, 0, wxEXPAND, FromDIP(5)); + m_presets_window->SetSizer(select_printer_sizer); + scrolled_window->Add(m_presets_window, 0, wxEXPAND, 0); + m_scrolled_preset_window->SetSizerAndFit(scrolled_window); + + horizontal_sizer->Add(m_scrolled_preset_window, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10)); + + return horizontal_sizer; +} + +void ExportConfigsDialog::data_init() +{ + PresetBundle preset_bundle(*wxGetApp().preset_bundle); + + const std::deque & printer_presets = preset_bundle.printers.get_presets(); + for (const Preset &printer_preset : printer_presets) { + + std::string preset_name = printer_preset.name; + if (!printer_preset.is_visible || "Default Printer" == preset_name) continue; + if (preset_bundle.printers.select_preset_by_name(preset_name, false)) { + preset_bundle.update_compatible(PresetSelectCompatibleType::Always); + + const std::deque &filament_presets = preset_bundle.filaments.get_presets(); + for (const Preset &filament_preset : filament_presets) { + if (filament_preset.is_system || filament_preset.is_default) continue; + if (filament_preset.is_compatible) { + Preset *new_filament_preset = new Preset(filament_preset); + m_filament_presets[preset_name].push_back(new_filament_preset); + } + } + + const std::deque &process_presets = preset_bundle.prints.get_presets(); + for (const Preset &process_preset : process_presets) { + if (process_preset.is_system || process_preset.is_default) continue; + if (process_preset.is_compatible) { + Preset *new_prpcess_preset = new Preset(process_preset); + m_process_presets[preset_name].push_back(new_prpcess_preset); + } + } + + Preset *new_printer_preset = new Preset(printer_preset); + m_printer_presets[preset_name] = new_printer_preset; + } + } + const std::deque &filament_presets = preset_bundle.filaments.get_presets(); + for (const Preset &filament_preset : filament_presets) { + if (filament_preset.is_system || filament_preset.is_default) continue; + Preset *new_filament_preset = new Preset(filament_preset); + const Preset *base_filament_preset = preset_bundle.filaments.get_preset_base(*new_filament_preset); + + std::string filament_preset_name = base_filament_preset->name; + std::string machine_name = get_machine_name(filament_preset_name); + m_filament_name_to_presets[get_filament_name(filament_preset_name)].push_back(std::make_pair(get_vendor_name(machine_name), new_filament_preset)); + } +} + +EditFilamentPresetDialog::EditFilamentPresetDialog(wxWindow *parent, FilamentInfomation *filament_info) + : DPIDialog(parent ? parent : nullptr, wxID_ANY, _L("Edit Filament"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) + , m_filament_id("") + , m_filament_name("") + , m_vendor_name("") + , m_filament_type("") + , m_filament_serial("") +{ + m_preset_tree_creater = new PresetTree(this); + + this->SetBackgroundColour(*wxWHITE); + this->SetMinSize(wxSize(FromDIP(600), -1)); + + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + m_main_sizer = new wxBoxSizer(wxVERTICAL); + // top line + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + m_main_sizer->Add(m_line_top, 0, wxEXPAND, 0); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + + wxStaticText* basic_infomation = new wxStaticText(this, wxID_ANY, _L("Basic Information")); + basic_infomation->SetFont(Label::Head_16); + + m_main_sizer->Add(basic_infomation, 0, wxALL, FromDIP(10)); + m_filament_id = filament_info->filament_id; + //std::string filament_name = filament_info->filament_name; + bool get_filament_presets = get_same_filament_id_presets(m_filament_id); + // get filament vendor, type, serial, and name + if (get_filament_presets && !m_printer_compatible_presets.empty()) { + std::shared_ptr preset; + for (std::pair>> pair : m_printer_compatible_presets) { + for (std::shared_ptr fialment_preset : pair.second) { + if (fialment_preset->inherits().empty()) { + preset = fialment_preset; + break; + } + } + } + if (!preset.get()) preset = m_printer_compatible_presets.begin()->second[0]; + m_filament_name = get_filament_name(preset->name); + auto vendor_names = dynamic_cast(preset->config.option("filament_vendor")); + if (vendor_names && !vendor_names->values.empty()) m_vendor_name = vendor_names->values[0]; + auto filament_types = dynamic_cast(preset->config.option("filament_type")); + if (filament_types && !filament_types->values.empty()) m_filament_type = filament_types->values[0]; + size_t index = m_filament_name.find(m_filament_type); + if (std::string::npos != index && index + m_filament_type.size() < m_filament_name.size()) { + m_filament_serial = m_filament_name.substr(index + m_filament_type.size()); + if (m_filament_serial.size() > 2 && m_filament_serial[0] == ' ') { + m_filament_serial = m_filament_serial.substr(1); + } + } + } + + m_main_sizer->Add(create_filament_basic_info(), 0, wxEXPAND | wxALL, 0); + + // divider line + auto line_divider = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + line_divider->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + m_main_sizer->Add(line_divider, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10)); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + + wxStaticText *presets_infomation = new wxStaticText(this, wxID_ANY, _L("Filament presets under this filament")); + presets_infomation->SetFont(Label::Head_16); + m_main_sizer->Add(presets_infomation, 0, wxLEFT | wxRIGHT, FromDIP(10)); + + m_main_sizer->Add(create_add_filament_btn(), 0, wxEXPAND | wxALL, 0); + m_main_sizer->Add(create_preset_tree_sizer(), 0, wxEXPAND | wxALL, 0); + m_note_text = new wxStaticText(this, wxID_ANY, _L("Note: If the only preset under this filament is deleted, the filament will be deleted after exiting the dialog.")); + m_main_sizer->Add(m_note_text, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + m_note_text->Hide(); + m_main_sizer->Add(create_button_sizer(), 0, wxEXPAND | wxALL, 0); + + update_preset_tree(); + + this->SetSizer(m_main_sizer); + this->Layout(); + this->Fit(); + wxGetApp().UpdateDlgDarkUI(this); +} +EditFilamentPresetDialog::~EditFilamentPresetDialog() {} + +void EditFilamentPresetDialog::on_dpi_changed(const wxRect &suggested_rect) { + /*m_add_filament_btn->Rescale(); + m_del_filament_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_del_filament_btn->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_del_filament_btn->SetCornerRadius(FromDIP(12)); + m_ok_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_ok_btn->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_ok_btn->SetCornerRadius(FromDIP(12));*/ + Layout(); +} + +bool EditFilamentPresetDialog::get_same_filament_id_presets(std::string filament_id) +{ + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + const std::deque &filament_presets = preset_bundle->filaments.get_presets(); + + m_printer_compatible_presets.clear(); + for (Preset const &preset : filament_presets) { + if (preset.is_system || preset.filament_id != filament_id) continue; + std::shared_ptr new_preset = std::make_shared(preset); + std::vector printers; + get_filament_compatible_printer(new_preset.get(), printers); + for (const std::string &printer_name : printers) { + m_printer_compatible_presets[printer_name].push_back(new_preset); + } + } + if (m_printer_compatible_presets.empty()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " no filament presets "; + return false; + } + + return true; +} + +void EditFilamentPresetDialog::update_preset_tree() +{ + this->Freeze(); + m_preset_tree_sizer->Clear(true); + for (std::pair>> printer_and_presets : m_printer_compatible_presets) { + m_preset_tree_sizer->Add(m_preset_tree_creater->get_preset_tree(printer_and_presets), 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 5); + } + if (m_printer_compatible_presets.size() == 1 && m_printer_compatible_presets.begin()->second.size() == 1) { + m_note_text->Show(); + } else { + m_note_text->Hide(); + } + + m_preset_tree_panel->SetSizerAndFit(m_preset_tree_sizer); + int width = m_preset_tree_panel->GetSize().GetWidth(); + int height = m_preset_tree_panel->GetSize().GetHeight(); + if (width < m_note_text->GetSize().GetWidth()) { + width = m_note_text->GetSize().GetWidth(); + m_preset_tree_panel->SetMinSize(wxSize(width, -1)); + } + int width_extend = 0; + int height_extend = 0; + if (width > 1000) height_extend = 22; + if (height > 400) width_extend = 22; + m_preset_tree_window->SetMinSize(wxSize(std::min(1000, width + width_extend), std::min(400, height + height_extend))); + m_preset_tree_window->SetMaxSize(wxSize(std::min(1000, width + width_extend), std::min(400, height + height_extend))); + m_preset_tree_window->SetSize(wxSize(std::min(1000, width + width_extend), std::min(400, height + height_extend))); + this->SetSizerAndFit(m_main_sizer); + + this->Layout(); + this->Fit(); + this->Refresh(); + wxGetApp().UpdateDlgDarkUI(this); + adjust_dialog_in_screen(this); + this->Thaw(); +} + +void EditFilamentPresetDialog::delete_preset() +{ + if (m_selected_printer.empty()) return; + if (m_need_delete_preset_index < 0) return; + std::unordered_map>>::iterator iter = m_printer_compatible_presets.find(m_selected_printer); + if (m_printer_compatible_presets.end() == iter) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " can not find printer and printer name is: " << m_selected_printer; + return; + } + std::vector>& filament_presets = iter->second; + if (m_need_delete_preset_index >= filament_presets.size()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " index error and selected printer is: " << m_selected_printer << " and index: " << m_need_delete_preset_index; + return; + } + std::shared_ptr need_delete_preset = filament_presets[m_need_delete_preset_index]; + // is selecetd filament preset + if (need_delete_preset->name == wxGetApp().preset_bundle->filaments.get_selected_preset_name()) { + wxGetApp().get_tab(need_delete_preset->type)->delete_preset(); + // is preset exist? exist: not delete + Preset *delete_preset = wxGetApp().preset_bundle->filaments.find_preset(need_delete_preset->name, false); + if (delete_preset) { + m_selected_printer.clear(); + m_need_delete_preset_index = -1; + return; + } + } else { + Preset *filament_preset = wxGetApp().preset_bundle->filaments.find_preset(need_delete_preset->name); + + // is root preset ? + bool is_base_preset = false; + if (filament_preset && wxGetApp().preset_bundle->filaments.get_preset_base(*filament_preset) == filament_preset) { + is_base_preset = true; + int count = 0; + wxString presets; + for (auto &preset2 : wxGetApp().preset_bundle->filaments) + if (preset2.inherits() == filament_preset->name) { + ++count; + presets += "\n - " + from_u8(preset2.name); + } + wxString msg; + if (count > 0) { + msg = _L("Presets inherited by other presets can not be deleted"); + msg += "\n"; + msg += _L_PLURAL("The following presets inherits this preset.", "The following preset inherits this preset.", count); + wxString title = _L("Delete Preset"); + MessageDialog(this, msg + presets, title, wxOK | wxICON_ERROR).ShowModal(); + m_selected_printer.clear(); + m_need_delete_preset_index = -1; + return; + } + } + wxString msg; + if (is_base_preset) { + msg = _L("Are you sure to delete the selected preset? \nIf the preset corresponds to a filament currently in use on your printer, please reset the filament information for that slot."); + } else { + msg = _L("Are you sure to delete the selected preset?"); + } + if (wxID_YES != MessageDialog(this, msg, _L("Delete preset"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal()) { + m_selected_printer.clear(); + m_need_delete_preset_index = -1; + return; + } + + // delete preset + std::string next_selected_preset_name = wxGetApp().preset_bundle->filaments.get_selected_preset().name; + bool delete_result = delete_filament_preset_by_name(need_delete_preset->name, next_selected_preset_name); + BOOST_LOG_TRIVIAL(info) << __LINE__ << " filament preset name: " << need_delete_preset->name << (delete_result ? " delete successful" : " delete failed"); + + wxGetApp().preset_bundle->filaments.select_preset_by_name(next_selected_preset_name, true); + for (size_t i = 0; i < wxGetApp().preset_bundle->filament_presets.size(); ++i) { + auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); + if (preset == nullptr) wxGetApp().preset_bundle->filament_presets[i] = wxGetApp().preset_bundle->filaments.get_selected_preset_name(); + } + } + + // remove preset shared_ptr from m_printer_compatible_presets + int last_index = filament_presets.size() - 1; + if (m_need_delete_preset_index != last_index) { + std::swap(filament_presets[m_need_delete_preset_index], filament_presets[last_index]); + } + filament_presets.pop_back(); + if (filament_presets.empty()) m_printer_compatible_presets.erase(iter); + + update_preset_tree(); + + m_selected_printer.clear(); + m_need_delete_preset_index = -1; +} + +void EditFilamentPresetDialog::edit_preset() +{ + if (m_selected_printer.empty()) return; + if (m_need_edit_preset_index < 0) return; + std::unordered_map>>::iterator iter = m_printer_compatible_presets.find(m_selected_printer); + if (m_printer_compatible_presets.end() == iter) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " can not find printer and printer name is: " << m_selected_printer; + return; + } + std::vector> &filament_presets = iter->second; + if (m_need_edit_preset_index >= filament_presets.size()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " index error and selected printer is: " << m_selected_printer << " and index: " << m_need_edit_preset_index; + return; + } + + // edit preset + std::shared_ptr need_edit_preset = filament_presets[m_need_edit_preset_index]; + std::string need_edit_preset_name = need_edit_preset->name; + Tab * tab = wxGetApp().get_tab(need_edit_preset->type); + if (tab == nullptr) { + m_selected_printer.clear(); + m_need_edit_preset_index = -1; + return; + } + + tab->restore_last_select_item(); + + wxGetApp().get_tab(need_edit_preset->type)->select_preset(need_edit_preset_name); + // when some preset have modified, if the printer is not need_edit_preset_name compatible printer, the preset will jump to other preset, need select again + if (!need_edit_preset->is_compatible) wxGetApp().get_tab(need_edit_preset->type)->select_preset(need_edit_preset_name); + + m_selected_printer.clear(); + m_need_edit_preset_index = -1; + + wxGetApp().params_dialog()->set_editing_filament_id(m_filament_id); + EndModal(wxID_EDIT); +} + +wxBoxSizer *EditFilamentPresetDialog::create_filament_basic_info() +{ + wxBoxSizer *basic_info_sizer = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer *vendor_sizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer *type_sizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer *serial_sizer = new wxBoxSizer(wxHORIZONTAL); + + //vendor + wxBoxSizer * vendor_key_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_vendor_text = new wxStaticText(this, wxID_ANY, _L("Vendor"), wxDefaultPosition, wxDefaultSize); + vendor_key_sizer->Add(static_vendor_text, 0, wxEXPAND | wxALL, 0); + vendor_key_sizer->SetMinSize(OPTION_SIZE); + vendor_sizer->Add(vendor_key_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer *vendor_value_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *vendor_text = new wxStaticText(this, wxID_ANY, from_u8(m_vendor_name), wxDefaultPosition, wxDefaultSize); + vendor_value_sizer->Add(vendor_text, 0, wxEXPAND | wxALL, 0); + vendor_sizer->Add(vendor_value_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + //type + wxBoxSizer * type_key_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_type_text = new wxStaticText(this, wxID_ANY, _L("Type"), wxDefaultPosition, wxDefaultSize); + type_key_sizer->Add(static_type_text, 0, wxEXPAND | wxALL, 0); + type_key_sizer->SetMinSize(OPTION_SIZE); + type_sizer->Add(type_key_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer * type_value_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *type_text = new wxStaticText(this, wxID_ANY, from_u8(m_filament_type), wxDefaultPosition, wxDefaultSize); + type_value_sizer->Add(type_text, 0, wxEXPAND | wxALL, 0); + type_sizer->Add(type_value_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + //serial + wxBoxSizer * serial_key_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *static_serial_text = new wxStaticText(this, wxID_ANY, _L("Serial"), wxDefaultPosition, wxDefaultSize); + serial_key_sizer->Add(static_serial_text, 0, wxEXPAND | wxALL, 0); + serial_key_sizer->SetMinSize(OPTION_SIZE); + serial_sizer->Add(serial_key_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + wxBoxSizer * serial_value_sizer = new wxBoxSizer(wxVERTICAL); + wxString full_filamnet_serial = from_u8(m_filament_serial); + wxString show_filament_serial = full_filamnet_serial; + if (m_filament_serial.size() > 40) { + show_filament_serial = from_u8(m_filament_serial.substr(0, 20)) + "..."; + } + wxStaticText *serial_text = new wxStaticText(this, wxID_ANY, show_filament_serial, wxDefaultPosition, wxDefaultSize); + wxToolTip * toolTip = new wxToolTip(full_filamnet_serial); + serial_text->SetToolTip(toolTip); + serial_value_sizer->Add(serial_text, 0, wxEXPAND | wxALL, 0); + serial_sizer->Add(serial_value_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + basic_info_sizer->Add(vendor_sizer, 0, wxEXPAND | wxALL, 0); + basic_info_sizer->Add(type_sizer, 0, wxEXPAND | wxALL, 0); + basic_info_sizer->Add(serial_sizer, 0, wxEXPAND | wxALL, 0); + + return basic_info_sizer; +} + +wxBoxSizer *EditFilamentPresetDialog::create_add_filament_btn() +{ + wxBoxSizer *add_filament_btn_sizer = new wxBoxSizer(wxHORIZONTAL); + m_add_filament_btn = new Button(this, _L("+ Add Preset")); + m_add_filament_btn->SetFont(Label::Body_10); + m_add_filament_btn->SetPaddingSize(wxSize(FromDIP(8), FromDIP(3))); + m_add_filament_btn->SetCornerRadius(FromDIP(8)); + + StateColor flush_bg_col(std::pair(wxColour(219, 253, 231), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(wxColour(238, 238, 238), StateColor::Normal)); + + StateColor flush_fg_col(std::pair(wxColour(107, 107, 106), StateColor::Pressed), std::pair(wxColour(107, 107, 106), StateColor::Hovered), + std::pair(wxColour(107, 107, 106), StateColor::Normal)); + + StateColor flush_bd_col(std::pair(wxColour(0, 150, 136), StateColor::Pressed), std::pair(wxColour(0, 150, 136), StateColor::Hovered), + std::pair(wxColour(172, 172, 172), StateColor::Normal)); + + m_add_filament_btn->SetBackgroundColor(flush_bg_col); + m_add_filament_btn->SetBorderColor(flush_bd_col); + m_add_filament_btn->SetTextColor(flush_fg_col); + add_filament_btn_sizer->Add(m_add_filament_btn, 0, wxEXPAND | wxALL, FromDIP(10)); + + m_add_filament_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { + CreatePresetForPrinterDialog dlg(nullptr, m_filament_type, m_filament_id, m_vendor_name, m_filament_name); + int res = dlg.ShowModal(); + if (res == wxID_OK) { + if (get_same_filament_id_presets(m_filament_id)) { + update_preset_tree(); + } + } + }); + + return add_filament_btn_sizer; +} + +wxBoxSizer *EditFilamentPresetDialog::create_preset_tree_sizer() +{ + wxBoxSizer *filament_preset_tree_sizer = new wxBoxSizer(wxHORIZONTAL); + m_preset_tree_window = new wxScrolledWindow(this); + m_preset_tree_window->SetScrollRate(5, 5); + m_preset_tree_window->SetBackgroundColour(PRINTER_LIST_COLOUR); + m_preset_tree_window->SetMinSize(wxSize(-1, FromDIP(400))); + m_preset_tree_window->SetMaxSize(wxSize(-1, FromDIP(300))); + m_preset_tree_window->SetSize(wxSize(-1, FromDIP(300))); + m_preset_tree_panel = new wxPanel(m_preset_tree_window); + m_preset_tree_sizer = new wxBoxSizer(wxVERTICAL); + m_preset_tree_panel->SetSizer(m_preset_tree_sizer); + m_preset_tree_panel->SetMinSize(wxSize(580, -1)); + m_preset_tree_panel->SetBackgroundColour(PRINTER_LIST_COLOUR); + wxBoxSizer* m_preset_tree_window_sizer = new wxBoxSizer(wxVERTICAL); + m_preset_tree_window_sizer->Add(m_preset_tree_panel, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10)); + m_preset_tree_window->SetSizerAndFit(m_preset_tree_window_sizer); + filament_preset_tree_sizer->Add(m_preset_tree_window, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return filament_preset_tree_sizer; +} + +wxBoxSizer *EditFilamentPresetDialog::create_button_sizer() +{ + wxBoxSizer *bSizer_button = new wxBoxSizer(wxHORIZONTAL); + + m_del_filament_btn = new Button(this, _L("Delete Filament")); + m_del_filament_btn->SetBackgroundColor(*wxRED); + m_del_filament_btn->SetBorderColor(*wxWHITE); + m_del_filament_btn->SetTextColor(wxColour(0xFFFFFE)); + m_del_filament_btn->SetFont(Label::Body_12); + m_del_filament_btn->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_del_filament_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_del_filament_btn->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_del_filament_btn, 0, wxLEFT | wxBOTTOM, FromDIP(10)); + + bSizer_button->Add(0, 0, 1, wxEXPAND, 0); + + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + + m_ok_btn = new Button(this, _L("OK")); + m_ok_btn->SetBackgroundColor(btn_bg_green); + m_ok_btn->SetBorderColor(*wxWHITE); + m_ok_btn->SetTextColor(wxColour(0xFFFFFE)); + m_ok_btn->SetFont(Label::Body_12); + m_ok_btn->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_ok_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_ok_btn->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_ok_btn, 0, wxRIGHT | wxBOTTOM, FromDIP(10)); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + m_del_filament_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent &e) { + WarningDialog dlg(this, _L("All the filament presets belong to this filament would be deleted. \nIf you are using this filament on your printer, please reset the filament information for that slot."), _L("Delete filament"), wxYES | wxCANCEL | wxCANCEL_DEFAULT | wxCENTRE); + int res = dlg.ShowModal(); + if (wxID_YES == res) { + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + std::set> inherit_preset_names; + std::set> root_preset_names; + for (std::pair>> printer_and_preset : m_printer_compatible_presets) { + for (std::shared_ptr preset : printer_and_preset.second) { + if (preset->inherits().empty()) { + root_preset_names.insert(preset); + } else { + inherit_preset_names.insert(preset); + } + } + } + // delete inherit preset first + std::string next_selected_preset_name = wxGetApp().preset_bundle->filaments.get_selected_preset().name; + for (std::shared_ptr preset : inherit_preset_names) { + bool delete_result = delete_filament_preset_by_name(preset->name, next_selected_preset_name); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " inherit filament name: " << preset->name << (delete_result ? " delete successful" : " delete failed"); + } + for (std::shared_ptr preset : root_preset_names) { + bool delete_result = delete_filament_preset_by_name(preset->name, next_selected_preset_name); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " root filament name: " << preset->name << (delete_result ? " delete successful" : " delete failed"); + } + m_printer_compatible_presets.clear(); + wxGetApp().preset_bundle->filaments.select_preset_by_name(next_selected_preset_name,true); + + for (size_t i = 0; i < wxGetApp().preset_bundle->filament_presets.size(); ++i) { + auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i]); + if (preset == nullptr) wxGetApp().preset_bundle->filament_presets[i] = wxGetApp().preset_bundle->filaments.get_selected_preset_name(); + } + EndModal(wxID_OK); + } + e.Skip(); + })); + + m_ok_btn->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { EndModal(wxID_OK); }); + + return bSizer_button; + +} + +CreatePresetForPrinterDialog::CreatePresetForPrinterDialog(wxWindow *parent, std::string filament_type, std::string filament_id, std::string filament_vendor, std::string filament_name) + : DPIDialog(parent ? parent : nullptr, wxID_ANY, _L("Add Preset"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) + , m_filament_id(filament_id) + , m_filament_name(filament_name) + , m_filament_vendor(filament_vendor) + , m_filament_type(filament_type) +{ + m_preset_bundle = std::make_shared(*(wxGetApp().preset_bundle)); + get_visible_printer_and_compatible_filament_presets(); + + this->SetBackgroundColour(*wxWHITE); + + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + wxBoxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); + // top line + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + main_sizer->Add(m_line_top, 0, wxEXPAND, 0); + main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + + wxStaticText *basic_infomation = new wxStaticText(this, wxID_ANY, _L("Add preset for new printer")); + basic_infomation->SetFont(Label::Head_16); + main_sizer->Add(basic_infomation, 0, wxALL, FromDIP(10)); + + main_sizer->Add(create_selected_printer_preset_sizer(), 0, wxALL, FromDIP(10)); + main_sizer->Add(create_selected_filament_preset_sizer(), 0, wxALL, FromDIP(10)); + main_sizer->Add(create_button_sizer(), 0, wxEXPAND | wxALL, FromDIP(10)); + + this->SetSizer(main_sizer); + this->Layout(); + this->Fit(); + wxGetApp().UpdateDlgDarkUI(this); +} + +CreatePresetForPrinterDialog::~CreatePresetForPrinterDialog() {} + +void CreatePresetForPrinterDialog::on_dpi_changed(const wxRect &suggested_rect) { + m_ok_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_ok_btn->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_ok_btn->SetCornerRadius(FromDIP(12)); + m_cancel_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_cancel_btn->SetMaxSize(wxSize(FromDIP(58), FromDIP(24))); + m_cancel_btn->SetCornerRadius(FromDIP(12)); + Layout(); +} + +void CreatePresetForPrinterDialog::get_visible_printer_and_compatible_filament_presets() +{ + const std::deque &printer_presets = m_preset_bundle->printers.get_presets(); + m_printer_compatible_filament_presets.clear(); + for (const Preset &printer_preset : printer_presets) { + if (printer_preset.is_visible) { + if (m_preset_bundle->printers.get_preset_base(printer_preset) != &printer_preset) continue; + if (m_preset_bundle->printers.select_preset_by_name(printer_preset.name, true)) { + m_preset_bundle->update_compatible(PresetSelectCompatibleType::Always); + const std::deque &filament_presets = m_preset_bundle->filaments.get_presets(); + for (const Preset &filament_preset : filament_presets) { + if (filament_preset.is_default || !filament_preset.is_compatible) continue; + ConfigOptionStrings *filament_types; + const Preset * filament_preset_base = m_preset_bundle->filaments.get_preset_base(filament_preset); + if (filament_preset_base == &filament_preset) { + filament_types = dynamic_cast(const_cast(&filament_preset)->config.option("filament_type")); + } else { + filament_types = dynamic_cast(const_cast(filament_preset_base)->config.option("filament_type")); + } + + if (filament_types && filament_types->values.empty()) continue; + const std::string filament_type = filament_types->values[0]; + std::string filament_type_ = system_filament_types_map[m_filament_type]; + if (filament_type_.empty()) filament_type_ = m_filament_type; + if (filament_type == filament_type_) { + m_printer_compatible_filament_presets[printer_preset.name].push_back(std::make_shared(filament_preset)); + } + } + } + } + } +} + +wxBoxSizer *CreatePresetForPrinterDialog::create_selected_printer_preset_sizer() +{ + wxBoxSizer *select_preseter_preset_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *printer_text = new wxStaticText(this, wxID_ANY, _L("Printer"), wxDefaultPosition, wxDefaultSize); + select_preseter_preset_sizer->Add(printer_text, 0, wxEXPAND | wxALL, 0); + m_selected_printer = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, PRINTER_PRESET_MODEL_SIZE, 0, nullptr, wxCB_READONLY); + select_preseter_preset_sizer->Add(m_selected_printer, 0, wxEXPAND | wxTOP, FromDIP(5)); + + wxArrayString printer_choices; + for (std::pair>> printer_to_filament_presets : m_printer_compatible_filament_presets) { + auto compatible_printer_name = printer_to_filament_presets.first; + if (compatible_printer_name.empty()) { + BOOST_LOG_TRIVIAL(info)<<__FUNCTION__ << " a printer has no name"; + continue; + } + wxString printer_name = from_u8(compatible_printer_name); + printer_choices.push_back(printer_name); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry, and visible printer is: " << compatible_printer_name; + } + m_selected_printer->Set(printer_choices); + + return select_preseter_preset_sizer; +} + +wxBoxSizer *CreatePresetForPrinterDialog::create_selected_filament_preset_sizer() +{ + wxBoxSizer * select_filament_preset_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *printer_text = new wxStaticText(this, wxID_ANY, _L("Copy preset from filament"), wxDefaultPosition, wxDefaultSize); + select_filament_preset_sizer->Add(printer_text, 0, wxEXPAND | wxALL, 0); + m_selected_filament = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, PRINTER_PRESET_MODEL_SIZE, 0, nullptr, wxCB_READONLY); + select_filament_preset_sizer->Add(m_selected_filament, 0, wxEXPAND | wxTOP, FromDIP(5)); + + m_selected_printer->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) { + wxString printer_name = m_selected_printer->GetStringSelection(); + std::unordered_map>>::iterator filament_iter = m_printer_compatible_filament_presets.find(into_u8(printer_name)); + if (m_printer_compatible_filament_presets.end() != filament_iter) { + filament_choice_to_filament_preset.clear(); + wxArrayString filament_choices; + for (std::shared_ptr filament_preset : filament_iter->second) { + wxString filament_name = wxString::FromUTF8(filament_preset->name); + filament_choice_to_filament_preset[filament_name] = filament_preset; + filament_choices.push_back(filament_name); + } + m_selected_filament->Set(filament_choices); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " count of compatible filament presets :" << filament_choices.size(); + if (filament_choices.size()) { m_selected_filament->SetSelection(0); } + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "printer preset not find compatible filament presets"; + } + }); + + return select_filament_preset_sizer; +} + +wxBoxSizer *CreatePresetForPrinterDialog::create_button_sizer() +{ + wxBoxSizer *bSizer_button = new wxBoxSizer(wxHORIZONTAL); + + bSizer_button->Add(0, 0, 1, wxEXPAND, 0); + + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + + m_ok_btn = new Button(this, _L("OK")); + m_ok_btn->SetBackgroundColor(btn_bg_green); + m_ok_btn->SetBorderColor(*wxWHITE); + m_ok_btn->SetTextColor(wxColour(0xFFFFFE)); + m_ok_btn->SetFont(Label::Body_12); + m_ok_btn->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_ok_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_ok_btn->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_ok_btn, 0, wxRIGHT | wxBOTTOM, FromDIP(10)); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + m_cancel_btn = new Button(this, _L("Cancel")); + m_cancel_btn->SetBackgroundColor(btn_bg_white); + m_cancel_btn->SetBorderColor(wxColour(38, 46, 48)); + m_cancel_btn->SetFont(Label::Body_12); + m_cancel_btn->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_cancel_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_cancel_btn->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_cancel_btn, 0, wxRIGHT | wxBOTTOM, FromDIP(10)); + + m_ok_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { + wxString selected_printer_name = m_selected_printer->GetStringSelection(); + std::string printer_name = into_u8(selected_printer_name); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " add preset: get compatible printer name:"; + + wxString filament_preset_name = m_selected_filament->GetStringSelection(); + std::unordered_map>::iterator iter = filament_choice_to_filament_preset.find(filament_preset_name); + if (filament_choice_to_filament_preset.end() != iter) { + std::shared_ptr filament_preset = iter->second; + PresetBundle * preset_bundle = wxGetApp().preset_bundle; + std::vector failures; + DynamicConfig dynamic_config; + dynamic_config.set_key_value("filament_vendor", new ConfigOptionStrings({m_filament_vendor})); + dynamic_config.set_key_value("compatible_printers", new ConfigOptionStrings({printer_name})); + dynamic_config.set_key_value("filament_type", new ConfigOptionStrings({m_filament_type})); + bool res = preset_bundle->filaments.clone_presets_for_filament(filament_preset.get(), failures, m_filament_name, m_filament_id, dynamic_config, printer_name); + if (!res) { + std::string failure_names; + for (std::string &failure : failures) { failure_names += failure + "\n"; } + MessageDialog dlg(this, _L("Some existing presets have failed to be created, as follows:\n") + from_u8(failure_names) + _L("\nDo you want to rewrite it?"), + wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), wxYES_NO | wxYES_DEFAULT | wxCENTRE); + if (dlg.ShowModal() == wxID_YES) { + res = preset_bundle->filaments.clone_presets_for_filament(filament_preset.get(), failures, m_filament_name, m_filament_id, dynamic_config, printer_name, true); + BOOST_LOG_TRIVIAL(info) << "clone filament have failures rewritten is successful? " << res; + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "have same name preset and not rewritten"; + return; + } + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "create filament preset successful and name is:" << m_filament_name + " @" + printer_name; + } + + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "filament choice not find filament preset and choice is:" << filament_preset_name; + MessageDialog dlg(this, _L("The filament choice not find filament preset, please reselect it"), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Info"), + wxYES | wxYES_DEFAULT | wxCENTRE); + dlg.ShowModal(); + return; + } + + EndModal(wxID_OK); + }); + m_cancel_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { EndModal(wxID_CANCEL); }); + + return bSizer_button; +} + +PresetTree::PresetTree(EditFilamentPresetDialog * dialog) +: m_parent_dialog(dialog) +{} + +wxPanel *PresetTree::get_preset_tree(std::pair>> printer_and_presets) +{ + wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL); + wxPanel * parent = m_parent_dialog->get_preset_tree_panel(); + wxPanel * panel = new wxPanel(parent); + wxColour backgroundColor = parent->GetBackgroundColour(); + panel->SetBackgroundColour(backgroundColor); + const std::string &printer_name = printer_and_presets.first; + sizer->Add(get_root_item(panel, printer_name), 0, wxEXPAND, 0); + int child_count = printer_and_presets.second.size(); + for (int i = 0; i < child_count; i++) { + if (i == child_count - 1) { + sizer->Add(get_child_item(panel, printer_and_presets.second[i], printer_name, i, true), 0, wxEXPAND, 0); + } else { + sizer->Add(get_child_item(panel, printer_and_presets.second[i], printer_name, i, false), 0, wxEXPAND, 0); + } + } + panel->SetSizerAndFit(sizer); + return panel; +} + +wxPanel *PresetTree::get_root_item(wxPanel *parent, const std::string &printer_name) +{ + wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); + wxPanel * panel = new wxPanel(parent); + wxColour backgroundColor = parent->GetBackgroundColour(); + panel->SetBackgroundColour(backgroundColor); + wxStaticText *preset_name = new wxStaticText(panel, wxID_ANY, from_u8(printer_name)); + preset_name->SetFont(Label::Body_11); + preset_name->SetForegroundColour(*wxBLACK); + sizer->Add(preset_name, 0, wxEXPAND | wxALL, 5); + panel->SetSizer(sizer); + + return panel; +} + +wxPanel *PresetTree::get_child_item(wxPanel *parent, std::shared_ptr preset, std::string printer_name, int preset_index, bool is_last) +{ + wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); + wxPanel * panel = new wxPanel(parent); + wxColour backgroundColor = parent->GetBackgroundColour(); + panel->SetBackgroundColour(backgroundColor); + sizer->Add(0, 0, 0, wxLEFT, 10); + wxPanel *line_left = new wxPanel(panel, wxID_ANY, wxDefaultPosition, is_last ? wxSize(1, 12) : wxSize(1, -1)); + line_left->SetBackgroundColour(*wxBLACK); + sizer->Add(line_left, 0, is_last ? wxALL : wxEXPAND | wxALL, 0); + wxPanel *line_right = new wxPanel(panel, wxID_ANY, wxDefaultPosition, wxSize(10, 1)); + line_right->SetBackgroundColour(*wxBLACK); + sizer->Add(line_right, 0, wxALL | wxALIGN_CENTER_VERTICAL, 0); + sizer->Add(0, 0, 0, wxLEFT, 5); + wxStaticText *preset_name = new wxStaticText(panel, wxID_ANY, from_u8(preset->name)); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " create child item: " << preset->name; + preset_name->SetFont(Label::Body_10); + preset_name->SetForegroundColour(*wxBLACK); + sizer->Add(preset_name, 0, wxEXPAND | wxALL, 5); + sizer->Add(0, 0, 1, wxEXPAND, 0); + + StateColor flush_bg_col(std::pair(wxColour(219, 253, 231), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(wxColour(238, 238, 238), StateColor::Normal)); + + StateColor flush_fg_col(std::pair(wxColour(107, 107, 106), StateColor::Pressed), std::pair(wxColour(107, 107, 106), StateColor::Hovered), + std::pair(wxColour(107, 107, 106), StateColor::Normal)); + + StateColor flush_bd_col(std::pair(wxColour(0, 150, 136), StateColor::Pressed), std::pair(wxColour(0, 150, 136), StateColor::Hovered), + std::pair(wxColour(172, 172, 172), StateColor::Normal)); + + Button *edit_preset_btn = new Button(panel, _L("Edit Preset")); + edit_preset_btn->SetFont(Label::Body_10); + edit_preset_btn->SetPaddingSize(wxSize(8, 3)); + edit_preset_btn->SetCornerRadius(8); + edit_preset_btn->SetBackgroundColor(flush_bg_col); + edit_preset_btn->SetBorderColor(flush_bd_col); + edit_preset_btn->SetTextColor(flush_fg_col); + //edit_preset_btn->Hide(); + sizer->Add(edit_preset_btn, 0, wxALL | wxALIGN_CENTER_VERTICAL, 0); + sizer->Add(0, 0, 0, wxLEFT, 5); + + Button *del_preset_btn = new Button(panel, _L("Delete Preset")); + del_preset_btn->SetFont(Label::Body_10); + del_preset_btn->SetPaddingSize(wxSize(8, 3)); + del_preset_btn->SetCornerRadius(8); + del_preset_btn->SetBackgroundColor(flush_bg_col); + del_preset_btn->SetBorderColor(flush_bd_col); + del_preset_btn->SetTextColor(flush_fg_col); + //del_preset_btn->Hide(); + sizer->Add(del_preset_btn, 0, wxALL | wxALIGN_CENTER_VERTICAL, 0); + + edit_preset_btn->Bind(wxEVT_BUTTON, [this, printer_name, preset_index](wxCommandEvent &e) { + wxGetApp().CallAfter([this, printer_name, preset_index]() { edit_preset(printer_name, preset_index); }); + }); + del_preset_btn->Bind(wxEVT_BUTTON, [this, printer_name, preset_index](wxCommandEvent &e) { + wxGetApp().CallAfter([this, printer_name, preset_index]() { delete_preset(printer_name, preset_index); }); + }); + + panel->SetSizer(sizer); + + return panel; +} + +void PresetTree::delete_preset(std::string printer_name, int need_delete_preset_index) +{ + m_parent_dialog->set_printer_name(printer_name); + m_parent_dialog->set_need_delete_preset_index(need_delete_preset_index); + m_parent_dialog->delete_preset(); +} + +void PresetTree::edit_preset(std::string printer_name, int need_edit_preset_index) +{ + m_parent_dialog->set_printer_name(printer_name); + m_parent_dialog->set_need_edit_preset_index(need_edit_preset_index); + m_parent_dialog->edit_preset(); +} + +} // namespace GUI + +} // namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/CreatePresetsDialog.hpp b/src/slic3r/GUI/CreatePresetsDialog.hpp new file mode 100644 index 00000000000..c2334176131 --- /dev/null +++ b/src/slic3r/GUI/CreatePresetsDialog.hpp @@ -0,0 +1,398 @@ +#ifndef slic3r_CreatePresetsDialog_hpp_ +#define slic3r_CreatePresetsDialog_hpp_ + +#include "libslic3r/Preset.hpp" +#include "wxExtensions.hpp" +#include "GUI_Utils.hpp" +#include "Widgets/Label.hpp" +#include "Widgets/TextInput.hpp" +#include "Widgets/Button.hpp" +#include "Widgets/RadioBox.hpp" +#include "Widgets/CheckBox.hpp" +#include "Widgets/ComboBox.hpp" +#include "miniz.h" +#include "ParamsDialog.hpp" + +namespace Slic3r { +namespace GUI { + +class CreateFilamentPresetDialog : public DPIDialog +{ +public: + CreateFilamentPresetDialog(wxWindow *parent); + ~CreateFilamentPresetDialog(); + +protected: + enum FilamentOptionType { + VENDOR = 0, + TYPE, + SERIAL, + FILAMENT_PRESET, + PRESET_FOR_PRINTER, + FILAMENT_NAME_COUNT + }; + +protected: + void on_dpi_changed(const wxRect &suggested_rect) override; + bool is_check_box_selected(); + wxBoxSizer *create_item(FilamentOptionType option_type); + wxBoxSizer *create_vendor_item(); + wxBoxSizer *create_type_item(); + wxBoxSizer *create_serial_item(); + wxBoxSizer *create_filament_preset_item(); + wxBoxSizer *create_filament_preset_for_printer_item(); + wxBoxSizer *create_button_item(); + +private: + void clear_filament_preset_map(); + wxArrayString get_filament_preset_choices(); + wxBoxSizer * create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector> &radiobox_list); + void select_curr_radiobox(std::vector> &radiobox_list, int btn_idx); + wxString curr_create_filament_type(); + void get_filament_presets_by_machine(); + void get_all_filament_presets(); + void get_all_visible_printer_name(); + void update_dialog_size(); + template + void sort_printer_by_nozzle(std::vector> &printer_name_to_filament_preset); + +private: + struct CreateType + { + wxString base_filament; + wxString base_filament_preset; + }; + +private: + std::vector> m_create_type_btns; + std::unordered_map<::CheckBox *, std::pair> m_filament_preset; + std::unordered_map<::CheckBox *, std::pair> m_machint_filament_preset; + std::unordered_map> m_filament_choice_map; + std::unordered_map m_public_name_to_filament_id_map; + std::unordered_map m_all_presets_map; + std::set m_visible_printers; + CreateType m_create_type; + Button * m_button_create = nullptr; + Button * m_button_cancel = nullptr; + ComboBox * m_filament_vendor_combobox = nullptr; + ::CheckBox * m_can_not_find_vendor_checkbox = nullptr; + ComboBox * m_filament_type_combobox = nullptr; + ComboBox * m_exist_vendor_combobox = nullptr; + ComboBox * m_filament_preset_combobox = nullptr; + TextInput * m_filament_custom_vendor_input = nullptr; + wxGridSizer * m_filament_presets_sizer = nullptr; + wxPanel * m_filament_preset_panel = nullptr; + wxScrolledWindow * m_scrolled_preset_panel = nullptr; + TextInput * m_filament_serial_input = nullptr; + wxBoxSizer * m_scrolled_sizer = nullptr; + wxStaticText * m_filament_preset_text = nullptr; + +}; + +class CreatePrinterPresetDialog : public DPIDialog +{ +public: + CreatePrinterPresetDialog(wxWindow *parent); + ~CreatePrinterPresetDialog(); + +protected: + void on_dpi_changed(const wxRect &suggested_rect) override; + +/******************************************************** Control Construction *****************************************************/ + wxBoxSizer *create_step_switch_item(); + //Create Printer Page1 + void create_printer_page1(wxWindow *parent); + wxBoxSizer *create_type_item(wxWindow *parent); + wxBoxSizer *create_printer_item(wxWindow *parent); + wxBoxSizer *create_nozzle_diameter_item(wxWindow *parent); + wxBoxSizer *create_bed_shape_item(wxWindow *parent); + wxBoxSizer *create_bed_size_item(wxWindow *parent); + wxBoxSizer *create_origin_item(wxWindow *parent); + wxBoxSizer *create_hot_bed_stl_item(wxWindow *parent); + wxBoxSizer *create_hot_bed_svg_item(wxWindow *parent); + wxBoxSizer *create_max_print_height_item(wxWindow *parent); + wxBoxSizer *create_page1_btns_item(wxWindow *parent); + //Improt Presets Page2 + void create_printer_page2(wxWindow *parent); + wxBoxSizer *create_printer_preset_item(wxWindow *parent); + wxBoxSizer *create_presets_item(wxWindow *parent); + wxBoxSizer *create_presets_template_item(wxWindow *parent); + wxBoxSizer *create_page2_btns_item(wxWindow *parent); + + void show_page1(); + void show_page2(); + +/********************************************************** Data Interaction *******************************************************/ + bool data_init(); + void set_current_visible_printer(); + void select_curr_radiobox(std::vector> &radiobox_list, int btn_idx); + void select_all_preset_template(std::vector> &preset_templates); + void deselect_all_preset_template(std::vector> &preset_templates); + void update_presets_list(bool jast_template = false); + void on_preset_model_value_change(wxCommandEvent &e); + void clear_preset_combobox(); + bool save_printable_area_config(Preset *preset); + bool check_printable_area(); + bool validate_input_valid(); + void load_texture(); + void load_model_stl(); + bool load_system_and_user_presets_with_curr_model(PresetBundle &temp_preset_bundle, bool just_template = false); + void generate_process_presets_data(std::vector presets, std::string nozzle); + void update_preset_list_size(); + wxArrayString printer_preset_sort_with_nozzle_diameter(const VendorProfile &vendor_profile, float nozzle_diameter); + + wxBoxSizer *create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector> &radiobox_list); + + wxString curr_create_preset_type(); + wxString curr_create_printer_type(); + +private: + struct CreatePrinterType + { + wxString create_printer; + wxString create_nozzle; + wxString base_template; + wxString base_curr_printer; + }; + + CreatePrinterType m_create_type; + std::vector> m_create_type_btns; + std::vector> m_create_presets_btns; + std::vector> m_filament_preset; + std::vector> m_process_preset; + std::unordered_map> m_printer_name_to_preset; + VendorProfile m_printer_preset_vendor_selected; + Slic3r::VendorProfile::PrinterModel m_printer_preset_model_selected; + bool rewritten = false; + Preset * m_printer_preset = nullptr; + wxStaticBitmap * m_step_1 = nullptr; + wxStaticBitmap * m_step_2 = nullptr; + Button * m_button_OK = nullptr; + Button * m_button_create = nullptr; + Button * m_button_page1_cancel = nullptr; + Button * m_button_page2_cancel = nullptr; + Button * m_button_page2_back = nullptr; + Button * m_button_bed_stl = nullptr; + Button * m_button_bed_svg = nullptr; + wxScrolledWindow * m_page1 = nullptr; + wxPanel * m_page2 = nullptr; + wxScrolledWindow * m_scrolled_preset_window = nullptr; + wxBoxSizer * m_scrooled_preset_sizer = nullptr; + ComboBox * m_select_vendor = nullptr; + ComboBox * m_select_model = nullptr; + ComboBox * m_select_printer = nullptr; + ::CheckBox * m_can_not_find_vendor_combox = nullptr; + wxStaticText * m_can_not_find_vendor_text = nullptr; + wxTextCtrl * m_custom_vendor_text_ctrl = nullptr; + wxTextCtrl * m_custom_model_text_ctrl = nullptr; + ComboBox * m_nozzle_diameter = nullptr; + ComboBox * m_printer_vendor = nullptr; + ComboBox * m_printer_model = nullptr; + TextInput * m_bed_size_x_input = nullptr; + TextInput * m_bed_size_y_input = nullptr; + TextInput * m_bed_origin_x_input = nullptr; + TextInput * m_bed_origin_y_input = nullptr; + TextInput * m_print_height_input = nullptr; + wxGridSizer * m_filament_preset_template_sizer = nullptr; + wxGridSizer * m_process_preset_template_sizer = nullptr; + wxPanel * m_filament_preset_panel = nullptr; + wxPanel * m_process_preset_panel = nullptr; + wxPanel * m_preset_template_panel = nullptr; + wxBoxSizer * m_filament_sizer = nullptr; + wxPanel * m_printer_info_panel = nullptr; + wxBoxSizer * m_page1_sizer = nullptr; + wxBoxSizer * m_printer_info_sizer = nullptr; + wxBoxSizer * m_page2_sizer = nullptr; + wxStaticText * m_upload_stl_tip_text = nullptr; + wxStaticText * m_upload_svg_tip_text = nullptr; + std::string m_custom_texture; + std::string m_custom_model; +}; + +enum SuccessType { + PRINTER = 0, + FILAMENT +}; + +class CreatePresetSuccessfulDialog : public DPIDialog +{ +public: + CreatePresetSuccessfulDialog(wxWindow *parent, const SuccessType &create_success_type); + ~CreatePresetSuccessfulDialog(); + +protected: + void on_dpi_changed(const wxRect &suggested_rect) override; + +private: + Button *m_button_ok = nullptr; + Button *m_button_cancel = nullptr; +}; + +class ExportConfigsDialog : public DPIDialog +{ +public: + ExportConfigsDialog(wxWindow *parent); + ~ExportConfigsDialog();//to do: delete preset + +protected: + + struct ExportType + { + wxString preset_bundle; + wxString filament_bundle; + wxString printer_preset; + wxString filament_preset; + wxString process_preset; + }; + + enum ExportCase { + INITIALIZE_FAIL = 0, + ADD_FILE_FAIL, + ADD_BUNDLE_STRUCTURE_FAIL, + FINALIZE_FAIL, + OPEN_ZIP_WRITTEN_FILE, + EXPORT_CANCEL, + EXPORT_SUCCESS, + CASE_COUNT, + }; + +private: + void data_init(); + void select_curr_radiobox(std::vector> &radiobox_list, int btn_idx); + void on_dpi_changed(const wxRect &suggested_rect) override; + void show_export_result(const ExportCase &export_case); + bool has_check_box_selected(); + bool preset_is_not_compatible_bbl_printer(Preset *preset); + std::string initial_file_path(const wxString &path, const std::string &sub_file_path); + std::string initial_file_name(const wxString &path, const std::string file_name); + wxBoxSizer *create_export_config_item(wxWindow *parent); + wxBoxSizer *create_button_item(wxWindow *parent); + wxBoxSizer *create_select_printer(wxWindow *parent); + wxBoxSizer *create_radio_item(wxString title, wxWindow *parent, wxString tooltip, std::vector> &radiobox_list); + int initial_zip_archive(mz_zip_archive &zip_archive, const std::string &file_path); + ExportCase save_zip_archive_to_file(mz_zip_archive &zip_archive); + ExportCase save_presets_to_zip(const std::string &export_file, const std::vector> &config_paths); + ExportCase archive_preset_bundle_to_file(const wxString &path); + ExportCase archive_filament_bundle_to_file(const wxString &path); + ExportCase archive_printer_preset_to_file(const wxString &path); + ExportCase archive_filament_preset_to_file(const wxString &path); + ExportCase archive_process_preset_to_file(const wxString &path); + +private: + std::vector> m_export_type_btns; + std::vector> m_preset; // for printer preset bundle,printer preset, process preset export + std::vector> m_printer_name; // for filament and peocess preset export, collaborate with m_filament_name_to_presets + std::unordered_map m_printer_presets;//first: printer name, second: printer presets have same printer name + std::unordered_map> m_filament_presets;//first: printer name, second: filament presets have same printer name + std::unordered_map> m_process_presets;//first: printer name, second: filament presets have same printer name + std::unordered_map>> m_filament_name_to_presets;//first: filament name, second presets have same filament name and printer name in vector + ExportType m_exprot_type; + wxBoxSizer * m_main_sizer = nullptr; + wxScrolledWindow * m_scrolled_preset_window = nullptr; + wxGridSizer * m_preset_sizer = nullptr; + wxPanel * m_presets_window = nullptr; + Button * m_button_ok = nullptr; + Button * m_button_cancel = nullptr; + wxStaticText * m_serial_text = nullptr; +}; + +class CreatePresetForPrinterDialog : public DPIDialog +{ +public: + CreatePresetForPrinterDialog(wxWindow *parent, std::string filament_type, std::string filament_id, std::string filament_vendor, std::string filament_name); + ~CreatePresetForPrinterDialog(); + +private: + void on_dpi_changed(const wxRect &suggested_rect) override; + void get_visible_printer_and_compatible_filament_presets(); + wxBoxSizer *create_selected_printer_preset_sizer(); + wxBoxSizer *create_selected_filament_preset_sizer(); + wxBoxSizer *create_button_sizer(); + +private: + std::string m_filament_id; + std::string m_filament_name; + std::string m_filament_vendor; + std::string m_filament_type; + std::shared_ptr m_preset_bundle; + std::string m_filamnt_type; + ComboBox * m_selected_printer = nullptr; + ComboBox * m_selected_filament = nullptr; + Button * m_ok_btn = nullptr; + Button * m_cancel_btn = nullptr; + std::unordered_map> filament_choice_to_filament_preset; + std::unordered_map>> m_printer_compatible_filament_presets; // need be used when add presets + +}; + +class EditFilamentPresetDialog; + +class PresetTree +{ +public: + PresetTree(EditFilamentPresetDialog *dialog); + + wxPanel *get_preset_tree(std::pair>> printer_and_presets); + +private: + wxPanel *get_root_item(wxPanel *parent, const std::string &printer_name); + + wxPanel *get_child_item(wxPanel *parent, std::shared_ptr preset, std::string printer_name, int preset_index, bool is_last = false); + + void delete_preset(std::string printer_name, int need_delete_preset_index); + + void edit_preset(std::string printer_name, int need_edit_preset_index); + +private: + EditFilamentPresetDialog * m_parent_dialog = nullptr; + std::pair>> m_printer_and_presets; + +}; + +class EditFilamentPresetDialog : public DPIDialog +{ +public: + EditFilamentPresetDialog(wxWindow *parent, FilamentInfomation *filament_info); + ~EditFilamentPresetDialog(); + + wxPanel *get_preset_tree_panel() { return m_preset_tree_panel; } + void set_printer_name(const std::string &printer_name) { m_selected_printer = printer_name; } + void set_need_delete_preset_index(int need_delete_preset_index) { m_need_delete_preset_index = need_delete_preset_index; } + void set_need_edit_preset_index(int need_edit_preset_index) { m_need_edit_preset_index = need_edit_preset_index; } + void delete_preset(); + void edit_preset(); + +private: + void on_dpi_changed(const wxRect &suggested_rect) override; + bool get_same_filament_id_presets(std::string filament_id); + void update_preset_tree(); + wxBoxSizer *create_filament_basic_info(); + wxBoxSizer *create_add_filament_btn(); + wxBoxSizer *create_preset_tree_sizer(); + wxBoxSizer *create_button_sizer(); + +private: + PresetTree * m_preset_tree_creater = nullptr; + std::string m_filament_id; + std::string m_filament_name; + std::string m_vendor_name; + std::string m_filament_type; + std::string m_filament_serial; + Button * m_add_filament_btn = nullptr; + Button * m_del_filament_btn = nullptr; + Button * m_ok_btn = nullptr; + wxBoxSizer * m_preset_tree_sizer = nullptr; + wxPanel * m_preset_tree_panel = nullptr; + wxScrolledWindow * m_preset_tree_window = nullptr; + wxBoxSizer * m_main_sizer = nullptr; + wxStaticText * m_note_text = nullptr; + int m_need_delete_preset_index = -1; + int m_need_edit_preset_index = -1; + std::string m_selected_printer = ""; + std::unordered_map>> m_printer_compatible_presets; + +}; + +} +} +#endif \ No newline at end of file diff --git a/src/slic3r/GUI/DailyTips.cpp b/src/slic3r/GUI/DailyTips.cpp new file mode 100644 index 00000000000..9558a863ba9 --- /dev/null +++ b/src/slic3r/GUI/DailyTips.cpp @@ -0,0 +1,614 @@ +#include "DailyTips.hpp" + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include + +namespace Slic3r { namespace GUI { + + +struct DailyTipsData { + std::string main_text; + std::string wiki_url; + std::string img_url; + std::string additional_text; // currently not used + std::string hyper_text; // currently not used + std::function hypertext_callback; // currently not used +}; + +class DailyTipsDataRenderer { +public: + DailyTipsDataRenderer(DailyTipsLayout layout); + ~DailyTipsDataRenderer(); + void update_data(const DailyTipsData& data); + void render(const ImVec2& pos, const ImVec2& size) const; + bool has_image() const; + void on_change_color_mode(bool is_dark); + void set_fade_opacity(float opacity); + +protected: + void load_texture_from_img_url(const std::string url); + void open_wiki() const; + // relative to the window's upper-left position + void render_img(const ImVec2& start_pos, const ImVec2& size) const; + void render_text(const ImVec2& start_pos, const ImVec2& size) const; + +private: + DailyTipsData m_data; + GLTexture* m_texture{ nullptr }; + GLTexture* m_placeholder_texture{ nullptr }; + bool m_is_dark{ false }; + DailyTipsLayout m_layout; + float m_fade_opacity{ 1.0f }; +}; + +DailyTipsDataRenderer::DailyTipsDataRenderer(DailyTipsLayout layout) + : m_layout(layout) +{ +} + +DailyTipsDataRenderer::~DailyTipsDataRenderer() { + if (m_texture) + delete m_texture; + if (m_placeholder_texture) + delete m_placeholder_texture; +} + +void DailyTipsDataRenderer::update_data(const DailyTipsData& data) +{ + m_data = data; + load_texture_from_img_url(m_data.img_url); +} + +void DailyTipsDataRenderer::load_texture_from_img_url(const std::string url) +{ + if (m_texture) { + delete m_texture; + m_texture = nullptr; + } + if (!url.empty()) { + m_texture = new GLTexture(); + m_texture->load_from_file(Slic3r::resources_dir() + "/" + url, true, GLTexture::None, false); + } + else { + if (!m_placeholder_texture) { + m_placeholder_texture = new GLTexture(); + m_placeholder_texture->load_from_file(Slic3r::resources_dir() + "/images/dailytips_placeholder.png", true, GLTexture::None, false); + } + } +} + +void DailyTipsDataRenderer::open_wiki() const +{ + if (!m_data.wiki_url.empty()) + { + wxGetApp().open_browser_with_warning_dialog(m_data.wiki_url); + } +} + +void DailyTipsDataRenderer::render(const ImVec2& pos, const ImVec2& size) const +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + ImGuiWindow* parent_window = ImGui::GetCurrentWindow(); + int window_flags = parent_window->Flags; + window_flags &= ~ImGuiWindowFlags_NoScrollbar; + window_flags &= ~ImGuiWindowFlags_NoScrollWithMouse; + std::string name = "##DailyTipsDataRenderer" + std::to_string(parent_window->ID); + ImGui::SetNextWindowPos(pos); + if (ImGui::BeginChild(name.c_str(), size, false, window_flags)) { + if (m_layout == DailyTipsLayout::Vertical) { + ImVec2 img_size = ImVec2(size.x, 9.0f / 16.0f * size.x); + render_img({ 0, 0 }, img_size); + float img_text_gap = ImGui::CalcTextSize("A").y; + render_text({ 0, img_size.y + img_text_gap }, size); + } + if (m_layout == DailyTipsLayout::Horizontal) { + ImVec2 img_size = ImVec2(16.0f / 9.0f * size.y, size.y); + render_img({ 0, 0 }, img_size); + float img_text_gap = ImGui::CalcTextSize("A").y; + render_text({ img_size.x + img_text_gap, 0 }, { size.x - img_size.x - img_text_gap, size.y }); + } + } + ImGui::EndChild(); +} + +bool DailyTipsDataRenderer::has_image() const +{ + return !m_data.img_url.empty(); +} + +void DailyTipsDataRenderer::on_change_color_mode(bool is_dark) +{ + m_is_dark = is_dark; +} + +void DailyTipsDataRenderer::set_fade_opacity(float opacity) +{ + m_fade_opacity = opacity; +} + +void DailyTipsDataRenderer::render_img(const ImVec2& start_pos, const ImVec2& size) const +{ + if (has_image()) + ImGui::Image((ImTextureID)(intptr_t)m_texture->get_id(), size, ImVec2(0, 0), ImVec2(1, 1), m_is_dark ? ImVec4(0.8, 0.8, 0.8, m_fade_opacity) : ImVec4(1, 1, 1, m_fade_opacity)); + else { + ImGui::Image((ImTextureID)(intptr_t)m_placeholder_texture->get_id(), size, ImVec2(0, 0), ImVec2(1, 1), m_is_dark ? ImVec4(0.8, 0.8, 0.8, m_fade_opacity) : ImVec4(1, 1, 1, m_fade_opacity)); + } +} + +void DailyTipsDataRenderer::render_text(const ImVec2& start_pos, const ImVec2& size) const +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + + ImGui::PushStyleColor(ImGuiCol_Text, m_is_dark ? ImVec4(1.0f, 1.0f, 1.0f, 0.88f * m_fade_opacity) : ImVec4(38 / 255.0f, 46 / 255.0f, 48 / 255.0f, m_fade_opacity)); + // main text + // first line is headline (for hint notification it must be divided by \n) + std::string title_line; + std::string content_lines; + size_t end_pos = m_data.main_text.find_first_of('\n'); + if (end_pos != std::string::npos) { + title_line = m_data.main_text.substr(0, end_pos); + title_line = ImGui::ColorMarkerStart + title_line + ImGui::ColorMarkerEnd; + content_lines = m_data.main_text.substr(end_pos + 1); + } + + ImGui::SetCursorPos(start_pos); + imgui.text(title_line); + + bool is_zh = false; + for (int i = 0; i < content_lines.size() - 1; i += 2) { + if ((content_lines[i] & 0x80) && (content_lines[i + 1] & 0x80)) + is_zh = true; + } + if (!is_zh) { + // problem in Chinese with spaces + ImGui::SetCursorPosX(start_pos.x); + imgui.text_wrapped(content_lines, size.x); + } + else { + Label* wrapped_text = new Label(wxGetApp().GetTopWindow()); + wrapped_text->Hide(); + wrapped_text->SetLabelText(wxString::FromUTF8(content_lines)); + wrapped_text->Wrap(size.x + ImGui::CalcTextSize("A").x * 5.0f); + std::string wrapped_content_lines = wrapped_text->GetLabel().ToUTF8().data(); + wrapped_text->Destroy(); + ImGui::SetCursorPosX(start_pos.x); + imgui.text(wrapped_content_lines); + } + + // wiki + if (!m_data.wiki_url.empty()) { + std::string tips_line = _u8L("For more information, please check out Wiki"); + std::string wiki_part_text = _u8L("Wiki"); + std::string first_part_text = tips_line.substr(0, tips_line.find(wiki_part_text)); + ImVec2 wiki_part_size = ImGui::CalcTextSize(wiki_part_text.c_str()); + ImVec2 first_part_size = ImGui::CalcTextSize(first_part_text.c_str()); + + //text + ImGui::SetCursorPosX(start_pos.x); + ImVec2 link_start_pos = ImGui::GetCursorScreenPos(); + imgui.text(first_part_text); + + ImColor HyperColor = ImColor(31, 142, 234, (int)(255 * m_fade_opacity)).Value; + ImVec2 wiki_part_rect_min = ImVec2(link_start_pos.x + first_part_size.x, link_start_pos.y); + ImVec2 wiki_part_rect_max = wiki_part_rect_min + wiki_part_size; + ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value); + ImGui::SetCursorScreenPos(wiki_part_rect_min); + imgui.text(wiki_part_text.c_str()); + ImGui::PopStyleColor(); + + //click behavior + if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) + { + //underline + ImVec2 lineEnd = ImGui::GetItemRectMax(); + lineEnd.y -= 2.0f; + ImVec2 lineStart = lineEnd; + lineStart.x = ImGui::GetItemRectMin().x; + ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, HyperColor); + + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + open_wiki(); + } + } + ImGui::PopStyleColor(); +} + +int DailyTipsPanel::uid = 0; + +DailyTipsPanel::DailyTipsPanel(bool can_expand, DailyTipsLayout layout) + : m_pos(ImVec2(0, 0)), + m_width(0), + m_height(0), + m_can_expand(can_expand), + m_layout(layout), + m_uid(DailyTipsPanel::uid++), + m_dailytips_renderer(std::make_unique(layout)) +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + float scale = imgui.get_font_size() / 15.0f; + m_footer_height = 58.0f * scale; + m_is_expanded = wxGetApp().app_config->get("show_hints") == "true"; +} + +void DailyTipsPanel::set_position(const ImVec2& pos) +{ + m_pos = pos; +} + +void DailyTipsPanel::set_size(const ImVec2& size) +{ + m_width = size.x; + m_height = size.y; + m_content_height = m_height - m_footer_height; +} + +void DailyTipsPanel::set_can_expand(bool can_expand) +{ + m_can_expand = can_expand; +} + +ImVec2 DailyTipsPanel::get_size() +{ + return ImVec2(m_width, m_height); +} + +void DailyTipsPanel::render() +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + float scale = imgui.get_font_size() / 15.0f; + + if (!m_first_enter) { + retrieve_data_from_hint_database(HintDataNavigation::Curr); + m_first_enter = true; + } + + push_styles(); + if (m_can_expand) { + if (m_is_expanded) { + m_height = m_content_height + m_footer_height; + } + else { + m_height = m_footer_height; + } + } + ImGui::SetNextWindowPos(m_pos); + ImGui::SetNextWindowSizeConstraints(ImVec2(m_width, m_height), ImVec2(m_width, m_height)); + int window_flags = ImGuiWindowFlags_NoTitleBar + | ImGuiWindowFlags_NoCollapse + | ImGuiWindowFlags_NoMove + | ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoScrollbar + | ImGuiWindowFlags_NoScrollWithMouse; + if (ImGui::BeginChild((std::string("##DailyTipsPanel") + std::to_string(m_uid)).c_str(), ImVec2(m_width, m_height), false, window_flags)) { + if (m_can_expand) { + if (m_is_expanded) { + m_dailytips_renderer->render({ m_pos.x, m_pos.y }, { m_width, m_content_height }); + render_controller_buttons({ m_pos.x, m_pos.y + m_height - m_footer_height }, { m_width, m_footer_height }); + } + else { + render_controller_buttons({ m_pos.x, m_pos.y + m_height - m_footer_height }, { m_width, m_footer_height }); + } + } + else { + m_dailytips_renderer->render({ m_pos.x, m_pos.y }, { m_width, m_content_height }); + render_controller_buttons({ m_pos.x, m_pos.y + m_height - m_footer_height }, { m_width, m_footer_height }); + } + + //{// for debug + // ImVec2 vMin = ImGui::GetWindowContentRegionMin(); + // ImVec2 vMax = ImGui::GetWindowContentRegionMax(); + // vMin += ImGui::GetWindowPos(); + // vMax += ImGui::GetWindowPos(); + // ImGui::GetForegroundDrawList()->AddRect(vMin, vMax, IM_COL32(180, 180, 255, 255)); + //} + } + ImGui::EndChild(); + pop_styles(); +} + +void DailyTipsPanel::retrieve_data_from_hint_database(HintDataNavigation nav) +{ + HintData* hint_data = HintDatabase::get_instance().get_hint(nav); + if (hint_data != nullptr) + { + DailyTipsData data{ hint_data->text, + hint_data->documentation_link, + hint_data->image_url, + hint_data->follow_text, + hint_data->hypertext, + hint_data->callback + }; + m_dailytips_renderer->update_data(data); + } +} + +void DailyTipsPanel::expand(bool expand) +{ + if (!m_can_expand) + return; + m_is_expanded = expand; + wxGetApp().app_config->set_bool("show_hints", expand); +} + +void DailyTipsPanel::collapse() +{ + if (!m_can_expand) + return; + m_is_expanded = false; + wxGetApp().app_config->set_bool("show_hints", false); +} + +bool DailyTipsPanel::is_expanded() +{ + return m_is_expanded; +} + +void DailyTipsPanel::on_change_color_mode(bool is_dark) +{ + m_is_dark = is_dark; + m_dailytips_renderer->on_change_color_mode(is_dark); +} + +void DailyTipsPanel::set_fade_opacity(float opacity) +{ + m_fade_opacity = opacity; + m_dailytips_renderer->set_fade_opacity(opacity); +} + +//void DailyTipsPanel::render_header(const ImVec2& pos, const ImVec2& size) +//{ +// ImGuiWrapper& imgui = *wxGetApp().imgui(); +// ImGuiWindow* parent_window = ImGui::GetCurrentWindow(); +// int window_flags = parent_window->Flags; +// std::string name = "##DailyTipsPanelHeader" + std::to_string(parent_window->ID); +// ImGui::SetNextWindowPos(pos); +// if (ImGui::BeginChild(name.c_str(), size, false, window_flags)) { +// ImVec2 text_pos = pos + ImVec2(0, (size.y - ImGui::CalcTextSize("A").y) / 2); +// ImGui::SetCursorScreenPos(text_pos); +// imgui.push_bold_font(); +// imgui.text(_u8L("Daily Tips")); +// imgui.pop_bold_font(); +// } +// ImGui::EndChild(); +//} + +void DailyTipsPanel::render_controller_buttons(const ImVec2& pos, const ImVec2& size) +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + float scale = imgui.get_font_size() / 15.0f; + ImGuiWindow* parent_window = ImGui::GetCurrentWindow(); + int window_flags = parent_window->Flags; + std::string name = "##DailyTipsPanelControllers" + std::to_string(parent_window->ID); + ImGui::SetNextWindowPos(pos); + if (ImGui::BeginChild(name.c_str(), size, false, window_flags)) { + ImVec2 button_size = ImVec2(38.0f, 38.0f) * scale; + float button_margin_x = 8.0f * scale; + std::wstring button_text; + + // collapse / expand + ImVec2 btn_pos = pos + ImVec2(0, (size.y - ImGui::CalcTextSize("A").y) / 2); + ImGui::SetCursorScreenPos(btn_pos); + if (m_can_expand) { + if (m_is_expanded) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImColor(144, 144, 144, (int)(255 * m_fade_opacity)).Value); + + button_text = ImGui::CollapseArrowIcon; + imgui.button((_L("Collapse") + button_text)); + ImVec2 collapse_btn_size = ImGui::CalcTextSize((_u8L("Collapse")).c_str()); + collapse_btn_size.x += button_size.x / 2.0f; + if (ImGui::IsMouseHoveringRect(btn_pos, btn_pos + collapse_btn_size, true)) + { + //underline + ImVec2 lineEnd = ImGui::GetItemRectMax(); + lineEnd.x -= ImGui::CalcTextSize("A").x / 2; + lineEnd.y -= 2; + ImVec2 lineStart = lineEnd; + lineStart.x = ImGui::GetItemRectMin().x; + ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, ImColor(144, 144, 144)); + + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + collapse(); + } + + ImGui::PopStyleColor(4); + } + else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_Text, m_is_dark ? ImColor(230, 230, 230, (int)(255 * m_fade_opacity)).Value : ImColor(38, 46, 48, (int)(255 * m_fade_opacity)).Value); + + // for bold font text, split text and icon-font button + imgui.push_bold_font(); + imgui.button((_L("Daily Tips"))); + imgui.pop_bold_font(); + ImVec2 expand_btn_size = ImGui::CalcTextSize((_u8L("Daily Tips")).c_str()); + ImGui::SetCursorScreenPos(ImVec2(btn_pos.x + expand_btn_size.x + ImGui::CalcTextSize(" ").x, btn_pos.y)); + button_text = ImGui::ExpandArrowIcon; + imgui.button(button_text.c_str()); + expand_btn_size.x += 19.0f * scale; + if (ImGui::IsMouseHoveringRect(btn_pos, btn_pos + expand_btn_size, true)) + { + //underline + ImVec2 lineEnd = ImGui::GetItemRectMax(); + lineEnd.x -= ImGui::CalcTextSize("A").x / 2; + lineEnd.y -= 2; + ImVec2 lineStart = lineEnd; + lineStart.x = ImGui::GetItemRectMin().x - expand_btn_size.x; + ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, m_is_dark ? ImColor(230, 230, 230, (int)(255 * m_fade_opacity)) : ImColor(38, 46, 48, (int)(255 * m_fade_opacity))); + + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + expand(); + } + + ImGui::PopStyleColor(4); + + ImGui::EndChild(); + return; + } + } + + // page index + m_page_index = HintDatabase::get_instance().get_index() + 1; + m_pages_count = HintDatabase::get_instance().get_count(); + std::string text_str = std::to_string(m_page_index) + "/" + std::to_string(m_pages_count); + float text_item_width = ImGui::CalcTextSize(text_str.c_str()).x; + ImGui::PushItemWidth(text_item_width); + float text_pos_x = (pos + size).x - button_margin_x * 2 - button_size.x * 2 - text_item_width; + float text_pos_y = pos.y + (size.y - ImGui::CalcTextSize("A").y) / 2; + ImGui::SetCursorScreenPos(ImVec2(text_pos_x, text_pos_y)); + ImGui::PushStyleColor(ImGuiCol_Text, m_is_dark ? ImColor(230, 230, 230, (int)(255 * m_fade_opacity)).Value : ImColor(38, 46, 48, (int)(255 * m_fade_opacity)).Value); + imgui.text(text_str); + ImGui::PopStyleColor(); + ImGui::PopItemWidth(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(.0f, .0f, .0f, .0f)); + + // prev button + ImColor button_text_color = m_is_dark ? ImColor(228, 228, 228, (int)(255 * m_fade_opacity)) : ImColor(38, 46, 48, (int)(255 * m_fade_opacity)); + ImVec2 prev_button_pos = pos + size + ImVec2(-button_margin_x - button_size.x * 2, -size.y + (size.y - button_size.y) / 2); + ImGui::SetCursorScreenPos(prev_button_pos); + button_text = ImGui::PrevArrowBtnIcon; + if (ImGui::IsMouseHoveringRect(prev_button_pos, prev_button_pos + button_size, true)) + { + button_text_color = ImColor(0, 150, 136, (int)(255 * m_fade_opacity)); + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + retrieve_data_from_hint_database(HintDataNavigation::Prev); + } + ImGui::PushStyleColor(ImGuiCol_Text, button_text_color.Value);// for icon-font button + imgui.button(button_text.c_str()); + ImGui::PopStyleColor(); + + // next button + button_text_color = m_is_dark ? ImColor(228, 228, 228, (int)(255 * m_fade_opacity)) : ImColor(38, 46, 48, (int)(255 * m_fade_opacity)); + ImVec2 next_button_pos = pos + size + ImVec2(-button_size.x, -size.y + (size.y - button_size.y) / 2); + ImGui::SetCursorScreenPos(next_button_pos); + button_text = ImGui::NextArrowBtnIcon; + if (ImGui::IsMouseHoveringRect(next_button_pos, next_button_pos + button_size, true)) + { + button_text_color = ImColor(0, 150, 136, (int)(255 * m_fade_opacity)); + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + retrieve_data_from_hint_database(HintDataNavigation::Next); + } + ImGui::PushStyleColor(ImGuiCol_Text, button_text_color.Value);// for icon-font button + imgui.button(button_text.c_str()); + ImGui::PopStyleColor(); + + ImGui::PopStyleColor(4); + } + ImGui::EndChild(); +} + +void DailyTipsPanel::push_styles() +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + float scale = imgui.get_font_size() / 15.0f; + imgui.push_common_window_style(scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + // framePadding cannot be zero. Otherwise, there is a problem with icon font button display + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1.0f, 1.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 4.0f * scale); + ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, m_is_dark ? ImGuiWrapper::COL_WINDOW_BG_DARK : ImGuiWrapper::COL_WINDOW_BG); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f)); +} + +void DailyTipsPanel::pop_styles() +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.pop_common_window_style(); + ImGui::PopStyleVar(6); + ImGui::PopStyleColor(4); +} + + +DailyTipsWindow::DailyTipsWindow() +{ + m_panel = new DailyTipsPanel(false, DailyTipsLayout::Vertical); +} + +void DailyTipsWindow::open() +{ + m_show = true; + m_panel->retrieve_data_from_hint_database(HintDataNavigation::Curr); +} + +void DailyTipsWindow::close() +{ + m_show = false; +} + +void DailyTipsWindow::render() +{ + if (!m_show) + return; + //if (m_show) + // ImGui::OpenPopup((_u8L("Daily Tips")).c_str()); + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + float scale = imgui.get_font_size() / 15.0f; + + const Size& cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size(); + ImVec2 center = ImVec2(cnv_size.get_width() * 0.5f, cnv_size.get_height() * 0.5f); + ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + + ImVec2 padding = ImVec2(25, 25) * scale; + imgui.push_menu_style(scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, padding); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 3) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 7) * scale); + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, m_is_dark ? ImVec4(54 / 255.0f, 54 / 255.0f, 60 / 255.0f, 1.00f) : ImVec4(245 / 255.0f, 245 / 255.0f, 245 / 255.0f, 1.00f)); + ImGui::GetCurrentContext()->DimBgRatio = 1.0f; + int windows_flag = + ImGuiWindowFlags_NoCollapse + | ImGuiWindowFlags_AlwaysAutoResize + | ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoScrollbar + | ImGuiWindowFlags_NoScrollWithMouse; + imgui.push_bold_font(); + //if (ImGui::BeginPopupModal((_u8L("Daily Tips")).c_str(), NULL, windows_flag)) + if (ImGui::Begin((_u8L("Daily Tips")).c_str(), &m_show, windows_flag)) + { + imgui.pop_bold_font(); + + ImVec2 panel_pos = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin(); + ImVec2 panel_size = ImVec2(400.0f, 435.0f) * scale; + m_panel->set_position(panel_pos); + m_panel->set_size(panel_size); + m_panel->render(); + + if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) { + m_show = false; + ImGui::CloseCurrentPopup(); + } + ImGui::End(); + //ImGui::EndPopup(); + } + else { + imgui.pop_bold_font(); + } + ImGui::PopStyleVar(4); + ImGui::PopStyleColor(); + imgui.pop_menu_style(); +} + +void DailyTipsWindow::on_change_color_mode(bool is_dark) +{ + m_is_dark = is_dark; + m_panel->on_change_color_mode(is_dark); +} + +}} \ No newline at end of file diff --git a/src/slic3r/GUI/DailyTips.hpp b/src/slic3r/GUI/DailyTips.hpp new file mode 100644 index 00000000000..508a8ad7e92 --- /dev/null +++ b/src/slic3r/GUI/DailyTips.hpp @@ -0,0 +1,74 @@ +#ifndef slic3r_GUI_DailyTips_hpp_ +#define slic3r_GUI_DailyTips_hpp_ + +#include "HintNotification.hpp" + +//#include +#include +#include +#include + +namespace Slic3r { namespace GUI { + +enum class DailyTipsLayout{ + Horizontal, + Vertical +}; + +class DailyTipsDataRenderer; +class DailyTipsPanel { + static int uid; +public: + DailyTipsPanel(bool can_expand = true, DailyTipsLayout layout = DailyTipsLayout::Vertical); + void set_position(const ImVec2& pos); + void set_size(const ImVec2& size); + void set_can_expand(bool can_expand); + ImVec2 get_size(); + void render(); + void retrieve_data_from_hint_database(HintDataNavigation nav); + void expand(bool expand = true); + void collapse(); + bool is_expanded(); + void on_change_color_mode(bool is_dark); + void set_fade_opacity(float opacity); + +protected: + void render_controller_buttons(const ImVec2& pos, const ImVec2& size); + void push_styles(); + void pop_styles(); + +private: + std::unique_ptr m_dailytips_renderer; + size_t m_page_index{ 0 }; + int m_pages_count; + bool m_is_expanded{ true }; + bool m_can_expand{ true }; + ImVec2 m_pos; + float m_width; + float m_height; + float m_content_height; + float m_footer_height; + int m_uid; + bool m_first_enter{ false }; + bool m_is_dark{ false }; + DailyTipsLayout m_layout{ DailyTipsLayout::Vertical }; + float m_fade_opacity{ 1.0f }; +}; + +class DailyTipsWindow { +public: + DailyTipsWindow(); + void open(); + void close(); + void render(); + void on_change_color_mode(bool is_dark); + +private: + DailyTipsPanel* m_panel{ nullptr }; + bool m_show{ false }; + bool m_is_dark{ false }; +}; + +}} + +#endif \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 0977a08da54..6aff1dff5cc 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -8,6 +8,7 @@ #include "MsgDialog.hpp" #include "Plater.hpp" #include "GUI_App.hpp" +#include "ReleaseNote.hpp" #include #include #include @@ -28,7 +29,7 @@ float string_to_float(const std::string& str_value) { return value; } -const int PRINTING_STAGE_COUNT = 32; +const int PRINTING_STAGE_COUNT = 36; std::string PRINTING_STAGE_STR[PRINTING_STAGE_COUNT] = { "printing", "bed_leveling", @@ -61,7 +62,11 @@ std::string PRINTING_STAGE_STR[PRINTING_STAGE_COUNT] = { "chamber_temperature_control_error_pause", "chamber_cooling", "user_insert_gcode_pause", - "motor_noise_showoff" + "motor_noise_showoff", + "nozzle_filament_covered_detected_pause", + "cutter_error_pause", + "first_layer_error_pause", + "nozzle_clog_pause" }; @@ -136,6 +141,14 @@ wxString get_stage_string(int stage) return _L("Paused by the Gcode inserted by user"); case 31: return _L("Motor noise showoff"); + case 32: + return _L("Nozzle filament covered detected pause"); + case 33: + return _L("Cutter error pause"); + case 34: + return _L("First layer error pause"); + case 35: + return _L("Nozzle clog pause"); default: ; } @@ -363,14 +376,13 @@ std::string MachineObject::parse_printer_type(std::string type_str) return "BL-P001"; } else if (type_str.compare("BL-P001") == 0) { return type_str; - } else if (type_str.compare("BL-P003") == 0) { + } else if (type_str.compare("BL-P002") == 0) { return type_str; } else { return DeviceManager::parse_printer_type(type_str); } return ""; } - std::string MachineObject::get_preset_printer_model_name(std::string printer_type) { return DeviceManager::get_printer_display_name(printer_type); @@ -383,7 +395,7 @@ std::string MachineObject::get_preset_printer_thumbnail_img(std::string printer_ wxString MachineObject::get_printer_type_display_str() { - std::string display_name = get_preset_printer_model_name(printer_type); + std::string display_name = get_preset_printer_model_name(printer_type); if (!display_name.empty()) return display_name; else @@ -393,10 +405,22 @@ wxString MachineObject::get_printer_type_display_str() std::string MachineObject::get_printer_thumbnail_img_str() { std::string img_str = get_preset_printer_thumbnail_img(printer_type); - if (!img_str.empty()) - return img_str; - else - return "printer_thumbnail"; + std::string img_url; + + if (!img_str.empty()) { + img_url = Slic3r::resources_dir() + "\\printers\\image\\" + img_str; + if (fs::exists(img_url + ".svg")) { + return img_url; + } + else { + img_url = img_str; + } + } + else { + img_url = "printer_thumbnail"; + } + + return img_url; } std::string MachineObject::get_ftp_folder() @@ -404,7 +428,6 @@ std::string MachineObject::get_ftp_folder() return DeviceManager::get_ftp_folder(printer_type); } - std::string MachineObject::get_access_code() { if (get_user_access_code().empty()) @@ -438,7 +461,7 @@ void MachineObject::set_user_access_code(std::string code, bool only_refresh) this->user_access_code = code; if (only_refresh && !code.empty()) { AppConfig* config = GUI::wxGetApp().app_config; - if (config) { + if (config && !code.empty()) { GUI::wxGetApp().app_config->set_str("user_access_code", dev_id, code); } } @@ -461,16 +484,12 @@ bool MachineObject::is_lan_mode_printer() return result; } -bool MachineObject::is_high_printer_type() -{ - return get_printer_series() == PrinterSeries::SERIES_X1; -} - PrinterSeries MachineObject::get_printer_series() const { - if (printer_type == "BL-P001" || printer_type == "BL-P002" || printer_type == "C13") + std::string series = DeviceManager::get_printer_series(printer_type); + if (series == "series_x1") return PrinterSeries::SERIES_X1; - else if (printer_type == "C11" || printer_type == "C12") + else if (series == "series_p1p") return PrinterSeries::SERIES_P1P; else return PrinterSeries::SERIES_P1P; @@ -481,16 +500,20 @@ PrinterArch MachineObject::get_printer_arch() const return DeviceManager::get_printer_arch(printer_type); } -//BBS: check if machine is enclosed -bool MachineObject::is_printer_enclosed() const +std::string MachineObject::get_printer_ams_type() const { - std::unordered_setenclosed_printers = { - "C12", - "BL-P002", - "BL-P001", - "C13" - }; - return enclosed_printers.find(printer_type) != enclosed_printers.end(); + return DeviceManager::get_printer_ams_type(printer_type); +} + +bool MachineObject::get_printer_is_enclosed() const +{ + return DeviceManager::get_printer_is_enclosed(printer_type); +} + +void MachineObject::reload_printer_settings() +{ + print_json.load_compatible_settings("", ""); + parse_json("{}"); } MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string id, std::string ip) @@ -747,89 +770,11 @@ bool MachineObject::can_unload_filament() return result; } -bool MachineObject::is_U0_firmware() -{ - auto ota_ver_it = module_vers.find("ota"); - if (ota_ver_it != module_vers.end()) { - if (ota_ver_it->second.sw_ver.compare("00.01.04.00") < 0) - return true; - } - return false; -} - bool MachineObject::is_support_ams_mapping() { - if (get_printer_series() == PrinterSeries::SERIES_X1 && printer_type != "C13") { - AppConfig* config = Slic3r::GUI::wxGetApp().app_config; - if (config) { - if (config->get("check_ams_version") == "0") - return true; - } - bool need_upgrade = false; - if (has_ams()) { - // compare ota version and ams version - auto ota_ver_it = module_vers.find("ota"); - if (ota_ver_it != module_vers.end()) { - if (!MachineObject::is_support_ams_mapping_version("ota", ota_ver_it->second.sw_ver)) { - need_upgrade = true; - } - } - for (int i = 0; i < 4; i++) { - std::string ams_id = (boost::format("ams/%1%") % i).str(); - auto ams_ver_it = module_vers.find(ams_id); - if (ams_ver_it != module_vers.end()) { - if (!MachineObject::is_support_ams_mapping_version("ams", ams_ver_it->second.sw_ver)) { - need_upgrade = true; - } - } - } - } - return !need_upgrade; - } - else { - return true; - } -} - -bool MachineObject::is_support_command_ams_switch() -{ - auto ota_ver_it = module_vers.find("ota"); - if (ota_ver_it != module_vers.end()) { - if (printer_type == "BL-P001" || printer_type == "BL-P002") { - - if (ota_ver_it->second.sw_ver.compare("01.05.06.01") < 0) { - return false; - } - - }else if (printer_type == "C11" || printer_type == "C12") { - - if (ota_ver_it->second.sw_ver.compare("01.02.99.10") < 0) { - return false; - } - } - } - return true; } -bool MachineObject::is_support_ams_mapping_version(std::string module, std::string version) -{ - bool result = true; - - if (module == "ota") { - if (version.compare("00.01.04.03") < 0) - return false; - } - else if (module == "ams") { - // omit ams version is empty - if (version.empty()) - return true; - if (version.compare("00.00.04.10") < 0) - return false; - } - return result; -} - static float calc_color_distance(wxColour c1, wxColour c2) { float lab[2][3]; @@ -862,6 +807,7 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std info.color = tray->second->color; info.type = tray->second->get_filament_type(); info.id = tray_index; + info.filament_id=tray->second->setting_id; tray_filaments.emplace(std::make_pair(tray_index, info)); } } @@ -979,14 +925,28 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std if (picked_src.find(i) != picked_src.end()) continue; for (int j = 0; j < distance_map[i].size(); j++) { - if (picked_tar.find(j) != picked_tar.end()) + if (picked_tar.find(j) != picked_tar.end()){ + if (distance_map[i][j].is_same_color + && distance_map[i][j].is_type_match + && distance_map[i][j].distance < (float)0.0001) { + min_val = distance_map[i][j].distance; + picked_src_idx = i; + picked_tar_idx = j; + } continue; + } + if (distance_map[i][j].is_same_color && distance_map[i][j].is_type_match) { if (min_val > distance_map[i][j].distance) { + min_val = distance_map[i][j].distance; picked_src_idx = i; picked_tar_idx = j; + } + else if (min_val == distance_map[i][j].distance && filaments[i].filament_id == tray_filaments[j].filament_id) { + picked_src_idx = i; + picked_tar_idx = j; } } } @@ -998,6 +958,7 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std result[picked_src_idx].color = tray->second.color; result[picked_src_idx].type = tray->second.type; result[picked_src_idx].distance = tray->second.distance; + result[picked_src_idx].filament_id = tray->second.filament_id; } else { FilamentInfo info; @@ -1404,6 +1365,19 @@ void MachineObject::parse_status(int flag) xcam_allow_prompt_sound = ((flag >> 17) & 0x1) != 0; } + is_support_filament_tangle_detect = ((flag >> 19) & 0x1) != 0; + + if (xcam_filament_tangle_detect_count > 0) + xcam_filament_tangle_detect_count--; + else { + xcam_filament_tangle_detect = ((flag >> 20) & 0x1) != 0; + } + + if(!is_support_motor_noise_cali){ + is_support_motor_noise_cali = ((flag >> 21) & 0x1) != 0; + } + + sdcard_state = MachineObject::SdcardState((flag >> 8) & 0x11); network_wired = ((flag >> 18) & 0x1) != 0; @@ -1426,8 +1400,7 @@ int MachineObject::get_bed_temperature_limit() return 120; } } else { - int limit = BED_TEMP_LIMIT; - DeviceManager::get_bed_temperature_limit(printer_type, limit); + int limit = bed_temperature_limit < 0?BED_TEMP_LIMIT:bed_temperature_limit; return limit; } return BED_TEMP_LIMIT; @@ -1478,130 +1451,23 @@ bool MachineObject::is_recording() return camera_recording; } -void MachineObject::parse_version_func() +std::string MachineObject::parse_version() { auto ota_version = module_vers.find("ota"); - auto esp32_version = module_vers.find("esp32"); - auto rv1126_version = module_vers.find("rv1126"); - if (get_printer_series() == PrinterSeries::SERIES_X1) { - if (ota_version != module_vers.end()) { - - if (printer_type != "C13") { - if (ota_version->second.sw_ver.compare("01.01.01.00") <= 0) { - ams_support_remain = false; - ams_support_auto_switch_filament_flag = false; - is_xcam_buildplate_supported = false; - xcam_support_recovery_step_loss = false; - is_support_send_to_sdcard = false; - is_support_1080dpi = false; - is_support_ai_monitoring = false; - is_support_ams_humidity = false; - } - else { - ams_support_remain = true; - ams_support_auto_switch_filament_flag = true; - is_xcam_buildplate_supported = true; - xcam_support_recovery_step_loss = true; - is_support_send_to_sdcard = true; - is_support_1080dpi = true; - is_support_ai_monitoring = true; - is_support_ams_humidity = true; - } - - if (ota_version != module_vers.end()) { - if (firmware_type == PrinterFirmwareType::FIRMWARE_TYPE_PRODUCTION) { - local_use_ssl_for_mqtt = ota_version->second.sw_ver.compare("01.03.01.04") >= 0; - } - - if (lifecycle == PrinterFirmwareType::FIRMWARE_TYPE_PRODUCTION) { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("01.05.06.05") >= 0; - } - else if (lifecycle == PrinterFirmwareType::FIRMWARE_TYPE_ENGINEER) { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("00.03.10.05") >= 0; - } - else { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("01.05.06.05") >= 0; - } - - is_support_remote_tunnel = true; - is_support_tunnel_mqtt = (ota_version->second.sw_ver.compare("01.05.06.06") >= 0 - || (rv1126_version != module_vers.end() && rv1126_version->second.sw_ver.compare("00.00.21.20") >= 0)); - } - local_camera_proto = local_rtsp_url.empty() ? -1 : local_rtsp_url == "disable" ? 0 - : boost::algorithm::starts_with(local_rtsp_url, "rtsps") ? 2 : 3; - file_proto = 2; - } - else { - ams_support_remain = true; - ams_support_auto_switch_filament_flag = true; - is_xcam_buildplate_supported = true; - xcam_support_recovery_step_loss = true; - is_support_send_to_sdcard = true; - is_support_1080dpi = true; - is_support_ai_monitoring = true; - is_support_ams_humidity = true; - is_support_mqtt_alive = true; - local_use_ssl_for_mqtt = true; - is_support_remote_tunnel = true; - is_support_tunnel_mqtt = true; - local_camera_proto = local_rtsp_url.empty() ? -1 : local_rtsp_url == "disable" ? 0 - : boost::algorithm::starts_with(local_rtsp_url, "rtsps") ? 2 : 3; - file_proto = 2; - } - } - } else if (printer_type == "C11") { - is_cloud_print_only = true; - if (ota_version != module_vers.end()) { - is_support_send_to_sdcard = ota_version->second.sw_ver.compare("01.02.00.00") >= 0; - is_support_ai_monitoring = ota_version->second.sw_ver.compare("01.02.99.00") >= 0; - is_support_remote_tunnel = ota_version->second.sw_ver.compare("01.02.99.00") >= 0; - is_support_tunnel_mqtt = (ota_version->second.sw_ver.compare("01.03.50.01") >= 0 || - (esp32_version != module_vers.end() && esp32_version->second.sw_ver.compare("01.05.15.00") >= 0)); - } - local_camera_proto = 1; - - if (esp32_version != module_vers.end()) { - ams_support_auto_switch_filament_flag = esp32_version->second.sw_ver.compare("00.03.11.50") >= 0; - } - - if (ota_version != module_vers.end()) { - if (lifecycle == PrinterFirmwareType::FIRMWARE_TYPE_PRODUCTION) { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("01.03.50.01") >= 0; - } - else if (lifecycle == PrinterFirmwareType::FIRMWARE_TYPE_ENGINEER) { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("00.06.03.51") >= 0; - } - else { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("01.03.50.01") >= 0; - } - } - } else if (printer_type == "C12") { - is_support_ai_monitoring = true; - is_cloud_print_only = true; - local_camera_proto = 1; - - if (ota_version != module_vers.end()) { - is_support_tunnel_mqtt = (ota_version->second.sw_ver.compare("01.03.50.01") >= 0 || - (esp32_version != module_vers.end() && esp32_version->second.sw_ver.compare("01.05.15.00") >= 0)); - is_support_remote_tunnel = ota_version->second.sw_ver.compare("01.03.50.01") >= 0; - if (lifecycle == PrinterFirmwareType::FIRMWARE_TYPE_PRODUCTION) { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("01.03.50.01") >= 0; - } - else if (lifecycle == PrinterFirmwareType::FIRMWARE_TYPE_ENGINEER) { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("00.06.03.51") >= 0; - } - else { - is_support_mqtt_alive = ota_version->second.sw_ver.compare("01.03.50.01") >= 0; - } - } - } else if (printer_type == "N1") { - is_support_remote_tunnel = true; - local_camera_proto = 1; - is_support_tunnel_mqtt = true; - is_support_ams_humidity = false; - is_support_1080dpi = true; - ams_support_remain = false; + if (ota_version != module_vers.end()) return ota_version->second.sw_ver; + auto series = get_printer_series(); + if (series == PrinterSeries::SERIES_X1) { + auto rv1126_version = module_vers.find("rv1126"); + if (rv1126_version != module_vers.end()) return rv1126_version->second.sw_ver; + } else if (series == PrinterSeries::SERIES_P1P) { + auto esp32_version = module_vers.find("esp32"); + if (esp32_version != module_vers.end()) return esp32_version->second.sw_ver; } + return ""; +} + +void MachineObject::parse_version_func() +{ } bool MachineObject::is_studio_cmd(int sequence_id) @@ -1623,6 +1489,16 @@ int MachineObject::command_get_version(bool with_retry) return this->publish_json(j.dump(), 1); } +int MachineObject::command_get_access_code() { + BOOST_LOG_TRIVIAL(info) << "command_get_access_code"; + json j; + j["system"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["system"]["command"] = "get_access_code"; + + return this->publish_json(j.dump()); +} + + int MachineObject::command_request_push_all(bool request_now) { auto curr_time = std::chrono::system_clock::now(); @@ -1764,6 +1640,7 @@ int MachineObject::command_control_fan_val(FanType fan_type, int val) int MachineObject::command_task_abort() { + BOOST_LOG_TRIVIAL(trace) << "command_task_abort: "; json j; j["print"]["command"] = "stop"; j["print"]["param"] = ""; @@ -1772,6 +1649,18 @@ int MachineObject::command_task_abort() return this->publish_json(j.dump(), 1); } +int MachineObject::command_task_cancel(std::string job_id) +{ + BOOST_LOG_TRIVIAL(trace) << "command_task_cancel: " << job_id; + json j; + j["print"]["command"] = "stop"; + j["print"]["param"] = ""; + j["print"]["job_id"] = job_id; + j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + + return this->publish_json(j.dump(), 1); +} + int MachineObject::command_task_pause() { json j; @@ -1817,17 +1706,16 @@ int MachineObject::command_set_chamber(int temp) int MachineObject::command_ams_switch(int tray_index, int old_temp, int new_temp) { BOOST_LOG_TRIVIAL(trace) << "ams_switch to " << tray_index << " with temp: " << old_temp << ", " << new_temp; - if (old_temp < 0) old_temp = FILAMENT_DEF_TEMP; if (new_temp < 0) new_temp = FILAMENT_DEF_TEMP; - int result = 0; + std::string gcode = ""; + int result = 0; //command - if (is_support_command_ams_switch()) { + if (is_support_command_ams_switch) { command_ams_change_filament(tray_index, old_temp, new_temp); } - //gcode else { std::string gcode = ""; if (tray_index == 255) { @@ -1967,6 +1855,20 @@ int MachineObject::command_set_chamber_light(LIGHT_EFFECT effect, int on_time, i return this->publish_json(j.dump()); } + +int MachineObject::command_set_printer_nozzle(std::string nozzle_type, float diameter) +{ + BOOST_LOG_TRIVIAL(info) << "command_set_printer_nozzle, nozzle_type = " << nozzle_type << " diameter = " << diameter; + json j; + j["system"]["command"] = "set_accessories"; + j["system"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["system"]["accessory_type"] = "nozzle"; + j["system"]["nozzle_type"] = nozzle_type; + j["system"]["nozzle_diameter"] = diameter; + return this->publish_json(j.dump()); +} + + int MachineObject::command_set_work_light(LIGHT_EFFECT effect, int on_time, int off_time, int loops, int interval) { json j; @@ -2065,6 +1967,15 @@ int MachineObject::command_set_prompt_sound(bool prompt_sound){ return this->publish_json(j.dump()); } +int MachineObject::command_set_filament_tangle_detect(bool filament_tangle_detect) { + json j; + j["print"]["command"] = "print_option"; + j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["print"]["filament_tangle_detect"] = filament_tangle_detect; + + return this->publish_json(j.dump()); +} + int MachineObject::command_ams_switch_filament(bool switch_filament) { json j; @@ -2104,13 +2015,6 @@ int MachineObject::command_axis_control(std::string axis, double unit, double in return -1; } - try { - json j; - j["axis_control"] = axis; - - NetworkAgent* agent = GUI::wxGetApp().getAgent(); - } - catch (...) {} return this->publish_gcode(cmd); } @@ -2316,8 +2220,7 @@ int MachineObject::command_get_flow_ratio_calibration_result(float nozzle_diamet int MachineObject::command_unload_filament() { - if (get_printer_series() == PrinterSeries::SERIES_X1 - && !this->is_function_supported(PrinterFunction::FUNC_VIRTUAL_TYAY)) { + if (get_printer_series() == PrinterSeries::SERIES_X1 && !ams_support_virtual_tray) { // fixed gcode file json j; j["print"]["command"] = "gcode_file"; @@ -2325,10 +2228,7 @@ int MachineObject::command_unload_filament() j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); return this->publish_json(j.dump()); } - else if (printer_type == "C11" - || (get_printer_series() == PrinterSeries::SERIES_X1 - && this->is_function_supported(PrinterFunction::FUNC_VIRTUAL_TYAY)) - ) { + else if (get_printer_series() == PrinterSeries::SERIES_P1P || (get_printer_series() == PrinterSeries::SERIES_X1 && ams_support_virtual_tray) ) { std::string gcode = DeviceManager::load_gcode(printer_type, "ams_unload.gcode"); if (gcode.empty()) { return -1; @@ -2444,6 +2344,13 @@ int MachineObject::command_xcam_control_allow_prompt_sound(bool on_off) return command_set_prompt_sound(on_off); } +int MachineObject::command_xcam_control_filament_tangle_detect(bool on_off) +{ + xcam_filament_tangle_detect = on_off; + xcam_filament_tangle_detect_count = HOLD_COUNT_MAX; + return command_set_filament_tangle_detect(on_off); +} + void MachineObject::set_bind_status(std::string status) { bind_user_name = status; @@ -2539,6 +2446,7 @@ void MachineObject::reset_update_time() { BOOST_LOG_TRIVIAL(trace) << "reset reset_update_time, dev_id =" << dev_id; last_update_time = std::chrono::system_clock::now(); + subscribe_counter = 3; } void MachineObject::reset() @@ -2558,11 +2466,13 @@ void MachineObject::reset() print_status = ""; last_mc_print_stage = -1; m_new_ver_list_exist = false; - m_is_support_show_bak = false; extruder_axis_status = LOAD; nozzle_diameter = 0.0f; network_wired = false; dev_connection_name = ""; + subscribe_counter = 3; + job_id_ = ""; + m_plate_index = -1; // reset print_json json empty_j; @@ -2579,11 +2489,6 @@ void MachineObject::set_print_state(std::string status) print_status = status; } -std::vector MachineObject::get_compatible_machine() -{ - return DeviceManager::get_compatible_machine(printer_type); -} - int MachineObject::connect(bool is_anonymous, bool use_openssl) { if (dev_ip.empty()) return -1; @@ -2653,161 +2558,24 @@ bool MachineObject::is_info_ready() return false; } -bool MachineObject::is_function_supported(PrinterFunction func) -{ - std::string func_name; - switch (func) { - case FUNC_MONITORING: - func_name = "FUNC_MONITORING"; - break; - case FUNC_TIMELAPSE: - func_name = "FUNC_TIMELAPSE"; - break; - case FUNC_RECORDING: - func_name = "FUNC_RECORDING"; - break; - case FUNC_FIRSTLAYER_INSPECT: - func_name = "FUNC_FIRSTLAYER_INSPECT"; - break; - case FUNC_AI_MONITORING: - parse_version_func(); - if (!is_support_ai_monitoring) - return false; - func_name = "FUNC_AI_MONITORING"; - break; - case FUNC_LIDAR_CALIBRATION: - func_name = "FUNC_LIDAR_CALIBRATION"; - break; - case FUNC_BUILDPLATE_MARKER_DETECT: - parse_version_func(); - if (!is_xcam_buildplate_supported) - return false; - func_name = "FUNC_BUILDPLATE_MARKER_DETECT"; - break; - case FUNC_AUTO_RECOVERY_STEP_LOSS: - parse_version_func(); - if (!xcam_support_recovery_step_loss) - return false; - func_name = "FUNC_AUTO_RECOVERY_STEP_LOSS"; - break; - case FUNC_FLOW_CALIBRATION: - func_name = "FUNC_FLOW_CALIBRATION"; - break; - case FUNC_AUTO_LEVELING: - func_name = "FUNC_AUTO_LEVELING"; - break; - case FUNC_CHAMBER_TEMP: - func_name = "FUNC_CHAMBER_TEMP"; - break; - case FUNC_CAMERA_VIDEO: - func_name = "FUNC_CAMERA_VIDEO"; - break; - case FUNC_MEDIA_FILE: - func_name = "FUNC_MEDIA_FILE"; - break; - case FUNC_PROMPT_SOUND: - func_name = "FUNC_PROMPT_SOUND"; - break; - case FUNC_REMOTE_TUNNEL: - parse_version_func(); - if (!is_support_remote_tunnel) - return false; - break; - case FUNC_LOCAL_TUNNEL: - parse_version_func(); - if (!local_camera_proto) return false; - break; - case FUNC_PRINT_WITHOUT_SD: - func_name = "FUNC_PRINT_WITHOUT_SD"; - break; - case FUNC_USE_AMS: - func_name = "FUNC_USE_AMS"; - break; - case FUNC_ALTER_RESOLUTION: - func_name = "FUNC_ALTER_RESOLUTION"; - break; - case FUNC_SEND_TO_SDCARD: - parse_version_func(); - if (!is_support_send_to_sdcard) - return false; - func_name = "FUNC_SEND_TO_SDCARD"; - break; - case FUNC_AUTO_SWITCH_FILAMENT: - parse_version_func(); - if (!ams_support_auto_switch_filament_flag) - return false; - func_name = "FUNC_AUTO_SWITCH_FILAMENT"; - break; - case FUNC_VIRTUAL_CAMERA: - func_name = "FUNC_VIRTUAL_CAMERA"; - break; - case FUNC_CHAMBER_FAN: - func_name = "FUNC_CHAMBER_FAN"; - break; - case FUNC_AUX_FAN: - func_name = "FUNC_AUX_FAN"; - break; - case FUNC_EXTRUSION_CALI: - if (!ams_support_virtual_tray) - return false; - func_name = "FUNC_EXTRUSION_CALI"; - break; - case FUNC_PRINT_ALL: - func_name = "FUNC_PRINT_ALL"; - break; - case FUNC_VIRTUAL_TYAY: - if (!ams_support_virtual_tray) - return false; - func_name = "FUNC_VIRTUAL_TYAY"; - break; - case FUNC_FILAMENT_BACKUP: - func_name = "FUNC_FILAMENT_BACKUP"; - break; - case FUNC_MOTOR_NOISE_CALI: - func_name = "FUNC_MOTOR_NOISE_CALI"; - break; - default: - return true; - } - return DeviceManager::is_function_supported(printer_type, func_name); -} std::vector MachineObject::get_resolution_supported() { - return DeviceManager::get_resolution_supported(printer_type); + return camera_resolution_supported; } -bool MachineObject::is_support_print_with_timelapse() +std::vector MachineObject::get_compatible_machine() { - //TODO version check, set true by default - return true; + return DeviceManager::get_compatible_machine(printer_type); } bool MachineObject::is_camera_busy_off() { - if (printer_type == "C11" || printer_type == "C12" || printer_type == "N1") + if (get_printer_series() == PrinterSeries::SERIES_P1P) return is_in_prepare() || is_in_upgrading(); return false; } -int MachineObject::get_local_camera_proto() -{ - if (!is_function_supported(PrinterFunction::FUNC_LOCAL_TUNNEL)) return 0; - return local_camera_proto; -} - -bool MachineObject::has_local_file_proto() -{ - parse_version_func(); - return file_proto & 1; -} - -bool MachineObject::has_remote_file_proto() -{ - parse_version_func(); - return file_proto & 2; -} - int MachineObject::publish_json(std::string json_str, int qos) { if (is_lan_mode_printer()) { @@ -2838,12 +2606,11 @@ int MachineObject::local_publish_json(std::string json_str, int qos) std::string MachineObject::setting_id_to_type(std::string setting_id, std::string tray_type) { std::string type; - PresetBundle* preset_bundle = GUI::wxGetApp().preset_bundle; if (preset_bundle) { for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { - if (it->filament_id.compare(setting_id) == 0) { + if (it->filament_id.compare(setting_id) == 0 && it->is_system) { std::string display_filament_type; it->config.get_filament_type(display_filament_type); type = display_filament_type; @@ -2853,13 +2620,21 @@ std::string MachineObject::setting_id_to_type(std::string setting_id, std::strin } if (tray_type != type || type.empty()) { - if (type.empty()) {type = tray_type;} - BOOST_LOG_TRIVIAL(info) << "The values of tray_info_idx and tray_type do not match tray_info_idx " << setting_id << " tray_type " << tray_type; + if (type.empty()) { type = tray_type; } + BOOST_LOG_TRIVIAL(info) << "The values of tray_info_idx and tray_type do not match tray_info_idx " << setting_id << " tray_type " << tray_type << " system_type" << type; } return type; } +template +static ENUM enum_index_of(char const *key, char const **enum_names, int enum_count, ENUM defl = static_cast(0)) +{ + for (int i = 0; i < enum_count; ++i) + if (strcmp(enum_names[i], key) == 0) return static_cast(i); + return defl; +} + int MachineObject::parse_json(std::string payload) { CNumericLocalesSetter locales_setter; @@ -2867,7 +2642,9 @@ int MachineObject::parse_json(std::string payload) parse_msg_count++; std::chrono::system_clock::time_point clock_start = std::chrono::system_clock::now(); this->set_online_state(true); - if (m_active_state == NotActive) m_active_state = Active; + + std::chrono::system_clock::time_point curr_time = std::chrono::system_clock::now(); + auto diff1 = std::chrono::duration_cast(curr_time - last_update_time); /* update last received time */ last_update_time = std::chrono::system_clock::now(); @@ -2881,12 +2658,15 @@ int MachineObject::parse_json(std::string payload) } if (j_pre.contains("print")) { + if (m_active_state == NotActive) m_active_state = Active; if (j_pre["print"].contains("command")) { if (j_pre["print"]["command"].get() == "push_status") { if (j_pre["print"].contains("msg")) { if (j_pre["print"]["msg"].get() == 0) { //all message BOOST_LOG_TRIVIAL(trace) << "static: get push_all msg, dev_id=" << dev_id; m_push_count++; + if (!printer_type.empty()) + print_json.load_compatible_settings(printer_type, ""); print_json.diff2all_base_reset(j_pre); } else if (j_pre["print"]["msg"].get() == 1) { //diff message if (print_json.diff2all(j_pre, j) == 0) { @@ -2907,30 +2687,278 @@ int MachineObject::parse_json(std::string payload) BOOST_LOG_TRIVIAL(warning) << "unsupported msg_type=" << j_pre["print"]["msg"].get(); } } + else { + if (!printer_type.empty() && connection_type() == "lan") + print_json.load_compatible_settings(printer_type, ""); + print_json.diff2all_base_reset(j_pre); + } + } + } + } + if (j_pre.contains("system")) { + if (j_pre["system"].contains("command")) { + if (j_pre["system"]["command"].get() == "get_access_code") { + if (j_pre["system"].contains("access_code")) { + std::string access_code = j_pre["system"]["access_code"].get(); + if (!access_code.empty()) { + set_access_code(access_code); + } + } + } + } + } + if (!restored_json) { + j = j_pre; + } + + uint64_t t_utc = j.value("t_utc", 0ULL); + if (t_utc > 0) + last_update_time = std::chrono::system_clock::time_point(t_utc * 1ms); + + BOOST_LOG_TRIVIAL(trace) << "parse_json: dev_id=" << dev_id << ", playload=" << j.dump(4); + + // Parse version info first, as if version arrive or change, 'print' need parse again with new compatible settings + try { + if (j.contains("info")) { + if (j["info"].contains("command") && j["info"]["command"].get() == "get_version") { + json j_module = j["info"]["module"]; + module_vers.clear(); + for (auto it = j_module.begin(); it != j_module.end(); it++) { + ModuleVersionInfo ver_info; + ver_info.name = (*it)["name"].get(); + if ((*it).contains("sw_ver")) + ver_info.sw_ver = (*it)["sw_ver"].get(); + if ((*it).contains("sn")) + ver_info.sn = (*it)["sn"].get(); + if ((*it).contains("hw_ver")) + ver_info.hw_ver = (*it)["hw_ver"].get(); + module_vers.emplace(ver_info.name, ver_info); + if (ver_info.name == "ota") { + NetworkAgent* agent = GUI::wxGetApp().getAgent(); + if (agent) agent->track_update_property("dev_ota_ver", ver_info.sw_ver); + } + } + + parse_version_func(); + + bool get_version_result = true; + if (j["info"].contains("result")) + if (j["info"]["result"].get() == "fail") + get_version_result = false; + if ((!check_version_valid() && get_version_retry-- >= 0) + && get_version_result) { + BOOST_LOG_TRIVIAL(info) << "get_version_retry = " << get_version_retry; + boost::thread retry = boost::thread([this] { + boost::this_thread::sleep_for(boost::chrono::milliseconds(RETRY_INTERNAL)); + GUI::wxGetApp().CallAfter([this] { + this->command_get_version(false); + }); + }); + } + } + std::string version = parse_version(); + if (!version.empty() && print_json.load_compatible_settings(printer_type, version)) { + // reload because compatible settings changed + j.clear(); + print_json.diff2all(json{}, j); + } + + } + } catch (...) {} + + + if (j.contains("print")) { + json jj = j["print"]; + int sequence_id = 0; + if (jj.contains("sequence_id")) { + if (jj["sequence_id"].is_string()) { + std::string str_seq = jj["sequence_id"].get(); + try { + sequence_id = stoi(str_seq); + } + catch(...) { + ; + } + } + } + + + //supported function + if (jj.contains("support_chamber_temp_edit")) { + if (jj["support_chamber_temp_edit"].is_boolean()) { + is_support_chamber_edit = jj["support_chamber_temp_edit"].get(); + } + } + + if (jj.contains("support_extrusion_cali")) { + if (jj["support_extrusion_cali"].is_boolean()) { + is_support_extrusion_cali = jj["support_extrusion_cali"].get(); + } + } + + if (jj.contains("support_first_layer_inspect")) { + if (jj["support_first_layer_inspect"].is_boolean()) { + is_support_first_layer_inspect = jj["support_first_layer_inspect"].get(); + } + } + + if (jj.contains("support_ai_monitoring")) { + if (jj["support_ai_monitoring"].is_boolean()) { + is_support_ai_monitoring = jj["support_ai_monitoring"].get(); + } + } + + if (jj.contains("support_lidar_calibration")) { + if (jj["support_lidar_calibration"].is_boolean()) { + is_support_lidar_calibration = jj["support_lidar_calibration"].get(); + } + } + + if (jj.contains("support_build_plate_marker_detect")) { + if (jj["support_build_plate_marker_detect"].is_boolean()) { + is_support_build_plate_marker_detect = jj["support_build_plate_marker_detect"].get(); + } + } + + if (jj.contains("support_flow_calibration")) { + if (jj["support_flow_calibration"].is_boolean()) { + is_support_flow_calibration = jj["support_flow_calibration"].get(); + } + } + + if (jj.contains("support_print_without_sd")) { + if (jj["support_print_without_sd"].is_boolean()) { + is_support_print_without_sd = jj["support_print_without_sd"].get(); + } + } + + if (jj.contains("support_print_all")) { + if (jj["support_print_all"].is_boolean()) { + is_support_print_all = jj["support_print_all"].get(); + } + } + + if (jj.contains("support_send_to_sd")) { + if (jj["support_send_to_sd"].is_boolean()) { + is_support_send_to_sdcard = jj["support_send_to_sd"].get(); + } + } + + if (jj.contains("support_aux_fan")) { + if (jj["support_aux_fan"].is_boolean()) { + is_support_aux_fan = jj["support_aux_fan"].get(); + } + } + + if (jj.contains("support_chamber_fan")) { + if (jj["support_chamber_fan"].is_boolean()) { + is_support_chamber_fan = jj["support_chamber_fan"].get(); + } + } + + if (jj.contains("support_filament_backup")) { + if (jj["support_filament_backup"].is_boolean()) { + is_support_filament_backup = jj["support_filament_backup"].get(); + } + } + + if (jj.contains("support_update_remain")) { + if (jj["support_update_remain"].is_boolean()) { + is_support_update_remain = jj["support_update_remain"].get(); + } + } + + if (jj.contains("support_auto_leveling")) { + if (jj["support_auto_leveling"].is_boolean()) { + is_support_auto_leveling = jj["support_auto_leveling"].get(); } } - } - if (!restored_json) { - j = j_pre; - } + if (jj.contains("support_auto_recovery_step_loss")) { + if (jj["support_auto_recovery_step_loss"].is_boolean()) { + is_support_auto_recovery_step_loss = jj["support_auto_recovery_step_loss"].get(); + } + } + + if (jj.contains("support_ams_humidity")) { + if (jj["support_ams_humidity"].is_boolean()) { + is_support_ams_humidity = jj["support_ams_humidity"].get(); + } + } + + if (jj.contains("support_prompt_sound")) { + if (jj["support_prompt_sound"].is_boolean()) { + is_support_prompt_sound = jj["support_prompt_sound"].get(); + } + } + + //if (jj.contains("support_filament_tangle_detect")) { + // if (jj["support_filament_tangle_detect"].is_boolean()) { + // is_support_filament_tangle_detect = jj["support_filament_tangle_detect"].get(); + // } + //} + + if (jj.contains("support_1080dpi")) { + if (jj["support_1080dpi"].is_boolean()) { + is_support_1080dpi = jj["support_1080dpi"].get(); + } + } + + if (jj.contains("support_cloud_print_only")) { + if (jj["support_cloud_print_only"].is_boolean()) { + is_support_cloud_print_only = jj["support_cloud_print_only"].get(); + } + } + + if (jj.contains("support_command_ams_switch")) { + if (jj["support_command_ams_switch"].is_boolean()) { + is_support_command_ams_switch = jj["support_command_ams_switch"].get(); + } + } + + if (jj.contains("support_mqtt_alive")) { + if (jj["support_mqtt_alive"].is_boolean()) { + is_support_mqtt_alive = jj["support_mqtt_alive"].get(); + } + } + + if (jj.contains("support_tunnel_mqtt")) { + if (jj["support_tunnel_mqtt"].is_boolean()) { + is_support_tunnel_mqtt = jj["support_tunnel_mqtt"].get(); + } + } - BOOST_LOG_TRIVIAL(trace) << "parse_json: dev_id=" << dev_id << ", playload=" << j.dump(4); + if (jj.contains("support_motor_noise_cali")) { + if (jj["support_motor_noise_cali"].is_boolean()) { + is_support_motor_noise_cali = jj["support_motor_noise_cali"].get(); + } + } - if (j.contains("print")) { - json jj = j["print"]; - int sequence_id = 0; - if (jj.contains("sequence_id")) { - if (jj["sequence_id"].is_string()) { - std::string str_seq = jj["sequence_id"].get(); - try { - sequence_id = stoi(str_seq); - } - catch(...) { - ; - } + if (jj.contains("support_timelapse")) { + if (jj["support_timelapse"].is_boolean()) { + is_support_timelapse = jj["support_timelapse"].get(); + } + } + + if (jj.contains("support_user_preset")) { + if (jj["support_user_preset"].is_boolean()) { + is_support_user_preset = jj["support_user_preset"].get(); + } + } + + if (jj.contains("nozzle_max_temperature")) { + if (jj["nozzle_max_temperature"].is_number_integer()) { + nozzle_max_temperature = jj["nozzle_max_temperature"].get(); + } + } + + if (jj.contains("bed_temperature_limit")) { + if (jj["bed_temperature_limit"].is_number_integer()) { + bed_temperature_limit = jj["bed_temperature_limit"].get(); } } + + if (jj.contains("command")) { if (jj["command"].get() == "ams_change_filament") { @@ -2947,13 +2975,19 @@ int MachineObject::parse_json(std::string payload) if (jj["command"].get() == "set_ctt") { if (m_agent && is_studio_cmd(sequence_id)) { if (jj["errno"].is_number()) { + wxString text; if (jj["errno"].get() == -2) { - wxString text = _L("Low temperature filament(PLA/PETG/TPU) is loaded in the extruder.In order to avoid extruder clogging,it is not allowed to set the chamber temperature above 45\u2103."); - GUI::wxGetApp().show_dialog(text); + text = _L("Low temperature filament(PLA/PETG/TPU) is loaded in the extruder.In order to avoid extruder clogging,it is not allowed to set the chamber temperature above 45\u2103."); } else if (jj["errno"].get() == -4) { - wxString text = _L("When you set the chamber temperature below 40\u2103, the chamber temperature control will not be activated. And the target chamber temperature will automatically be set to 0\u2103."); - GUI::wxGetApp().show_dialog(text); + text = _L("When you set the chamber temperature below 40\u2103, the chamber temperature control will not be activated. And the target chamber temperature will automatically be set to 0\u2103."); + } + if(!text.empty()){ +#if __WXOSX__ + set_ctt_dlg(text); +#else + GUI::wxGetApp().show_dialog(text); +#endif } } } @@ -2962,7 +2996,7 @@ int MachineObject::parse_json(std::string payload) if (jj["command"].get() == "push_status") { m_push_count++; - last_push_time = std::chrono::system_clock::now(); + last_push_time = last_update_time; #pragma region printing // U0 firmware if (jj.contains("print_type")) { @@ -3074,6 +3108,14 @@ int MachineObject::parse_json(std::string payload) if (jj.contains("gcode_state")) { this->set_print_state(jj["gcode_state"].get()); } + if (jj.contains("job_id")) { + is_support_wait_sending_finish = true; + this->job_id_ = jj["job_id"].get(); + } + else { + is_support_wait_sending_finish = false; + } + if (jj.contains("queue_number")) { this->queue_number = jj["queue_number"].get(); } else { @@ -3110,6 +3152,7 @@ int MachineObject::parse_json(std::string payload) if (idx_start > 0 && idx_end > idx_start) { try { plate_index = atoi(m_gcode_file.substr(idx_start, idx_end - idx_start).c_str()); + this->m_plate_index = plate_index; } catch (...) { ; @@ -3247,7 +3290,7 @@ int MachineObject::parse_json(std::string payload) /*get filam_bak*/ try { if (jj.contains("filam_bak")) { - m_is_support_show_bak = true; + is_support_show_filament_backup = true; filam_bak.clear(); if (jj["filam_bak"].is_array()) { for (auto it = jj["filam_bak"].begin(); it != jj["filam_bak"].end(); it++) { @@ -3256,7 +3299,7 @@ int MachineObject::parse_json(std::string payload) } } else { - m_is_support_show_bak = false; + is_support_show_filament_backup = false; } } catch (...) { @@ -3331,6 +3374,17 @@ int MachineObject::parse_json(std::string payload) ; } + try { + if (jj.contains("nozzle_type")) { + if (jj["nozzle_type"].is_string()) { + nozzle_type = jj["nozzle_type"].get(); + } + } + } + catch (...) { + ; + } + #pragma region upgrade try { if (jj.contains("upgrade_state")) { @@ -3432,11 +3486,12 @@ int MachineObject::parse_json(std::string payload) // parse camera info try { if (jj.contains("ipcam")) { - if (jj["ipcam"].contains("ipcam_record")) { + json const & ipcam = jj["ipcam"]; + if (ipcam.contains("ipcam_record")) { if (camera_recording_hold_count > 0) camera_recording_hold_count--; else { - if (jj["ipcam"]["ipcam_record"].get() == "enable") { + if (ipcam["ipcam_record"].get() == "enable") { camera_recording_when_printing = true; } else { @@ -3444,11 +3499,11 @@ int MachineObject::parse_json(std::string payload) } } } - if (jj["ipcam"].contains("timelapse")) { + if (ipcam.contains("timelapse")) { if (camera_timelapse_hold_count > 0) camera_timelapse_hold_count--; else { - if (jj["ipcam"]["timelapse"].get() == "enable") { + if (ipcam["timelapse"].get() == "enable") { camera_timelapse = true; } else { @@ -3456,25 +3511,44 @@ int MachineObject::parse_json(std::string payload) } } } - if (jj["ipcam"].contains("ipcam_dev")) { - if (jj["ipcam"]["ipcam_dev"].get() == "1") { + if (ipcam.contains("ipcam_dev")) { + if (ipcam["ipcam_dev"].get() == "1") { has_ipcam = true; } else { has_ipcam = false; } } - if (jj["ipcam"].contains("resolution")) { + if (ipcam.contains("resolution")) { if (camera_resolution_hold_count > 0) camera_resolution_hold_count--; else { - camera_resolution = jj["ipcam"]["resolution"].get(); + camera_resolution = ipcam["resolution"].get(); } } - if (jj["ipcam"].contains("rtsp_url")) { - local_rtsp_url = jj["ipcam"]["rtsp_url"].get(); + if (ipcam.contains("resolution_supported")) { + std::vector resolution_supported; + for (auto res : ipcam["resolution_supported"]) + resolution_supported.emplace_back(res.get()); + camera_resolution_supported.swap(resolution_supported); } - if (jj["ipcam"].contains("tutk_server")) { - tutk_state = jj["ipcam"]["tutk_server"].get(); + if (ipcam.contains("liveview")) { + char const *local_protos[] = { "none", "local", "rtsps", "rtsp" }; + liveview_local = enum_index_of(ipcam["liveview"].value("local", "none").c_str(), local_protos, 4, LiveviewLocal::LVL_None); + liveview_remote = ipcam["liveview"].value("remote", "disabled") == "enabled"; + } + if (ipcam.contains("file")) { + file_local = ipcam["file"].value("local", "disabled") == "enabled"; + file_remote = ipcam["file"].value("remote", "disabled") == "enabled"; + file_model_download = ipcam["file"].value("model_download", "disabled") == "enabled"; + } + virtual_camera = ipcam.value("virtual_camera", "disabled") == "enabled"; + if (ipcam.contains("rtsp_url")) { + local_rtsp_url = ipcam["rtsp_url"].get(); + liveview_local = local_rtsp_url.empty() ? LVL_None : local_rtsp_url == "disable" + ? LVL_None : boost::algorithm::starts_with(local_rtsp_url, "rtsps") ? LVL_Rtsps : LVL_Rtsp; + } + if (ipcam.contains("tutk_server")) { + tutk_state = ipcam["tutk_server"].get(); } } } @@ -3518,9 +3592,9 @@ int MachineObject::parse_json(std::string payload) else { if (jj["xcam"].contains("buildplate_marker_detector")) { xcam_buildplate_marker_detector = jj["xcam"]["buildplate_marker_detector"].get(); - is_xcam_buildplate_supported = true; + is_support_build_plate_marker_detect = true; } else { - is_xcam_buildplate_supported = false; + is_support_build_plate_marker_detect = false; } } } @@ -3973,6 +4047,7 @@ int MachineObject::parse_json(std::string payload) } } else { ams_support_virtual_tray = false; + is_support_extrusion_cali = false; } } catch (...) { @@ -3983,6 +4058,21 @@ int MachineObject::parse_json(std::string payload) } else if (jj["command"].get() == "gcode_line") { //ack of gcode_line BOOST_LOG_TRIVIAL(debug) << "parse_json, ack of gcode_line = " << j.dump(4); + if (m_agent && is_studio_cmd(sequence_id)) { + json t; + t["dev_id"] = this->dev_id; + t["signal"] = this->wifi_signal; + m_agent->track_event("ack_cmd_gcode_line", t.dump()); + } + } else if (jj["command"].get() == "project_prepare") { + //ack of project file + BOOST_LOG_TRIVIAL(info) << "parse_json, ack of project_prepare = " << j.dump(4); + if (m_agent) { + if (jj.contains("job_id")) { + this->job_id_ = jj["job_id"].get(); + } + } + } else if (jj["command"].get() == "project_file") { //ack of project file BOOST_LOG_TRIVIAL(debug) << "parse_json, ack of project_file = " << j.dump(4); @@ -3991,8 +4081,8 @@ int MachineObject::parse_json(std::string payload) json t; t["dev_id"] = this->dev_id; t["signal"] = this->wifi_signal; + m_agent->track_event("ack_cmd_project_file", t.dump()); } - std::string result; if (jj.contains("result")) { result = jj["result"].get(); @@ -4012,13 +4102,13 @@ int MachineObject::parse_json(std::string payload) tray_id = jj["tray_id"].get(); } if (ams_id == 255 && tray_id == VIRTUAL_TRAY_ID) { - BOOST_LOG_TRIVIAL(trace) << "ams_filament_setting, parse tray info"; + BOOST_LOG_TRIVIAL(info) << "ams_filament_setting, parse tray info"; vt_tray.nozzle_temp_max = std::to_string(jj["nozzle_temp_max"].get()); vt_tray.nozzle_temp_min = std::to_string(jj["nozzle_temp_min"].get()); vt_tray.color = jj["tray_color"].get(); vt_tray.setting_id = jj["tray_info_idx"].get(); //vt_tray.type = jj["tray_type"].get(); - vt_tray.type = setting_id_to_type(vt_tray.setting_id, jj["tray_info_idx"].get()); + vt_tray.type = setting_id_to_type(vt_tray.setting_id, jj["tray_type"].get()); // delay update vt_tray.set_hold_count(); } else { @@ -4369,42 +4459,6 @@ int MachineObject::parse_json(std::string payload) } } - try { - if (j.contains("info")) { - if (j["info"].contains("command") && j["info"]["command"].get() == "get_version") { - json j_module = j["info"]["module"]; - module_vers.clear(); - for (auto it = j_module.begin(); it != j_module.end(); it++) { - ModuleVersionInfo ver_info; - ver_info.name = (*it)["name"].get(); - if ((*it).contains("sw_ver")) - ver_info.sw_ver = (*it)["sw_ver"].get(); - if ((*it).contains("sn")) - ver_info.sn = (*it)["sn"].get(); - if ((*it).contains("hw_ver")) - ver_info.hw_ver = (*it)["hw_ver"].get(); - module_vers.emplace(ver_info.name, ver_info); - } - parse_version_func(); - - bool get_version_result = true; - if (j["info"].contains("result")) - if (j["info"]["result"].get() == "fail") - get_version_result = false; - if ((!check_version_valid() && get_version_retry-- >= 0) - && get_version_result) { - BOOST_LOG_TRIVIAL(info) << "get_version_retry = " << get_version_retry; - boost::thread retry = boost::thread([this] { - boost::this_thread::sleep_for(boost::chrono::milliseconds(RETRY_INTERNAL)); - GUI::wxGetApp().CallAfter([this] { - this->command_get_version(false); - }); - }); - } - } - } - } catch (...) {} - try { if (j.contains("camera")) { if (j["camera"].contains("command")) { @@ -4483,6 +4537,25 @@ int MachineObject::parse_json(std::string payload) return 0; } +void MachineObject::set_ctt_dlg( wxString text){ + if (!m_set_ctt_dlg) { + m_set_ctt_dlg = true; + auto print_error_dlg = new GUI::SecondaryCheckDialog(nullptr, wxID_ANY, _L("Warning"), GUI::SecondaryCheckDialog::ButtonStyle::ONLY_CONFIRM); + print_error_dlg->update_text(text); + print_error_dlg->Bind(wxEVT_SHOW, [this](auto& e) { + if (!e.IsShown()) { + m_set_ctt_dlg = false; + } + }); + print_error_dlg->Bind(wxEVT_CLOSE_WINDOW, [this](auto& e) { + e.Skip(); + m_set_ctt_dlg = false; + }); + print_error_dlg->on_show(); + + } +} + int MachineObject::publish_gcode(std::string gcode_str) { json j; @@ -4545,7 +4618,8 @@ void MachineObject::update_model_task() delete rating_info; rating_info = nullptr; } - get_model_task_thread = new boost::thread([this, curr_instance_id]{ + get_model_task_thread = new boost::thread([this, curr_instance_id, token = std::weak_ptr(m_token)]{ + if (token.expired()) { return; } try { std::string rating_result; unsigned int http_code = 404; @@ -4554,7 +4628,7 @@ void MachineObject::update_model_task() res = m_agent->get_model_mall_rating_result(curr_instance_id, rating_result, http_code, http_error); request_model_result++; BOOST_LOG_TRIVIAL(info) << "request times: " << request_model_result << " http code: " << http_code; - rating_info = new RatingInfo(); + auto rating_info = new RatingInfo(); rating_info->http_code = http_code; if (0 == res && 200 == http_code) { try { @@ -4568,6 +4642,9 @@ void MachineObject::update_model_task() } else { rating_info->request_successful = false; BOOST_LOG_TRIVIAL(info) << "can not get rating id"; + Slic3r::GUI::wxGetApp().CallAfter([this, token, rating_info]() { + if (!token.expired()) this->rating_info = rating_info; + }); return; } if (rating_json.contains("score")) { @@ -4580,12 +4657,18 @@ void MachineObject::update_model_task() if (rating_json.contains("images")) { rating_info->image_url_paths = rating_json["images"].get>(); } + Slic3r::GUI::wxGetApp().CallAfter([this, token, rating_info]() { + if (!token.expired()) this->rating_info = rating_info; + }); } catch (...) { BOOST_LOG_TRIVIAL(info) << "parse model mall result json failed"; } } else { rating_info->request_successful = false; + Slic3r::GUI::wxGetApp().CallAfter([this, token, rating_info]() { + if (!token.expired()) this->rating_info = rating_info; + }); BOOST_LOG_TRIVIAL(info) << "model mall result request failed, request time: " << request_model_result << " http_code: " << http_code << " error msg: " << http_error; return; @@ -4619,77 +4702,76 @@ void MachineObject::update_slice_info(std::string project_id, std::string profil BOOST_LOG_TRIVIAL(trace) << "slice_info: start"; slice_info = new BBLSliceInfo(); get_slice_info_thread = new boost::thread([this, project_id, profile_id, subtask_id, plate_idx] { - int plate_index = -1; + int plate_index = -1; - if (!m_agent) return; + if (!m_agent) return; - if (plate_idx >= 0) { - plate_index = plate_idx; - } else { + if (plate_idx >= 0) { + plate_index = plate_idx; + } + else { + std::string subtask_json; + unsigned http_code = 0; + std::string http_body; + if (m_agent->get_subtask_info(subtask_id, &subtask_json, &http_code, &http_body) == 0) { + try { + if (!subtask_json.empty()) { - std::string subtask_json; - unsigned http_code = 0; - std::string http_body; - if (m_agent->get_subtask_info(subtask_id, &subtask_json, &http_code, &http_body) == 0) { - try { - if (!subtask_json.empty()){ - - json task_j = json::parse(subtask_json); - if (task_j.contains("content")) { - std::string content_str = task_j["content"].get(); - json content_j = json::parse(content_str); - plate_index = content_j["info"]["plate_idx"].get(); - } + json task_j = json::parse(subtask_json); + if (task_j.contains("content")) { + std::string content_str = task_j["content"].get(); + json content_j = json::parse(content_str); + plate_index = content_j["info"]["plate_idx"].get(); + } - if (task_j.contains("context") && task_j["context"].contains("plates")) { - for (int i = 0; i < task_j["context"]["plates"].size(); i++) { - if (task_j["context"]["plates"][i].contains("index") && task_j["context"]["plates"][i]["index"].get() == plate_index) { + if (task_j.contains("context") && task_j["context"].contains("plates")) { + for (int i = 0; i < task_j["context"]["plates"].size(); i++) { + if (task_j["context"]["plates"][i].contains("index") && task_j["context"]["plates"][i]["index"].get() == plate_index) { + if (task_j["context"]["plates"][i].contains("thumbnail") && task_j["context"]["plates"][i]["thumbnail"].contains("url")) { slice_info->thumbnail_url = task_j["context"]["plates"][i]["thumbnail"]["url"].get(); - BOOST_LOG_TRIVIAL(trace) << "task_info: thumbnail url=" << slice_info->thumbnail_url; } + if (task_j["context"]["plates"][i].contains("prediction")) { + slice_info->prediction = task_j["context"]["plates"][i]["prediction"].get(); + } + if (task_j["context"]["plates"][i].contains("weight")) { + slice_info->weight = task_j["context"]["plates"][i]["weight"].get(); + } + if (!task_j["context"]["plates"][i]["filaments"].is_null()) { + for (auto filament : task_j["context"]["plates"][i]["filaments"]) { + FilamentInfo f; + if(filament.contains("color")){ + f.color = filament["color"].get(); + } + if (filament.contains("type")) { + f.type = filament["type"].get(); + } + if (filament.contains("used_g")) { + f.used_g = stof(filament["used_g"].get()); + } + if (filament.contains("used_m")) { + f.used_m = stof(filament["used_m"].get()); + } + slice_info->filaments_info.push_back(f); + } + } + BOOST_LOG_TRIVIAL(trace) << "task_info: thumbnail url=" << slice_info->thumbnail_url; } } - else { - BOOST_LOG_TRIVIAL(error) << "task_info: no context or plates"; - } } - } - catch(...) { - } - } else { - BOOST_LOG_TRIVIAL(error) << "task_info: get subtask id failed!"; - } - } - - if (plate_index >= 0) { - std::string slice_json; - m_agent->get_slice_info(project_id, profile_id, plate_index, &slice_json); - if (slice_json.empty()) return; - //parse json - try { - json j = json::parse(slice_json); - if (!j["prediction"].is_null()) - slice_info->prediction = j["prediction"].get(); - if (!j["weight"].is_null()) - slice_info->weight = j["weight"].get(); - if (!j["thumbnail"].is_null()) { - //slice_info->thumbnail_url = j["thumbnail"]["url"].get(); - BOOST_LOG_TRIVIAL(trace) << "slice_info: thumbnail url=" << slice_info->thumbnail_url; - } - if (!j["filaments"].is_null()) { - for (auto filament : j["filaments"]) { - FilamentInfo f; - f.color = filament["color"].get(); - f.type = filament["type"].get(); - f.used_g = string_to_float(filament["used_g"].get()); - f.used_m = string_to_float(filament["used_m"].get()); - slice_info->filaments_info.push_back(f); + else { + BOOST_LOG_TRIVIAL(error) << "task_info: no context or plates"; } } - } catch(...) { - ; + } + catch (...) { } } + else { + BOOST_LOG_TRIVIAL(error) << "task_info: get subtask id failed!"; + } + } + + this->m_plate_index = plate_index; }); } } @@ -4935,6 +5017,7 @@ void DeviceManager::on_machine_alive(std::string json_str) obj->bind_state = bind_state; obj->bind_sec_link = sec_link; obj->dev_connection_name = connection_name; + obj->m_is_online = true; //load access code AppConfig* config = Slic3r::GUI::wxGetApp().app_config; @@ -5013,6 +5096,12 @@ MachineObject* DeviceManager::get_local_selected_machine() return get_local_machine(local_selected_machine); } +void DeviceManager::reload_printer_settings() +{ + for (auto obj : this->userMachineList) + obj.second->reload_printer_settings(); +} + MachineObject* DeviceManager::get_default_machine() { std::string dev_id; @@ -5104,6 +5193,10 @@ bool DeviceManager::set_selected_machine(std::string dev_id, bool need_disconnec if (it->second->connection_type() != "lan") { // only reset update time it->second->reset_update_time(); + + // check subscribe state + Slic3r::GUI::wxGetApp().on_start_subscribe_again(dev_id); + return true; } else { // lan mode printer reconnect printer @@ -5329,101 +5422,62 @@ void DeviceManager::load_last_machine() } } -json DeviceManager::function_table = json::object(); json DeviceManager::filaments_blacklist = json::object(); + + std::string DeviceManager::parse_printer_type(std::string type_str) { - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("printer_type")) { - return printer["printer_type"].get(); - } - } - } - } - return ""; + return get_value_from_config(type_str, "printer_type"); } - std::string DeviceManager::get_printer_display_name(std::string type_str) { - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("display_name")) { - return printer["display_name"].get(); - } - } - } - } - return ""; + return get_value_from_config(type_str, "display_name"); } - std::string DeviceManager::get_ftp_folder(std::string type_str) { - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("ftp_folder")) { - return printer["ftp_folder"].get(); - } - } - } - } - return ""; + return get_value_from_config(type_str, "ftp_folder"); } - PrinterArch DeviceManager::get_printer_arch(std::string type_str) { - PrinterArch arch = PrinterArch::ARCH_CORE_XY; - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("printer_arch")) { - return get_printer_arch_by_str(printer["printer_arch"].get()); - } - } - } - } - return arch; + return get_printer_arch_by_str(get_value_from_config(type_str, "printer_arch")); } - std::string DeviceManager::get_printer_thumbnail_img(std::string type_str) { - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("printer_thumbnail_image")) { - return printer["printer_thumbnail_image"].get(); - } - } - } - } - return ""; + return get_value_from_config(type_str, "printer_thumbnail_image"); } - -bool DeviceManager::is_function_supported(std::string type_str, std::string function_name) +std::string DeviceManager::get_printer_ams_type(std::string type_str) { - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("func")) { - if (printer["func"].contains(function_name)) - return printer["func"][function_name].get(); - } - } - } - } - return true; + return get_value_from_config(type_str, "use_ams_type"); +} +std::string DeviceManager::get_printer_series(std::string type_str) +{ + return get_value_from_config(type_str, "printer_series"); +} +std::string DeviceManager::get_printer_diagram_img(std::string type_str) +{ + return get_value_from_config(type_str, "printer_connect_help_image"); +} +std::string DeviceManager::get_printer_ams_img(std::string type_str) +{ + return get_value_from_config(type_str, "printer_use_ams_image"); } +bool DeviceManager::get_printer_is_enclosed(std::string type_str) { + return get_value_from_config(type_str, "printer_is_enclosed"); +} std::vector DeviceManager::get_resolution_supported(std::string type_str) { std::vector resolution_supported; - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { + + std::string config_file = Slic3r::resources_dir() + "/printers/" + type_str + ".json"; + std::ifstream json_file(config_file.c_str()); + try { + json jj; + if (json_file.is_open()) { + json_file >> jj; + if (jj.contains("00.00.00.00")) { + json const& printer = jj["00.00.00.00"]; if (printer.contains("camera_resolution")) { for (auto res : printer["camera_resolution"]) resolution_supported.emplace_back(res.get()); @@ -5431,59 +5485,33 @@ std::vector DeviceManager::get_resolution_supported(std::string typ } } } + catch (...) {} return resolution_supported; } -bool DeviceManager::get_bed_temperature_limit(std::string type_str, int &limit) -{ - bool result = false; - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("bed_temperature_limit")) { - limit = printer["bed_temperature_limit"].get(); - return true; - } - } - } - } - return result; -} - -bool DeviceManager::get_nozzle_max_temperature(std::string type_str, int& limit) -{ - bool result = false; - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("nozzle_max_temperature")) { - limit = printer["nozzle_max_temperature"].get(); - return true; - } - } - } - } - return result; -} - -bool DeviceManager::load_functional_config(std::string config_file) +std::vector DeviceManager::get_compatible_machine(std::string type_str) { + std::vector compatible_machine; + std::string config_file = Slic3r::resources_dir() + "/printers/" + type_str + ".json"; std::ifstream json_file(config_file.c_str()); try { + json jj; if (json_file.is_open()) { - json_file >> DeviceManager::function_table; - return true; - } else { - BOOST_LOG_TRIVIAL(error) << "load functional config failed, file = " << config_file; + json_file >> jj; + if (jj.contains("00.00.00.00")) { + json const& printer = jj["00.00.00.00"]; + if (printer.contains("compatible_machine")) { + for (auto res : printer["compatible_machine"]) + compatible_machine.emplace_back(res.get()); + } + } } } - catch(...) { - BOOST_LOG_TRIVIAL(error) << "load functional config failed, file = " << config_file; - return false; - } - return true; + catch (...) {} + return compatible_machine; } + bool DeviceManager::load_filaments_blacklist_config(std::string config_file) { filaments_blacklist = json::object(); @@ -5586,20 +5614,4 @@ std::string DeviceManager::load_gcode(std::string type_str, std::string gcode_fi return ""; } -std::vector DeviceManager::get_compatible_machine(std::string type_str) -{ - std::vector compatible_machine; - if (DeviceManager::function_table.contains("printers")) { - for (auto printer : DeviceManager::function_table["printers"]) { - if (printer.contains("model_id") && printer["model_id"].get() == type_str) { - if (printer.contains("compatible_machine")) { - for (auto res : printer["compatible_machine"]) - compatible_machine.emplace_back(res.get()); - } - } - } - } - return compatible_machine; -} - } // namespace Slic3r diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index a3ff947dd6d..9a57ed0276b 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -7,13 +7,14 @@ #include #include #include +#include #include "nlohmann/json.hpp" #include "libslic3r/ProjectTask.hpp" #include "slic3r/Utils/json_diff.hpp" #include "slic3r/Utils/NetworkAgent.hpp" #include "CameraPopup.hpp" #include "libslic3r/calib.hpp" - +#include "libslic3r/Utils.hpp" #define USE_LOCAL_SOCKET_BIND 0 #define DISCONNECT_TIMEOUT 30000.f // milliseconds @@ -51,7 +52,7 @@ using namespace nlohmann; namespace Slic3r { - +class SecondaryCheckDialog; enum PrinterArch { ARCH_CORE_XY, ARCH_I3, @@ -63,55 +64,7 @@ enum PrinterSeries { SERIES_UNKNOWN, }; -enum PRINTING_STAGE { - PRINTING_STAGE_PRINTING = 0, - PRINTING_STAGE_BED_LEVELING, - PRINTING_STAGE_HEADBED, - PRINTING_STAGE_XY_MECH_MODE, - PRINTING_STAGE_CHANGE_MATERIAL, - PRINTING_STAGE_M400_PAUSE, - PRINTING_STAGE_FILAMENT_RUNOUT_PAUSE, - PRINTING_STAGE_HOTEND_HEATING, - PRINTING_STAGE_EXTRUDER_SCAN, - PRINTING_STAGE_BED_SCAN, - PRINTING_STAGE_FIRST_LAYER_SCAN, - PRINTING_STAGE_SURFACE_TYPE_IDENT, - PRINTING_STAGE_SCANNER_PARAM_CALI, - PRINTING_STAGE_TOOHEAD_HOMING, - PRINTING_STAGE_NOZZLE_TIP_CLEANING, - PRINTING_STAGE_COUNT -}; - enum PrinterFunction { - FUNC_MONITORING = 0, - FUNC_TIMELAPSE, - FUNC_RECORDING, - FUNC_FIRSTLAYER_INSPECT, - FUNC_AI_MONITORING, - FUNC_LIDAR_CALIBRATION, - FUNC_BUILDPLATE_MARKER_DETECT, - FUNC_AUTO_RECOVERY_STEP_LOSS, - FUNC_FLOW_CALIBRATION, - FUNC_AUTO_LEVELING, - FUNC_CHAMBER_TEMP, - FUNC_CAMERA_VIDEO, - FUNC_MEDIA_FILE, - FUNC_REMOTE_TUNNEL, - FUNC_LOCAL_TUNNEL, - FUNC_PRINT_WITHOUT_SD, - FUNC_VIRTUAL_CAMERA, - FUNC_USE_AMS, - FUNC_ALTER_RESOLUTION, - FUNC_SEND_TO_SDCARD, - FUNC_AUTO_SWITCH_FILAMENT, - FUNC_CHAMBER_FAN, - FUNC_AUX_FAN, - FUNC_EXTRUSION_CALI, - FUNC_PROMPT_SOUND, - FUNC_VIRTUAL_TYAY, - FUNC_PRINT_ALL, - FUNC_FILAMENT_BACKUP, - FUNC_MOTOR_NOISE_CALI, FUNC_MAX }; @@ -359,7 +312,8 @@ struct DisValue { class MachineObject { private: - NetworkAgent* m_agent { nullptr }; + NetworkAgent * m_agent{nullptr}; + std::shared_ptr m_token = std::make_shared(1); bool check_valid_ip(); void _parse_print_option_ack(int option); @@ -452,12 +406,14 @@ class MachineObject bool local_use_ssl_for_mqtt { true }; bool local_use_ssl_for_ftp { true }; float nozzle_diameter { 0.0f }; + int subscribe_counter{3}; + std::string nozzle_type; std::string dev_connection_type; /* lan | cloud */ std::string connection_type() { return dev_connection_type; } std::string dev_connection_name; /* lan | eth */ - void set_dev_ip(std::string ip) {dev_ip = ip;}; - bool has_access_right() { return !get_access_code().empty(); } + void set_dev_ip(std::string ip) {dev_ip = ip;} std::string get_ftp_folder(); + bool has_access_right() { return !get_access_code().empty(); } std::string get_access_code(); void set_access_code(std::string code, bool only_refresh = true); @@ -465,24 +421,26 @@ class MachineObject void erase_user_access_code(); std::string get_user_access_code(); bool is_lan_mode_printer(); - bool is_high_printer_type(); //PRINTER_TYPE printer_type = PRINTER_3DPrinter_UKNOWN; std::string printer_type; /* model_id */ PrinterSeries get_printer_series() const; PrinterArch get_printer_arch() const; - bool is_printer_enclosed() const; + std::string get_printer_ams_type() const; + bool get_printer_is_enclosed() const; + + void reload_printer_settings(); std::string printer_thumbnail_img; std::string monitor_upgrade_printer_img; wxString get_printer_type_display_str(); - std::string get_printer_thumbnail_img_str(); + std::string product_name; // set by iot service, get /user/print std::vector filam_bak; - bool m_is_support_show_bak{false}; + std::string bind_user_name; std::string bind_user_id; @@ -492,8 +450,10 @@ class MachineObject time_t last_alive; bool m_is_online; bool m_lan_mode_connection_state{false}; + bool m_set_ctt_dlg{ false }; void set_lan_mode_connection_state(bool state) {m_lan_mode_connection_state = state;}; bool get_lan_mode_connection_state() {return m_lan_mode_connection_state;}; + void set_ctt_dlg( wxString text); int parse_msg_count = 0; int keep_alive_count = 0; std::chrono::system_clock::time_point last_update_time; /* last received print data from machine */ @@ -503,7 +463,6 @@ class MachineObject std::chrono::system_clock::time_point last_request_start; /* last received print push from machine */ int m_active_state = 0; // 0 - not active, 1 - active, 2 - update-to-date - bool is_support_tunnel_mqtt = false; bool is_tunnel_mqtt = false; /* ams properties */ @@ -518,10 +477,8 @@ class MachineObject bool ams_insert_flag { false }; bool ams_power_on_flag { false }; bool ams_calibrate_remain_flag { false }; - bool ams_support_auto_switch_filament_flag { true }; bool ams_auto_switch_filament_flag { false }; bool ams_support_use_ams { false }; - bool ams_support_remain { true }; bool ams_support_virtual_tray { true }; int ams_humidity; int ams_user_setting_hold_count = 0; @@ -553,10 +510,7 @@ class MachineObject void _parse_ams_status(int ams_status); bool has_ams() { return ams_exist_bits != 0; } bool can_unload_filament(); - bool is_U0_firmware(); bool is_support_ams_mapping(); - bool is_support_command_ams_switch(); - static bool is_support_ams_mapping_version(std::string module, std::string version); int ams_filament_mapping(std::vector filaments, std::vector &result, std::vector exclude_id = std::vector()); bool is_valid_mapping_result(std::vector& result, bool check_empty_slot = false); @@ -724,39 +678,74 @@ class MachineObject int camera_recording_hold_count = 0; int camera_timelapse_hold_count = 0; int camera_resolution_hold_count = 0; - std::string camera_resolution = ""; + std::string camera_resolution = ""; + std::vector camera_resolution_supported; bool xcam_first_layer_inspector { false }; int xcam_first_layer_hold_count = 0; - int local_camera_proto = -1; - int file_proto = 0; std::string local_rtsp_url; std::string tutk_state; - bool is_support_remote_tunnel{false}; + enum LiveviewLocal { + LVL_None, + LVL_Local, + LVL_Rtsps, + LVL_Rtsp + } liveview_local{ LVL_None }; + bool liveview_remote{false}; + bool file_local{false}; + bool file_remote{false}; + bool file_model_download{false}; + bool virtual_camera{false}; bool xcam_ai_monitoring{ false }; int xcam_ai_monitoring_hold_count = 0; std::string xcam_ai_monitoring_sensitivity; - bool is_xcam_buildplate_supported { true }; bool xcam_buildplate_marker_detector{ false }; int xcam_buildplate_marker_hold_count = 0; - bool xcam_support_recovery_step_loss { true }; bool xcam_auto_recovery_step_loss{ false }; bool xcam_allow_prompt_sound{ false }; + bool xcam_filament_tangle_detect{ false }; int xcam_auto_recovery_hold_count = 0; int xcam_prompt_sound_hold_count = 0; + int xcam_filament_tangle_detect_count = 0; int ams_print_option_count = 0; - /*not support U2*/ - bool is_support_1080dpi {false}; + //supported features + bool is_support_chamber_edit{false}; + bool is_support_extrusion_cali{false}; + bool is_support_first_layer_inspect{false}; bool is_support_ai_monitoring {false}; - bool is_support_ams_humidity {true}; - bool is_cloud_print_only {false}; + bool is_support_lidar_calibration {false}; + bool is_support_build_plate_marker_detect{false}; + bool is_support_flow_calibration{false}; + bool is_support_print_without_sd{false}; + bool is_support_print_all{false}; + bool is_support_send_to_sdcard {false}; + bool is_support_aux_fan {false}; + bool is_support_chamber_fan{false}; + bool is_support_filament_backup{false}; + bool is_support_show_filament_backup{false}; + bool is_support_timelapse{false}; + bool is_support_update_remain{false}; + bool is_support_auto_leveling{false}; + bool is_support_auto_recovery_step_loss{false}; + bool is_support_ams_humidity {false}; + bool is_support_prompt_sound{false}; + bool is_support_filament_tangle_detect{false}; + bool is_support_1080dpi {false}; + bool is_support_cloud_print_only {false}; + bool is_support_command_ams_switch{false}; bool is_support_mqtt_alive {false}; + bool is_support_tunnel_mqtt{false}; + bool is_support_motor_noise_cali{false}; + bool is_support_wait_sending_finish{false}; + bool is_support_user_preset{false}; + + int nozzle_max_temperature = -1; + int bed_temperature_limit = -1; /* sdcard */ MachineObject::SdcardState sdcard_state { NO_SDCARD }; MachineObject::SdcardState get_sdcard_state(); - bool is_support_send_to_sdcard { true }; /* HMS */ std::vector hms_list; @@ -772,6 +761,7 @@ class MachineObject std::string profile_id_; std::string task_id_; std::string subtask_id_; + std::string job_id_; std::string last_subtask_id_; BBLSliceInfo* slice_info {nullptr}; boost::thread* get_slice_info_thread { nullptr }; @@ -780,7 +770,7 @@ class MachineObject bool is_makeworld_subtask(); - int plate_index { -1 }; + int m_plate_index { -1 }; std::string m_gcode_file; int gcode_file_prepare_percent = 0; BBLSubTask* subtask_; @@ -801,6 +791,7 @@ class MachineObject MachineObject(NetworkAgent* agent, std::string name, std::string id, std::string ip); ~MachineObject(); + std::string parse_version(); void parse_version_func(); bool is_studio_cmd(int seq); /* command commands */ @@ -808,6 +799,9 @@ class MachineObject int command_request_push_all(bool request_now = false); int command_pushing(std::string cmd); int command_clean_print_error(std::string task_id, int print_error); + int command_set_printer_nozzle(std::string nozzle_type, float diameter); + int command_get_access_code(); + /* command upgrade */ int command_upgrade_confirm(); @@ -822,6 +816,8 @@ class MachineObject int command_control_fan(FanType fan_type, bool on_off); int command_control_fan_val(FanType fan_type, int val); int command_task_abort(); + /* cancelled the job_id */ + int command_task_cancel(std::string job_id); int command_task_pause(); int command_task_resume(); int command_set_bed(int temp); @@ -847,9 +843,13 @@ class MachineObject // set printing speed int command_set_printing_speed(PrintingSpeedLevel lvl); - //set pormpt sound + //set prompt sound int command_set_prompt_sound(bool prompt_sound); + //set fliament tangle detect + int command_set_filament_tangle_detect(bool fliament_tangle_detect); + + // set print option int command_set_printing_option(bool auto_recovery); @@ -884,6 +884,7 @@ class MachineObject int command_xcam_control_buildplate_marker_detector(bool on_off); int command_xcam_control_auto_recovery_step_loss(bool on_off); int command_xcam_control_allow_prompt_sound(bool on_off); + int command_xcam_control_filament_tangle_detect(bool on_off); /* common apis */ inline bool is_local() { return !dev_ip.empty(); } @@ -902,20 +903,16 @@ class MachineObject static bool is_in_printing_status(std::string status); void set_print_state(std::string status); - std::vector get_compatible_machine(); bool is_connected(); bool is_connecting(); void set_online_state(bool on_off); bool is_online() { return m_is_online; } bool is_info_ready(); - bool is_function_supported(PrinterFunction func); - std::vector get_resolution_supported(); - bool is_support_print_with_timelapse(); bool is_camera_busy_off(); - int get_local_camera_proto(); - bool has_local_file_proto(); - bool has_remote_file_proto(); + + std::vector get_resolution_supported(); + std::vector get_compatible_machine(); /* Msg for display MsgFn */ typedef std::function MsgFn; @@ -964,6 +961,7 @@ class DeviceManager MachineObject* get_my_machine(std::string dev_id); void erase_user_machine(std::string dev_id); void clean_user_info(); + void reload_printer_settings(); bool set_selected_machine(std::string dev_id, bool need_disconnect = false); MachineObject* get_selected_machine(); @@ -989,21 +987,41 @@ class DeviceManager static json function_table; static json filaments_blacklist; + template + static T get_value_from_config(std::string type_str, std::string item){ + std::string config_file = Slic3r::resources_dir() + "/printers/" + type_str + ".json"; + boost::nowide::ifstream json_file(config_file.c_str()); + try { + json jj; + if (json_file.is_open()) { + json_file >> jj; + if (jj.contains("00.00.00.00")) { + json const& printer = jj["00.00.00.00"]; + if (printer.contains(item)) { + return printer[item].get(); + } + } + } + } + catch (...) {} + return ""; + } + static std::string parse_printer_type(std::string type_str); static std::string get_printer_display_name(std::string type_str); static std::string get_printer_thumbnail_img(std::string type_str); + static std::string get_printer_ams_type(std::string type_str); + static std::string get_printer_series(std::string type_str); + static std::string get_printer_diagram_img(std::string type_str); + static std::string get_printer_ams_img(std::string type_str); static PrinterArch get_printer_arch(std::string type_str); static std::string get_ftp_folder(std::string type_str); - static bool is_function_supported(std::string type_str, std::string function_name); + static bool get_printer_is_enclosed(std::string type_str); static std::vector get_resolution_supported(std::string type_str); - - static bool get_bed_temperature_limit(std::string type_str, int& limit); - static bool get_nozzle_max_temperature(std::string type_str, int& limit); - static bool load_functional_config(std::string config_file); + static std::vector get_compatible_machine(std::string type_str); static bool load_filaments_blacklist_config(std::string config_file); static void check_filaments_in_blacklist(std::string tag_vendor, std::string tag_type, bool& in_blacklist, std::string& ac, std::string& info); static std::string load_gcode(std::string type_str, std::string gcode_file); - static std::vector get_compatible_machine(std::string type_str); }; } // namespace Slic3r diff --git a/src/slic3r/GUI/ExtraRenderers.cpp b/src/slic3r/GUI/ExtraRenderers.cpp index 4e3577b19ea..068a4632462 100644 --- a/src/slic3r/GUI/ExtraRenderers.cpp +++ b/src/slic3r/GUI/ExtraRenderers.cpp @@ -225,7 +225,8 @@ wxWindow* BitmapTextRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelRec bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) { wxTextCtrl* text_editor = wxDynamicCast(ctrl, wxTextCtrl); - if (!text_editor || text_editor->GetValue().IsEmpty()) + auto item = GetView()->GetModel()->GetParent(m_item); + if (!text_editor || (item.IsOk() && text_editor->GetValue().IsEmpty())) return false; m_was_unusable_symbol = Slic3r::GUI::Plater::has_illegal_filename_characters(text_editor->GetValue()); diff --git a/src/slic3r/GUI/ExtrusionCalibration.cpp b/src/slic3r/GUI/ExtrusionCalibration.cpp index ce7e2a8c59b..f4c17b5b750 100644 --- a/src/slic3r/GUI/ExtrusionCalibration.cpp +++ b/src/slic3r/GUI/ExtrusionCalibration.cpp @@ -508,7 +508,7 @@ bool ExtrusionCalibration::check_k_validation(wxString k_text) ; } - if (k < 0 || k > 0.5) + if (k < 0 || k > 0.3) return false; return true; } @@ -544,8 +544,8 @@ void ExtrusionCalibration::on_click_save(wxCommandEvent &event) wxString k_text = m_k_val->GetTextCtrl()->GetValue(); wxString n_text = m_n_val->GetTextCtrl()->GetValue(); if (!ExtrusionCalibration::check_k_validation(k_text)) { - wxString k_tips = _L("Please input a valid value (K in 0~0.5)"); - wxString kn_tips = _L("Please input a valid value (K in 0~0.5, N in 0.6~2.0)"); + wxString k_tips = _L("Please input a valid value (K in 0~0.3)"); + wxString kn_tips = _L("Please input a valid value (K in 0~0.3, N in 0.6~2.0)"); MessageDialog msg_dlg(nullptr, k_tips, wxEmptyString, wxICON_WARNING | wxOK); msg_dlg.ShowModal(); return; diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 3565a40b956..235ba99509d 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -131,7 +131,9 @@ void Field::PostInitialize() // For the mode, when settings are in non-modal dialog, neither dialog nor tabpanel doesn't receive wxEVT_KEY_UP event, when some field is selected. // So, like a workaround check wxEVT_KEY_UP event for the Filed and switch between tabs if Ctrl+(1-4) was pressed if (getWindow()) { - if (m_opt.readonly) getWindow()->Disable(); + if (m_opt.readonly) { + this->disable(); + } getWindow()->Bind(wxEVT_KEY_UP, [](wxKeyEvent& evt) { if ((evt.GetModifiers() & wxMOD_CONTROL) != 0) { int tab_id = -1; @@ -424,6 +426,12 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true continue; } } + else if (m_opt_id == "printable_area") { + if (0 <= x && x <= 1000 && 0 <= y && y <= 1000) { + out_values.push_back(Vec2d(x, y)); + continue; + } + } else { if (0 < x && x < 1000 && 0 < y && y < 1000) { out_values.push_back(Vec2d(x, y)); @@ -1333,7 +1341,7 @@ void Choice::set_value(const boost::any& value, bool change_event) if (m_opt_id.compare("host_type") == 0 && val != 0 && m_opt.enum_values.size() > field->GetCount()) // for case, when PrusaLink isn't used as a HostType val--; - if (m_opt_id == "top_surface_pattern" || m_opt_id == "bottom_surface_pattern" || m_opt_id == "internal_solid_infill_pattern" || m_opt_id == "sparse_infill_pattern" || m_opt_id == "support_style") + if (m_opt_id == "top_surface_pattern" || m_opt_id == "bottom_surface_pattern" || m_opt_id == "internal_solid_infill_pattern" || m_opt_id == "sparse_infill_pattern" || m_opt_id == "support_style" || m_opt_id == "curr_bed_type") { std::string key; const t_config_enum_values& map_names = *m_opt.enum_keys_map; @@ -1420,7 +1428,8 @@ boost::any& Choice::get_value() { if (m_opt.nullable && field->GetSelection() == -1) m_value = ConfigOptionEnumsGenericNullable::nil_value(); - else if (m_opt_id == "top_surface_pattern" || m_opt_id == "bottom_surface_pattern" || m_opt_id == "internal_solid_infill_pattern" || m_opt_id == "sparse_infill_pattern" || m_opt_id == "support_style") { + else if (m_opt_id == "top_surface_pattern" || m_opt_id == "bottom_surface_pattern" || m_opt_id == "internal_solid_infill_pattern" || m_opt_id == "sparse_infill_pattern" || + m_opt_id == "support_style" || m_opt_id == "curr_bed_type") { const std::string& key = m_opt.enum_values[field->GetSelection()]; m_value = int(m_opt.enum_keys_map->at(key)); } diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 0f031ca839e..aedc729bc07 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -898,9 +898,9 @@ void GCodeViewer::update_by_mode(ConfigOptionMode mode) view_type_items.push_back(EViewType::LayerTimeLog); view_type_items.push_back(EViewType::FanSpeed); view_type_items.push_back(EViewType::Temperature); - if (mode == ConfigOptionMode::comDevelop) { - view_type_items.push_back(EViewType::Tool); - } + //if (mode == ConfigOptionMode::comDevelop) { + // view_type_items.push_back(EViewType::Tool); + //} for (int i = 0; i < view_type_items.size(); i++) { view_type_items_str.push_back(get_view_type_string(view_type_items[i])); @@ -913,9 +913,9 @@ view_type_items.push_back(EViewType::LayerTimeLog); options_items.push_back(EMoveType::Retract); options_items.push_back(EMoveType::Unretract); options_items.push_back(EMoveType::Wipe); - if (mode == ConfigOptionMode::comDevelop) { - options_items.push_back(EMoveType::Tool_change); - } + //if (mode == ConfigOptionMode::comDevelop) { + // options_items.push_back(EMoveType::Tool_change); + //} //BBS: seam is not real move and extrusion, put at last line options_items.push_back(EMoveType::Seam); } @@ -3072,10 +3072,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const progress_dialog->Destroy(); } -//BBS: always load shell when preview -void GCodeViewer::load_shells(const Print& print, bool force_previewing) +void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_previewing) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": force_previewing=%1%") %force_previewing; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": initialized=%1%, force_previewing=%2%")%initialized %force_previewing; if ((print.id().id == m_shells.print_id)&&(print.get_modified_count() == m_shells.print_modify_count)) { //BBS: update force previewing logic if (force_previewing) @@ -3123,7 +3122,7 @@ void GCodeViewer::load_shells(const Print& print, bool force_previewing) instance_ids.resize(instance_index); size_t current_volumes_count = m_shells.volumes.volumes.size(); - m_shells.volumes.load_object(model_obj, object_idx, instance_ids); + m_shells.volumes.load_object(model_obj, object_idx, instance_ids, "object", initialized); // adjust shells' z if raft is present const SlicingParameters& slicing_parameters = obj->slicing_parameters(); @@ -3140,24 +3139,24 @@ void GCodeViewer::load_shells(const Print& print, bool force_previewing) // Orca: disable wipe tower shell // if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) { - // // BBS: adds wipe tower's volume - // std::vector print_extruders = print.extruders(true); - // int extruders_count = print_extruders.size(); - - // const double max_z = print.objects()[0]->model_object()->get_model()->bounding_box().max(2); - // const PrintConfig& config = print.config(); - // if (config.enable_prime_tower && - // (print.enable_timelapse_print() || (extruders_count > 1 && (config.print_sequence == PrintSequence::ByLayer)))) { - // const float depth = print.wipe_tower_data(extruders_count).depth; - // const float brim_width = print.wipe_tower_data(extruders_count).brim_width; - - // int plate_idx = print.get_plate_index(); - // Vec3d plate_origin = print.get_plate_origin(); - // double wipe_tower_x = config.wipe_tower_x.get_at(plate_idx) + plate_origin(0); - // double wipe_tower_y = config.wipe_tower_y.get_at(plate_idx) + plate_origin(1); - // m_shells.volumes.load_wipe_tower_preview(1000, wipe_tower_x, wipe_tower_y, config.prime_tower_width, depth, max_z, config.wipe_tower_rotation_angle, - // !print.is_step_done(psWipeTower), brim_width, initialized); - // } + // // BBS: adds wipe tower's volume + // std::vector print_extruders = print.extruders(true); + // int extruders_count = print_extruders.size(); + + // const double max_z = print.objects()[0]->model_object()->get_model()->bounding_box().max(2); + // const PrintConfig& config = print.config(); + // if (config.enable_prime_tower && + // (print.enable_timelapse_print() || (extruders_count > 1 && (config.print_sequence == PrintSequence::ByLayer)))) { + // const float depth = print.wipe_tower_data(extruders_count).depth; + // const float brim_width = print.wipe_tower_data(extruders_count).brim_width; + + // int plate_idx = print.get_plate_index(); + // Vec3d plate_origin = print.get_plate_origin(); + // double wipe_tower_x = config.wipe_tower_x.get_at(plate_idx) + plate_origin(0); + // double wipe_tower_y = config.wipe_tower_y.get_at(plate_idx) + plate_origin(1); + // m_shells.volumes.load_wipe_tower_preview(1000, wipe_tower_x, wipe_tower_y, config.prime_tower_width, depth, max_z, config.wipe_tower_rotation_angle, + // !print.is_step_done(psWipeTower), brim_width, initialized); + // } // } // remove modifiers @@ -4080,16 +4079,26 @@ void GCodeViewer::render_all_plates_stats(const std::vector offsets; - std::map volume_of_extruders_all_plates; // map + std::map model_volume_of_extruders_all_plates; // map std::map flushed_volume_of_extruders_all_plates; // map + std::map wipe_tower_volume_of_extruders_all_plates; // map std::vector model_used_filaments_m_all_plates; std::vector model_used_filaments_g_all_plates; std::vector flushed_filaments_m_all_plates; std::vector flushed_filaments_g_all_plates; + std::vector wipe_tower_used_filaments_m_all_plates; + std::vector wipe_tower_used_filaments_g_all_plates; float total_time_all_plates = 0.0f; float total_cost_all_plates = 0.0f; bool show_detailed_statistics_page = false; - + struct ColumnData { + enum { + Model = 1, + Flushed = 2, + WipeTower = 4, + }; + }; + int displayed_columns = 0; auto max_width = [](const std::vector& items, const std::string& title, float extra_size = 0.0f) { float ret = ImGui::CalcTextSize(title.c_str()).x; for (const std::string& item : items) { @@ -4169,15 +4178,23 @@ void GCodeViewer::render_all_plates_stats(const std::vector(m_time_estimate_mode)]; total_time_all_plates += plate_time_mode.time; @@ -4187,18 +4204,27 @@ void GCodeViewer::render_all_plates_stats(const std::vectorprint_statistics().total_cost; } - for (auto it = volume_of_extruders_all_plates.begin(); it != volume_of_extruders_all_plates.end(); it++) { + for (auto it = model_volume_of_extruders_all_plates.begin(); it != model_volume_of_extruders_all_plates.end(); it++) { auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(it->second, it->first); + if (model_used_filament_m != 0.0 || model_used_filament_g != 0.0) + displayed_columns |= ColumnData::Model; model_used_filaments_m_all_plates.push_back(model_used_filament_m); model_used_filaments_g_all_plates.push_back(model_used_filament_g); } for (auto it = flushed_volume_of_extruders_all_plates.begin(); it != flushed_volume_of_extruders_all_plates.end(); it++) { auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(it->second, it->first); if (flushed_filament_m != 0.0 || flushed_filament_g != 0.0) - show_detailed_statistics_page = true; + displayed_columns |= ColumnData::Flushed; flushed_filaments_m_all_plates.push_back(flushed_filament_m); flushed_filaments_g_all_plates.push_back(flushed_filament_g); } + for (auto it = wipe_tower_volume_of_extruders_all_plates.begin(); it != wipe_tower_volume_of_extruders_all_plates.end(); it++) { + auto [wipe_tower_filament_m, wipe_tower_filament_g] = get_used_filament_from_volume(it->second, it->first); + if (wipe_tower_filament_m != 0.0 || wipe_tower_filament_g != 0.0) + displayed_columns |= ColumnData::WipeTower; + wipe_tower_used_filaments_m_all_plates.push_back(wipe_tower_filament_m); + wipe_tower_used_filaments_g_all_plates.push_back(wipe_tower_filament_g); + } char buff[64]; double longest_str = 0.0; @@ -4207,25 +4233,40 @@ void GCodeViewer::render_all_plates_stats(const std::vector> columns_offsets; columns_offsets.push_back({ std::to_string(it->first + 1), offsets[0] }); char buf[64]; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1.0; - if (show_detailed_statistics_page) { + if (displayed_columns == ColumnData::Model) { + char buf[64]; + ::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", model_used_filaments_m_all_plates[i], model_used_filaments_g_all_plates[i] / unit_conver); + columns_offsets.push_back({ buf, offsets[2] }); + } + if (displayed_columns == (ColumnData::Model | ColumnData::Flushed)) { ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m_all_plates[i], model_used_filaments_g_all_plates[i] / unit_conver); columns_offsets.push_back({ buf, offsets[1] }); @@ -4233,12 +4274,22 @@ void GCodeViewer::render_all_plates_stats(const std::vectorfirst], columns_offsets); @@ -4619,8 +4670,17 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv std::vector flushed_filaments_m; std::vector flushed_filaments_g; double total_flushed_filament_m = 0, total_flushed_filament_g = 0; - bool show_model_used_filaments = true; - bool show_flushed_filaments = true; + std::vector wipe_tower_used_filaments_m; + std::vector wipe_tower_used_filaments_g; + double total_wipe_tower_used_filament_m = 0, total_wipe_tower_used_filament_g = 0; + struct ColumnData { + enum { + Model = 1, + Flushed = 2, + WipeTower = 4, + }; + }; + int displayed_columns = 0; const PrintStatistics& ps = wxGetApp().plater()->get_partplate_list().get_current_fff_print().print_statistics(); double koef = imperial_units ? GizmoObjectManipulation::in_to_mm : 1000.0; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1; @@ -4701,39 +4761,76 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv case EViewType::ColorPrint: { for (size_t extruder_id : m_extruder_ids) { - if (m_print_statistics.volumes_per_extruder.find(extruder_id) == m_print_statistics.volumes_per_extruder.end()) continue; - double volume = m_print_statistics.volumes_per_extruder.at(extruder_id); - auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(volume, extruder_id); - model_used_filaments_m.push_back(model_used_filament_m); - model_used_filaments_g.push_back(model_used_filament_g); - total_model_used_filament_m += model_used_filament_m; - total_model_used_filament_g += model_used_filament_g; + if (m_print_statistics.volumes_per_extruder.find(extruder_id) == m_print_statistics.volumes_per_extruder.end()) { + model_used_filaments_m.push_back(0.0); + model_used_filaments_g.push_back(0.0); + } + else { + double volume = m_print_statistics.volumes_per_extruder.at(extruder_id); + auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(volume, extruder_id); + model_used_filaments_m.push_back(model_used_filament_m); + model_used_filaments_g.push_back(model_used_filament_g); + total_model_used_filament_m += model_used_filament_m; + total_model_used_filament_g += model_used_filament_g; + displayed_columns |= ColumnData::Model; + } + } + + for (size_t extruder_id : m_extruder_ids) { + if (m_print_statistics.wipe_tower_volumes_per_extruder.find(extruder_id) == m_print_statistics.wipe_tower_volumes_per_extruder.end()) { + wipe_tower_used_filaments_m.push_back(0.0); + wipe_tower_used_filaments_g.push_back(0.0); + } + else { + double volume = m_print_statistics.wipe_tower_volumes_per_extruder.at(extruder_id); + auto [wipe_tower_used_filament_m, wipe_tower_used_filament_g] = get_used_filament_from_volume(volume, extruder_id); + wipe_tower_used_filaments_m.push_back(wipe_tower_used_filament_m); + wipe_tower_used_filaments_g.push_back(wipe_tower_used_filament_g); + total_wipe_tower_used_filament_m += wipe_tower_used_filament_m; + total_wipe_tower_used_filament_g += wipe_tower_used_filament_g; + displayed_columns |= ColumnData::WipeTower; + } } - if (model_used_filaments_m.size() == 0 || model_used_filaments_g.size() == 0) - show_model_used_filaments = false; for (size_t extruder_id : m_extruder_ids) { - if (m_print_statistics.flush_per_filament.find(extruder_id) == m_print_statistics.flush_per_filament.end()) continue; - double volume = m_print_statistics.flush_per_filament.at(extruder_id); - auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(volume, extruder_id); - flushed_filaments_m.push_back(flushed_filament_m); - flushed_filaments_g.push_back(flushed_filament_g); - total_flushed_filament_m += flushed_filament_m; - total_flushed_filament_g += flushed_filament_g; + if (m_print_statistics.flush_per_filament.find(extruder_id) == m_print_statistics.flush_per_filament.end()) { + flushed_filaments_m.push_back(0.0); + flushed_filaments_g.push_back(0.0); + } + else { + double volume = m_print_statistics.flush_per_filament.at(extruder_id); + auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(volume, extruder_id); + flushed_filaments_m.push_back(flushed_filament_m); + flushed_filaments_g.push_back(flushed_filament_g); + total_flushed_filament_m += flushed_filament_m; + total_flushed_filament_g += flushed_filament_g; + displayed_columns |= ColumnData::Flushed; + } } - if (flushed_filaments_m.size() == 0 || flushed_filaments_g.size() == 0) - show_flushed_filaments = false; std::vector total_filaments; char buffer[64]; ::sprintf(buffer, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", ps.total_used_filament / /*1000*/koef, ps.total_weight / unit_conver); total_filaments.push_back(buffer); - offsets = calculate_offsets({ {_u8L("Filament"), {""}}, {_u8L("Model"), total_filaments}, {_u8L("Flushed"), total_filaments}, /*{_u8L("Tower"), total_filaments},*/ {_u8L("Total"), total_filaments} }, icon_size); - if (m_extruder_ids.size() <= 1 || !show_flushed_filaments) + + if (displayed_columns == ColumnData::Model) { + offsets = calculate_offsets({ {_u8L("Filament"), {""}}, {_u8L("Model"), total_filaments}, {_u8L("Flushed"), total_filaments}, {_u8L("Total"), total_filaments} }, icon_size); append_headers({ {_u8L("Filament"), offsets[0]}, {_u8L("Model"), offsets[2]}}); - else - append_headers({ {_u8L("Filament"), offsets[0]}, {_u8L("Model"), offsets[1]}, {_u8L("Flushed"), offsets[2]}, /*{_u8L("Tower"), offsets[3]},*/ {_u8L("Total"), offsets[3]}});// to add Tower + } + else if (displayed_columns == (ColumnData::Model | ColumnData::Flushed)) { + offsets = calculate_offsets({ {_u8L("Filament"), {""}}, {_u8L("Model"), total_filaments}, {_u8L("Flushed"), total_filaments}, {_u8L("Total"), total_filaments} }, icon_size); + append_headers({ {_u8L("Filament"), offsets[0]}, {_u8L("Model"), offsets[1]}, {_u8L("Flushed"), offsets[2]}, {_u8L("Total"), offsets[3]} }); + } + else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "displayed_columns: " << displayed_columns; + if (displayed_columns != (ColumnData::Model | ColumnData::Flushed | ColumnData::WipeTower)) + displayed_columns = (ColumnData::Model | ColumnData::Flushed | ColumnData::WipeTower); + + offsets = calculate_offsets({ {_u8L("Filament"), {""}}, {_u8L("Model"), total_filaments}, {_u8L("Flushed"), total_filaments}, {_u8L("Tower"), total_filaments}, {_u8L("Total"), total_filaments} }, icon_size); + append_headers({ {_u8L("Filament"), offsets[0]}, {_u8L("Model"), offsets[1]}, {_u8L("Flushed"), offsets[2]}, {_u8L("Tower"), offsets[3]}, {_u8L("Total"), offsets[4]} }); + } + break; } default: { break; } @@ -4824,8 +4921,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f)); append_item(EItemType::None, Travel_Colors[0], { {_u8L("travel"), offsets[0] }}, true, travel_visible, [this, travel_visible]() { m_buffers[buffer_id(EMoveType::Travel)].visible = !m_buffers[buffer_id(EMoveType::Travel)].visible; - // update buffers' render paths - refresh_render_paths(false, false); + // update buffers' render paths, and update m_tools.m_tool_colors and m_extrusions.ranges + refresh(*m_gcode_result, wxGetApp().plater()->get_extruder_colors_from_plater_config(m_gcode_result)); update_moves_slider(); wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); }); @@ -4854,105 +4951,69 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv //BBS: replace model custom gcode with current plate custom gcode const std::vector& custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().get_curr_plate_custom_gcodes().gcodes : m_custom_gcode_per_print_z; size_t total_items = 1; - for (size_t extruder_id : m_extruder_ids) { - total_items += color_print_ranges(extruder_id, custom_gcode_per_print_z).size(); - } + // BBS: no ColorChange type, use ToolChange + //for (size_t extruder_id : m_extruder_ids) { + // total_items += color_print_ranges(extruder_id, custom_gcode_per_print_z).size(); + //} const bool need_scrollable = static_cast(total_items) * (icon_size + ImGui::GetStyle().ItemSpacing.y) > child_height; // add scrollable region, if needed if (need_scrollable) ImGui::BeginChild("color_prints", { -1.0f, child_height }, false); - if (m_extruder_ids.size() == 1) { // single extruder use case - const std::vector>> cp_values = color_print_ranges(0, custom_gcode_per_print_z); - const int items_cnt = static_cast(cp_values.size()); - auto extruder_idx = m_extruder_ids[0]; - if (items_cnt == 0) { // There are no color changes, but there are some pause print or custom Gcode - std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), offsets[0] }); + // shows only extruders actually used + size_t i = 0; + for (auto extruder_idx : m_extruder_ids) { + const bool filament_visible = m_tools.m_tool_visibles[extruder_idx]; + if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { + std::vector> columns_offsets; + columns_offsets.push_back({ std::to_string(extruder_idx + 1), offsets[0] }); + + char buf[64]; + if (displayed_columns == ColumnData::Model) { char buf[64]; - ::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", model_used_filaments_m[0], model_used_filaments_g[0] / unit_conver); + ::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i] / unit_conver); columns_offsets.push_back({ buf, offsets[2] }); - - append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_idx], columns_offsets, false); - } - else { - for (int i = items_cnt; i >= 0; --i) { - // create label for color change item - if (i == 0) { - append_item(EItemType::Rect, m_tools.m_tool_colors[0], {{ upto_label(cp_values.front().second.first), offsets[1]} }, false); - break; - } - else if (i == items_cnt) { - append_item(EItemType::Rect, cp_values[i - 1].first, { {above_label(cp_values[i - 1].second.second), offsets[1]} }, false); - continue; - } - append_item(EItemType::Rect, cp_values[i - 1].first, { {fromto_label(cp_values[i - 1].second.second, cp_values[i].second.first), offsets[1]} }, false); } - } - } - else { // multi extruder use case - // shows only extruders actually used - size_t i = 0; - for (auto extruder_idx : m_extruder_ids) { - const std::vector>> cp_values = color_print_ranges(extruder_idx, custom_gcode_per_print_z); - const int items_cnt = static_cast(cp_values.size()); - if (items_cnt == 0) { // There are no color changes, but there are some pause print or custom Gcode - const bool filament_visible = m_tools.m_tool_visibles[extruder_idx]; - if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) { - std::vector> columns_offsets; - columns_offsets.push_back({ std::to_string(extruder_idx + 1), offsets[0] }); - - char buf[64]; - if (show_flushed_filaments) { - ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m[i], model_used_filaments_g[i] / unit_conver); - columns_offsets.push_back({ buf, offsets[1] }); - - ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", flushed_filaments_m[i], flushed_filaments_g[i] / unit_conver); - columns_offsets.push_back({ buf, offsets[2] }); - - ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", (model_used_filaments_m[i] + flushed_filaments_m[i]), - (model_used_filaments_g[i] + flushed_filaments_g[i]) / unit_conver); - columns_offsets.push_back({ buf, offsets[3] }); - } - else { - char buf[64]; - ::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i] / unit_conver); - columns_offsets.push_back({buf, offsets[2]}); - } + if (displayed_columns == (ColumnData::Model | ColumnData::Flushed)) { + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m[i], model_used_filaments_g[i] / unit_conver); + columns_offsets.push_back({ buf, offsets[1] }); - append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_idx], columns_offsets, false, filament_visible, [this, extruder_idx]() { - m_tools.m_tool_visibles[extruder_idx] = !m_tools.m_tool_visibles[extruder_idx]; - // update buffers' render paths - refresh_render_paths(false, false); - update_moves_slider(); - wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); - }); - } + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", flushed_filaments_m[i], flushed_filaments_g[i] / unit_conver); + columns_offsets.push_back({ buf, offsets[2] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", (model_used_filaments_m[i] + flushed_filaments_m[i]), + (model_used_filaments_g[i] + flushed_filaments_g[i]) / unit_conver); + columns_offsets.push_back({ buf, offsets[3] }); } - else { - for (int j = items_cnt; j >= 0; --j) { - // create label for color change item - std::string label = _u8L("Filament") + " " + std::to_string(extruder_idx + 1); - if (j == 0) { - label += " " + upto_label(cp_values.front().second.first); - append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_idx], { { label, 0 } }, false); - break; - } - else if (j == items_cnt) { - label += " " + above_label(cp_values[j - 1].second.second); - append_item(EItemType::Rect, cp_values[j - 1].first, { { label, 0 } }, false); - continue; - } + if (displayed_columns == (ColumnData::Model | ColumnData::Flushed | ColumnData::WipeTower)) { + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m[i], model_used_filaments_g[i] / unit_conver); + columns_offsets.push_back({ buf, offsets[1] }); - label += " " + fromto_label(cp_values[j - 1].second.second, cp_values[j].second.first); - append_item(EItemType::Rect, cp_values[j - 1].first, { { label, 0 } }, false); - } + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", flushed_filaments_m[i], flushed_filaments_g[i] / unit_conver); + columns_offsets.push_back({ buf, offsets[2] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", wipe_tower_used_filaments_m[i], wipe_tower_used_filaments_g[i] / unit_conver); + columns_offsets.push_back({ buf, offsets[3] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", (model_used_filaments_m[i] + flushed_filaments_m[i] + wipe_tower_used_filaments_m[i]), + (model_used_filaments_g[i] + flushed_filaments_g[i] + wipe_tower_used_filaments_g[i]) / unit_conver); + columns_offsets.push_back({ buf, offsets[4] }); } - i++; + + + append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_idx], columns_offsets, false, filament_visible, [this, extruder_idx]() { + m_tools.m_tool_visibles[extruder_idx] = !m_tools.m_tool_visibles[extruder_idx]; + // update buffers' render paths + refresh_render_paths(false, false); + update_moves_slider(); + wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); + }); } + i++; } + if (need_scrollable) ImGui::EndChild(); @@ -4967,13 +5028,13 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv std::vector> columns_offsets; columns_offsets.push_back({ _u8L("Total"), offsets[0] }); - if (!show_flushed_filaments) { + if (displayed_columns == ColumnData::Model) { ::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", total_model_used_filament_m, total_model_used_filament_g / unit_conver); columns_offsets.push_back({ buf, offsets[2] }); append_item(EItemType::None, m_tools.m_tool_colors[0], columns_offsets); } - else { + if (displayed_columns == (ColumnData::Model | ColumnData::Flushed)) { ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_model_used_filament_m, total_model_used_filament_g / unit_conver); columns_offsets.push_back({ buf, offsets[1] }); @@ -4981,9 +5042,25 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv columns_offsets.push_back({ buf, offsets[2] }); bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; - ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_model_used_filament_m + total_flushed_filament_m, (total_model_used_filament_g + total_flushed_filament_g) / unit_conver); + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_model_used_filament_m + total_flushed_filament_m , (total_model_used_filament_g + total_flushed_filament_g) / unit_conver); + columns_offsets.push_back({ buf, offsets[3] }); + + append_item(EItemType::None, m_tools.m_tool_colors[0], columns_offsets); + } + if (displayed_columns == (ColumnData::Model | ColumnData::Flushed | ColumnData::WipeTower)) { + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_model_used_filament_m, total_model_used_filament_g / unit_conver); + columns_offsets.push_back({ buf, offsets[1] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_flushed_filament_m, total_flushed_filament_g / unit_conver); + columns_offsets.push_back({ buf, offsets[2] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_wipe_tower_used_filament_m, total_wipe_tower_used_filament_g / unit_conver); columns_offsets.push_back({ buf, offsets[3] }); + bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_model_used_filament_m + total_flushed_filament_m + total_wipe_tower_used_filament_m, (total_model_used_filament_g + total_flushed_filament_g + total_wipe_tower_used_filament_g) / unit_conver); + columns_offsets.push_back({ buf, offsets[4] }); + append_item(EItemType::None, m_tools.m_tool_colors[0], columns_offsets); } } diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index d0bfdc544f2..0d730bb0f97 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -772,6 +772,7 @@ Range layer_duration_log; std::vector options_items; bool m_legend_enabled{ true }; + float m_legend_height; PrintEstimatedStatistics m_print_statistics; PrintEstimatedStatistics::ETimeMode m_time_estimate_mode{ PrintEstimatedStatistics::ETimeMode::Normal }; #if ENABLE_GCODE_VIEWER_STATISTICS @@ -810,7 +811,7 @@ mutable bool m_no_render_path { false }; void reset(); //BBS: always load shell at preview void reset_shell(); - void load_shells(const Print& print, bool force_previewing = false); + void load_shells(const Print& print, bool initialized, bool force_previewing = false); void set_shells_on_preview(bool is_previewing) { m_shells.previewing = is_previewing; } //BBS: add all plates filament statistics void render_all_plates_stats(const std::vector& gcode_result_list, bool show = true) const; @@ -877,6 +878,7 @@ mutable bool m_no_render_path { false }; bool is_legend_enabled() const { return m_legend_enabled; } void enable_legend(bool enable) { m_legend_enabled = enable; } + float get_legend_height() { return m_legend_height; } void export_toolpaths_to_obj(const char* filename) const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8bbab3a2bf1..25a142b1068 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -41,6 +41,7 @@ #include "I18N.hpp" #include "NotificationManager.hpp" #include "format.hpp" +#include "DailyTips.hpp" #include "slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp" #include "slic3r/Utils/UndoRedo.hpp" @@ -1134,6 +1135,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) , m_moving(false) , m_tab_down(false) , m_cursor_type(Standard) + , m_color_by("volume") , m_reload_delayed(false) , m_render_sla_auxiliaries(true) , m_labels(*this) @@ -1234,6 +1236,8 @@ void GLCanvas3D::on_change_color_mode(bool is_dark, bool reinit) { wxGetApp().imgui()->on_change_color_mode(is_dark); // Notification wxGetApp().plater()->get_notification_manager()->on_change_color_mode(is_dark); + // DailyTips Window + wxGetApp().plater()->get_dailytips()->on_change_color_mode(is_dark); // Preview Slider IMSlider* m_layers_slider = get_gcode_viewer().get_layers_slider(); IMSlider* m_moves_slider = get_gcode_viewer().get_moves_slider(); @@ -1472,6 +1476,11 @@ Camera& GLCanvas3D::get_camera() return camera; } +void GLCanvas3D::set_color_by(const std::string& value) +{ + m_color_by = value; +} + void GLCanvas3D::refresh_camera_scene_box() { wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box()); @@ -1726,47 +1735,6 @@ bool GLCanvas3D::make_current_for_postinit() { return _set_current(); } -Points GLCanvas3D::estimate_wipe_tower_points(int plate_index, bool global) const -{ - PartPlateList & ppl = wxGetApp().plater()->get_partplate_list(); - DynamicPrintConfig &proj_cfg = wxGetApp().preset_bundle->project_config; - auto & print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); - int plate_count = ppl.get_plate_count(); - float x = dynamic_cast(proj_cfg.option("wipe_tower_x"))->get_at(plate_index); - float y = dynamic_cast(proj_cfg.option("wipe_tower_y"))->get_at(plate_index); - if (plate_index >= plate_count) { plate_index = 0; } - float w = dynamic_cast(m_config->option("prime_tower_width"))->value; - auto part_plate = ppl.get_plate(plate_index); - const auto &wipe_tower_data = print.wipe_tower_data(part_plate->get_extruders(true).size()); - // float v = dynamic_cast(m_config->option("prime_volume"))->value; - const DynamicPrintConfig &print_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; - Vec3d wipe_tower_size = part_plate->estimate_wipe_tower_size(print_cfg, w, wipe_tower_data.depth); - - if (wipe_tower_size(1) == 0) { - // when depth is unavailable (no items on this plate), we have to estimate the depth using the extruder number of all plates - std::set extruder_ids; - if (global) { - auto objs = wxGetApp().obj_list()->objects(); - for (ModelObject *obj : *objs) { - for (ModelVolume *volume : obj->volumes) { - std::vector es = volume->get_extruders(); - extruder_ids.insert(es.begin(), es.end()); - } - } - } else { - PartPlate* pl = ppl.get_plate(plate_index); - std::vector es = pl->get_extruders(); - extruder_ids.insert(es.begin(), es.end()); - } - int extruder_size = extruder_ids.size(); - wipe_tower_size(1) = extruder_size * print.wipe_tower_data(extruder_size).depth + 2 * print.wipe_tower_data().brim_width; - } - Vec3d plate_origin = ppl.get_plate(plate_index)->get_origin(); - Point wt_min_corner{scale_(x), scale_(y)}; - Point wt_max_corner(scale_(x + wipe_tower_size(0)), scale_(y + wipe_tower_size(1))); - return {wt_min_corner, {wt_max_corner.x(), wt_min_corner.y()}, wt_max_corner, {wt_min_corner.x(), wt_max_corner.y()}}; -} - void GLCanvas3D::render(bool only_init) { if (m_in_render) { @@ -2021,6 +1989,7 @@ void GLCanvas3D::render(bool only_init) bottom_margin = SLIDER_BOTTOM_MARGIN * scale_factor * GCODE_VIEWER_SLIDER_SCALE; } wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin); + wxGetApp().plater()->get_dailytips()->render(); } wxGetApp().imgui()->render(); @@ -2068,6 +2037,11 @@ void GLCanvas3D::select_curr_plate_all() m_dirty = true; } +void GLCanvas3D::select_object_from_idx(std::vector& object_idxs) { + m_selection.add_object_from_idx(object_idxs); + m_dirty = true; +} + //BBS void GLCanvas3D::remove_curr_plate_all() { @@ -2173,7 +2147,7 @@ std::vector GLCanvas3D::load_object(const ModelObject& model_object, int ob instance_idxs.emplace_back(i); } } - return m_volumes.load_object(&model_object, obj_idx, instance_idxs); + return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized); } std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) @@ -2484,7 +2458,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh // later in this function. it->volume_idx = m_volumes.volumes.size(); - m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_canvas_type == ECanvasType::CanvasAssembleView); + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized, m_canvas_type == ECanvasType::CanvasAssembleView); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; } else { @@ -2638,19 +2612,36 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re const DynamicPrintConfig &print_cfg = wxGetApp().preset_bundle->prints.get_edited_preset().config; Vec3d wipe_tower_size = ppl.get_plate(plate_id)->estimate_wipe_tower_size(print_cfg, w, wipe_tower_data.depth); - const float margin = 15.f; + const float margin = WIPE_TOWER_MARGIN; BoundingBoxf3 plate_bbox = wxGetApp().plater()->get_partplate_list().get_plate(plate_id)->get_bounding_box(); coordf_t plate_bbox_x_max_local_coord = plate_bbox.max(0) - plate_origin(0); coordf_t plate_bbox_y_max_local_coord = plate_bbox.max(1) - plate_origin(1); + bool need_update = false; if (x + margin + wipe_tower_size(0) > plate_bbox_x_max_local_coord) { x = plate_bbox_x_max_local_coord - wipe_tower_size(0) - margin; + need_update = true; + } + else if (x < margin) { + x = margin; + need_update = true; + } + if (need_update) { ConfigOptionFloat wt_x_opt(x); dynamic_cast(proj_cfg.option("wipe_tower_x"))->set_at(&wt_x_opt, plate_id, 0); + need_update = false; } + if (y + margin + wipe_tower_size(1) > plate_bbox_y_max_local_coord) { y = plate_bbox_y_max_local_coord - wipe_tower_size(1) - margin; + need_update = true; + } + else if (y < margin) { + y = margin; + need_update = true; + } + if (need_update) { ConfigOptionFloat wt_y_opt(y); - dynamic_cast(proj_cfg.option("wipe_tower_y"))->set_at(&wt_y_opt, plate_id, 0); + dynamic_cast(proj_cfg.option("wipe_tower_y"))->set_at(&wt_y_opt, plate_id, 0); } int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( @@ -2756,7 +2747,7 @@ void GLCanvas3D::load_shells(const Print& print, bool force_previewing) { if (m_initialized) { - m_gcode_viewer.load_shells(print, force_previewing); + m_gcode_viewer.load_shells(print, m_initialized, force_previewing); m_gcode_viewer.update_shells_color_by_extruder(m_config); } } @@ -3122,6 +3113,14 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) #endif /* __APPLE__ */ post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); break; +#ifdef __APPLE__ + case 'k': + case 'K': +#else /* __APPLE__ */ + case WXK_CONTROL_K: +#endif /* __APPLE__ */ + post_event(SimpleEvent(EVT_GLTOOLBAR_CLONE)); + break; default: evt.Skip(); } } else { @@ -4708,6 +4707,13 @@ void GLCanvas3D::do_center() m_selection.center(); } +void GLCanvas3D::do_center_plate(const int plate_idx) { + if (m_model == nullptr) + return; + + m_selection.center_plate(plate_idx); +} + void GLCanvas3D::do_mirror(const std::string& snapshot_type) { if (m_model == nullptr) @@ -4868,6 +4874,12 @@ GLCanvas3D::WipeTowerInfo GLCanvas3D::get_wipe_tower_info(int plate_idx) const float brim_width = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_float("prime_tower_brim_width"); wti.m_bb.offset((brim_width)); + // BBS: the wipe tower pos might be outside bed + PartPlate* plate = wxGetApp().plater()->get_partplate_list().get_plate(plate_idx); + Vec2d plate_size = plate->get_size(); + wti.m_pos.x() = std::clamp(wti.m_pos.x(), 0.0, plate_size(0) - wti.m_bb.size().x()); + wti.m_pos.y() = std::clamp(wti.m_pos.y(), 0.0, plate_size(1) - wti.m_bb.size().y()); + // BBS: add partplate logic wti.m_plate_idx = plate_idx; break; @@ -4898,8 +4910,8 @@ std::vector GLCanvas3D::get_empty_cells(const Vec2f start_point, const Ve Vec2d vmin(build_volume.min.x(), build_volume.min.y()), vmax(build_volume.max.x(), build_volume.max.y()); BoundingBoxf bbox(vmin, vmax); std::vector cells; - for (float x = bbox.min.x(); x < bbox.max.x(); x += step(0)) - for (float y = bbox.min.y(); y < bbox.max.y(); y += step(1)) + for (float x = bbox.min.x()+step(0)/2; x < bbox.max.x()-step(0)/2; x += step(0)) + for (float y = bbox.min.y()+step(1)/2; y < bbox.max.y()-step(1)/2; y += step(1)) { cells.emplace_back(x, y); } @@ -6123,6 +6135,7 @@ bool GLCanvas3D::_init_main_toolbar() item.left.render_callback = nullptr; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); }; item.visibility_callback = GLToolbarItem::Default_Visibility_Callback; + item.left.toggable = false; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_split_to_objects(); }; if (!m_main_toolbar.add_item(item)) return false; @@ -7624,6 +7637,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() m_sel_plate_toolbar.m_items[i]->selected = false; } all_plates_stats_item->selected = true; + wxGetApp().plater()->update(true, true); wxCommandEvent evt = wxCommandEvent(EVT_GLTOOLBAR_SLICE_ALL); wxPostEvent(wxGetApp().plater(), evt); } @@ -7708,6 +7722,8 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() all_plates_stats_item->selected = false; item->selected = true; // begin to slicing plate + if (item->slice_state != IMToolbarItem::SliceState::SLICED) + wxGetApp().plater()->update(true, true); wxCommandEvent* evt = new wxCommandEvent(EVT_GLTOOLBAR_SELECT_SLICED_PLATE); evt->SetInt(i); wxQueueEvent(wxGetApp().plater(), evt); @@ -9176,13 +9192,13 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) break; case SLICING_SERIOUS_WARNING: if (state) - notification_manager.push_slicing_serious_warning_notification(text, {conflictObj}); + notification_manager.push_slicing_serious_warning_notification(text, conflictObj ? std::vector{conflictObj} : std::vector{}); else notification_manager.close_slicing_serious_warning_notification(text); break; case SLICING_ERROR: if (state) - notification_manager.push_slicing_error_notification(text, {conflictObj}); + notification_manager.push_slicing_error_notification(text, conflictObj ? std::vector{conflictObj} : std::vector{}); else notification_manager.close_slicing_error_notification(text); break; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 523b0d5f6e1..901ff007cd7 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -582,6 +582,8 @@ class GLCanvas3D // I just don't want to do it now before a release (Lukas Matena 24.3.2019) bool m_render_sla_auxiliaries; + std::string m_color_by; + bool m_reload_delayed; RenderStats m_render_stats; @@ -629,7 +631,7 @@ class GLCanvas3D int split_to_objects_count = 0; int split_to_part_count = 0; int custom_height_count = 0; - int custom_painting_count = 0; + int assembly_view_count = 0; public: OrientSettings& get_orient_settings() @@ -812,6 +814,7 @@ class GLCanvas3D void set_color_clip_plane_colors(const std::array& colors) { m_volumes.set_color_clip_plane_colors(colors); } void refresh_camera_scene_box(); + void set_color_by(const std::string& value); BoundingBoxf3 volumes_bounding_box(bool current_plate_only = false) const; BoundingBoxf3 scene_bounding_box() const; @@ -902,6 +905,7 @@ class GLCanvas3D //BBS void select_curr_plate_all(); + void select_object_from_idx(std::vector& object_idxs); void remove_curr_plate_all(); void update_plate_thumbnails(); @@ -967,6 +971,7 @@ class GLCanvas3D void do_rotate(const std::string& snapshot_type); void do_scale(const std::string& snapshot_type); void do_center(); + void do_center_plate(const int plate_idx); void do_mirror(const std::string& snapshot_type); void update_gizmos_on_off_state(); @@ -1108,9 +1113,6 @@ class GLCanvas3D bool make_current_for_postinit(); - //BBS - Points estimate_wipe_tower_points(int plate_index, bool global = true) const; - private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 9a29714f288..8485bfdb884 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -100,6 +100,7 @@ #include "ReleaseNote.hpp" #include "PrivacyUpdateDialog.hpp" #include "ModelMall.hpp" +#include "HintNotification.hpp" //#ifdef WIN32 //#include "BaseException.h" @@ -1020,6 +1021,14 @@ void GUI_App::post_init() if (! this->initialized()) throw Slic3r::RuntimeError("Calling post_init() while not yet initialized"); + if (app_config->get("sync_user_preset") == "true") { + // BBS loading user preset + // Always async, not such startup step + // BOOST_LOG_TRIVIAL(info) << "Loading user presets..."; + // scrn->SetText(_L("Loading user presets...")); + if (m_agent) { start_sync_user_preset(); } + } + bool switch_to_3d = false; if (!this->init_params->input_files.empty()) { @@ -1242,8 +1251,6 @@ void GUI_App::post_init() hms_query->check_hms_info(); }); - std::string functional_config_file = Slic3r::resources_dir() + "/config.json"; - DeviceManager::load_functional_config(encode_path(functional_config_file.c_str())); std::string filaments_blacklist_config_file = Slic3r::resources_dir() + "/printers/filaments_blacklist.json"; DeviceManager::load_filaments_blacklist_config(encode_path(filaments_blacklist_config_file.c_str())); @@ -1332,21 +1339,6 @@ void GUI_App::shutdown() if (m_is_recreating_gui) return; m_is_closing = true; - stop_sync_user_preset(); - - if (m_device_manager) { - delete m_device_manager; - m_device_manager = nullptr; - } - - if (m_agent) { - //BBS avoid a crash on mac platform -#ifdef __WINDOWS__ - m_agent->start_discovery(false, false); -#endif - delete m_agent; - m_agent = nullptr; - } BOOST_LOG_TRIVIAL(info) << "GUI_App::shutdown exit"; } @@ -1848,6 +1840,8 @@ void GUI_App::init_networking_callbacks() obj->is_tunnel_mqtt = tunnel; obj->command_request_push_all(true); obj->command_get_version(); + obj->erase_user_access_code(); + obj->command_get_access_code(); GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj); } }); @@ -1860,6 +1854,12 @@ void GUI_App::init_networking_callbacks() } ); + m_agent->set_on_subscribe_failure_fn([this](std::string dev_id) { + CallAfter([this, dev_id] { + on_start_subscribe_again(dev_id); + }); + }); + m_agent->set_on_local_connect_fn( [this](int state, std::string dev_id, std::string msg) { if (m_is_closing) { @@ -2220,7 +2220,8 @@ void GUI_App::on_start_subscribe_again(std::string dev_id) MachineObject* obj = dev->get_selected_machine(); if (!obj) return; - if ( (dev_id == obj->dev_id) && obj->is_connecting() ) { + if ( (dev_id == obj->dev_id) && obj->is_connecting() && obj->subscribe_counter > 0) { + obj->subscribe_counter--; if(wxGetApp().getAgent()) wxGetApp().getAgent()->set_user_selected_machine(dev_id); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": dev_id=" << obj->dev_id; } @@ -2263,6 +2264,27 @@ bool GUI_App::OnInit() } } +int GUI_App::OnExit() +{ + stop_sync_user_preset(); + + if (m_device_manager) { + delete m_device_manager; + m_device_manager = nullptr; + } + + if (m_agent) { + // BBS avoid a crash on mac platform +#ifdef __WINDOWS__ + m_agent->start_discovery(false, false); +#endif + delete m_agent; + m_agent = nullptr; + } + + return wxApp::OnExit(); +} + class wxBoostLog : public wxLog { void DoLogText(const wxString &msg) override { @@ -2496,7 +2518,6 @@ bool GUI_App::on_init_inner() dialog.SetExtendedMessage(extmsg);*/ - std::string skip_version_str = this->app_config->get("app", "skip_version"); bool skip_this_version = false; if (!skip_version_str.empty()) { @@ -2515,7 +2536,7 @@ bool GUI_App::on_init_inner() dialog.update_version_info(extmsg, version_info.version_str); //dialog.update_version_info(version_info.description); if (evt.GetInt() != 0) { - dialog.m_remind_choice->Hide(); + dialog.m_button_skip_version->Hide(); } switch (dialog.ShowModal()) { @@ -2612,16 +2633,6 @@ bool GUI_App::on_init_inner() } //} - if (app_config->get("sync_user_preset") == "true") { - //BBS loading user preset - // Always async, not such startup step - //BOOST_LOG_TRIVIAL(info) << "Loading user presets..."; - //scrn->SetText(_L("Loading user presets...")); - if (m_agent) { - start_sync_user_preset(); - } - } - #ifdef WIN32 #if !wxVERSION_EQUAL_OR_GREATER_THAN(3,1,3) register_win32_dpi_event(); @@ -2879,14 +2890,16 @@ bool GUI_App::on_init_network(bool try_backup) if (create_network_agent) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", create network agent..."); - m_agent = new Slic3r::NetworkAgent(); + //std::string data_dir = wxStandardPaths::Get().GetUserDataDir().ToUTF8().data(); + std::string data_directory = data_dir(); + + m_agent = new Slic3r::NetworkAgent(data_directory); if (!m_device_manager) m_device_manager = new Slic3r::DeviceManager(m_agent); else m_device_manager->set_agent(m_agent); - //std::string data_dir = wxStandardPaths::Get().GetUserDataDir().ToUTF8().data(); - std::string data_directory = data_dir(); + //BBS set config dir if (m_agent) { @@ -3009,7 +3022,7 @@ void GUI_App::update_publish_status() bool GUI_App::has_model_mall() { - if (auto cc = app_config->get_country_code(); cc == "CN" || cc == "") + if (auto cc = app_config->get_region(); cc == "CNH" || cc == "China" || cc == "") return false; return true; } @@ -4049,8 +4062,8 @@ void GUI_App::on_http_error(wxCommandEvent &evt) if (code == HttpErrorVersionLimited) { MessageDialog msg_dlg(nullptr, _L("The version of Orca Slicer is too low and needs to be updated to the latest version before it can be used normally"), "", wxAPPLY | wxOK); if (msg_dlg.ShowModal() == wxOK) { - return; } + } // request login @@ -4058,9 +4071,15 @@ void GUI_App::on_http_error(wxCommandEvent &evt) if (m_agent) { if (m_agent->is_user_login()) { this->request_user_logout(); - MessageDialog msg_dlg(nullptr, _L("Login information expired. Please login again."), "", wxAPPLY | wxOK); - if (msg_dlg.ShowModal() == wxOK) { - return; + + if (!m_show_http_errpr_msgdlg) { + MessageDialog msg_dlg(nullptr, _L("Login information expired. Please login again."), "", wxAPPLY | wxOK); + m_show_http_errpr_msgdlg = true; + auto modal_result = msg_dlg.ShowModal(); + if (modal_result == wxOK || modal_result == wxCLOSE) { + m_show_http_errpr_msgdlg = false; + return; + } } } } @@ -4516,6 +4535,7 @@ void GUI_App::reload_settings() if (preset_bundle && m_agent) { std::map> user_presets; m_agent->get_user_presets(&user_presets); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " cloud user preset number is: " << user_presets.size(); preset_bundle->load_user_presets(*app_config, user_presets, ForwardCompatibilitySubstitutionRule::Enable); preset_bundle->save_user_presets(*app_config, get_delete_cache_presets()); mainframe->update_side_preset_ui(); @@ -4542,18 +4562,25 @@ void GUI_App::sync_preset(Preset* preset) int result = -1; unsigned int http_code = 200; std::string updated_info; + long long update_time = 0; // only sync user's preset if (!preset->is_user()) return; if (preset->is_custom_defined()) return; - if (preset->setting_id.empty() && preset->sync_info.empty() && !preset->base_id.empty()) { - std::map values_map; + auto setting_id = preset->setting_id; + std::map values_map; + if (setting_id.empty() && preset->sync_info.empty()) { + if (m_create_preset_blocked[preset->type]) + return; int ret = preset_bundle->get_differed_values_to_update(*preset, values_map); if (!ret) { std::string new_setting_id = m_agent->request_setting_id(preset->name, &values_map, &http_code); if (!new_setting_id.empty()) { - preset->setting_id = new_setting_id; + setting_id = new_setting_id; result = 0; + auto update_time_str = values_map[BBL_JSON_KEY_UPDATE_TIME]; + if (!update_time_str.empty()) + update_time = std::atoll(update_time_str.c_str()); } else { BOOST_LOG_TRIVIAL(trace) << "[sync_preset]init: request_setting_id failed, http code "<sync_info.compare("create") == 0) && !preset->base_id.empty()) { - std::map values_map; + else if (preset->sync_info.compare("create") == 0) { + if (m_create_preset_blocked[preset->type]) + return; int ret = preset_bundle->get_differed_values_to_update(*preset, values_map); if (!ret) { std::string new_setting_id = m_agent->request_setting_id(preset->name, &values_map, &http_code); if (!new_setting_id.empty()) { - preset->setting_id = new_setting_id; + setting_id = new_setting_id; result = 0; + auto update_time_str = values_map[BBL_JSON_KEY_UPDATE_TIME]; + if (!update_time_str.empty()) + update_time = std::atoll(update_time_str.c_str()); } else { BOOST_LOG_TRIVIAL(trace) << "[sync_preset]create: request_setting_id failed, http code "<sync_info.compare("update") == 0) && !preset->base_id.empty()) { - if (!preset->setting_id.empty()) { - std::map values_map; + else if (preset->sync_info.compare("update") == 0) { + if (!setting_id.empty()) { int ret = preset_bundle->get_differed_values_to_update(*preset, values_map); if (!ret) { - if (values_map[BBL_JSON_KEY_BASE_ID] == preset->setting_id) { - //clear the setting_id in this case - preset->setting_id.clear(); + if (auto iter = values_map.find(BBL_JSON_KEY_BASE_ID); iter != values_map.end() && iter->second == setting_id) { + //clear the setting_id in this case ??? + setting_id.clear(); result = 0; } else { - result = m_agent->put_setting(preset->setting_id, preset->name, &values_map, &http_code); + result = m_agent->put_setting(setting_id, preset->name, &values_map, &http_code); if (http_code >= 400) { result = 0; updated_info = "hold"; - BOOST_LOG_TRIVIAL(error) << "[sync_preset] put setting_id = " << preset->setting_id << " failed, http_code = " << http_code; + BOOST_LOG_TRIVIAL(error) << "[sync_preset] put setting_id = " << setting_id << " failed, http_code = " << http_code; + } else { + auto update_time_str = values_map[BBL_JSON_KEY_UPDATE_TIME]; + if (!update_time_str.empty()) + update_time = std::atoll(update_time_str.c_str()); } } @@ -4627,19 +4661,34 @@ void GUI_App::sync_preset(Preset* preset) } } - //update sync_info preset info in file + if (http_code >= 400 && values_map["code"] == "14") { // Limit + m_create_preset_blocked[preset->type] = true; + CallAfter([this] { + plater()->get_notification_manager()->push_notification(NotificationType::BBLUserPresetExceedLimit); + static bool dialog_notified = false; + if (dialog_notified) + return; + dialog_notified = true; + if (mainframe == nullptr) + return; + auto msg = _L("The number of user presets cached in the cloud has exceeded the upper limit, newly created user presets can only be used locally."); + MessageDialog(mainframe, msg, _L("Sync user presets"), wxICON_WARNING | wxOK).ShowModal(); + }); + return; // this error not need hold, and should not hold + } + // update sync_info preset info in file if (result == 0) { //PresetBundle* preset_bundle = wxGetApp().preset_bundle; if (!this->preset_bundle) return; BOOST_LOG_TRIVIAL(trace) << "sync_preset: sync operation: " << preset->sync_info << " success! preset = " << preset->name; if (preset->type == Preset::Type::TYPE_FILAMENT) { - preset_bundle->filaments.set_sync_info_and_save(preset->name, preset->setting_id, updated_info); + preset_bundle->filaments.set_sync_info_and_save(preset->name, setting_id, updated_info, update_time); } else if (preset->type == Preset::Type::TYPE_PRINT) { - preset_bundle->prints.set_sync_info_and_save(preset->name, preset->setting_id, updated_info); + preset_bundle->prints.set_sync_info_and_save(preset->name, setting_id, updated_info, update_time); } else if (preset->type == Preset::Type::TYPE_PRINTER) { - preset_bundle->printers.set_sync_info_and_save(preset->name, preset->setting_id, updated_info); + preset_bundle->printers.set_sync_info_and_save(preset->name, setting_id, updated_info, update_time); } } } @@ -4652,12 +4701,15 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg) if (!m_agent || !m_agent->is_user_login()) return; // has already start sync - if (enable_sync) return; + if (m_user_sync_token) return; ProgressFn progressFn; WasCancelledFn cancelFn; std::function finishFn; + BOOST_LOG_TRIVIAL(info) << "start_sync_service..."; + // BBS + m_user_sync_token.reset(new int(0)); if (with_progress_dlg) { auto dlg = new ProgressDialog(_L("Loading"), "", 100, this->mainframe, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); dlg->Update(0, _L("Loading user preset")); @@ -4667,36 +4719,50 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg) }); }; cancelFn = [this, dlg]() { - return dlg->WasCanceled(); + return m_is_closing || dlg->WasCanceled(); }; - finishFn = [this, userid = m_agent->get_user_id(), dlg](bool ok) { + finishFn = [this, userid = m_agent->get_user_id(), dlg, t = std::weak_ptr(m_user_sync_token)](bool ok) { CallAfter([=]{ dlg->Destroy(); - if (ok && m_agent && userid == m_agent->get_user_id()) reload_settings(); + if (ok && m_agent && t.lock() == m_user_sync_token && userid == m_agent->get_user_id()) reload_settings(); }); }; } else { - finishFn = [this, userid = m_agent->get_user_id()](bool ok) { + finishFn = [this, userid = m_agent->get_user_id(), t = std::weak_ptr(m_user_sync_token)](bool ok) { CallAfter([=] { - if (ok && m_agent && userid == m_agent->get_user_id()) reload_settings(); + if (ok && m_agent && t.lock() == m_user_sync_token && userid == m_agent->get_user_id()) reload_settings(); }); }; } - BOOST_LOG_TRIVIAL(info) << "start_sync_service..."; - //BBS - enable_sync = true; m_sync_update_thread = Slic3r::create_thread( - [this, progressFn, cancelFn, finishFn] { + [this, progressFn, cancelFn, finishFn, t = std::weak_ptr(m_user_sync_token)] { // get setting list, update setting list std::string version = preset_bundle->get_vendor_profile_version(PresetBundle::BBL_BUNDLE).to_string(); - int ret = m_agent->get_setting_list(version, progressFn, cancelFn); + int ret = m_agent->get_setting_list2(version, [this](auto info) { + auto type = info[BBL_JSON_KEY_TYPE]; + auto name = info[BBL_JSON_KEY_NAME]; + auto setting_id = info[BBL_JSON_KEY_SETTING_ID]; + auto update_time_str = info[BBL_JSON_KEY_UPDATE_TIME]; + long long update_time = 0; + if (!update_time_str.empty()) + update_time = std::atoll(update_time_str.c_str()); + if (type == "filament") { + return preset_bundle->filaments.need_sync(name, setting_id, update_time); + } else if (type == "print") { + return preset_bundle->prints.need_sync(name, setting_id, update_time); + } else if (type == "printer") { + return preset_bundle->printers.need_sync(name, setting_id, update_time); + } else { + return true; + } + }, progressFn, cancelFn); finishFn(ret == 0); int count = 0, sync_count = 0; std::vector presets_to_sync; - while (enable_sync) { + while (!t.expired()) { count++; if (count % 20 == 0) { if (m_agent) { @@ -4706,26 +4772,39 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg) //sync preset if (!preset_bundle) continue; - sync_count = preset_bundle->prints.get_user_presets(presets_to_sync); + int total_count = 0; + sync_count = preset_bundle->prints.get_user_presets(preset_bundle, presets_to_sync); if (sync_count > 0) { for (Preset& preset : presets_to_sync) { sync_preset(&preset); + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); } } + total_count += sync_count; - sync_count = preset_bundle->filaments.get_user_presets(presets_to_sync); + sync_count = preset_bundle->filaments.get_user_presets(preset_bundle, presets_to_sync); if (sync_count > 0) { for (Preset& preset : presets_to_sync) { sync_preset(&preset); + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); } } + total_count += sync_count; - sync_count = preset_bundle->printers.get_user_presets(presets_to_sync); + sync_count = preset_bundle->printers.get_user_presets(preset_bundle, presets_to_sync); if (sync_count > 0) { for (Preset& preset : presets_to_sync) { sync_preset(&preset); + boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); } } + total_count += sync_count; + + if (total_count == 0) { + CallAfter([this] { + plater()->get_notification_manager()->close_notification_of_type(NotificationType::BBLUserPresetExceedLimit); + }); + } unsigned int http_code = 200; @@ -4738,6 +4817,7 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg) if (result == 0) { preset_deleted_from_cloud(del_setting_id); it = delete_cache_presets.erase(it); + m_create_preset_blocked = { false, false, false, false, false, false }; BOOST_LOG_TRIVIAL(trace) << "sync_preset: sync operation: delete success! setting id = " << del_setting_id; } else { @@ -4755,12 +4835,16 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg) void GUI_App::stop_sync_user_preset() { - if (!enable_sync) + if (!m_user_sync_token) return; - enable_sync = false; - if (m_sync_update_thread.joinable()) - m_sync_update_thread.detach(); + m_user_sync_token.reset(); + if (m_sync_update_thread.joinable()) { + if (m_is_closing) + m_sync_update_thread.join(); + else + m_sync_update_thread.detach(); + } } void GUI_App::start_http_server() @@ -5127,6 +5211,7 @@ bool GUI_App::load_language(wxString language, bool initial) //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. //wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified((_L("*") + " ").ToUTF8().data()); + HintDatabase::get_instance().reinit(); return true; } @@ -5138,6 +5223,11 @@ Tab* GUI_App::get_tab(Preset::Type type) return nullptr; } +Tab* GUI_App::get_plate_tab() +{ + return plate_tab; +} + Tab* GUI_App::get_model_tab(bool part) { return model_tabs_list[part ? 1 : 0]; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 7a0631c05fe..b2d09bff396 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -275,6 +275,7 @@ class GUI_App : public wxApp Slic3r::DeviceManager* m_device_manager { nullptr }; NetworkAgent* m_agent { nullptr }; std::vector need_delete_presets; // store setting ids of preset + std::vector m_create_preset_blocked { false, false, false, false, false, false }; // excceed limit bool m_networking_compatible { false }; bool m_networking_need_update { false }; bool m_networking_cancel_update { false }; @@ -289,10 +290,11 @@ class GUI_App : public wxApp HMSQuery *hms_query { nullptr }; boost::thread m_sync_update_thread; - bool enable_sync = false; + std::shared_ptr m_user_sync_token; bool m_is_dark_mode{ false }; bool m_adding_script_handler { false }; bool m_side_popup_status{false}; + bool m_show_http_errpr_msgdlg{false}; wxString m_info_dialog_content; HttpServer m_http_server; bool m_show_gcode_window{true}; @@ -303,6 +305,7 @@ class GUI_App : public wxApp void check_filaments_in_blacklist(std::string tag_supplier, std::string tag_material, bool& in_blacklist, std::string& action, std::string& info); std::string get_local_models_path(); bool OnInit() override; + int OnExit() override; bool initialized() const { return m_initialized; } std::map test_url_state; @@ -480,6 +483,7 @@ class GUI_App : public wxApp bool load_language(wxString language, bool initial); Tab* get_tab(Preset::Type type); + Tab* get_plate_tab(); Tab* get_model_tab(bool part = false); Tab* get_layer_tab(); ConfigOptionMode get_mode(); @@ -583,6 +587,7 @@ class GUI_App : public wxApp std::vector tabs_list; std::vector model_tabs_list; + Tab* plate_tab; RemovableDriveManager* removable_drive_manager() { return m_removable_drive_manager.get(); } //OtherInstanceMessageHandler* other_instance_message_handler() { return m_other_instance_message_handler.get(); } diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index f3a68b2608d..ac95f301295 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -77,7 +77,7 @@ std::map> SettingsFactory::OBJECT_C {"seam_position", "",2}, {"slice_closing_radius", "",3}, {"resolution", "",4}, {"xy_hole_compensation", "",5}, {"xy_contour_compensation", "",6}, {"elefant_foot_compensation", "",7}, - {"make_overhang_printable_angle","", 8},{"make_overhang_printable_hole_size","",9} + {"make_overhang_printable_angle","", 8},{"make_overhang_printable_hole_size","",9}, {"wall_sequence","",10} }}, { L("Support"), {{"brim_type", "",1},{"brim_width", "",2},{"brim_object_gap", "",3}, {"enable_support", "",4},{"support_type", "",5},{"support_threshold_angle", "",6},{"support_on_build_plate_only", "",7}, @@ -715,7 +715,7 @@ wxMenuItem* MenuFactory::append_menu_item_fix_through_netfabb(wxMenu* menu) void MenuFactory::append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu) { - append_menu_item(menu, wxID_ANY, _L("Export as STL") + dots, "", + append_menu_item(menu, wxID_ANY, _L("Export as one STL") + dots, "", [](wxCommandEvent&) { plater()->export_stl(false, true); }, "", nullptr, [is_mulity_menu]() { const Selection& selection = plater()->canvas3D()->get_selection(); @@ -724,6 +724,14 @@ void MenuFactory::append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu) else return selection.is_single_full_instance() || selection.is_single_full_object(); }, m_parent); + if (!is_mulity_menu) + return; + append_menu_item(menu, wxID_ANY, _L("Export as STLs") + dots, "", + [](wxCommandEvent&) { plater()->export_stl(false, true, true); }, "", nullptr, + []() { + const Selection& selection = plater()->canvas3D()->get_selection(); + return selection.is_multiple_full_instance() || selection.is_multiple_full_object(); + }, m_parent); } void MenuFactory::append_menu_item_reload_from_disk(wxMenu* menu) @@ -1482,7 +1490,12 @@ wxMenu* MenuFactory::assemble_part_menu() void MenuFactory::append_menu_item_clone(wxMenu* menu) { - append_menu_item(menu, wxID_ANY, _L("Clone") , "", +#ifdef __APPLE__ + static const wxString ctrl = ("Ctrl+"); +#else + static const wxString ctrl = _L("Ctrl+"); +#endif + append_menu_item(menu, wxID_ANY, _L("Clone") + "\t" + ctrl + "K", "", [this](wxCommandEvent&) { plater()->clone_selection(); }, "", nullptr, diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp index 135e109a6ad..76dd2686336 100644 --- a/src/slic3r/GUI/GUI_ObjectLayers.cpp +++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp @@ -213,17 +213,23 @@ void ObjectLayers::update_layers_list() m_object = objects_ctrl->object(obj_idx); if (!m_object || m_object->layer_config_ranges.empty()) return; - // Delete all controls from options group - m_grid_sizer->Clear(true); + auto range = objects_ctrl->GetModel()->GetLayerRangeByItem(item); - // Add new control according to the selected item + // only call sizer->Clear(true) via CallAfter, otherwise crash happens in Linux when press enter in Height Range + // because an element cannot be destroyed while there are pending events for this element.(https://github.com/wxWidgets/Phoenix/issues/1854) + wxGetApp().CallAfter([this, type, objects_ctrl, range]() { + // Delete all controls from options group + m_grid_sizer->Clear(true); - if (type & itLayerRoot) - create_layers_list(); - else - create_layer(objects_ctrl->GetModel()->GetLayerRangeByItem(item), nullptr, nullptr); + // Add new control according to the selected item - m_parent->Layout(); + if (type & itLayerRoot) + create_layers_list(); + else + create_layer(range, nullptr, nullptr); + + m_parent->Layout(); + }); } void ObjectLayers::update_scene_from_editor_selection() const diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 678b4018e5c..4677536bd31 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -60,8 +60,11 @@ static PrinterTechnology printer_technology() static const Selection& scene_selection() { - //BBS return current canvas3D return wxGetApp().plater()->get_view3D_canvas3D()->get_selection(); - return wxGetApp().plater()->get_current_canvas3D()->get_selection(); + //BBS AssembleView canvas has its own selection + if (wxGetApp().plater()->get_current_canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView) + return wxGetApp().plater()->get_assmeble_canvas3D()->get_selection(); + + return wxGetApp().plater()->get_view3D_canvas3D()->get_selection(); } // Config from current edited printer preset @@ -276,6 +279,7 @@ ObjectList::ObjectList(wxWindow* parent) : Bind(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, &ObjectList::OnDropPossible, this); Bind(wxEVT_DATAVIEW_ITEM_DROP, &ObjectList::OnDrop, this); + Bind(wxEVT_DATAVIEW_ITEM_START_EDITING, &ObjectList::OnStartEditing, this); Bind(wxEVT_DATAVIEW_ITEM_EDITING_STARTED, &ObjectList::OnEditingStarted, this); Bind(wxEVT_DATAVIEW_ITEM_EDITING_DONE, &ObjectList::OnEditingDone, this); @@ -381,7 +385,8 @@ void ObjectList::create_objects_ctrl() // And Icon can be consisting of several bitmaps BitmapTextRenderer* bmp_text_renderer = new BitmapTextRenderer(); bmp_text_renderer->set_can_create_editor_ctrl_function([this]() { - return m_objects_model->GetItemType(GetSelection()) & (itVolume | itObject); + auto type = m_objects_model->GetItemType(GetSelection()); + return type & (itVolume | itObject | itPlate); }); // BBS @@ -792,6 +797,22 @@ void ObjectList::printable_state_changed(const std::vector& ov_i wxGetApp().plater()->update(); } +void ObjectList::assembly_plate_object_name() +{ + m_objects_model->assembly_name(); +} + +void ObjectList::selected_object(ObjectDataViewModelNode* item) +{ + if (!item) { + return; + } + this->SetFocus(); + select_item(wxDataViewItem(item)); + ensure_current_item_visible(); + selection_changed(); +} + void ObjectList::update_objects_list_filament_column(size_t filaments_count) { assert(filaments_count >= 1); @@ -912,6 +933,20 @@ void ObjectList::update_filament_in_config(const wxDataViewItem& item) void ObjectList::update_name_in_model(const wxDataViewItem& item) const { + if (m_objects_model->GetItemType(item) & itPlate) { + std::string name = m_objects_model->GetName(item).ToUTF8().data(); + int plate_idx = -1; + const ItemType type0 = m_objects_model->GetItemType(item, plate_idx); + if (plate_idx >= 0) { + auto plate = wxGetApp().plater()->get_partplate_list().get_plate(plate_idx); + if (plate->get_plate_name() != name) { + plate->set_plate_name(name); + } + m_objects_model->SetCurSelectedPlateFullName(plate_idx, name); + } + return; + } + const int obj_idx = m_objects_model->GetObjectIdByItem(item); if (obj_idx < 0) return; const int volume_id = m_objects_model->GetVolumeIdByItem(item); @@ -1248,7 +1283,9 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me get_selected_item_indexes(obj_idx, vol_idx, item); //wxGetApp().plater()->PopupObjectTable(obj_idx, vol_idx, mouse_pos); - if (m_objects_model->GetItemType(item) & itLayer) + if (m_objects_model->GetItemType(item) & itPlate) + dynamic_cast(wxGetApp().get_plate_tab())->reset_model_config(); + else if (m_objects_model->GetItemType(item) & itLayer) dynamic_cast(wxGetApp().get_layer_tab())->reset_model_config(); else dynamic_cast(wxGetApp().get_model_tab(vol_idx >= 0))->reset_model_config(); @@ -1273,6 +1310,10 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me void ObjectList::show_context_menu(const bool evt_context_menu) { + // BBS Disable menu popup if current canvas is Preview + if (wxGetApp().plater()->get_current_canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasPreview) + return; + wxMenu* menu {nullptr}; Plater* plater = wxGetApp().plater(); @@ -1454,7 +1495,7 @@ void ObjectList::key_event(wxKeyEvent& event) undo(); else if (wxGetKeyState(wxKeyCode('X')) && wxGetKeyState(WXK_CONTROL)) cut(); - else if (wxGetKeyState(wxKeyCode('M')) && wxGetKeyState(WXK_CONTROL)) + else if (wxGetKeyState(wxKeyCode('K')) && wxGetKeyState(WXK_CONTROL)) clone(); //else if (event.GetUnicodeKey() == '+') // increase_instances(); @@ -3370,6 +3411,8 @@ void ObjectList::part_selection_changed() wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " "); #endif + if (!this->IsShown()) + update_and_show_layers = false; if (printer_technology() == ptSLA) update_and_show_layers = false; else if (update_and_show_layers) { @@ -4533,12 +4576,15 @@ void ObjectList::update_selections() void ObjectList::update_selections_on_canvas() { - Selection& selection = wxGetApp().plater()->get_current_canvas3D()->get_selection(); + auto canvas_type = wxGetApp().plater()->get_current_canvas3D()->get_canvas_type(); + GLCanvas3D* canvas = canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView ? wxGetApp().plater()->get_current_canvas3D() : wxGetApp().plater()->get_view3D_canvas3D(); + Selection& selection = canvas->get_selection(); const int sel_cnt = GetSelectedItemsCount(); if (sel_cnt == 0) { selection.remove_all(); - wxGetApp().plater()->get_current_canvas3D()->update_gizmos_on_off_state(); + if (canvas_type != GLCanvas3D::ECanvasType::CanvasPreview) + wxGetApp().plater()->get_current_canvas3D()->update_gizmos_on_off_state(); return; } @@ -4642,7 +4688,8 @@ void ObjectList::update_selections_on_canvas() selection.add_volumes(mode, volume_idxs, single_selection); } - wxGetApp().plater()->get_current_canvas3D()->update_gizmos_on_off_state(); + if (canvas_type != GLCanvas3D::ECanvasType::CanvasPreview) + wxGetApp().plater()->get_current_canvas3D()->update_gizmos_on_off_state(); wxGetApp().plater()->canvas3D()->render(); } @@ -5467,8 +5514,10 @@ void ObjectList::msw_rescale() void ObjectList::sys_color_changed() { wxGetApp().UpdateDVCDarkUI(this, true); - + msw_rescale(); + + if (m_objects_model) { m_objects_model->sys_color_changed(); } } void ObjectList::ItemValueChanged(wxDataViewEvent &event) @@ -5483,6 +5532,22 @@ void ObjectList::ItemValueChanged(wxDataViewEvent &event) } } +void GUI::ObjectList::OnStartEditing(wxDataViewEvent &event) +{ + auto col = event.GetColumn(); + auto item = event.GetItem(); + if (col == colName) { + ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID(); + if (node->GetType() & itPlate) { + int plate_idx = node->GetPlateIdx(); + if (plate_idx >= 0) { + auto plate = wxGetApp().plater()->get_partplate_list().get_plate(plate_idx); + m_objects_model->SetName(from_u8(plate->get_plate_name()), GetSelection()); + } + } + } +} + // Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. // Here the last active column is forgotten, so when leaving the editing mode, the next mouse click will not enter the editing mode of the newly selected column. void ObjectList::OnEditingStarted(wxDataViewEvent &event) @@ -5558,6 +5623,17 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event) if (event.GetColumn() != colName) return; + if (event.IsEditCancelled()) { + if (m_objects_model->GetItemType(event.GetItem()) & itPlate) { + int plate_idx = -1; + m_objects_model->GetItemType(event.GetItem(), plate_idx); + if (plate_idx >= 0) { + auto plate = wxGetApp().plater()->get_partplate_list().get_plate(plate_idx); + m_objects_model->SetCurSelectedPlateFullName(plate_idx, plate->get_plate_name()); + } + } + } + const auto renderer = dynamic_cast(GetColumn(colName)->GetRenderer()); #if __WXOSX__ SetAcceleratorTable(m_accel); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 8bd1e8fbdf7..0a95ecb4155 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -185,6 +185,7 @@ class ObjectList : public wxDataViewCtrl // because it would turn off the gizmos (mainly a problem for the SLA gizmo) wxDataViewItem m_last_selected_item {nullptr}; + #ifdef __WXMSW__ // Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. int m_last_selected_column = -1; @@ -216,6 +217,7 @@ class ObjectList : public wxDataViewCtrl ModelObject* object(const int obj_idx) const ; + void create_objects_ctrl(); // BBS void update_objects_list_filament_column(size_t filaments_count); @@ -454,6 +456,10 @@ class ObjectList : public wxDataViewCtrl void object_config_options_changed(const ObjectVolumeID& ov_id); void printable_state_changed(const std::vector& ov_ids); + // search objectlist + void assembly_plate_object_name(); + void selected_object(ObjectDataViewModelNode* item); + private: #ifdef __WXOSX__ // void OnChar(wxKeyEvent& event); @@ -472,6 +478,7 @@ class ObjectList : public wxDataViewCtrl void ItemValueChanged(wxDataViewEvent &event); // Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected. + void OnStartEditing(wxDataViewEvent &event); void OnEditingStarted(wxDataViewEvent &event); void OnEditingDone(wxDataViewEvent &event); diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index a1790174162..ff9521b5845 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -199,7 +199,9 @@ bool ObjectSettings::update_settings_list() wxDataViewItemArray items; objects_ctrl->GetSelections(items); - std::map object_configs; + std::map plate_configs; + std::map object_configs; + bool is_plate_settings = false; bool is_object_settings = false; bool is_volume_settings = false; bool is_layer_range_settings = false; @@ -207,6 +209,22 @@ bool ObjectSettings::update_settings_list() ModelObject * parent_object = nullptr; for (auto item : items) { auto type = objects_model->GetItemType(item); + if (type == itPlate) { + is_plate_settings = true; + + int plate_id = objects_model->GetPlateIdByItem(item); + + static ModelConfig cfg; + PartPlateList& ppl = wxGetApp().plater()->get_partplate_list(); + + if (plate_id < 0 || plate_id >= ppl.get_plate_count()) { + plate_id = ppl.get_curr_plate_index(); + } + assert(plate_id >= 0 && plate_id < ppl.get_plate_count()); + + cfg.assign_config(*ppl.get_plate(plate_id)->config()); + plate_configs.emplace(ppl.get_plate(plate_id), &cfg); + } if (type != itObject && type != itVolume && type != itLayerRoot && type != itLayer) { continue; } @@ -241,33 +259,45 @@ bool ObjectSettings::update_settings_list() } } + auto tab_plate = dynamic_cast(wxGetApp().get_plate_tab()); auto tab_object = dynamic_cast(wxGetApp().get_model_tab()); auto tab_volume = dynamic_cast(wxGetApp().get_model_tab(true)); auto tab_layer = dynamic_cast(wxGetApp().get_layer_tab()); - if (is_object_settings) { + if (is_plate_settings) { + tab_object->set_model_config({}); + tab_volume->set_model_config({}); + tab_layer->set_model_config({}); + tab_plate->set_model_config(plate_configs); + ;// m_tab_active = tab_plate; + } + else if (is_object_settings) { tab_object->set_model_config(object_configs); tab_volume->set_model_config({}); tab_layer->set_model_config({}); - m_tab_active = tab_object; + tab_plate->set_model_config({}); + //m_tab_active = tab_object; } else if (is_volume_settings) { tab_object->set_model_config({ {parent_object, &parent_object->config} }); tab_volume->set_model_config(object_configs); tab_layer->set_model_config({}); - m_tab_active = tab_volume; + tab_plate->set_model_config({}); + //m_tab_active = tab_volume; } else if (is_layer_range_settings) { tab_object->set_model_config({ {parent_object, &parent_object->config} }); tab_volume->set_model_config({}); tab_layer->set_model_config(object_configs); - m_tab_active = tab_layer; + tab_plate->set_model_config({}); + //m_tab_active = tab_layer; } else { tab_object->set_model_config({}); tab_volume->set_model_config({}); tab_layer->set_model_config({}); - m_tab_active = nullptr; + tab_plate->set_model_config({}); + //m_tab_active = nullptr; } ((ParamsPanel*) tab_object->GetParent())->set_active_tab(nullptr); return true; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 3c76e7d9d8e..af4dbc40fc5 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -123,6 +123,11 @@ void View3D::select_curr_plate_all() m_canvas->select_curr_plate_all(); } +void View3D::select_object_from_idx(std::vector& object_idxs) { + if (m_canvas != nullptr) + m_canvas->select_object_from_idx(object_idxs); +} + //BBS void View3D::remove_curr_plate_all() { @@ -154,6 +159,11 @@ void View3D::center_selected() m_canvas->do_center(); } +void View3D::center_selected_plate(const int plate_idx) { + if (m_canvas != nullptr) + m_canvas->do_center_plate(plate_idx); +} + void View3D::mirror_selection(Axis axis) { if (m_canvas != nullptr) diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 88e13366405..2ce7e67ec10 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -58,12 +58,14 @@ class View3D : public wxPanel //BBS void select_curr_plate_all(); + void select_object_from_idx(std::vector &object_idxs); void remove_curr_plate_all(); void select_all(); void deselect_all(); void delete_selected(); void center_selected(); + void center_selected_plate(const int plate_idx); void mirror_selection(Axis axis); bool is_layers_editing_enabled() const; diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index 6fbec69ba79..64bd8e64998 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -457,6 +457,14 @@ class WindowMetrics std::ostream& operator<<(std::ostream &os, const WindowMetrics& metrics); +inline int hex_digit_to_int(const char c) +{ + return + (c >= '0' && c <= '9') ? int(c - '0') : + (c >= 'A' && c <= 'F') ? int(c - 'A') + 10 : + (c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1; +} + class TaskTimer { std::chrono::milliseconds start_timer; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index b79dfb1ec2b..c6ee8f4e047 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -59,7 +59,8 @@ bool GLGizmoMmuSegmentation::on_is_selectable() const bool GLGizmoMmuSegmentation::on_is_activable() const { - return GLGizmoPainterBase::on_is_activable() && wxGetApp().filaments_cnt() > 1; + const Selection& selection = m_parent.get_selection(); + return !selection.is_empty() && (selection.is_single_full_instance() || selection.is_any_volume()) && wxGetApp().filaments_cnt() > 1; } //BBS: use the global one in 3DScene.cpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 0d8461395f4..e7793c017d9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -1507,9 +1507,7 @@ void GLGizmoText::generate_text_volume(bool is_temp) new_model_volume->set_text_info(text_info); new_model_volume->name = model_volume->name; new_model_volume->set_type(model_volume->type()); - if (model_volume->config.option("extruder")) - new_model_volume->config.set("extruder", model_volume->config.extruder()); - + new_model_volume->config.apply(model_volume->config); std::swap(model_object->volumes[m_volume_idx], model_object->volumes.back()); model_object->delete_volume(model_object->volumes.size() - 1); plater->update(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 33983628552..d6e90935094 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -320,6 +320,11 @@ void GLGizmosManager::reset_all_states() if (! m_enabled || m_serializing) return; + const EType current = get_current_type(); + if (current != Undefined) + // close any open gizmo + open_gizmo(current); + activate_gizmo(Undefined); m_hover = Undefined; } @@ -1324,12 +1329,18 @@ std::string get_name_from_gizmo_etype(GLGizmosManager::EType type) return "Scale"; case GLGizmosManager::EType::Flatten: return "Flatten"; + case GLGizmosManager::EType::Cut: + return "Cut"; + case GLGizmosManager::EType::MeshBoolean: + return "MeshBoolean"; case GLGizmosManager::EType::FdmSupports: return "FdmSupports"; case GLGizmosManager::EType::Seam: return "Seam"; case GLGizmosManager::EType::Text: return "Text"; + case GLGizmosManager::EType::MmuSegmentation: + return "Color Painting"; default: return ""; } diff --git a/src/slic3r/GUI/HMS.cpp b/src/slic3r/GUI/HMS.cpp index 2f24569a6d6..c1b73f2c08b 100644 --- a/src/slic3r/GUI/HMS.cpp +++ b/src/slic3r/GUI/HMS.cpp @@ -139,7 +139,13 @@ std::string HMSQuery::hms_language_code() // set language code to en by default return "en"; std::string lang_code = wxGetApp().app_config->get_language_code(); - if (lang_code.empty()) { + if (lang_code.compare("uk") == 0 + || lang_code.compare("cs") == 0 + || lang_code.compare("ru") == 0) { + BOOST_LOG_TRIVIAL(info) << "HMS: using english for lang_code = " << lang_code; + return "en"; + } + else if (lang_code.empty()) { // set language code to en by default return "en"; } diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index 786868235c9..c431e0fafb1 100644 --- a/src/slic3r/GUI/HintNotification.cpp +++ b/src/slic3r/GUI/HintNotification.cpp @@ -303,10 +303,22 @@ void HintDatabase::uninit() m_used_ids.clear(); m_used_ids_loaded = false; } +void HintDatabase::reinit() +{ + if (m_initialized) + uninit(); + init(); +} void HintDatabase::init() { load_hints_from_file(std::move(boost::filesystem::path(resources_dir()) / "data" / "hints.ini")); m_initialized = true; + init_random_hint_id(); +} +void HintDatabase::init_random_hint_id() +{ + srand(time(NULL)); + m_hint_id = rand() % m_loaded_hints.size(); } void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) { @@ -340,6 +352,7 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) std::string enabled_tags; // optional link to documentation (accessed from button) std::string documentation_link; + std::string img_url; // randomized weighted order variables size_t weight = 1; bool was_displayed = is_used(id_string); @@ -404,6 +417,9 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) if (dict.find("documentation_link") != dict.end()) { documentation_link = dict["documentation_link"]; } + if (dict.find("image") != dict.end()) { + img_url = dict["image"]; + } if (dict.find("weight") != dict.end()) { weight = (size_t)std::max(1, std::atoi(dict["weight"].c_str())); @@ -414,7 +430,7 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) //link to internet if (dict["hypertext_type"] == "link") { std::string hypertext_link = dict["hypertext_link"]; - HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [hypertext_link]() { launch_browser_if_allowed(hypertext_link); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, img_url, [hypertext_link]() { launch_browser_if_allowed(hypertext_link); } }; m_loaded_hints.emplace_back(hint_data); // highlight settings } @@ -422,28 +438,28 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) std::string opt = dict["hypertext_settings_opt"]; Preset::Type type = static_cast(std::atoi(dict["hypertext_settings_type"].c_str())); std::wstring category = boost::nowide::widen(dict["hypertext_settings_category"]); - HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, img_url, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } }; m_loaded_hints.emplace_back(hint_data); // open preferences } else if (dict["hypertext_type"] == "preferences") { std::string page = dict["hypertext_preferences_page"]; std::string item = dict["hypertext_preferences_item"]; - HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [page, item]() { wxGetApp().open_preferences(1, page); } };// 1 is to modify + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, img_url, [page, item]() { wxGetApp().open_preferences(1, page); } };// 1 is to modify m_loaded_hints.emplace_back(hint_data); } else if (dict["hypertext_type"] == "plater") { std::string item = dict["hypertext_plater_item"]; - HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, img_url, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } }; m_loaded_hints.emplace_back(hint_data); } else if (dict["hypertext_type"] == "gizmo") { std::string item = dict["hypertext_gizmo_item"]; - HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, img_url, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } }; m_loaded_hints.emplace_back(hint_data); } else if (dict["hypertext_type"] == "gallery") { - HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, []() { + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, img_url, []() { // Deselect all objects, otherwise gallery wont show. wxGetApp().plater()->canvas3D()->deselect_all(); //wxGetApp().obj_list()->load_shape_object_from_gallery(); } @@ -453,23 +469,23 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) else if (dict["hypertext_type"] == "menubar") { wxString menu(_("&" + dict["hypertext_menubar_menu_name"])); wxString item(_(dict["hypertext_menubar_item_name"])); - HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [menu, item]() { wxGetApp().mainframe->open_menubar_item(menu, item); } }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, img_url, [menu, item]() { wxGetApp().mainframe->open_menubar_item(menu, item); } }; m_loaded_hints.emplace_back(hint_data); } } else { // plain text without hypertext - HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link }; + HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, img_url }; m_loaded_hints.emplace_back(hint_data); } } } } -HintData* HintDatabase::get_hint(bool new_hint/* = true*/) +HintData* HintDatabase::get_hint(HintDataNavigation nav) { if (!m_initialized) { init(); - new_hint = true; + nav = HintDataNavigation::Random; } if (m_loaded_hints.empty()) { @@ -479,20 +495,34 @@ HintData* HintDatabase::get_hint(bool new_hint/* = true*/) try { - if (new_hint) - m_hint_id = get_next(); + if (nav == HintDataNavigation::Next) + m_hint_id = get_next_hint_id(); + if(nav == HintDataNavigation::Prev) + m_hint_id = get_prev_hint_id(); + if (nav == HintDataNavigation::Curr) + ; + if (nav == HintDataNavigation::Random) + init_random_hint_id(); } catch (const std::exception&) { return nullptr; } + return &m_loaded_hints[m_hint_id]; +} +size_t HintDatabase::get_next_hint_id() +{ + return m_hint_id < m_loaded_hints.size() - 1 ? m_hint_id + 1 : 0; +} - return &m_loaded_hints[m_hint_id]; +size_t HintDatabase::get_prev_hint_id() +{ + return m_hint_id > 0 ? m_hint_id - 1 : m_loaded_hints.size() - 1; } -size_t HintDatabase::get_next() +size_t HintDatabase::get_random_next() { if (!m_sorted_hints) { @@ -1110,7 +1140,7 @@ void NotificationManager::HintNotification::open_documentation() } void NotificationManager::HintNotification::retrieve_data(bool new_hint/* = true*/) { - HintData* hint_data = HintDatabase::get_instance().get_hint(new_hint); + HintData* hint_data = HintDatabase::get_instance().get_hint(new_hint ? HintDataNavigation::Next : HintDataNavigation::Curr); if (hint_data == nullptr) close(); diff --git a/src/slic3r/GUI/HintNotification.hpp b/src/slic3r/GUI/HintNotification.hpp index d0444cd8fe9..89a2871c5ac 100644 --- a/src/slic3r/GUI/HintNotification.hpp +++ b/src/slic3r/GUI/HintNotification.hpp @@ -18,9 +18,17 @@ struct HintData std::string enabled_tags; bool runtime_disable; // if true - hyperlink will check before every click if not in disabled mode std::string documentation_link; + std::string image_url; std::function callback{ nullptr }; }; +enum class HintDataNavigation { + Curr, + Prev, + Next, + Random, +}; + class HintDatabase { public: @@ -40,7 +48,8 @@ class HintDatabase void operator=(HintDatabase const&) = delete; // return true if HintData filled; - HintData* get_hint(bool new_hint = true); + HintData* get_hint(HintDataNavigation nav); + size_t get_index() { return m_hint_id; } size_t get_count() { if (!m_initialized) return 0; @@ -49,14 +58,18 @@ class HintDatabase // resets m_initiailized to false and writes used if was initialized // used when reloading in runtime - like change language void uninit(); + void reinit(); private: void init(); + void init_random_hint_id(); void load_hints_from_file(const boost::filesystem::path& path); bool is_used(const std::string& id); void set_used(const std::string& id); void clear_used(); // Returns position in m_loaded_hints with next hint chosed randomly with weights - size_t get_next(); + size_t get_next_hint_id(); + size_t get_prev_hint_id(); + size_t get_random_next(); size_t m_hint_id; bool m_initialized{ false }; std::vector m_loaded_hints; diff --git a/src/slic3r/GUI/IMSlider.cpp b/src/slic3r/GUI/IMSlider.cpp index 3f4dbd00c03..b44fcc7f996 100644 --- a/src/slic3r/GUI/IMSlider.cpp +++ b/src/slic3r/GUI/IMSlider.cpp @@ -618,6 +618,43 @@ void IMSlider::draw_colored_band(const ImRect& groove, const ImRect& slideable_r } } +void IMSlider::draw_custom_label_block(const ImVec2 anchor, Type type) +{ + wxString label; + switch (type) + { + case ColorChange: + label = _L("Color"); + break; + case PausePrint: + label = _L("Pause"); + break; + case ToolChange: + label = _L("Color"); + break; + case Template: + label = _L("Template"); + break; + case Custom: + label = _L("Custom"); + break; + case Unknown: + break; + default: + break; + } + const ImVec2 text_size = ImGui::CalcTextSize(into_u8(label).c_str()); + const ImVec2 padding = ImVec2(4, 2) * m_scale; + const ImU32 clr = IM_COL32(255, 111, 0, 255); + const float rounding = 2.0f * m_scale; + ImVec2 block_pos = { anchor.x - text_size.x - padding.x * 2, anchor.y - text_size.y / 2 - padding.y }; + ImVec2 block_size = { text_size.x + padding.x * 2, text_size.y + padding.y * 2 }; + ImGui::RenderFrame(block_pos, block_pos + block_size, clr, false, rounding); + ImGui::PushStyleColor(ImGuiCol_Text, { 1,1,1,1 }); + ImGui::RenderText(block_pos + padding, into_u8(label).c_str()); + ImGui::PopStyleColor(); +} + void IMSlider::draw_ticks(const ImRect& slideable_region) { //if(m_draw_mode != dmRegular) // return; @@ -691,6 +728,11 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) { ImVec2 icon_pos = ImVec2(slideable_region.GetCenter().x + icon_offset.x, tick_pos - icon_offset.y); button_with_pos(custom_icon_id, icon_size, icon_pos); } + + //draw label block + ImVec2 label_block_anchor = ImVec2(slideable_region.GetCenter().x - tick_offset.y, tick_pos); + draw_custom_label_block(label_block_anchor, tick_it->type); + ++tick_it; } @@ -698,6 +740,10 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) { GetSelection() == ssLower ? m_ticks.ticks.find(TickCode{this->GetLowerValue()}) : m_ticks.ticks.end(); if (tick_it != m_ticks.ticks.end()) { + //draw label block again, to keep it in front + ImVec2 label_block_anchor = ImVec2(slideable_region.GetCenter().x - tick_offset.y, get_tick_pos(tick_it->tick)); + draw_custom_label_block(label_block_anchor, tick_it->type); + // draw delete icon ImVec2 icon_pos = ImVec2(slideable_region.GetCenter().x + icon_offset.x, get_tick_pos(tick_it->tick) - icon_offset.y); button_with_pos(m_delete_icon_id, icon_size, icon_pos); @@ -1128,9 +1174,7 @@ void IMSlider::render_input_custom_gcode(std::string custom_gcode) } const int text_height = 6; - ImGui::InputTextMultiline("##text", m_custom_gcode, sizeof(m_custom_gcode), ImVec2(-1, ImGui::GetTextLineHeight() * text_height), ImGuiInputTextFlags_CallbackAlways, [](ImGuiInputTextCallbackData* data) { - return data->CursorPos = data->BufTextLen; - }); + ImGui::InputTextMultiline("##text", m_custom_gcode, sizeof(m_custom_gcode), ImVec2(-1, ImGui::GetTextLineHeight() * text_height)); ImGui::NewLine(); ImGui::SameLine(ImGui::GetStyle().WindowPadding.x * 14); diff --git a/src/slic3r/GUI/IMSlider.hpp b/src/slic3r/GUI/IMSlider.hpp index 56f359793ad..2bf700787fe 100644 --- a/src/slic3r/GUI/IMSlider.hpp +++ b/src/slic3r/GUI/IMSlider.hpp @@ -145,6 +145,7 @@ class IMSlider void render_edit_menu(const TickCode& tick); //menu void draw_background_and_groove(const ImRect& bg_rect, const ImRect& groove); void draw_colored_band(const ImRect& groove, const ImRect& slideable_region); + void draw_custom_label_block(const ImVec2 anchor, Type type); void draw_ticks(const ImRect& slideable_region); void draw_tick_on_mouse_position(const ImRect& slideable_region); void show_tooltip(const TickCode& tick); //menu diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 6d72a5e6f47..7622f355229 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -63,8 +63,8 @@ static const std::map font_icons = { {ImGui::MinimalizeHoverButton , "notification_minimalize_hover" }, {ImGui::RightArrowButton , "notification_right" }, {ImGui::RightArrowHoverButton , "notification_right_hover" }, - {ImGui::PreferencesButton , "notification_preferences" }, - {ImGui::PreferencesHoverButton , "notification_preferences_hover"}, + //{ImGui::PreferencesButton , "notification_preferences" }, + //{ImGui::PreferencesHoverButton , "notification_preferences_hover"}, #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT {ImGui::SliderFloatEditBtnIcon, "edit_button" }, #endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT @@ -73,6 +73,7 @@ static const std::map font_icons = { {ImGui::TriangleButtonIcon , "triangle_paint" }, {ImGui::FillButtonIcon , "fill_paint" }, {ImGui::HeightRangeIcon , "height_range" }, + {ImGui::ConfirmIcon , "confirm" }, {ImGui::GapFillIcon , "gap_fill" }, {ImGui::FoldButtonIcon , "im_fold" }, {ImGui::UnfoldButtonIcon , "im_unfold" }, @@ -82,14 +83,15 @@ static const std::map font_icons = { {ImGui::MinimalizeHoverDarkButton , "notification_minimalize_hover_dark" }, {ImGui::RightArrowDarkButton , "notification_right_dark" }, {ImGui::RightArrowHoverDarkButton , "notification_right_hover_dark" }, - {ImGui::PreferencesDarkButton , "notification_preferences_dark" }, - {ImGui::PreferencesHoverDarkButton , "notification_preferences_hover_dark"}, + //{ImGui::PreferencesDarkButton , "notification_preferences_dark" }, + //{ImGui::PreferencesHoverDarkButton , "notification_preferences_hover_dark"}, {ImGui::ClipboardBtnDarkIcon , "copy_menu_dark" }, {ImGui::CircleButtonDarkIcon , "circle_paint_dark" }, {ImGui::TriangleButtonDarkIcon , "triangle_paint_dark" }, {ImGui::FillButtonDarkIcon , "fill_paint_dark" }, {ImGui::HeightRangeDarkIcon , "height_range_dark" }, + {ImGui::ConfirmDarkIcon , "confirm_dark" }, {ImGui::GapFillDarkIcon , "gap_fill_dark" }, {ImGui::SphereButtonDarkIcon , "toolbar_modifier_sphere_dark" }, @@ -102,6 +104,10 @@ static const std::map font_icons = { {ImGui::CloseBlockNotifButton , "block_notification_close" }, {ImGui::CloseBlockNotifHoverButton , "block_notification_close_hover" }, + + {ImGui::CollapseArrowIcon, "notification_collapse" }, + {ImGui::ExpandArrowIcon, "notification_expand" }, + {ImGui::OpenArrowIcon, "notification_arrow_open" }, }; static const std::map font_icons_large = { {ImGui::CloseNotifButton , "notification_close" }, @@ -119,15 +125,18 @@ static const std::map font_icons_large = { // {ImGui::CustomSeamMarker , "seam" }, // {ImGui::MmuSegmentationMarker , "mmu_segmentation" }, // {ImGui::VarLayerHeightMarker , "layers" }, - {ImGui::DocumentationButton , "notification_documentation" }, - {ImGui::DocumentationHoverButton, "notification_documentation_hover"}, + //{ImGui::DocumentationButton , "notification_documentation" }, + //{ImGui::DocumentationHoverButton, "notification_documentation_hover"}, //{ImGui::InfoMarker , "notification_info" }, // dark mode icon {ImGui::CloseNotifDarkButton , "notification_close_dark" }, {ImGui::CloseNotifHoverDarkButton , "notification_close_hover_dark" }, - {ImGui::DocumentationDarkButton , "notification_documentation_dark" }, - {ImGui::DocumentationHoverDarkButton, "notification_documentation_hover_dark"}, + //{ImGui::DocumentationDarkButton , "notification_documentation_dark" }, + //{ImGui::DocumentationHoverDarkButton, "notification_documentation_hover_dark"}, {ImGui::BlockNotifErrorIcon, "block_notification_error" }, + {ImGui::PrevArrowBtnIcon, "notification_arrow_left" }, + {ImGui::NextArrowBtnIcon, "notification_arrow_right" }, + {ImGui::CompleteIcon, "notification_slicing_complete" }, }; static const std::map font_icons_extra_large = { @@ -383,6 +392,7 @@ void ImGuiWrapper::set_language(const std::string &language) } else if (lang == "ko") { ranges = ImGui::GetIO().Fonts->GetGlyphRangesKorean(); // Default + Korean characters m_font_cjk = true; + m_is_korean = true; } else if (lang == "zh") { ranges = (language == "zh_TW") ? // Traditional Chinese @@ -2683,12 +2693,12 @@ void ImGuiWrapper::destroy_fonts_texture() { const char* ImGuiWrapper::clipboard_get(void* user_data) { - ImGuiWrapper *self = reinterpret_cast(user_data); + ImGuiWrapper* self = reinterpret_cast(user_data); const char* res = ""; if (wxTheClipboard->Open()) { - if (wxTheClipboard->IsSupported(wxDF_TEXT)) { + if (wxTheClipboard->IsSupported(wxDF_TEXT) || wxTheClipboard->IsSupported(wxDF_UNICODETEXT)) { wxTextDataObject data; wxTheClipboard->GetData(data); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 58e42f1996a..f3e8e346712 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -55,6 +55,7 @@ class ImGuiWrapper const ImWchar* m_glyph_basic_ranges { nullptr }; // Chinese, Japanese, Korean bool m_font_cjk{ false }; + bool m_is_korean{ false }; float m_font_size{ 18.0 }; unsigned m_font_texture{ 0 }; unsigned m_font_another_texture{ 0 }; diff --git a/src/slic3r/GUI/ImageGrid.cpp b/src/slic3r/GUI/ImageGrid.cpp index e1ba370c075..2ab6748f4e5 100644 --- a/src/slic3r/GUI/ImageGrid.cpp +++ b/src/slic3r/GUI/ImageGrid.cpp @@ -122,6 +122,12 @@ void Slic3r::GUI::ImageGrid::SetSelecting(bool selecting) void Slic3r::GUI::ImageGrid::DoActionOnSelection(int action) { DoAction(-1, action); } +void Slic3r::GUI::ImageGrid::ShowDownload(bool show) +{ + m_show_download = show; + Refresh(); +} + void Slic3r::GUI::ImageGrid::Rescale() { m_title_mask = wxBitmap(); @@ -266,10 +272,13 @@ std::pair Slic3r::GUI::ImageGrid::HitTest(wxPoint const &pt) auto & file = m_file_sys->GetFile(index); int btn = file.IsDownload() && file.DownloadProgress() >= 0 ? 3 : 2; if (m_file_sys->GetFileType() == PrinterFileSystem::F_MODEL) { - btn = 3; + if (m_show_download) + btn = 3; hover_rect.y -= m_content_rect.GetHeight() * 64 / 264; } - if (hover_rect.Contains(off.x, off.y)) { return {HIT_ACTION, index * 4 + off.x * btn / hover_rect.GetWidth()}; } // Two buttons + if (hover_rect.Contains(off.x, off.y)) { + return {HIT_ACTION, index * 4 + off.x * btn / hover_rect.GetWidth()}; + } // Two buttons } return {HIT_ITEM, index}; } @@ -593,12 +602,12 @@ void Slic3r::GUI::ImageGrid::renderContent1(wxDC &dc, wxPoint const &pt, int ind bool show_download_state_always = true; // Draw checked icon if (m_selecting && !show_download_state_always) - dc.DrawBitmap(selected ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), pt + wxPoint{10, m_content_rect.GetHeight() - m_checked_icon.GetBmpHeight() - 10}); + dc.DrawBitmap(selected ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), pt + wxPoint{10, 10}); // can't handle alpha // dc.GradientFillLinear({pt.x, pt.y, m_border_size.GetWidth(), 60}, wxColour(0x6F, 0x6F, 0x6F, 0x99), wxColour(0x6F, 0x6F, 0x6F, 0), wxBOTTOM); else if (m_file_sys->GetGroupMode() == PrinterFileSystem::G_NONE) { wxString nonHoverText; - wxString secondAction = _L("Download"); + wxString secondAction = m_show_download ? _L("Download") : ""; wxString thirdAction; int states = 0; // Draw download progress @@ -644,7 +653,7 @@ void Slic3r::GUI::ImageGrid::renderContent1(wxDC &dc, wxPoint const &pt, int ind dc.DrawText(date, pt + wxPoint{24, 16}); } if (m_selecting && show_download_state_always) - dc.DrawBitmap(selected ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), pt + wxPoint{10, m_content_rect.GetHeight() - m_checked_icon.GetBmpHeight() - 10}); + dc.DrawBitmap(selected ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), pt + wxPoint{10, 10}); } void Slic3r::GUI::ImageGrid::renderContent2(wxDC &dc, wxPoint const &pt, int index, bool hit) diff --git a/src/slic3r/GUI/ImageGrid.h b/src/slic3r/GUI/ImageGrid.h index 78f970e2ef0..34e016c06f9 100644 --- a/src/slic3r/GUI/ImageGrid.h +++ b/src/slic3r/GUI/ImageGrid.h @@ -49,6 +49,8 @@ class ImageGrid : public wxWindow void DoActionOnSelection(int action); + void ShowDownload(bool show); + public: void Rescale(); @@ -127,6 +129,7 @@ class ImageGrid : public wxWindow // wxBitmap m_button_background; bool m_selecting = false; + bool m_show_download = false; enum HitType { HIT_NONE, diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index 708e65f806f..e4c45f4292b 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -57,7 +57,7 @@ class WipeTower: public GLCanvas3D::WipeTowerInfo { ret.is_wipe_tower = true; ++ret.priority; - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " arrange: wipe tower info:" << m_bb << ", m_pos: " << m_pos.transpose(); + BOOST_LOG_TRIVIAL(debug) << " arrange: wipe tower info:" << m_bb << ", m_pos: " << m_pos.transpose(); return ret; } @@ -240,6 +240,21 @@ void ArrangeJob::prepare_all() { plate_list.preprocess_exclude_areas(m_unselected, MAX_NUM_PLATES); } +arrangement::ArrangePolygon estimate_wipe_tower_info(int plate_index, std::set& extruder_ids) +{ + PartPlateList& ppl = wxGetApp().plater()->get_partplate_list(); + const auto& full_config = wxGetApp().preset_bundle->full_config(); + int plate_count = ppl.get_plate_count(); + int plate_index_valid = std::min(plate_index, plate_count - 1); + + // we have to estimate the depth using the extruder number of all plates + int extruder_size = extruder_ids.size(); + + auto arrange_poly = ppl.get_plate(plate_index_valid)->estimate_wipe_tower_polygon(full_config, plate_index, extruder_size); + arrange_poly.bed_idx = plate_index; + return arrange_poly; +} + // 准备料塔。逻辑如下: // 1. 以下几种情况不需要料塔: // 1)料塔被禁用, @@ -255,10 +270,11 @@ void ArrangeJob::prepare_wipe_tower() bool need_wipe_tower = false; // if wipe tower is explicitly disabled, no need to estimate - DynamicPrintConfig ¤t_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; - auto op = current_config.option("enable_prime_tower"); + DynamicPrintConfig& current_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + auto op = current_config.option("enable_prime_tower"); bool enable_prime_tower = op && op->getBool(); if (!enable_prime_tower || params.is_seq_print) return; + bool smooth_timelapse = false; auto sop = current_config.option("timelapse_type"); if (sop) { smooth_timelapse = sop->getInt() == TimelapseType::tlSmooth; } @@ -266,7 +282,7 @@ void ArrangeJob::prepare_wipe_tower() // estimate if we need wipe tower for all plates: // need wipe tower if some object has multiple extruders (has paint-on colors or support material) - for (const auto &item : m_selected) { + for (const auto& item : m_selected) { std::set obj_extruders; obj_extruders.insert(item.extrude_ids.begin(), item.extrude_ids.end()); if (obj_extruders.size() > 1) { @@ -278,11 +294,11 @@ void ArrangeJob::prepare_wipe_tower() // if multile extruders have same bed temp, we need wipe tower // 允许不同材料落在相同盘,且所有选定对象中使用了多种热床温度相同的材料 - if (params.allow_multi_materials_on_same_plate) { + if (params.allow_multi_materials_on_same_plate) { std::map> bedTemp2extruderIds; - for (const auto &item : m_selected) + for (const auto& item : m_selected) for (auto id : item.extrude_ids) { bedTemp2extruderIds[item.bed_temp].insert(id); } - for (const auto &be : bedTemp2extruderIds) { + for (const auto& be : bedTemp2extruderIds) { if (be.second.size() > 1) { need_wipe_tower = true; BOOST_LOG_TRIVIAL(info) << "arrange: need wipe tower because allow_multi_materials_on_same_plate=true and we have multiple extruders of same type"; @@ -293,24 +309,42 @@ void ArrangeJob::prepare_wipe_tower() BOOST_LOG_TRIVIAL(info) << "arrange: need_wipe_tower=" << need_wipe_tower; - // check all plates to see if wipe tower is already there - ArrangePolygon wipe_tower_ap; - wipe_tower_ap.name = "WipeTower"; + ArrangePolygon wipe_tower_ap; + wipe_tower_ap.name = "WipeTower"; wipe_tower_ap.is_virt_object = true; - wipe_tower_ap.is_wipe_tower = true; - const GLCanvas3D *canvas3D = static_cast(m_plater->canvas3D()); + wipe_tower_ap.is_wipe_tower = true; + const GLCanvas3D* canvas3D = static_cast(m_plater->canvas3D()); + + std::set extruder_ids; + PartPlateList& ppl = wxGetApp().plater()->get_partplate_list(); + int plate_count = ppl.get_plate_count(); + if (!only_on_partplate) { + extruder_ids = ppl.get_extruders(true); + } + + int bedid_unlocked = 0; for (int bedid = 0; bedid < MAX_NUM_PLATES; bedid++) { + int plate_index_valid = std::min(bedid, plate_count - 1); + PartPlate* pl = ppl.get_plate(plate_index_valid); + if(bedidis_locked()) + continue; if (auto wti = get_wipe_tower(*m_plater, bedid)) { // wipe tower is already there - wipe_tower_ap = get_wipetower_arrange_poly(&wti); - wipe_tower_ap.bed_idx = bedid; + wipe_tower_ap = get_wipetower_arrange_poly(&wti); + wipe_tower_ap.bed_idx = bedid_unlocked; m_unselected.emplace_back(wipe_tower_ap); - } else if (need_wipe_tower) { - wipe_tower_ap.translation = {0, 0}; - wipe_tower_ap.poly.contour.points = canvas3D->estimate_wipe_tower_points(bedid, !only_on_partplate); - wipe_tower_ap.bed_idx = bedid; + } + else if (need_wipe_tower) { + if (only_on_partplate) { + auto plate_extruders = pl->get_extruders(true); + extruder_ids.clear(); + extruder_ids.insert(plate_extruders.begin(), plate_extruders.end()); + } + wipe_tower_ap = estimate_wipe_tower_info(bedid, extruder_ids); + wipe_tower_ap.bed_idx = bedid_unlocked; m_unselected.emplace_back(wipe_tower_ap); } + bedid_unlocked++; } } @@ -338,7 +372,6 @@ void ArrangeJob::prepare_partplate() { return; } - params.is_seq_print = plate->get_real_print_seq() == PrintSequence::ByObject; Model& model = m_plater->model(); // Go through the objects and check if inside the selection @@ -364,7 +397,7 @@ void ArrangeJob::prepare_partplate() { //skip this object due to be not in current plate, treated as locked ap.itemid = m_locked.size(); m_locked.emplace_back(std::move(ap)); - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, name %2%") % oidx % mo->name; + //BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, name %2%") % oidx % mo->name; } } } @@ -520,11 +553,13 @@ void ArrangeJob::process() BOOST_LOG_TRIVIAL(warning)<< "Arrange full params: "<< params.to_json(); BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%") % m_selected.size(); for (auto selected : m_selected) { - BOOST_LOG_TRIVIAL(debug) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx<<", filemant_type:" << selected.filament_temp_type; + BOOST_LOG_TRIVIAL(debug) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx << ", filemant_type:" << selected.filament_temp_type + << ", trans: " << selected.translation.transpose(); } - BOOST_LOG_TRIVIAL(debug) << "items unselected before arrange: "; + BOOST_LOG_TRIVIAL(debug) << "arrange: items unselected before arrange: " << m_unselected.size(); for (auto item : m_unselected) - BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); + BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose() + <<", bbox:"<(selected.translation(X)) << ","<< unscale(selected.translation(Y)); - BOOST_LOG_TRIVIAL(debug) << "items unselected after arrange: "; + BOOST_LOG_TRIVIAL(debug) << "arrange: items unselected after arrange: "<< m_unselected.size(); for (auto item : m_unselected) BOOST_LOG_TRIVIAL(debug) << item.name << ", bed: " << item.bed_idx << ", trans: " << item.translation.transpose(); } @@ -714,11 +749,10 @@ arrangement::ArrangeParams init_arrange_params(Plater *p) auto & print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); const PrintConfig& print_config = print.config(); - - params.clearance_height_to_rod = print.config().extruder_clearance_height_to_rod.value; - params.clearance_height_to_lid = print.config().extruder_clearance_height_to_lid.value; - params.cleareance_radius = print.config().extruder_clearance_radius.value; - params.printable_height = print.config().printable_height.value; + params.clearance_height_to_rod = print_config.extruder_clearance_height_to_rod.value; + params.clearance_height_to_lid = print_config.extruder_clearance_height_to_lid.value; + params.cleareance_radius = print_config.extruder_clearance_radius.value; + params.printable_height = print_config.printable_height.value; params.allow_rotations = settings.enable_rotation; params.align_center = print_config.best_object_pos.value; params.allow_multi_materials_on_same_plate = settings.allow_multi_materials_on_same_plate; @@ -731,7 +765,11 @@ arrangement::ArrangeParams init_arrange_params(Plater *p) if (state == Job::JobPrepareState::PREPARE_STATE_MENU) { PartPlateList &plate_list = p->get_partplate_list(); PartPlate * plate = plate_list.get_curr_plate(); - params.is_seq_print = plate->get_real_print_seq() == PrintSequence::ByObject; + bool plate_same_as_global = true; + params.is_seq_print = plate->get_real_print_seq(&plate_same_as_global) == PrintSequence::ByObject; + // if plate's print sequence is not the same as global, the settings.distance is no longer valid, we set it to auto + if (!plate_same_as_global) + params.min_obj_distance = 0; } if (params.is_seq_print) { diff --git a/src/slic3r/GUI/Jobs/BindJob.cpp b/src/slic3r/GUI/Jobs/BindJob.cpp index a35047450d9..9534128af9d 100644 --- a/src/slic3r/GUI/Jobs/BindJob.cpp +++ b/src/slic3r/GUI/Jobs/BindJob.cpp @@ -107,7 +107,7 @@ void BindJob::process() if (result < 0) { BOOST_LOG_TRIVIAL(trace) << "login: result = " << result; - if (result_code == BAMBU_NETWORK_ERR_BIND_ECODE_LOGIN_REPORT_FAILED) { + if (result_code == BAMBU_NETWORK_ERR_BIND_ECODE_LOGIN_REPORT_FAILED || result_code == BAMBU_NETWORK_ERR_BIND_GET_PRINTER_TICKET_TIMEOUT) { int error_code; try diff --git a/src/slic3r/GUI/Jobs/FillBedJob.cpp b/src/slic3r/GUI/Jobs/FillBedJob.cpp index 40dbe30a2df..37dfd138645 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.cpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.cpp @@ -223,7 +223,7 @@ void FillBedJob::process() params.progressind = [this](unsigned st,std::string str="") { if (st > 0) - update_status(st, _L("Filling bed " + str)); + update_status(st, _L("Filling") + " " + wxString::FromUTF8(str)); }; params.on_packed = [&do_stop] (const ArrangePolygon &ap) { @@ -236,8 +236,8 @@ void FillBedJob::process() // finalize just here. update_status(m_status_range, was_canceled() ? - _(L("Bed filling canceled.")) : - _(L("Bed filling done."))); + _L("Bed filling canceled.") : + _L("Bed filling done.")); } void FillBedJob::finalize() @@ -289,6 +289,7 @@ void FillBedJob::finalize() auto obj_list = m_plater->sidebar().obj_list(); for (size_t i = oldSize; i < newSize; i++) { obj_list->add_object_to_list(i, true, true, false); + obj_list->update_printable_state(i, 0); } BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": paste_objects_into_list"; diff --git a/src/slic3r/GUI/Jobs/PrintJob.cpp b/src/slic3r/GUI/Jobs/PrintJob.cpp index 7da188fc10e..186f031f5f5 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.cpp +++ b/src/slic3r/GUI/Jobs/PrintJob.cpp @@ -29,6 +29,9 @@ static wxString desc_upload_ftp_failed = _L("Failed to upload print file to static wxString sending_over_lan_str = _L("Sending print job over LAN"); static wxString sending_over_cloud_str = _L("Sending print job through cloud service"); +static wxString wait_sending_finish = _L("Print task sending times out."); +static wxString desc_wait_sending_finish = _L("The printer timed out while receiving a print job. Please check if the network is functioning properly and send the print again."); + PrintJob::PrintJob(std::shared_ptr pri, Plater* plater, std::string dev_id) : PlaterJob{ std::move(pri), plater }, m_dev_id(dev_id), @@ -242,7 +245,6 @@ void PrintJob::process() params.dst_file = m_dst_path; } - if (wxGetApp().model().model_info && wxGetApp().model().model_info.get()) { ModelInfo* model_info = wxGetApp().model().model_info.get(); auto origin_profile_id = model_info->metadata_items.find(BBL_DESIGNER_PROFILE_ID_TAG); @@ -276,7 +278,17 @@ void PrintJob::process() catch (...) {} } } - + + if (!wxGetApp().model().stl_design_id.empty()) { + int stl_design_id = 0; + try { + stl_design_id = std::stoi(wxGetApp().model().stl_design_id); + } + catch (const std::exception& e) { + stl_design_id = 0; + } + params.stl_design_id = stl_design_id; + } if (params.preset_name.empty() && m_print_type == "from_normal") { params.preset_name = wxString::Format("%s_plate_%d", m_project_name, curr_plate_idx).ToStdString(); } if (params.project_name.empty()) {params.project_name = m_project_name;} @@ -296,6 +308,7 @@ void PrintJob::process() 70, // PrintingStageWaiting 75, // PrintingStageRecord 97, // PrintingStageSending + 100, // PrintingStageFinished 100 // PrintingStageFinished }; @@ -391,8 +404,53 @@ void PrintJob::process() return was_canceled(); }; - auto wait_fn = [this](int state, std::string job_info) { - // TODO + + DeviceManager* dev = wxGetApp().getDeviceManager(); + MachineObject* obj = dev->get_selected_machine(); + + auto wait_fn = [this, curr_percent, &obj](int state, std::string job_info) { + BOOST_LOG_TRIVIAL(info) << "print_job: get_job_info = " << job_info; + + if (!obj->is_support_wait_sending_finish) { + return true; + } + + std::string curr_job_id; + json job_info_j; + try { + job_info_j.parse(job_info); + if (job_info_j.contains("job_id")) { + curr_job_id = job_info_j["job_id"].get(); + } + BOOST_LOG_TRIVIAL(trace) << "print_job: curr_obj_id=" << curr_job_id; + + } catch(...) { + ; + } + + if (obj) { + int time_out = 0; + while (time_out < PRINT_JOB_SENDING_TIMEOUT) { + BOOST_LOG_TRIVIAL(trace) << "print_job: obj job_id = " << obj->job_id_; + if (!obj->job_id_.empty() && obj->job_id_.compare(curr_job_id) == 0) { + BOOST_LOG_TRIVIAL(info) << "print_job: got job_id = " << obj->job_id_ << ", time_out=" << time_out; + return true; + } + if (obj->is_in_printing_status(obj->print_status)) { + BOOST_LOG_TRIVIAL(info) << "print_job: printer has enter printing status, s = " << obj->print_status; + return true; + } + time_out++; + boost::this_thread::sleep_for(boost::chrono::milliseconds(1000)); + } + //this->update_status(curr_percent, _L("Print task sending times out.")); + m_plater->update_print_error_info(BAMBU_NETWORK_ERR_TIMEOUT, wait_sending_finish.ToStdString(), desc_wait_sending_finish.ToStdString()); + BOOST_LOG_TRIVIAL(info) << "print_job: timeout, cancel the job" << obj->job_id_; + /* handle tiemout */ + obj->command_task_cancel(curr_job_id); + return false; + } + BOOST_LOG_TRIVIAL(info) << "print_job: obj is null"; return true; }; diff --git a/src/slic3r/GUI/Jobs/PrintJob.hpp b/src/slic3r/GUI/Jobs/PrintJob.hpp index 8fa902f7db5..9c12013a07c 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.hpp +++ b/src/slic3r/GUI/Jobs/PrintJob.hpp @@ -10,6 +10,8 @@ namespace fs = boost::filesystem; namespace Slic3r { namespace GUI { +#define PRINT_JOB_SENDING_TIMEOUT 25 + class PrintPrepareData { public: diff --git a/src/slic3r/GUI/Jobs/SendJob.cpp b/src/slic3r/GUI/Jobs/SendJob.cpp index ba5dc450bb9..ced162784cd 100644 --- a/src/slic3r/GUI/Jobs/SendJob.cpp +++ b/src/slic3r/GUI/Jobs/SendJob.cpp @@ -142,7 +142,7 @@ void SendJob::process() result = m_agent->start_send_gcode_to_sdcard(params, nullptr, nullptr, nullptr); if (result != 0) { BOOST_LOG_TRIVIAL(error) << "access code is invalid"; - m_enter_ip_address_fun_fail(); + m_enter_ip_address_fun_fail(result); m_job_finished = true; return; } @@ -228,9 +228,10 @@ void SendJob::process() const int StagePercentPoint[(int)PrintingStageFinished + 1] = { 20, // PrintingStageCreate 30, // PrintingStageUpload - 99, // PrintingStageWaiting - 99, // PrintingStageRecord - 99, // PrintingStageSending + 99, // PrintingStageWaiting + 99, // PrintingStageRecord + 99, // PrintingStageSending + 100, // PrintingStageFinished 100 // PrintingStageFinished }; @@ -381,7 +382,7 @@ void SendJob::process() else { BOOST_LOG_TRIVIAL(error) << "send_job: send ok."; wxCommandEvent* evt = new wxCommandEvent(m_print_job_completed_id); - evt->SetString(params.project_name); + evt->SetString(from_u8(params.project_name)); wxQueueEvent(m_plater, evt); m_job_finished = true; } @@ -392,7 +393,7 @@ void SendJob::on_success(std::function success) m_success_fun = success; } -void SendJob::on_check_ip_address_fail(std::function func) +void SendJob::on_check_ip_address_fail(std::function func) { m_enter_ip_address_fun_fail = func; } diff --git a/src/slic3r/GUI/Jobs/SendJob.hpp b/src/slic3r/GUI/Jobs/SendJob.hpp index 3f5129bafc5..179d4f94765 100644 --- a/src/slic3r/GUI/Jobs/SendJob.hpp +++ b/src/slic3r/GUI/Jobs/SendJob.hpp @@ -23,7 +23,7 @@ class SendJob : public PlaterJob bool m_is_check_mode{false}; bool m_check_and_continue{false}; std::function m_success_fun{nullptr}; - std::function m_enter_ip_address_fun_fail{nullptr}; + std::function m_enter_ip_address_fun_fail{nullptr}; std::function m_enter_ip_address_fun_success{nullptr}; protected: @@ -60,7 +60,7 @@ class SendJob : public PlaterJob bool is_finished() { return m_job_finished; } void process() override; void on_success(std::function success); - void on_check_ip_address_fail(std::function func); + void on_check_ip_address_fail(std::function func); void on_check_ip_address_success(std::function func); void finalize() override; void set_project_name(std::string name); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 7dde189cbab..0f065ff28fd 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -197,6 +197,8 @@ void KBShortcutsDialog::fill_shortcuts() { ctrl + "P", L("Preferences") }, //3D control { ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") }, + // Switch table page + { ctrl + "Tab", L("Switch table page")}, //DEL #ifdef __APPLE__ {"fn+⌫", L("Delete selected")}, @@ -282,7 +284,7 @@ void KBShortcutsDialog::fill_shortcuts() {ctrl + "V", L("Paste from clipboard")}, {ctrl + "X", L("Cut")}, {ctrl + "A", L("Select all objects")}, - {ctrl + "M", L("Clone selected")}, + {ctrl + "K", L("Clone selected")}, {ctrl + "Z", L("Undo")}, {ctrl + "Y", L("Redo")}, {L("Space"), L("Select the object/part and press space to change the name")}, diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 6e5328da9cb..cda31f97908 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -60,11 +60,13 @@ #include "NetworkTestDialog.hpp" #include "ConfigWizard.hpp" #include "Widgets/WebView.hpp" +#include "DailyTips.hpp" #ifdef _WIN32 #include #include #endif // _WIN32 +#include namespace Slic3r { @@ -511,7 +513,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ // BBS: backup project if (wxGetApp().app_config->get("backup_switch") == "true") { std::string backup_interval; - if (!wxGetApp().app_config->get("", "backup_interval", backup_interval)) + if (!wxGetApp().app_config->get("app", "backup_interval", backup_interval)) backup_interval = "10"; Slic3r::set_backup_interval(boost::lexical_cast(backup_interval)); } else { @@ -551,7 +553,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ } return;} #endif - if (evt.CmdDown() && evt.GetKeyCode() == 'R') { if (m_slice_enable) { wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE)); this->m_tabpanel->SetSelection(tpPreview); } return; } + if (evt.CmdDown() && evt.GetKeyCode() == 'R') { if (m_slice_enable) { wxGetApp().plater()->update(true, true); wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE)); this->m_tabpanel->SetSelection(tpPreview); } return; } if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'G') { m_plater->apply_background_progress(); m_print_enable = get_enable_print_status(); @@ -571,7 +573,11 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ if (evt.CmdDown() && evt.GetKeyCode() == 'O') { m_plater->load_project(); return;} if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'S') { if (can_save_as()) m_plater->save_project(true); return;} else if (evt.CmdDown() && evt.GetKeyCode() == 'S') { if (can_save()) m_plater->save_project(); return;} - + if (evt.CmdDown() && evt.GetKeyCode() == 'F') { + if (m_plater && (m_tabpanel->GetSelection() == TabPosition::tp3DEditor || m_tabpanel->GetSelection() == TabPosition::tpPreview)) { + m_plater->sidebar().can_search(); + } + } #ifdef __APPLE__ if (evt.CmdDown() && evt.GetKeyCode() == ',') #else @@ -591,7 +597,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ if (evt.CmdDown() && evt.GetKeyCode() == 'I') { if (!can_add_models()) return; - if (m_plater) { m_plater->add_model(); } + if (m_plater) { m_plater->add_file(); } return; } evt.Skip(); @@ -729,8 +735,8 @@ void MainFrame::update_layout() case ESettingsLayout::Old: { m_plater->Reparent(m_tabpanel); - m_tabpanel->InsertPage(tp3DEditor, m_plater, _L("Prepare"), std::string("tab_3d_active"), std::string("tab_3d_active")); - m_tabpanel->InsertPage(tpPreview, m_plater, _L("Preview"), std::string("tab_preview_active"), std::string("tab_preview_active")); + m_tabpanel->InsertPage(tp3DEditor, m_plater, _L("Prepare"), std::string("tab_3d_active"), std::string("tab_3d_active"), false); + m_tabpanel->InsertPage(tpPreview, m_plater, _L("Preview"), std::string("tab_preview_active"), std::string("tab_preview_active"), false); m_main_sizer->Add(m_tabpanel, 1, wxEXPAND | wxTOP, 0); m_tabpanel->Bind(wxCUSTOMEVT_NOTEBOOK_SEL_CHANGED, [this](wxCommandEvent& evt) @@ -898,7 +904,7 @@ void MainFrame::show_calibration_button(bool show) if (shown2 == show) ; else if (show) - m_tabpanel->InsertPage(tpCalibration, m_calibration, _L("Calibration"), std::string("tab_monitor_active"), std::string("tab_monitor_active")); + m_tabpanel->InsertPage(tpCalibration, m_calibration, _L("Calibration"), std::string("tab_monitor_active"), std::string("tab_monitor_active"), false); else m_tabpanel->RemovePage(tpCalibration); } @@ -1034,7 +1040,7 @@ void MainFrame::init_tabpanel() { select_tab(MainFrame::tpHome); m_webview->load_url(url); }); - m_tabpanel->AddPage(m_webview, "", "tab_home_active", "tab_home_active"); + m_tabpanel->AddPage(m_webview, "", "tab_home_active", "tab_home_active", false); m_param_panel = new ParamsPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); } @@ -1049,7 +1055,7 @@ void MainFrame::init_tabpanel() { //BBS add pages m_monitor = new MonitorPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_monitor->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(m_monitor, _L("Device"), std::string("tab_monitor_active"), std::string("tab_monitor_active")); + m_tabpanel->AddPage(m_monitor, _L("Device"), std::string("tab_monitor_active"), std::string("tab_monitor_active"), false); m_printer_view = new PrinterWebView(m_tabpanel); Bind(EVT_LOAD_PRINTER_URL, [this](LoadPrinterViewEvent &evt) { @@ -1062,11 +1068,11 @@ void MainFrame::init_tabpanel() { m_project = new ProjectPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_project->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(m_project, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice")); + m_tabpanel->AddPage(m_project, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice"), false); m_calibration = new CalibrationPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); m_calibration->SetBackgroundColour(*wxWHITE); - m_tabpanel->AddPage(m_calibration, _L("Calibration"), std::string("tab_monitor_active"), std::string("tab_monitor_active")); + m_tabpanel->AddPage(m_calibration, _L("Calibration"), std::string("tab_monitor_active"), std::string("tab_monitor_active"), false); if (m_plater) { // load initial config @@ -1205,6 +1211,7 @@ void MainFrame::create_preset_tabs() m_param_dialog = new ParamsDialog(m_plater); add_created_tab(new TabPrint(m_param_panel), "cog"); + add_created_tab(new TabPrintPlate(m_param_panel), "cog"); add_created_tab(new TabPrintObject(m_param_panel), "cog"); add_created_tab(new TabPrintPart(m_param_panel), "cog"); add_created_tab(new TabPrintLayer(m_param_panel), "cog"); @@ -1224,6 +1231,10 @@ void MainFrame::add_created_tab(Tab* panel, const std::string& bmp_name /*= ""* { panel->create_preset_tab(); + if (panel->type() == Preset::TYPE_PLATE) { + wxGetApp().tabs_list.pop_back(); + wxGetApp().plate_tab = panel; + } // BBS: model config if (panel->type() == Preset::TYPE_MODEL) { wxGetApp().tabs_list.pop_back(); @@ -1807,7 +1818,7 @@ bool MainFrame::get_enable_print_status() } else if (m_print_select == eExportSlicedFile) { - if (!current_plate->is_slice_result_ready_for_print()) + if (!current_plate->is_slice_result_ready_for_export()) { enable = false; } @@ -1830,7 +1841,7 @@ bool MainFrame::get_enable_print_status() } else if (m_print_select == eExportAllSlicedFile) { - if (!part_plate_list.is_all_slice_results_ready_for_print()) + if (!part_plate_list.is_all_slice_result_ready_for_export()) { enable = false; } @@ -2020,6 +2031,7 @@ void MainFrame::on_sys_color_changed() tab->sys_color_changed(); for (auto tab : wxGetApp().model_tabs_list) tab->sys_color_changed(); + wxGetApp().plate_tab->sys_color_changed(); MenuFactory::sys_color_changed(m_menubar); @@ -2054,7 +2066,7 @@ static wxMenu* generate_help_menu() [](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); }); append_menu_item(helpMenu, wxID_ANY, _L("Show Tip of the Day"), _L("Show Tip of the Day"), [](wxCommandEvent&) { - wxGetApp().plater()->get_notification_manager()->push_hint_notification(false); + wxGetApp().plater()->get_dailytips()->open(); wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); }); @@ -2145,7 +2157,6 @@ static void add_common_view_menu_items(wxMenu* view_menu, MainFrame* mainFrame, void MainFrame::init_menubar_as_editor() { #ifdef __APPLE__ - wxMenuBar::SetAutoWindowMenu(false); m_menubar = new wxMenuBar(); #endif @@ -2241,9 +2252,12 @@ void MainFrame::init_menubar_as_editor() wxMenu* export_menu = new wxMenu(); // BBS export as STL - append_menu_item(export_menu, wxID_ANY, _L("Export all objects as STL") + dots, _L("Export all objects as STL"), + append_menu_item(export_menu, wxID_ANY, _L("Export all objects as one STL") + dots, _L("Export all objects as one STL"), [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "menu_export_stl", nullptr, [this](){return can_export_model(); }, this); + append_menu_item(export_menu, wxID_ANY, _L("Export all objects as STLs") + dots, _L("Export all objects as STLs"), + [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(false, false, true); }, "menu_export_stl", nullptr, + [this](){return can_export_model(); }, this); append_menu_item(export_menu, wxID_ANY, _L("Export Generic 3MF") + dots/* + "\tCtrl+G"*/, _L("Export 3mf file without using some 3mf-extensions"), [this](wxCommandEvent&) { if (m_plater) m_plater->export_core_3mf(); }, "menu_export_sliced_file", nullptr, [this](){return can_export_model(); }, this); @@ -2419,7 +2433,7 @@ void MainFrame::init_menubar_as_editor() "", nullptr, [this](){return can_delete_all(); }, this); editMenu->AppendSeparator(); // BBS Clone Selected - append_menu_item(editMenu, wxID_ANY, _L("Clone selected") + "\t" + ctrl + "M", + append_menu_item(editMenu, wxID_ANY, _L("Clone selected") + "\t" + ctrl + "K", _L("Clone copies of selections"),[this, handle_key_event](wxCommandEvent&) { wxKeyEvent e; e.SetEventType(wxEVT_KEY_DOWN); @@ -2672,7 +2686,6 @@ void MainFrame::init_menubar_as_editor() // Help menu auto helpMenu = generate_help_menu(); - #ifndef __APPLE__ m_topbar->SetFileMenu(fileMenu); if (editMenu) @@ -3020,6 +3033,10 @@ struct ConfigsOverwriteConfirmDialog : MessageDialog void MainFrame::export_config() { + ExportConfigsDialog export_configs_dlg(nullptr); + export_configs_dlg.ShowModal(); + return; + // Generate a cummulative configuration for the selected print, filaments and printer. wxDirDialog dlg(this, _L("Choose a directory"), from_u8(!m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir()), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); @@ -3056,7 +3073,7 @@ void MainFrame::load_config_file() // return; wxFileDialog dlg(this, _L("Select profile to load:"), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), - "config.json", "Config files (*.json)|*.json", wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST); + "config.json", "Config files (*.json;*.zip;*.bbscfg;*.bbsflmt)|*.json;*.zip;*.bbscfg;*.bbsflmt", wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST); wxArrayString files; if (dlg.ShowModal() != wxID_OK) return; @@ -3077,7 +3094,14 @@ void MainFrame::load_config_file() if (!cfiles.empty()) { wxGetApp().app_config->update_config_dir(get_dir_name(cfiles.back())); wxGetApp().load_current_presets(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " presets has been import,and size is" << cfiles.size(); + NetworkAgent* agent = wxGetApp().getAgent(); + if (agent) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " user is: " << agent->get_user_id(); + } } + wxGetApp().preset_bundle->update_compatible(PresetSelectCompatibleType::Always); + update_side_preset_ui(); MessageDialog dlg2(this, wxString::Format(_L_PLURAL("There is %d config imported. (Only non-system and compatible configs)", "There are %d configs imported. (Only non-system and compatible configs)", cfiles.size()), cfiles.size()), _L("Import result"), wxOK); @@ -3391,6 +3415,8 @@ std::wstring MainFrame::FileHistory::GetThumbnailUrl(int index) const void MainFrame::FileHistory::AddFileToHistory(const wxString &file) { + if (this->m_fileMaxFiles == 0) + return; wxFileHistory::AddFileToHistory(file); if (m_load_called) m_thumbnails.push_front(bbs_3mf_get_thumbnail(into_u8(file).c_str())); @@ -3400,6 +3426,8 @@ void MainFrame::FileHistory::AddFileToHistory(const wxString &file) void MainFrame::FileHistory::RemoveFileFromHistory(size_t i) { + if (i >= m_thumbnails.size()) // FIX zero max + return; wxFileHistory::RemoveFileFromHistory(i); m_thumbnails.erase(m_thumbnails.begin() + i); } diff --git a/src/slic3r/GUI/MediaFilePanel.cpp b/src/slic3r/GUI/MediaFilePanel.cpp index a2f5e793c69..dded21372bd 100644 --- a/src/slic3r/GUI/MediaFilePanel.cpp +++ b/src/slic3r/GUI/MediaFilePanel.cpp @@ -201,22 +201,24 @@ MediaFilePanel::~MediaFilePanel() void MediaFilePanel::SetMachineObject(MachineObject* obj) { std::string machine = obj ? obj->dev_id : ""; - if (obj && obj->is_function_supported(PrinterFunction::FUNC_MEDIA_FILE)) { - m_supported = true; + if (obj) { m_lan_mode = obj->is_lan_mode_printer(); m_lan_ip = obj->dev_ip; m_lan_passwd = obj->get_access_code(); - m_local_support = obj->has_local_file_proto(); - m_remote_support = obj->has_remote_file_proto(); + m_dev_ver = obj->get_ota_version(); + m_local_support = obj->file_local; + m_remote_support = obj->file_remote; + m_model_download_support = obj->file_model_download; } else { - m_supported = false; m_lan_mode = false; m_lan_ip.clear(); m_lan_passwd.clear(); + m_dev_ver.clear(); m_local_support = false; m_remote_support = false; + m_model_download_support = false; } - if (machine == m_machine) { + if (machine == m_machine && m_image_grid->GetFileSystem()) { if (m_waiting_enable && IsEnabled()) { auto fs = m_image_grid->GetFileSystem(); if (fs) fs->Retry(); @@ -235,7 +237,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) SetSelecting(false); if (m_machine.empty()) { m_image_grid->SetStatus(m_bmp_failed, _L("No printers.")); - } else if (!m_supported) { + } else if (!m_local_support && !m_remote_support) { m_image_grid->SetStatus(m_bmp_failed, _L("Initialize failed (Not supported on the current printer version)!")); } else { boost::shared_ptr fs(new PrinterFileSystem); @@ -250,6 +252,8 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) m_time_panel->Show(fs->GetFileType() < PrinterFileSystem::F_MODEL); //m_manage_panel->Show(fs->GetFileType() < PrinterFileSystem::F_MODEL); m_button_management->Enable(fs->GetCount() > 0); + bool download_support = fs->GetFileType() < PrinterFileSystem::F_MODEL || m_model_download_support; + m_image_grid->ShowDownload(download_support); if (fs->GetCount() == 0) SetSelecting(false); }); @@ -278,7 +282,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) case PrinterFileSystem::ListSyncing: icon = m_bmp_loading; msg = _L("Loading file list..."); break; case PrinterFileSystem::ListReady: icon = extra == 0 ? m_bmp_empty : m_bmp_failed; msg = extra == 0 ? _L("No files [%d]") : _L("Load failed [%d]"); break; } - if (!e.GetString().IsEmpty()) msg = _L(e.GetString()); + if (!e.GetString().IsEmpty()) msg = e.GetString(); if (fs->GetCount() == 0 && !msg.empty()) m_image_grid->SetStatus(icon, msg); if (e.GetInt() == PrinterFileSystem::Initializing) @@ -307,6 +311,9 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) return; int result = e.GetExtraLong(); + if (result > 1 && !e.GetString().IsEmpty()) + MessageDialog(this, e.GetString(), _L("Download failed"), wxOK | wxICON_ERROR).ShowModal(); + NetworkAgent* agent = wxGetApp().getAgent(); if (result > 1 || result == 0) { json j; @@ -373,7 +380,9 @@ void MediaFilePanel::SetSelecting(bool selecting) { m_image_grid->SetSelecting(selecting); m_button_management->SetLabel(selecting ? _L("Cancel") : _L("Select")); - m_manage_panel->GetSizer()->Show(m_button_download, selecting); + auto fs = m_image_grid->GetFileSystem(); + bool download_support = fs && fs->GetFileType() < PrinterFileSystem::F_MODEL || m_model_download_support; + m_manage_panel->GetSizer()->Show(m_button_download, selecting && download_support); m_manage_panel->GetSizer()->Show(m_button_delete, selecting); m_manage_panel->Layout(); } @@ -395,6 +404,8 @@ void MediaFilePanel::modeChanged(wxCommandEvent& e1) m_last_mode = mode; } +extern wxString hide_passwd(wxString url, std::vector const &passwords); + void MediaFilePanel::fetchUrl(boost::weak_ptr wfs) { boost::shared_ptr fs(wfs.lock()); @@ -412,7 +423,8 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr wfs) return; } if ((m_lan_mode || !m_remote_support) && m_local_support && !m_lan_ip.empty()) { - std::string url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; + std::string url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd + + "&device=" + m_machine + "&dev_ver=" + m_dev_ver; fs->SetUrl(url); return; } @@ -429,13 +441,13 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr wfs) NetworkAgent *agent = wxGetApp().getAgent(); if (agent) { agent->get_camera_url(m_machine, - [this, wfs](std::string url) { - BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: camera_url: " << url; - CallAfter([this, url, wfs] { + [this, wfs, m = m_machine, v = m_dev_ver](std::string url) { + BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: camera_url: " << hide_passwd(url, {"authkey=", "passwd="}); + CallAfter([=] { boost::shared_ptr fs(wfs.lock()); if (!fs || fs != m_image_grid->GetFileSystem()) return; if (boost::algorithm::starts_with(url, "bambu:///")) { - fs->SetUrl(url); + fs->SetUrl(url + "&device=" + m + "&dev_ver=" + v); } else { m_image_grid->SetStatus(m_bmp_failed, wxString::Format(_L("Initialize failed (%s)!"), url.empty() ? _L("Network unreachable") : from_u8(url))); fs->SetUrl("3"); @@ -504,7 +516,13 @@ void MediaFilePanel::doAction(size_t index, int action) auto &file = fs->GetFile(index); - int gcode_file_count = Slic3r::GUI::wxGetApp().plater()->update_print_required_data(config, model, plate_data_list, from_u8(file.name).ToStdString(), file.path); + + std::string file_path = file.path; + if (!file_path.empty() && file_path[0] == '/') { + file_path.erase(0, 1); + } + + int gcode_file_count = Slic3r::GUI::wxGetApp().plater()->update_print_required_data(config, model, plate_data_list, file.name, file_path); if (gcode_file_count > 0) { wxPostEvent(Slic3r::GUI::wxGetApp().plater(), SimpleEvent(EVT_PRINT_FROM_SDCARD_VIEW)); diff --git a/src/slic3r/GUI/MediaFilePanel.h b/src/slic3r/GUI/MediaFilePanel.h index 7e4e6451fba..8b9d84ae473 100644 --- a/src/slic3r/GUI/MediaFilePanel.h +++ b/src/slic3r/GUI/MediaFilePanel.h @@ -79,10 +79,11 @@ class MediaFilePanel : public wxPanel std::string m_lan_ip; std::string m_lan_user; std::string m_lan_passwd; - bool m_supported = false; + std::string m_dev_ver; bool m_lan_mode = false; bool m_local_support = false; bool m_remote_support = false; + bool m_model_download_support = false; bool m_waiting_enable = false; int m_last_mode = 0; diff --git a/src/slic3r/GUI/MediaPlayCtrl.cpp b/src/slic3r/GUI/MediaPlayCtrl.cpp index 9f3f0723417..f5f6e35b896 100644 --- a/src/slic3r/GUI/MediaPlayCtrl.cpp +++ b/src/slic3r/GUI/MediaPlayCtrl.cpp @@ -9,6 +9,7 @@ #include "DownloadProgressDialog.hpp" #include +#include #undef pid_t #include #ifdef __WIN32__ @@ -41,7 +42,23 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const w wxLaunchDefaultBrowser(url); }); - Bind(wxEVT_RIGHT_UP, [this](auto & e) { wxClipboard & c = *wxTheClipboard; if (c.Open()) { c.SetData(new wxTextDataObject(m_url)); c.Close(); } }); + Bind(wxEVT_RIGHT_UP, [this](auto & e) { + wxClipboard & c = *wxTheClipboard; + if (c.Open()) { + if (wxGetKeyState(WXK_SHIFT)) { + if (c.IsSupported(wxDF_TEXT)) { + wxTextDataObject data; + c.GetData(data); + Stop(); + m_url = data.GetText(); + load(); + } + } else { + c.SetData(new wxTextDataObject(m_url)); + } + c.Close(); + } + }); wxBoxSizer * sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_button_play, 0, wxEXPAND | wxALL, 0); @@ -77,21 +94,23 @@ MediaPlayCtrl::~MediaPlayCtrl() void MediaPlayCtrl::SetMachineObject(MachineObject* obj) { std::string machine = obj ? obj->dev_id : ""; - if (obj && obj->is_function_supported(PrinterFunction::FUNC_CAMERA_VIDEO)) { + if (obj) { m_camera_exists = obj->has_ipcam; + m_dev_ver = obj->get_ota_version(); m_lan_mode = obj->is_lan_mode_printer(); - m_lan_proto = obj->get_local_camera_proto(); + m_lan_proto = obj->liveview_local; + m_remote_support = obj->liveview_remote; m_lan_ip = obj->dev_ip; m_lan_passwd = obj->get_access_code(); - m_remote_support = obj->is_function_supported(PrinterFunction::FUNC_REMOTE_TUNNEL); m_device_busy = obj->is_camera_busy_off(); m_tutk_state = obj->tutk_state; } else { m_camera_exists = false; m_lan_mode = false; - m_lan_proto = -1; + m_lan_proto = MachineObject::LVL_None; m_lan_ip.clear(); m_lan_passwd.clear(); + m_dev_ver.clear(); m_tutk_state.clear(); m_remote_support = true; m_device_busy = false; @@ -121,6 +140,26 @@ void MediaPlayCtrl::SetMachineObject(MachineObject* obj) SetStatus("", false); } +wxString hide_passwd(wxString url, std::vector const &passwords) +{ + for (auto &p : passwords) { + auto i = url.find(p); + if (i == wxString::npos) + continue; + auto j = i + p.length(); + if (p[p.length() - 1] == '=') { + i = j; + j = url.find('&', i); + if (j == wxString::npos) + j = url.length(); + } + auto l = size_t(j - i); + if (j == url.length() || url[j] == '@' || url[j] == '&') + url.replace(i, l, l, wxUniChar('*')); + } + return url; +} + void MediaPlayCtrl::Play() { if (!m_next_retry.IsValid() || wxDateTime::Now() < m_next_retry) @@ -153,30 +192,19 @@ void MediaPlayCtrl::Play() m_button_play->SetIcon("media_stop"); NetworkAgent *agent = wxGetApp().getAgent(); std::string agent_version = agent ? agent->get_version() : ""; - if (m_lan_proto > 0 && (m_lan_mode || m_lan_proto == 1 || !m_remote_support) && !m_disable_lan && !m_lan_ip.empty()) { + if (m_lan_proto > MachineObject::LVL_None && (m_lan_mode || !m_remote_support) && !m_disable_lan && !m_lan_ip.empty()) { m_disable_lan = m_remote_support && !m_lan_mode; // try remote next time - if (m_lan_proto == 1) - m_url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd + "&device=" + m_machine + "&version=" + agent_version; - else if (m_lan_proto == 2) - m_url = "bambu:///rtsps___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?device=" + m_machine + "&version=" + agent_version; - else if (m_lan_proto == 3) - m_url = "bambu:///rtsp___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?device=" + m_machine + "&version=" + agent_version; - BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << m_url.substr(0, 16); - m_last_state = MEDIASTATE_LOADING; - SetStatus(_L("Loading...")); - if (wxGetApp().app_config->get("internal_developer_mode") == "true") { - std::string file_h264 = data_dir() + "/video.h264"; - std::string file_info = data_dir() + "/video.info"; - BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl dump video to " << file_h264; - // closed by BambuSource - FILE *dump_h264_file = boost::nowide::fopen(file_h264.c_str(), "wb"); - FILE *dump_info_file = boost::nowide::fopen(file_info.c_str(), "wb"); - m_url = m_url + "&dump_h264=" + boost::lexical_cast(dump_h264_file); - m_url = m_url + "&dump_info=" + boost::lexical_cast(dump_info_file); - } - boost::unique_lock lock(m_mutex); - m_tasks.push_back(m_url); - m_cond.notify_all(); + if (m_lan_proto == MachineObject::LVL_Local) + m_url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; + else if (m_lan_proto == MachineObject::LVL_Rtsps) + m_url = "bambu:///rtsps___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsps"; + else if (m_lan_proto == MachineObject::LVL_Rtsp) + m_url = "bambu:///rtsp___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsp"; + m_url += "&device=" + m_machine; + m_url += "&version=" + agent_version; + m_url += "&dev_ver=" + m_dev_ver; + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(m_url, {m_lan_passwd} ); + load(); return; } @@ -202,12 +230,13 @@ void MediaPlayCtrl::Play() SetStatus(_L("Initializing...")); if (agent) { - agent->get_camera_url(m_machine, [this, m = m_machine, v = agent_version](std::string url) { + agent->get_camera_url(m_machine, [this, m = m_machine, v = agent_version, dv = m_dev_ver](std::string url) { if (boost::algorithm::starts_with(url, "bambu:///")) { url += "&device=" + m; url += "&version=" + v; + url += "&dev_ver=" + dv; } - BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << url.substr(0, 16) << ", machine: " << m_machine; + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: " << hide_passwd(url, {"authkey=", "passwd="}) << ", machine: " << m_machine; CallAfter([this, m, url] { if (m != m_machine) { BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for machine: " << m; @@ -219,15 +248,7 @@ void MediaPlayCtrl::Play() m_failed_code = 3; Stop(wxString::Format(_L("Initialize failed (%s)!"), url.empty() ? _L("Network unreachable") : from_u8(url))); } else { - m_last_state = MEDIASTATE_LOADING; - SetStatus(_L("Loading...")); - if (wxGetApp().app_config->get("internal_developer_mode") == "true") { - BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl dump video to " << boost::filesystem::current_path(); - m_url = m_url + "&dump=video.h264"; - } - boost::unique_lock lock(m_mutex); - m_tasks.push_back(m_url); - m_cond.notify_all(); + load(); } } else { BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for state: " << m_last_state; @@ -267,19 +288,6 @@ void MediaPlayCtrl::Stop(wxString const &msg) if (last_state != wxMEDIASTATE_PLAYING && m_failed_code != 0 && m_last_failed_codes.find(m_failed_code) == m_last_failed_codes.end() && (m_user_triggered || m_failed_retry > 3)) { - json j; - j["stage"] = last_state; - j["dev_id"] = m_machine; - j["dev_ip"] = m_lan_ip; - j["result"] = "failed"; - j["user_triggered"] = m_user_triggered; - j["failed_retry"] = m_failed_retry; - j["tunnel"] = remote ? "remote" : "local"; - j["code"] = m_failed_code; - if (remote) - j["tutk_state"] = m_tutk_state; - j["msg"] = into_u8(msg); - NetworkAgent *agent = wxGetApp().getAgent(); m_last_failed_codes.insert(m_failed_code); } @@ -377,14 +385,34 @@ void MediaPlayCtrl::ToggleStream() wxGetApp().app_config->set("not_show_vcamera_stop_prev", "1"); if (res == wxID_CANCEL) return; } + if (m_lan_proto > MachineObject::LVL_None && (m_lan_mode || !m_remote_support) && !m_disable_lan && !m_lan_ip.empty()) { + std::string url; + if (m_lan_proto == MachineObject::LVL_Local) + url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; + else if (m_lan_proto == MachineObject::LVL_Rtsps) + url = "bambu:///rtsps___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsps"; + else if (m_lan_proto == MachineObject::LVL_Rtsp) + url = "bambu:///rtsp___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsp"; + url += "&device=" + m_machine; + url += "&dev_ver=" + m_dev_ver; + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << hide_passwd(url, {m_lan_passwd}); + std::string file_url = data_dir() + "/cameratools/url.txt"; + boost::nowide::ofstream file(file_url); + auto url2 = encode_path(url.c_str()); + file.write(url2.c_str(), url2.size()); + file.close(); + m_streaming = true; + return; + } NetworkAgent *agent = wxGetApp().getAgent(); if (!agent) return; - agent->get_camera_url(m_machine, [this, m = m_machine, v = agent->get_version()](std::string url) { + agent->get_camera_url(m_machine, [this, m = m_machine, v = agent->get_version(), dv = m_dev_ver](std::string url) { if (boost::algorithm::starts_with(url, "bambu:///")) { url += "&device=" + m; url += "&version=" + v; + url += "&dev_ver=" + dv; } - BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << url.substr(0, 16); + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::ToggleStream: " << hide_passwd(url, {"authkey=", "passwd="}); CallAfter([this, m, url] { if (m != m_machine) return; if (url.empty() || !boost::algorithm::starts_with(url, "bambu:///")) { @@ -403,6 +431,10 @@ void MediaPlayCtrl::ToggleStream() }); } +void MediaPlayCtrl::msw_rescale() { + m_button_play->Rescale(); +} + void MediaPlayCtrl::onStateChanged(wxMediaEvent &event) { auto last_state = m_last_state; @@ -430,14 +462,6 @@ void MediaPlayCtrl::onStateChanged(wxMediaEvent &event) m_last_state = state; SetStatus(_L("Playing..."), false); - // track event - json j; - j["stage"] = std::to_string(m_last_state); - j["dev_id"] = m_machine; - j["dev_ip"] = m_lan_ip; - j["result"] = "success"; - j["code"] = 0; - NetworkAgent* agent = wxGetApp().getAgent(); m_failed_retry = 0; m_failed_code = 0; @@ -476,6 +500,25 @@ void MediaPlayCtrl::SetStatus(wxString const &msg2, bool hyperlink) bool MediaPlayCtrl::IsStreaming() const { return m_streaming; } +void MediaPlayCtrl::load() +{ + m_last_state = MEDIASTATE_LOADING; + SetStatus(_L("Loading...")); + if (wxGetApp().app_config->get("internal_developer_mode") == "true") { + std::string file_h264 = data_dir() + "/video.h264"; + std::string file_info = data_dir() + "/video.info"; + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl dump video to " << file_h264; + // closed by BambuSource + FILE *dump_h264_file = boost::nowide::fopen(file_h264.c_str(), "wb"); + FILE *dump_info_file = boost::nowide::fopen(file_info.c_str(), "wb"); + m_url = m_url + "&dump_h264=" + boost::lexical_cast(dump_h264_file); + m_url = m_url + "&dump_info=" + boost::lexical_cast(dump_info_file); + } + boost::unique_lock lock(m_mutex); + m_tasks.push_back(m_url); + m_cond.notify_all(); +} + void MediaPlayCtrl::on_show_hide(wxShowEvent &evt) { evt.Skip(); @@ -495,7 +538,7 @@ void MediaPlayCtrl::media_proc() } wxString url = m_tasks.front(); if (m_tasks.size() >= 2 && !url.IsEmpty() && url[0] != '<' && m_tasks[1] == "") { - BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: busy skip url" << url; + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl: busy skip url: " << hide_passwd(url, {"authkey=", "passwd=", m_lan_passwd}); m_tasks.pop_front(); m_tasks.pop_front(); continue; @@ -565,7 +608,9 @@ bool MediaPlayCtrl::start_stream_service(bool *need_install) std::string file_dll2 = data_dir() + "/plugins/BambuSource.dll"; if (!boost::filesystem::exists(file_dll) || boost::filesystem::last_write_time(file_dll) != boost::filesystem::last_write_time(file_dll2)) boost::filesystem::copy_file(file_dll2, file_dll, boost::filesystem::copy_option::overwrite_if_exists); - boost::process::child process_source(file_source, file_url2.data().AsInternal(), boost::process::start_dir(start_dir), boost::process::windows::create_no_window, + static std::locale tmp = std::locale(std::locale(), new boost::nowide::utf8_codecvt()); + boost::process::imbue(tmp); + boost::process::child process_source(file_source, into_u8(file_url2), boost::process::start_dir(start_dir), boost::process::windows::create_no_window, boost::process::std_out > intermediate, boost::process::limit_handles); boost::process::child process_ffmpeg(file_ffmpeg, configss, boost::process::windows::create_no_window, boost::process::std_in < intermediate, boost::process::limit_handles); @@ -630,20 +675,20 @@ void wxMediaCtrl2::DoSetSize(int x, int y, int width, int height, int sizeFlags) #else wxMediaCtrl::DoSetSize(x, y, width, height, sizeFlags); #endif - if (sizeFlags & wxSIZE_USE_EXISTING) return; - wxSize size = GetVideoSize(); - if (size.GetWidth() <= 0) - size = wxSize{16, 9}; - int maxHeight = (width * size.GetHeight() + size.GetHeight() - 1) / size.GetWidth(); - if (maxHeight != GetMaxHeight()) { - // BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl2::DoSetSize: width: " << width << ", height: " << height << ", maxHeight: " << maxHeight; - SetMaxSize({-1, maxHeight}); - CallAfter([this] { - if (auto p = GetParent()) { - p->Layout(); - p->Refresh(); - } - }); - } + //if (sizeFlags & wxSIZE_USE_EXISTING) return; + //wxSize size = GetVideoSize(); + //if (size.GetWidth() <= 0) + // size = wxSize{16, 9}; + //int maxHeight = (width * size.GetHeight() + size.GetHeight() - 1) / size.GetWidth(); + //if (maxHeight != GetMaxHeight()) { + // // BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl2::DoSetSize: width: " << width << ", height: " << height << ", maxHeight: " << maxHeight; + // SetMaxSize({-1, maxHeight}); + // CallAfter([this] { + // if (auto p = GetParent()) { + // p->Layout(); + // p->Refresh(); + // } + // }); + //} } diff --git a/src/slic3r/GUI/MediaPlayCtrl.h b/src/slic3r/GUI/MediaPlayCtrl.h index 14ab40af5ff..79ce3a4b9ca 100644 --- a/src/slic3r/GUI/MediaPlayCtrl.h +++ b/src/slic3r/GUI/MediaPlayCtrl.h @@ -40,6 +40,8 @@ class MediaPlayCtrl : public wxPanel void ToggleStream(); + void msw_rescale(); + protected: void onStateChanged(wxMediaEvent & event); @@ -52,6 +54,8 @@ class MediaPlayCtrl : public wxPanel void SetStatus(wxString const &msg, bool hyperlink = true); private: + void load(); + void on_show_hide(wxShowEvent & evt); void media_proc(); @@ -73,6 +77,7 @@ class MediaPlayCtrl : public wxPanel std::string m_lan_ip; std::string m_lan_user; std::string m_lan_passwd; + std::string m_dev_ver; std::string m_tutk_state; bool m_camera_exists = false; bool m_lan_mode = false; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 18a86fb8ff1..4e0e8a009e5 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -176,12 +176,13 @@ bool MeshClipper::has_valid_contour() const return m_result && std::any_of(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland& isl) { return !isl.expoly.empty(); }); } -std::vector MeshClipper::point_per_contour() const -{ - assert(m_result); +std::vector MeshClipper::point_per_contour() const { std::vector out; - - for (const CutIsland& isl : m_result->cut_islands) { + if (m_result == std::nullopt) { + return out; + } + assert(m_result); + for (auto isl : m_result->cut_islands) { assert(isl.expoly.contour.size() > 2); // Now return a point lying inside the contour but not in a hole. // We do this by taking a point lying close to the edge, repeating diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index 64060b69580..ed323417aab 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -60,12 +60,11 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he topsizer->Add(LOGO_GAP, 0, 0, wxEXPAND, 0); topsizer->Add(rightsizer, 1, wxTOP | wxEXPAND, BORDER); - btn_sizer->AddStretchSpacer(); - main_sizer->Add(topsizer, 1, wxEXPAND); m_dsa_sizer = new wxBoxSizer(wxHORIZONTAL); - btn_sizer->Add(m_dsa_sizer,1,wxEXPAND,0); + btn_sizer->Add(0, 0, 0, wxLEFT, FromDIP(120)); + btn_sizer->Add(m_dsa_sizer, 0, wxEXPAND,0); btn_sizer->Add(0, 0, 1, wxEXPAND, 5); main_sizer->Add(btn_sizer, 0, wxBOTTOM | wxRIGHT | wxEXPAND, BORDER); @@ -485,4 +484,65 @@ void DownloadDialog::SetExtendedMessage(const wxString &extendedMessage) Fit(); } -}} // namespace Slic3r::GUI +DeleteConfirmDialog::DeleteConfirmDialog(wxWindow *parent, const wxString &title, const wxString &msg) + : DPIDialog(parent ? parent : nullptr, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) +{ + this->SetBackgroundColour(*wxWHITE); + this->SetSize(wxSize(FromDIP(450), FromDIP(200))); + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + wxBoxSizer *m_main_sizer = new wxBoxSizer(wxVERTICAL); + // top line + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(0xA6, 0xa9, 0xAA)); + m_main_sizer->Add(m_line_top, 0, wxEXPAND, 0); + m_main_sizer->Add(0, 0, 0, wxTOP, FromDIP(5)); + + m_msg_text = new wxStaticText(this, wxID_ANY, msg); + m_main_sizer->Add(m_msg_text, 0, wxEXPAND | wxALL, FromDIP(10)); + + wxBoxSizer *bSizer_button = new wxBoxSizer(wxHORIZONTAL); + bSizer_button->Add(0, 0, 1, wxEXPAND, 0); + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + m_cancel_btn = new Button(this, _L("Cancel")); + m_cancel_btn->SetBackgroundColor(btn_bg_white); + m_cancel_btn->SetBorderColor(*wxBLACK); + m_cancel_btn->SetTextColor(wxColour(*wxBLACK)); + m_cancel_btn->SetFont(Label::Body_12); + m_cancel_btn->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_cancel_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_cancel_btn->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_cancel_btn, 0, wxRIGHT | wxBOTTOM, FromDIP(10)); + + + m_del_btn = new Button(this, _L("Delete")); + m_del_btn->SetBackgroundColor(*wxRED); + m_del_btn->SetBorderColor(*wxWHITE); + m_del_btn->SetTextColor(wxColour(0xFFFFFE)); + m_del_btn->SetFont(Label::Body_12); + m_del_btn->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_del_btn->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_del_btn->SetCornerRadius(FromDIP(12)); + bSizer_button->Add(m_del_btn, 0, wxRIGHT | wxBOTTOM, FromDIP(10)); + + m_main_sizer->Add(bSizer_button, 0, wxEXPAND, 0); + m_del_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { EndModal(wxID_OK); }); + m_cancel_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { EndModal(wxID_CANCEL); }); + + SetSizer(m_main_sizer); + Layout(); + Fit(); + wxGetApp().UpdateDlgDarkUI(this); +} + +DeleteConfirmDialog::~DeleteConfirmDialog() {} + + +void DeleteConfirmDialog::on_dpi_changed(const wxRect &suggested_rect) {} + + +} // namespace GUI + +} // namespace Slic3r diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index a136d2eed19..58e113acbef 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -378,6 +378,19 @@ class DownloadDialog : public MsgDialog wxString msg; }; +class DeleteConfirmDialog : public DPIDialog +{ +public: + DeleteConfirmDialog(wxWindow *parent, const wxString &title, const wxString &msg); + ~DeleteConfirmDialog(); + virtual void on_dpi_changed(const wxRect &suggested_rect); + +private: + wxString msg; + Button * m_del_btn = nullptr; + Button * m_cancel_btn = nullptr; + wxStaticText *m_msg_text = nullptr; +}; } } diff --git a/src/slic3r/GUI/NetworkTestDialog.cpp b/src/slic3r/GUI/NetworkTestDialog.cpp index bc612308886..195c0d55b4e 100644 --- a/src/slic3r/GUI/NetworkTestDialog.cpp +++ b/src/slic3r/GUI/NetworkTestDialog.cpp @@ -24,6 +24,8 @@ NetworkTestDialog::NetworkTestDialog(wxWindow* parent, wxWindowID id, const wxSt wxSize(1000, 700), /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER) { + this->SetBackgroundColour(wxColour(255, 255, 255)); + this->SetSizeHints(wxDefaultSize, wxDefaultSize); wxBoxSizer* main_sizer; @@ -49,20 +51,26 @@ NetworkTestDialog::NetworkTestDialog(wxWindow* parent, wxWindowID id, const wxSt this->Layout(); this->Centre(wxBOTH); + wxGetApp().UpdateDlgDarkUI(this); } wxBoxSizer* NetworkTestDialog::create_top_sizer(wxWindow* parent) { + StateColor btn_bg(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), std::pair(wxColour(255, 255, 255), StateColor::Enabled)); auto sizer = new wxBoxSizer(wxVERTICAL); auto line_sizer = new wxBoxSizer(wxHORIZONTAL); - btn_start = new wxButton(this, wxID_ANY, _L("Start Test Multi-Thread"), wxDefaultPosition, wxDefaultSize, 0); + btn_start = new Button(this, _L("Start Test Multi-Thread")); + btn_start->SetBackgroundColor(btn_bg); line_sizer->Add(btn_start, 0, wxALL, 5); - btn_start_sequence = new wxButton(this, wxID_ANY, _L("Start Test Single-Thread"), wxDefaultPosition, wxDefaultSize, 0); + btn_start_sequence = new Button(this, _L("Start Test Single-Thread")); + btn_start_sequence->SetBackgroundColor(btn_bg); + line_sizer->Add(btn_start_sequence, 0, wxALL, 5); - btn_download_log = new wxButton(this, wxID_ANY, _L("Export Log"), wxDefaultPosition, wxDefaultSize, 0); + btn_download_log = new Button(this, _L("Export Log")); + btn_download_log->SetBackgroundColor(btn_bg); line_sizer->Add(btn_download_log, 0, wxALL, 5); btn_download_log->Hide(); @@ -130,7 +138,9 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent) grid_sizer->SetFlexibleDirection(wxBOTH); grid_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); - btn_link = new wxButton(this, wxID_ANY, _L("Test BambuLab"), wxDefaultPosition, wxDefaultSize, 0); + StateColor btn_bg(std::pair(wxColour(0, 137, 123), StateColor::Pressed),std::pair(wxColour(38, 166, 154), StateColor::Hovered), std::pair(wxColour(255,255,255), StateColor::Enabled)); + btn_link = new Button(this, _L("Test BambuLab")); + btn_link->SetBackgroundColor(btn_bg); grid_sizer->Add(btn_link, 0, wxEXPAND | wxALL, 5); text_link_title = new wxStaticText(this, wxID_ANY, _L("Test BambuLab:"), wxDefaultPosition, wxDefaultSize, 0); @@ -141,10 +151,12 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent) text_link_val->Wrap(-1); grid_sizer->Add(text_link_val, 0, wxALL, 5); - btn_bing = new wxButton(this, wxID_ANY, _L("Test Bing.com"), wxDefaultPosition, wxDefaultSize, 0); + btn_bing = new Button(this, _L("Test Bing.com")); + btn_bing->SetBackgroundColor(btn_bg); grid_sizer->Add(btn_bing, 0, wxEXPAND | wxALL, 5); - text_bing_title = new wxStaticText(this, wxID_ANY, _L("Test bing.com:"), wxDefaultPosition, wxDefaultSize, 0); + text_bing_title = new wxStaticText(this, wxID_ANY, _L("Test bing.com:"), wxDefaultPosition, wxDefaultSize, 0); + text_bing_title->Wrap(-1); grid_sizer->Add(text_bing_title, 0, wxALIGN_RIGHT | wxALL, 5); @@ -152,7 +164,8 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent) text_bing_val->Wrap(-1); grid_sizer->Add(text_bing_val, 0, wxALL, 5); - btn_iot = new wxButton(this, wxID_ANY, _L("Test HTTP"), wxDefaultPosition, wxDefaultSize, 0); + btn_iot = new Button(this, _L("Test HTTP")); + btn_iot->SetBackgroundColor(btn_bg); grid_sizer->Add(btn_iot, 0, wxEXPAND | wxALL, 5); text_iot_title = new wxStaticText(this, wxID_ANY, _L("Test HTTP Service:"), wxDefaultPosition, wxDefaultSize, 0); @@ -163,7 +176,8 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent) text_iot_value->Wrap(-1); grid_sizer->Add(text_iot_value, 0, wxALL, 5); - btn_oss = new wxButton(this, wxID_ANY, _L("Test storage"), wxDefaultPosition, wxDefaultSize, 0); + btn_oss = new Button(this, _L("Test storage")); + btn_oss->SetBackgroundColor(btn_bg); grid_sizer->Add(btn_oss, 0, wxEXPAND | wxALL, 5); text_oss_title = new wxStaticText(this, wxID_ANY, _L("Test Storage Upload:"), wxDefaultPosition, wxDefaultSize, 0); @@ -174,7 +188,8 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent) text_oss_value->Wrap(-1); grid_sizer->Add(text_oss_value, 0, wxALL, 5); - btn_oss_upgrade = new wxButton(this, wxID_ANY, _L("Test storage upgrade"), wxDefaultPosition, wxDefaultSize, 0); + btn_oss_upgrade = new Button(this, _L("Test storage upgrade")); + btn_oss_upgrade->SetBackgroundColor(btn_bg); grid_sizer->Add(btn_oss_upgrade, 0, wxEXPAND | wxALL, 5); text_oss_upgrade_title = new wxStaticText(this, wxID_ANY, _L("Test Storage Upgrade:"), wxDefaultPosition, wxDefaultSize, 0); @@ -185,7 +200,8 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent) text_oss_upgrade_value->Wrap(-1); grid_sizer->Add(text_oss_upgrade_value, 0, wxALL, 5); - btn_oss_download = new wxButton(this, wxID_ANY, _L("Test storage download"), wxDefaultPosition, wxDefaultSize, 0); + btn_oss_download = new Button(this, _L("Test storage download")); + btn_oss_download->SetBackgroundColor(btn_bg); grid_sizer->Add(btn_oss_download, 0, wxEXPAND | wxALL, 5); text_oss_download_title = new wxStaticText(this, wxID_ANY, _L("Test Storage Download:"), wxDefaultPosition, wxDefaultSize, 0); @@ -196,7 +212,21 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent) text_oss_download_value->Wrap(-1); grid_sizer->Add(text_oss_download_value, 0, wxALL, 5); - btn_oss_upload = new wxButton(this, wxID_ANY, _L("Test Storage Upload"), wxDefaultPosition, wxDefaultSize, 0); + btn_network_plugin=new Button(this, _L("Test plugin download")); + btn_network_plugin->SetBackgroundColor(btn_bg); + grid_sizer->Add(btn_network_plugin, 0, wxEXPAND | wxALL, 5); + + text_network_plugin_title=new wxStaticText(this, wxID_ANY, _L("Test Plugin Download:"), wxDefaultPosition, wxDefaultSize, 0); + text_network_plugin_title->Wrap(-1); + grid_sizer->Add(text_network_plugin_title, 0, wxALIGN_RIGHT | wxALL, 5); + + text_network_plugin_value=new wxStaticText(this, wxID_ANY, _L("N/A"), wxDefaultPosition, wxDefaultSize, 0); + text_network_plugin_value->Wrap(-1); + grid_sizer->Add(text_network_plugin_value, 0, wxALL, 5); + + + btn_oss_upload = new Button(this, _L("Test Storage Upload")); + btn_oss_upload->SetBackgroundColor(btn_bg); grid_sizer->Add(btn_oss_upload, 0, wxEXPAND | wxALL, 5); text_oss_upload_title = new wxStaticText(this, wxID_ANY, _L("Test Storage Upload:"), wxDefaultPosition, wxDefaultSize, 0); @@ -237,6 +267,10 @@ wxBoxSizer* NetworkTestDialog::create_content_sizer(wxWindow* parent) start_test_oss_download_thread(); }); + btn_network_plugin->Bind(wxEVT_BUTTON, [this](wxCommandEvent &evt) { + start_test_plugin_download_thread(); + }); + return sizer; } wxBoxSizer* NetworkTestDialog::create_result_sizer(wxWindow* parent) @@ -273,7 +307,9 @@ void NetworkTestDialog::init_bind() text_oss_download_value->SetLabelText(evt.GetString()); } else if (evt.GetInt() == TEST_OSS_UPLOAD_JOB) { text_oss_upload_value->SetLabelText(evt.GetString()); - } + } else if (evt.GetInt() == TEST_PLUGIN_JOB){ + text_network_plugin_value->SetLabelText(evt.GetString()); + } std::time_t t = std::time(0); std::tm* now_time = std::localtime(&t); @@ -314,12 +350,14 @@ wxString NetworkTestDialog::get_dns_info() void NetworkTestDialog::start_all_job() { - start_test_bing_thread(); start_test_bambulab_thread(); + start_test_bing_thread(); + start_test_iot_thread(); start_test_oss_thread(); start_test_oss_upgrade_thread(); start_test_oss_download_thread(); + start_test_plugin_download_thread(); start_test_ping_thread(); } @@ -336,6 +374,8 @@ void NetworkTestDialog::start_all_job_sequence() start_test_oss_upgrade(); if (m_closing) return; start_test_oss_download(); + if (m_closing) return; + start_test_plugin_download(); update_status(-1, "end_test_sequence"); }); } @@ -347,6 +387,7 @@ void NetworkTestDialog::start_test_bing() std::string url = "http://www.bing.com/"; Slic3r::Http http = Slic3r::Http::get(url); + update_status(-1, "[test_bing]: url=" + url); int result = -1; http.timeout_max(10) @@ -399,6 +440,7 @@ void NetworkTestDialog::start_test_bambulab() AppConfig* app_config = wxGetApp().app_config; std::string url = wxGetApp().get_http_url(app_config->get_country_code()) + query_params; Slic3r::Http http = Slic3r::Http::get(url); + update_status(-1, "[test_bambulab]: url=" + url); int result = -1; http.header("accept", "application/json") .timeout_max(10) @@ -467,6 +509,7 @@ void NetworkTestDialog::start_test_oss() } Slic3r::Http http = Slic3r::Http::get(url); + update_status(-1, "[test_oss]: url=" + url); int result = -1; http.timeout_max(15) @@ -513,6 +556,7 @@ void NetworkTestDialog::start_test_oss_upgrade() } Slic3r::Http http = Slic3r::Http::get(url); + update_status(-1, "[test_oss_upgrade]: url=" + url); int result = -1; http.timeout_max(15) @@ -576,7 +620,7 @@ void NetworkTestDialog::start_test_oss_download() try { json j = json::parse(body); std::string message = j["message"].get(); - + if (message == "success") { json resource = j.at("resources"); if (resource.is_array()) { @@ -672,7 +716,7 @@ void NetworkTestDialog::start_test_oss_download() file.write(body.c_str(), body.size()); file.close(); fs::rename(tmp_path, target_file_path); - this->update_status(TEST_OSS_DOWNLOAD_JOB, "test storage download ok"); + //this->update_status(TEST_OSS_DOWNLOAD_JOB, "test storage download ok"); }) .on_error([this, &result](std::string body, std::string error, unsigned int status) { BOOST_LOG_TRIVIAL(error) << "[test_oss_download] downloading... on_error: " << error << ", body = " << body; @@ -693,7 +737,141 @@ void NetworkTestDialog::start_test_oss_download() void NetworkTestDialog::start_test_oss_upload() { - ; + +} + +void NetworkTestDialog:: start_test_plugin_download(){ + int result = 0; + // get country_code + AppConfig *app_config = wxGetApp().app_config; + if (!app_config) { + update_status(TEST_PLUGIN_JOB, "app config is nullptr"); + return; + } + + m_in_testing[TEST_PLUGIN_JOB] = true; + update_status(TEST_PLUGIN_JOB, "test plugin download start..."); + m_download_cancel = false; + // get temp path + fs::path target_file_path = (fs::temp_directory_path() / "test_plugin_download.zip"); + fs::path tmp_path = target_file_path; + tmp_path += (boost::format(".%1%%2%") % get_current_pid() % ".tmp").str(); + + // get_url + std::string url = wxGetApp().get_plugin_url("plugins", app_config->get_country_code()); + std::string download_url; + Slic3r::Http http_url = Slic3r::Http::get(url); + http_url + .on_complete([&download_url,this](std::string body, unsigned status) { + try { + json j = json::parse(body); + std::string message = j["message"].get(); + + if (message == "success") { + json resource = j.at("resources"); + if (resource.is_array()) { + for (auto iter = resource.begin(); iter != resource.end(); iter++) { + Semver version; + std::string url; + std::string type; + std::string vendor; + std::string description; + for (auto sub_iter = iter.value().begin(); sub_iter != iter.value().end(); sub_iter++) { + if (boost::iequals(sub_iter.key(), "type")) { + type = sub_iter.value(); + BOOST_LOG_TRIVIAL(info) << "[test_plugin_download]: get version of settings's type, " << sub_iter.value(); + } else if (boost::iequals(sub_iter.key(), "version")) { + version = *(Semver::parse(sub_iter.value())); + } else if (boost::iequals(sub_iter.key(), "description")) { + description = sub_iter.value(); + } else if (boost::iequals(sub_iter.key(), "url")) { + url = sub_iter.value(); + } + } + BOOST_LOG_TRIVIAL(info) << "[test_plugin_download]: get type " << type << ", version " << version.to_string() << ", url " << url; + download_url = url; + this->update_status(-1, "[test_plugin_download]: downloadurl=" + download_url); + } + } + } else { + BOOST_LOG_TRIVIAL(info) << "[test_plugin_download]: get version of plugin failed, body=" << body; + } + } catch (...) { + BOOST_LOG_TRIVIAL(error) << "[test_plugin_download]: catch unknown exception"; + ; + } + }) + .on_error([&result, this](std::string body, std::string error, unsigned int status) { + BOOST_LOG_TRIVIAL(error) << "[test_plugin_download] on_error: " << error << ", body = " << body; + wxString info = wxString::Format("status=%u, body=%s, error=%s", status, body, error); + this->update_status(TEST_PLUGIN_JOB, "test plugin download failed"); + this->update_status(-1, info); + result = -1; + }) + .perform_sync(); + + + if (result < 0) { + this->update_status(TEST_PLUGIN_JOB, "test plugin download failed"); + m_in_testing[TEST_PLUGIN_JOB] = false; + return; + } + + if (download_url.empty()) { + BOOST_LOG_TRIVIAL(info) << "[test_plugin_download]: no availaible plugin found for this app version: " << SLIC3R_VERSION; + this->update_status(TEST_PLUGIN_JOB, "test plugin download failed"); + m_in_testing[TEST_PLUGIN_JOB] = false; + return; + } + if (m_download_cancel) { + this->update_status(TEST_PLUGIN_JOB, "test plugin download canceled"); + m_in_testing[TEST_PLUGIN_JOB] = false; + return; + } + + bool cancel = false; + BOOST_LOG_TRIVIAL(info) << "[test_plugin_download] get_url = " << download_url; + + // download + Slic3r::Http http = Slic3r::Http::get(download_url); + int reported_percent = 0; + http.on_progress([this, &result, &reported_percent](Slic3r::Http::Progress progress, bool &cancel) { + int percent = 0; + if (progress.dltotal != 0) { percent = progress.dlnow * 100 / progress.dltotal; } + if (percent - reported_percent >= 5) { + reported_percent = percent; + std::string download_progress_info = (boost::format("downloading %1%%%") % percent).str(); + this->update_status(TEST_PLUGIN_JOB, download_progress_info); + } + + BOOST_LOG_TRIVIAL(info) << "[test_plugin_download] progress: " << reported_percent; + cancel = m_download_cancel; + + if (cancel) result = -1; + }) + .on_complete([this, tmp_path, target_file_path](std::string body, unsigned status) { + BOOST_LOG_TRIVIAL(info) << "[test_plugin_download] completed"; + bool cancel = false; + fs::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc); + file.write(body.c_str(), body.size()); + file.close(); + fs::rename(tmp_path, target_file_path); + }) + .on_error([this, &result](std::string body, std::string error, unsigned int status) { + BOOST_LOG_TRIVIAL(error) << "[test_plugin_download] downloading... on_error: " << error << ", body = " << body; + wxString info = wxString::Format("status=%u, body=%s, error=%s", status, body, error); + this->update_status(TEST_PLUGIN_JOB, "test plugin download failed"); + this->update_status(-1, info); + result = -1; + }); + http.perform_sync(); + if (result < 0) { + this->update_status(TEST_PLUGIN_JOB, "test plugin download failed"); + } else { + this->update_status(TEST_PLUGIN_JOB, "test plugin download ok"); + } + m_in_testing[TEST_PLUGIN_JOB] = false; + return; } void NetworkTestDialog::start_test_ping_thread() @@ -756,6 +934,13 @@ void NetworkTestDialog::start_test_oss_upload_thread() }); } +void NetworkTestDialog:: start_test_plugin_download_thread(){ + + test_job[TEST_PLUGIN_JOB] = new boost::thread([this] { + start_test_plugin_download(); + }); +} + void NetworkTestDialog::on_close(wxCloseEvent& event) { m_download_cancel = true; @@ -795,6 +980,7 @@ void NetworkTestDialog::set_default() text_oss_upgrade_value->SetLabelText(NA_STR); text_oss_download_value->SetLabelText(NA_STR); text_oss_upload_value->SetLabelText(NA_STR); + text_network_plugin_value->SetLabelText(NA_STR); //text_ping_value->SetLabelText(NA_STR); m_download_cancel = false; m_closing = false; diff --git a/src/slic3r/GUI/NetworkTestDialog.hpp b/src/slic3r/GUI/NetworkTestDialog.hpp index a9b93796c44..bf56b3db453 100644 --- a/src/slic3r/GUI/NetworkTestDialog.hpp +++ b/src/slic3r/GUI/NetworkTestDialog.hpp @@ -6,6 +6,7 @@ #include "GUI_Utils.hpp" #include "wxExtensions.hpp" +#include #include #include #include @@ -41,15 +42,16 @@ enum TestJob { TEST_OSS_DOWNLOAD_JOB = 5, TEST_OSS_UPLOAD_JOB = 6, TEST_PING_JOB = 7, - TEST_JOB_MAX = 8 + TEST_PLUGIN_JOB = 8, + TEST_JOB_MAX = 9 }; class NetworkTestDialog : public DPIDialog { protected: - wxButton* btn_start; - wxButton* btn_start_sequence; - wxButton* btn_download_log; + Button* btn_start; + Button* btn_start_sequence; + Button* btn_download_log; wxStaticText* text_basic_info; wxStaticText* text_version_title; wxStaticText* text_version_val; @@ -57,27 +59,30 @@ class NetworkTestDialog : public DPIDialog wxStaticText* txt_sys_info_value; wxStaticText* txt_dns_info_title; wxStaticText* txt_dns_info_value; - wxButton* btn_link; + Button* btn_link; wxStaticText* text_link_title; wxStaticText* text_link_val; - wxButton* btn_bing; + Button* btn_bing; wxStaticText* text_bing_title; wxStaticText* text_bing_val; - wxButton* btn_iot; + Button* btn_iot; wxStaticText* text_iot_title; wxStaticText* text_iot_value; - wxButton* btn_oss; + Button* btn_oss; wxStaticText* text_oss_title; wxStaticText* text_oss_value; - wxButton* btn_oss_upgrade; + Button* btn_oss_upgrade; wxStaticText* text_oss_upgrade_title; wxStaticText* text_oss_upgrade_value; - wxButton* btn_oss_download; + Button* btn_oss_download; wxStaticText* text_oss_download_title; wxStaticText* text_oss_download_value; - wxButton* btn_oss_upload; + Button* btn_oss_upload; wxStaticText* text_oss_upload_title; wxStaticText* text_oss_upload_value; + Button* btn_network_plugin; + wxStaticText* text_network_plugin_title; + wxStaticText* text_network_plugin_value; wxStaticText* text_ping_title; wxStaticText* text_ping_value; wxStaticText* text_result; @@ -118,6 +123,7 @@ class NetworkTestDialog : public DPIDialog void start_test_oss_download_thread(); void start_test_oss_upload_thread(); void start_test_ping_thread(); + void start_test_plugin_download_thread(); void start_test_bing(); void start_test_bambulab(); @@ -126,6 +132,7 @@ class NetworkTestDialog : public DPIDialog void start_test_oss_upgrade(); void start_test_oss_download(); void start_test_oss_upload(); + void start_test_plugin_download(); void on_close(wxCloseEvent& event); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 585d5a8322b..81a5511cd67 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -1,6 +1,7 @@ #include "NotificationManager.hpp" #include "HintNotification.hpp" +#include "SlicingProgressNotification.hpp" #include "GUI.hpp" #include "ImGuiWrapper.hpp" #include "wxExtensions.hpp" @@ -39,6 +40,7 @@ namespace GUI { wxDEFINE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent); wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent); wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); +wxDEFINE_EVENT(EVT_PRINTER_CONFIG_UPDATE_AVAILABLE_CLICKED, PrinterConfigUpdateAvailableClickedEvent); namespace { /* // not used? @@ -221,7 +223,6 @@ void NotificationManager::PopNotification::restore_default_theme() void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin) { - if (m_state == EState::Unknown) init(); @@ -250,14 +251,13 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init // top y of window m_top_y = initial_y + m_window_height; + // position of upper-right corner ImVec2 win_pos(1.0f * (float)cnv_size.get_width() - right_gap, 1.0f * (float)cnv_size.get_height() - m_top_y); imgui.set_next_window_pos(win_pos.x, win_pos.y, ImGuiCond_Always, 1.0f, 0.0f); imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always); - // find if hovered FIXME: do it only in update state? if (m_state == EState::Hovered) { - m_state = EState::Unknown; init(); } @@ -284,11 +284,11 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init use_bbl_theme(); - if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { + int window_flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; + if (imgui.begin(name, window_flags)) { ImVec2 win_size = ImGui::GetWindowSize(); bbl_render_left_sign(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y); - render_left_sign(imgui); render_text(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y); render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y); @@ -544,10 +544,13 @@ void NotificationManager::PopNotification::init() count_spaces(); count_lines(); - if (m_lines_count == 3) - m_multiline = true; + if (m_lines_count <= 6) { + if (m_state == EState::Unknown) // if is default state + m_multiline = true; + } + m_notification_start = GLCanvas3D::timestamp_now(); - if (m_state == EState::Unknown) + if (m_state == EState::Unknown || m_state == EState::Hovered) m_state = EState::Shown; } void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui) @@ -971,7 +974,6 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64 // reset timers - hovered state is set in render if (m_state == EState::Hovered) { - m_state = EState::Unknown; init(); // Timers when not fading } else if (m_state != EState::NotFading && m_state != EState::FadingOut && m_state != EState::ClosePending && m_state != EState::Finished && get_duration() != 0 && !paused) { @@ -1408,275 +1410,6 @@ void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGu } ImGui::PopStyleColor(5); } -//------SlicingProgressNotification -void NotificationManager::SlicingProgressNotification::init() -{ - if (m_sp_state == SlicingProgressState::SP_PROGRESS) { - ProgressBarNotification::init(); - //if (m_state == EState::NotFading && m_percentage >= 1.0f) - // m_state = EState::Shown; - } - else { - PopNotification::init(); - } - -} -bool NotificationManager::SlicingProgressNotification::set_progress_state(float percent) -{ - if (percent < 0.f) - return true;//set_progress_state(SlicingProgressState::SP_CANCELLED); - else if (percent >= 1.f) - return set_progress_state(SlicingProgressState::SP_COMPLETED); - else - return set_progress_state(SlicingProgressState::SP_PROGRESS, percent); -} -bool NotificationManager::SlicingProgressNotification::set_progress_state(NotificationManager::SlicingProgressNotification::SlicingProgressState state, float percent/* = 0.f*/) -{ - switch (state) - { - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: - m_state = EState::Hidden; - set_percentage(-1); - m_has_print_info = false; - set_export_possible(false); - m_sp_state = state; - return true; - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_BEGAN: - m_state = EState::Hidden; - set_percentage(-1); - m_has_print_info = false; - set_export_possible(false); - m_sp_state = state; - m_current_fade_opacity = 1; - return true; - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: - if ((m_sp_state != SlicingProgressState::SP_BEGAN && m_sp_state != SlicingProgressState::SP_PROGRESS) || percent < m_percentage) - return false; - set_percentage(percent); - m_has_cancel_button = true; - m_sp_state = state; - m_current_fade_opacity = 1; - return true; - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: - set_percentage(-1); - m_has_cancel_button = false; - m_has_print_info = false; - set_export_possible(false); - m_sp_state = state; - return true; - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: - if (m_sp_state != SlicingProgressState::SP_BEGAN && m_sp_state != SlicingProgressState::SP_PROGRESS) - return false; - set_percentage(1); - m_has_cancel_button = false; - m_has_print_info = false; - // m_export_possible is important only for SP_PROGRESS state, thus we can reset it here - set_export_possible(false); - m_sp_state = state; - return true; - default: - break; - } - return false; -} -void NotificationManager::SlicingProgressNotification::set_status_text(const std::string& text) -{ - switch (m_sp_state) - { - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: - m_state = EState::Hidden; - break; - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: - { - NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text + "." }; - update(data); - m_state = EState::NotFading; - } - break; - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: - { - NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text }; - update(data); - m_state = EState::Shown; - } - break; - case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: - { - NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, _u8L("Slice ok.") }; - update(data); - m_state = EState::Shown; - } - break; - default: - break; - } -} -void NotificationManager::SlicingProgressNotification::set_print_info(const std::string& info) -{ - if (m_sp_state != SlicingProgressState::SP_COMPLETED) { - set_progress_state (SlicingProgressState::SP_COMPLETED); - } else { - m_has_print_info = true; - m_print_info = info; - } -} -void NotificationManager::SlicingProgressNotification::set_sidebar_collapsed(bool collapsed) -{ - m_sidebar_collapsed = collapsed; - if (m_sp_state == SlicingProgressState::SP_COMPLETED && collapsed) - m_state = EState::NotFading; -} - -void NotificationManager::SlicingProgressNotification::on_cancel_button() -{ - if (m_cancel_callback){ - if (!m_cancel_callback()) { - set_progress_state(SlicingProgressState::SP_NO_SLICING); - } - } -} -int NotificationManager::SlicingProgressNotification::get_duration() -{ - if (m_sp_state == SlicingProgressState::SP_CANCELLED) - return 2; - else if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed) - return 2; - else - return 0; -} -bool NotificationManager::SlicingProgressNotification::update_state(bool paused, const int64_t delta) -{ - bool ret = ProgressBarNotification::update_state(paused, delta); - // sets Estate to hidden - if (get_state() == PopNotification::EState::ClosePending || get_state() == PopNotification::EState::Finished) - set_progress_state(SlicingProgressState::SP_NO_SLICING); - return ret; -} -void NotificationManager::SlicingProgressNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) -{ - if (m_sp_state == SlicingProgressState::SP_PROGRESS /*|| (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)*/) { - ProgressBarNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - /* // enable for hypertext during slicing (correct call of export_enabled needed) - if (m_multiline) { - // two lines text, one line bar - ImGui::SetCursorPosX(m_left_indentation); - ImGui::SetCursorPosY(m_line_height / 4); - imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); - ImGui::SetCursorPosX(m_left_indentation); - ImGui::SetCursorPosY(m_line_height + m_line_height / 4); - std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0)); - imgui.text(line.c_str()); - if (m_sidebar_collapsed && m_sp_state == SlicingProgressState::SP_PROGRESS && m_export_possible) { - ImVec2 text_size = ImGui::CalcTextSize(line.c_str()); - render_hypertext(imgui, m_left_indentation + text_size.x + 4, m_line_height + m_line_height / 4, m_hypertext); - } - if (m_has_cancel_button) - render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - } - else { - //one line text, one line bar - ImGui::SetCursorPosX(m_left_indentation); - ImGui::SetCursorPosY(m_line_height / 4); - std::string line = m_text1.substr(0, m_endlines[0]); - imgui.text(line.c_str()); - if (m_sidebar_collapsed && m_sp_state == SlicingProgressState::SP_PROGRESS && m_export_possible) { - ImVec2 text_size = ImGui::CalcTextSize(line.c_str()); - render_hypertext(imgui, m_left_indentation + text_size.x + 4, m_line_height / 4, m_hypertext); - } - if (m_has_cancel_button) - render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - } - */ - } else if (m_sp_state == SlicingProgressState::SP_COMPLETED && m_sidebar_collapsed) { - // "Slicing Finished" on line 1 + hypertext, print info on line - ImVec2 win_size(win_size_x, win_size_y); - ImVec2 text1_size = ImGui::CalcTextSize(m_text1.c_str()); - float x_offset = m_left_indentation; - std::string fulltext = m_text1 + m_hypertext + m_text2; - ImVec2 text_size = ImGui::CalcTextSize(fulltext.c_str()); - float cursor_y = win_size.y / 2 - text_size.y / 2; - if (m_sidebar_collapsed && m_has_print_info) { - x_offset = 20; - cursor_y = win_size.y / 2 + win_size.y / 6 - text_size.y / 2; - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(cursor_y); - imgui.text(m_print_info.c_str()); - cursor_y = win_size.y / 2 - win_size.y / 6 - text_size.y / 2; - } - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(cursor_y); - imgui.text(m_text1.c_str()); - if (m_sidebar_collapsed) - render_hypertext(imgui, x_offset + text1_size.x + 4, cursor_y, m_hypertext); - } else { - PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - } -} -void NotificationManager::SlicingProgressNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) -{ - if (m_sp_state != SlicingProgressState::SP_PROGRESS) { - return; - } - ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); -} -void NotificationManager::SlicingProgressNotification::render_hypertext(ImGuiWrapper& imgui,const float text_x, const float text_y, const std::string text, bool more) -{ - if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed) - return; - ProgressBarNotification::render_hypertext(imgui, text_x, text_y, text, more); -} -void NotificationManager::SlicingProgressNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) -{ - ImVec2 win_size(win_size_x, win_size_y); - ImVec2 win_pos(win_pos_x, win_pos_y); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); - push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); - push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); - - - std::string button_text; - button_text = ImGui::CancelButton; - - if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y), - ImVec2(win_pos.x, win_pos.y + win_size.y - (m_minimize_b_visible ? 2 * m_line_height : 0)), - true)) - { - button_text = ImGui::CancelHoverButton; - } - ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); - ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); - ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f); - ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); - if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) - { - on_cancel_button(); - } - - //invisible large button - ImGui::SetCursorPosX(win_size.x - m_line_height * 2.35f); - ImGui::SetCursorPosY(0); - if (imgui.button(" ", m_line_height * 2.125, win_size.y - (m_minimize_b_visible ? 2 * m_line_height : 0))) - { - on_cancel_button(); - } - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); -} - -void NotificationManager::SlicingProgressNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) -{ - // Do not render close button while showing progress - cancel button is rendered instead - if (m_sp_state != SlicingProgressState::SP_PROGRESS) { - ProgressBarNotification::render_close_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - } -} //------ProgressIndicatorNotification------- void NotificationManager::ProgressIndicatorNotification::set_status_text(const char* text) { @@ -1700,6 +1433,7 @@ void NotificationManager::ProgressIndicatorNotification::init() else { m_lines_count = 2; m_endlines.push_back(m_endlines.back()); + m_multiline = false; } switch (m_progress_state) { @@ -1845,20 +1579,25 @@ void NotificationManager::push_validate_error_notification(StringObjectException { auto po = dynamic_cast(error.object); auto mo = po ? po->model_object() : dynamic_cast(error.object); - auto callback = (mo || !error.opt_key.empty()) ? [id = mo ? mo->id() : 0, opt = error.opt_key](wxEvtHandler *) { - auto & objects = wxGetApp().model().objects; - auto iter = id.id ? std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }) : objects.end(); - if (iter != objects.end()) - wxGetApp().obj_list()->select_items({{*iter, nullptr}}); - if (!opt.empty()) { - if (iter != objects.end()) - wxGetApp().params_panel()->switch_to_object(); - wxGetApp().sidebar().jump_to_option(opt, Preset::TYPE_PRINT, L""); - } else { - wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); - } - return false; - } : std::function(); + std::function callback; + if (mo || !error.opt_key.empty()) { + callback = + [id = mo ? mo->id() : 0, opt = error.opt_key](wxEvtHandler*) { + auto& objects = wxGetApp().model().objects; + auto iter = id.id ? std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }) : objects.end(); + if (iter != objects.end()) + wxGetApp().obj_list()->select_items({ {*iter, nullptr} }); + if (!opt.empty()) { + if (iter != objects.end()) + wxGetApp().params_panel()->switch_to_object(); + wxGetApp().sidebar().jump_to_option(opt, Preset::TYPE_PRINT, L""); + } + else { + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + } + return false; + }; + } auto link = (mo || !error.opt_key.empty()) ? _u8L("Jump to") : ""; if (mo) link += std::string(" [") + mo->name + "]"; if (!error.opt_key.empty()) link += std::string(" (") + error.opt_key + ")"; @@ -1873,19 +1612,22 @@ void NotificationManager::push_slicing_error_notification(const std::string &tex if (optr) ids.push_back(optr->id()); } - auto callback = !objs.empty() ? [ids](wxEvtHandler *) { - auto & objects = wxGetApp().model().objects; - std::vector ovs; - for (auto id : ids) { - auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }); - if (iter != objects.end()) { ovs.push_back({*iter, nullptr}); } - } - if (!ovs.empty()) { - wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); - wxGetApp().obj_list()->select_items(ovs); - } - return false; - } : std::function(); + std::function callback; + if (!objs.empty()) { + callback = [ids](wxEvtHandler*) { + auto& objects = wxGetApp().model().objects; + std::vector ovs; + for (auto id : ids) { + auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }); + if (iter != objects.end()) { ovs.push_back({ *iter, nullptr }); } + } + if (!ovs.empty()) { + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + wxGetApp().obj_list()->select_items(ovs); + } + return false; + }; + } auto link = callback ? _u8L("Jump to") : ""; if (!objs.empty()) { link += " ["; @@ -1905,15 +1647,18 @@ void NotificationManager::push_slicing_error_notification(const std::string &tex } void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, ModelObject const * obj, ObjectID oid, int warning_step, int warning_msg_id, NotificationLevel level/* = NotificationLevel::WarningNotificationLevel*/) { - auto callback = obj ? [id = obj->id()](wxEvtHandler *) { - auto & objects = wxGetApp().model().objects; - auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }); - if (iter != objects.end()) { - wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); - wxGetApp().obj_list()->select_items({{*iter, nullptr}}); - } - return false; - } : std::function(); + std::function callback; + if (obj) { + callback = [id = obj->id()](wxEvtHandler*) { + auto& objects = wxGetApp().model().objects; + auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }); + if (iter != objects.end()) { + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + wxGetApp().obj_list()->select_items({ {*iter, nullptr} }); + } + return false; + }; + } auto link = callback ? _u8L("Jump to") : ""; if (obj) link += std::string(" [") + obj->name + "]"; NotificationData data { NotificationType::SlicingWarning, level, 0, _u8L("Warning:") + "\n" + text, link, callback }; @@ -2139,21 +1884,22 @@ void NotificationManager::push_slicing_serious_warning_notification(const std::s for (auto optr : objs) { if (optr) ids.push_back(optr->id()); } - auto callback = !objs.empty() ? - [ids](wxEvtHandler *) { - auto & objects = wxGetApp().model().objects; - std::vector ovs; - for (auto id : ids) { - auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }); - if (iter != objects.end()) { ovs.push_back({*iter, nullptr}); } - } - if (!ovs.empty()) { - wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); - wxGetApp().obj_list()->select_items(ovs); - } - return false; - } : - std::function(); + std::function callback; + if (!objs.empty()) { + callback = [ids](wxEvtHandler*) { + auto& objects = wxGetApp().model().objects; + std::vector ovs; + for (auto id : ids) { + auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }); + if (iter != objects.end()) { ovs.push_back({ *iter, nullptr }); } + } + if (!ovs.empty()) { + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + wxGetApp().obj_list()->select_items(ovs); + } + return false; + }; + } auto link = callback ? _u8L("Jump to") : ""; if (!objs.empty()) { link += " ["; @@ -2197,6 +1943,22 @@ void NotificationManager::init_slicing_progress_notification(std::function(data, m_id_provider, m_evt_handler, cancel_callback), 0); } +void NotificationManager::update_slicing_notif_dailytips(bool need_change) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + SlicingProgressNotification* spn = dynamic_cast(notification.get()); + if (need_change) { + wxGetApp().plater()->get_dailytips()->close(); + spn->get_dailytips_panel()->retrieve_data_from_hint_database(HintDataNavigation::Random); + wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); + } + return; + } + } + // Slicing progress notification was not found - init it thru plater so correct cancel callback function is appended + wxGetApp().plater()->init_notification_manager(); +} void NotificationManager::set_slicing_progress_began() { for (std::unique_ptr & notification : m_pop_notifications) { @@ -2354,6 +2116,7 @@ int NotificationManager::progress_indicator_get_range() const void NotificationManager::push_hint_notification(bool open_next) { + return; for (std::unique_ptr& notification : m_pop_notifications) { if (notification->get_type() == NotificationType::DidYouKnowHint) { (dynamic_cast(notification.get()))->open_next(); @@ -2472,6 +2235,7 @@ void NotificationManager::render_notifications(GLCanvas3D &canvas, float overlay float bottom_up_last_y = bottom_margin * m_scale; + int i = 0; for (const auto& notification : m_pop_notifications) { if (notification->get_data().level == NotificationLevel::ErrorNotificationLevel || notification->get_data().level == NotificationLevel::SeriousWarningNotificationLevel) { notification->bbl_render_block_notification(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale); @@ -2479,13 +2243,19 @@ void NotificationManager::render_notifications(GLCanvas3D &canvas, float overlay bottom_up_last_y = notification->get_top() + GAP_WIDTH; } else { - if (notification->get_state() != PopNotification::EState::Hidden) { + if (notification->get_state() != PopNotification::EState::Hidden && notification->get_state() != PopNotification::EState::Finished) { + i++; notification->render(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale); if (notification->get_state() != PopNotification::EState::Finished) bottom_up_last_y = notification->get_top() + GAP_WIDTH; } } } + for (const auto& notification : m_pop_notifications) { + if (notification->get_data().type == NotificationType::SlicingProgress && notification->get_state() != PopNotification::EState::Hidden && notification->get_state() != PopNotification::EState::Finished) { + ;// assert(i <= 1); + } + } m_last_render = GLCanvas3D::timestamp_now(); } @@ -2952,7 +2722,10 @@ void NotificationManager::bbl_chose_sole_text_notification(NotificationType sTyp void NotificationManager::set_scale(float scale) { - if(m_scale != scale)m_scale = scale; + if(m_scale != scale) m_scale = scale; + for (auto& notif : m_pop_notifications) { + notif->set_scale(scale); + } } diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 021f0446f8d..91211a661e1 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -27,6 +27,8 @@ using ExportGcodeNotificationClickedEvent = SimpleEvent; wxDECLARE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent); using PresetUpdateAvailableClickedEvent = SimpleEvent; wxDECLARE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); +using PrinterConfigUpdateAvailableClickedEvent = SimpleEvent; +wxDECLARE_EVENT(EVT_PRINTER_CONFIG_UPDATE_AVAILABLE_CLICKED, PrinterConfigUpdateAvailableClickedEvent); using CancelFn = std::function; @@ -141,6 +143,8 @@ enum class NotificationType BBLPluginInstallHint, BBLPluginUpdateAvailable, BBLPreviewOnlyMode, + BBLPrinterConfigUpdateAvailable, + BBLUserPresetExceedLimit, }; class NotificationManager @@ -240,6 +244,7 @@ class NotificationManager // notifications with progress bar // slicing progress void init_slicing_progress_notification(std::function cancel_callback); + void update_slicing_notif_dailytips(bool need_change); void set_slicing_progress_began(); // percentage negative = canceled, <0-1) = progress, 1 = completed void set_slicing_progress_percentage(const std::string& text, float percentage); @@ -412,7 +417,8 @@ class NotificationManager // set start of notification to now. Used by delayed notifications void reset_timer() { m_notification_start = GLCanvas3D::timestamp_now(); m_state = EState::Shown; } void set_Multiline(bool Multi) { m_multiline = Multi; } - void on_change_color_mode(bool is_dark); + virtual void on_change_color_mode(bool is_dark); + void set_scale(float scale) { m_scale = scale; } protected: // Call after every size change @@ -545,6 +551,8 @@ class NotificationManager size_t m_lines_count{ 1 }; // Target for wxWidgets events sent by clicking on the hyperlink available at some notifications. wxEvtHandler* m_evt_handler; + + float m_scale = 1.0f; }; @@ -639,74 +647,6 @@ class NotificationManager long m_hover_time{ 0 }; UploadJobState m_uj_state{ UploadJobState::PB_PROGRESS }; }; - class SlicingProgressNotification : public ProgressBarNotification - { - public: - // Inner state of notification, Each state changes bahaviour of the notification - enum class SlicingProgressState - { - SP_NO_SLICING, // hidden - SP_BEGAN, // still hidden but allows to go to SP_PROGRESS state. This prevents showing progress after slicing was canceled. - SP_PROGRESS, // never fades outs, no close button, has cancel button - SP_CANCELLED, // fades after 10 seconds, simple message - SP_COMPLETED // Has export hyperlink and print info, fades after 20 sec if sidebar is shown, otherwise no fade out - }; - SlicingProgressNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, std::function callback) - : ProgressBarNotification(n, id_provider, evt_handler) - , m_cancel_callback(callback) - { - set_progress_state(SlicingProgressState::SP_NO_SLICING); - m_has_cancel_button = false; - m_render_percentage = true; - } - // sets text of notification - call after setting progress state - void set_status_text(const std::string& text); - // sets cancel button callback - void set_cancel_callback(std::function callback) { m_cancel_callback = callback; } - bool has_cancel_callback() const { return m_cancel_callback != nullptr; } - // sets SlicingProgressState, negative percent means canceled, returns true if state was set succesfully. - bool set_progress_state(float percent); - // sets SlicingProgressState, percent is used only at progress state. Returns true if state was set succesfully. - bool set_progress_state(SlicingProgressState state,float percent = 0.f); - // sets additional string of print info and puts notification into Completed state. - void set_print_info(const std::string& info); - // sets fading if in Completed state. - void set_sidebar_collapsed(bool collapsed); - // Calls inherited update_state and ensures Estate goes to hidden not closing. - bool update_state(bool paused, const int64_t delta) override; - // Switch between technology to provide correct text. - void set_fff(bool b) { m_is_fff = b; } - void set_fdm(bool b) { m_is_fff = b; } - void set_sla(bool b) { m_is_fff = !b; } - void set_export_possible(bool b) { m_export_possible = b; } - protected: - void init() override; - void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; - void render_bar(ImGuiWrapper& imgui, - const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y) override; - void render_cancel_button(ImGuiWrapper& imgui, - const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y) override; - void render_close_button(ImGuiWrapper& imgui, - const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y) override; - void render_hypertext(ImGuiWrapper& imgui, - const float text_x, const float text_y, - const std::string text, - bool more = false) override ; - void on_cancel_button(); - int get_duration() override; - // if returns false, process was already canceled - std::function m_cancel_callback; - SlicingProgressState m_sp_state { SlicingProgressState::SP_PROGRESS }; - bool m_has_print_info { false }; - std::string m_print_info; - bool m_sidebar_collapsed { false }; - bool m_is_fff { true }; - // if true, it is possible show export hyperlink in state SP_PROGRESS - bool m_export_possible { false }; - }; class ProgressIndicatorNotification : public ProgressBarNotification { @@ -804,6 +744,9 @@ class NotificationManager std::vector> m_types_and_counts; }; + // in SlicingProgressNotification.hpp + class SlicingProgressNotification; + // in HintNotification.hpp class HintNotification; @@ -915,6 +858,21 @@ class NotificationManager return true; }}, + NotificationData{NotificationType::BBLPrinterConfigUpdateAvailable, NotificationLevel::ImportantNotificationLevel, BBL_NOTICE_MAX_INTERVAL, + _u8L("New printer config available."), _u8L("Details"), + [](wxEvtHandler *evnthndlr) { + if (evnthndlr != nullptr) wxPostEvent(evnthndlr, PrinterConfigUpdateAvailableClickedEvent(EVT_PRINTER_CONFIG_UPDATE_AVAILABLE_CLICKED)); + return true; + }}, + + NotificationData{NotificationType::BBLUserPresetExceedLimit, NotificationLevel::WarningNotificationLevel, BBL_NOTICE_MAX_INTERVAL, + _u8L("The number of user presets cached in the cloud has exceeded the upper limit, newly created user presets can only be used locally."), + _u8L("Wiki"), + [](wxEvtHandler* evnthndlr) { + wxLaunchDefaultBrowser("https://wiki.bambulab.com/en/software/bambu-studio/3rd-party-printer-profile#cloud-user-presets-limit"); + return false; + }}, + NotificationData{NotificationType::UndoDesktopIntegrationFail, NotificationLevel::WarningNotificationLevel, 10, _u8L("Undo integration failed.") }, NotificationData{NotificationType::ExportOngoing, NotificationLevel::RegularNotificationLevel, 0, _u8L("Exporting.")}, @@ -929,7 +887,7 @@ class NotificationManager }; public: void set_scale(float scale = 1.0); - float m_scale = 1.0; + float m_scale = 1.0f; }; }//namespace GUI diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 6352c9253a1..a82153c1f38 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -166,8 +166,14 @@ bool ObjectDataViewModelNode::valid() assert(m_idx >= -1); return m_idx >= -1; } + #endif /* NDEBUG */ +void ObjectDataViewModelNode::sys_color_changed() +{ + m_printable_icon = m_printable == piUndef ? m_empty_bmp : create_scaled_bitmap(m_printable == piPrintable ? "check_on" : "check_off_focused"); +} + void ObjectDataViewModelNode::set_icons() { set_action_icon(false); @@ -190,6 +196,8 @@ void ObjectDataViewModelNode::set_extruder_icon() void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable) { + if (m_printable == printable) + return; m_printable = printable; m_printable_icon = m_printable == piUndef ? m_empty_bmp : create_scaled_bitmap(m_printable == piPrintable ? "check_on" : "check_off_focused"); @@ -197,9 +205,11 @@ void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable) void ObjectDataViewModelNode::set_action_icon(bool enable) { + if (m_action_enable == enable) + return; m_action_enable = enable; auto undo = enable ? "lock_normal" : "dot"; - m_action_icon_name = m_type & itPlate ? "dot" : + m_action_icon_name = m_type & itPlate ? undo : m_type & itObject ? undo : m_type & (itVolume | itLayer) ? undo : /*m_type & itInstance*/ "set_separate_obj"; m_action_icon = create_scaled_bitmap(m_action_icon_name); // FIXME: pass window ptr @@ -208,6 +218,8 @@ void ObjectDataViewModelNode::set_action_icon(bool enable) // BBS void ObjectDataViewModelNode::set_color_icon(bool enable) { + if (m_color_enable == enable) + return; m_color_enable = enable; if ((m_type & itObject) && enable) m_color_icon = create_scaled_bitmap("mmu_segmentation"); @@ -217,6 +229,8 @@ void ObjectDataViewModelNode::set_color_icon(bool enable) void ObjectDataViewModelNode::set_support_icon(bool enable) { + if (m_support_enable == enable) + return; m_support_enable = enable; if ((m_type & itObject) && enable) m_support_icon = create_scaled_bitmap("toolbar_support"); @@ -226,6 +240,8 @@ void ObjectDataViewModelNode::set_support_icon(bool enable) void ObjectDataViewModelNode::set_sinking_icon(bool enable) { + if (m_sink_enable == enable) + return; m_sink_enable = enable; if ((m_type & itObject) && enable) m_sinking_icon = create_scaled_bitmap("objlist_sinking"); @@ -459,7 +475,7 @@ wxBitmap& ObjectDataViewModel::GetWarningBitmap(const std::string& warning_icon_ wxDataViewItem ObjectDataViewModel::AddPlate(PartPlate* part_plate, wxString name, bool refresh) { int plate_idx = part_plate ? part_plate->get_index() : -1; - wxString plate_name; + wxString plate_name = name; if (name.empty()) { plate_name = _L("Plate"); plate_name += wxString::Format(" %d", plate_idx + 1); @@ -1364,6 +1380,19 @@ int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const return it - m_objects.begin(); } +int ObjectDataViewModel::GetPlateIdByItem(const wxDataViewItem& item) const +{ + if (!item.IsOk()) + return -1; + + ObjectDataViewModelNode* node = static_cast(item.GetID()); + auto it = find(m_plates.begin(), m_plates.end(), node); + if (it == m_plates.end()) + return -1; + + return it - m_plates.begin(); +} + int ObjectDataViewModel::GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const { wxASSERT(item.IsOk()); @@ -1469,6 +1498,64 @@ void ObjectDataViewModel::UpdateItemNames() ItemsChanged(changed_items); } +void ObjectDataViewModel::assembly_name() +{ + assembly_name_list.clear(); + for (int i = 0; i < m_plates.size(); ++i) { + assembly_name(m_plates[i], m_plates[i]->GetName()); + } + search_found_list = assembly_name_list; +} + +void ObjectDataViewModel::assembly_name(ObjectDataViewModelNode* item, wxString name) +{ + auto type = this->GetItemType(wxDataViewItem(item)); + if (type != itPlate) { + wxString str = name + ":" + item->GetName(); + assembly_name_list.push_back(std::make_pair(item, str)); + } + for (size_t i = 0; i < item->GetChildCount(); ++i) { + wxString str_name = name + ":" + item->GetName(); + if (type == itPlate) { + str_name = name; + } + assembly_name(item->GetNthChild(i), str_name); + } +} + +void ObjectDataViewModel::search_object(wxString search_text) +{ + if (search_text.empty()) { + search_found_list = assembly_name_list; + } + else { + search_found_list.clear(); + search_text = search_text.MakeLower(); + + for (auto pair : assembly_name_list) { + wxString need_str = pair.second.AfterFirst(':'); + need_str = need_str.MakeLower(); + size_t pos = need_str.find(search_text); + if ( pos != wxString::npos) { + size_t len = search_text.length(); + size_t before_size = pair.second.BeforeFirst(':').length(); + wxString new_search_str = "" + pair.second.Mid(before_size + pos + 1, len) + ""; + wxString new_str = pair.second.Mid(0, before_size + pos + 1) + new_search_str + pair.second.Mid(before_size + pos + len + 1, wxString::npos); + + search_found_list.push_back(std::make_pair(pair.first, new_str)); + } + } + } +} + +void ObjectDataViewModel::sys_color_changed() +{ + for (ObjectDataViewModelNode *item : m_objects) { + item->sys_color_changed(); + ItemChanged(wxDataViewItem((void *) item)); + } +} + // BBS: add use_obj_extruder void ObjectDataViewModel::UpdateVolumesExtruderBitmap(wxDataViewItem obj_item, bool use_obj_extruder) { diff --git a/src/slic3r/GUI/ObjectDataViewModel.hpp b/src/slic3r/GUI/ObjectDataViewModel.hpp index 9d0e32385c6..624b432df30 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.hpp +++ b/src/slic3r/GUI/ObjectDataViewModel.hpp @@ -302,6 +302,7 @@ class ObjectDataViewModelNode bool has_warning_icon() const { return !m_warning_icon_name.empty(); } std::string warning_icon_name() const { return m_warning_icon_name; } bool has_lock() const { return m_has_lock; } + void sys_color_changed(); private: friend class ObjectDataViewModel; @@ -329,6 +330,9 @@ class ObjectDataViewModel :public wxDataViewModel ObjectDataViewModelNode* m_plate_outside; wxDataViewCtrl* m_ctrl { nullptr }; + std::vector> assembly_name_list; + std::vector> search_found_list; + public: ObjectDataViewModel(); ~ObjectDataViewModel(); @@ -370,6 +374,7 @@ class ObjectDataViewModel :public wxDataViewModel wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); int GetIdByItem(const wxDataViewItem& item) const; + int GetPlateIdByItem(const wxDataViewItem& item) const; int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; int GetObjectIdByItem(const wxDataViewItem& item) const; int GetVolumeIdByItem(const wxDataViewItem& item) const; @@ -483,6 +488,14 @@ class ObjectDataViewModel :public wxDataViewModel // BBS void UpdateItemNames(); + void assembly_name(ObjectDataViewModelNode* item, wxString name); + void assembly_name(); + std::vector> get_assembly_name_list() { return assembly_name_list; } + void search_object(wxString search_text); + std::vector> get_found_list() { return search_found_list; } + + void sys_color_changed(); + private: wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type); wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index b78cd0b062f..086e90fc57a 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -236,26 +236,26 @@ void OptionsGroup::activate_line(Line& line) m_use_custom_ctrl_as_parent = false; - if (line.full_width && ( - line.widget != nullptr || - !line.get_extra_widgets().empty()) - ) { - // BBS: new layout - const auto h_sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(h_sizer, 1, wxEXPAND | wxALL, wxOSX ? 0 : 15); + if (line.full_width && ( + line.widget != nullptr || + !line.get_extra_widgets().empty()) + ) { + // BBS: new layout + const auto h_sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(h_sizer, 1, wxEXPAND | wxALL, wxOSX ? 0 : 15); if (line.widget != nullptr) { - // description lines - h_sizer->Add(line.widget(this->ctrl_parent()), 0, wxEXPAND | wxLEFT, titleWidth * wxGetApp().em_unit()); + // description lines + sizer->Add(line.widget(this->ctrl_parent()), 0, wxEXPAND | wxALL, wxOSX ? 0 : 15); return; } - if (!line.get_extra_widgets().empty()) { + if (!line.get_extra_widgets().empty()) { bool is_first_item = true; - for (auto extra_widget : line.get_extra_widgets()) { - h_sizer->Add(extra_widget(this->ctrl_parent()), is_first_item ? 1 : 0, wxLEFT, titleWidth * wxGetApp().em_unit()); - is_first_item = false; - } - return; - } + for (auto extra_widget : line.get_extra_widgets()) { + h_sizer->Add(extra_widget(this->ctrl_parent()), is_first_item ? 1 : 0, wxLEFT, titleWidth * wxGetApp().em_unit()); + is_first_item = false; + } + return; + } } auto option_set = line.get_options(); @@ -1028,8 +1028,19 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config ret = config.opt_int(opt_key, idx); break; case coEnum: + if (!config.has("first_layer_sequence_choice") && opt_key == "first_layer_sequence_choice") { + // reset to Auto value + ret = 0; + break; + } + if (!config.has("curr_bed_type") && opt_key == "curr_bed_type") { + // reset to global value + DynamicConfig& global_cfg = wxGetApp().preset_bundle->project_config; + ret = global_cfg.option("curr_bed_type")->getInt(); + break; + } ret = config.option(opt_key)->getInt(); - break; + break; // BBS case coEnums: ret = config.opt_int(opt_key, idx); @@ -1039,7 +1050,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config break; case coPoints: if (opt_key == "printable_area") - ret = config.option(opt_key)->values; + ret = get_thumbnails_string(config.option(opt_key)->values); else if (opt_key == "bed_exclude_area") ret = get_thumbnails_string(config.option(opt_key)->values); else if (opt_key == "thumbnails") @@ -1154,7 +1165,7 @@ boost::any ConfigOptionsGroup::get_config_value2(const DynamicPrintConfig& confi break; case coPoints: if (opt_key == "printable_area") - ret = config.option(opt_key)->values; + ret = get_thumbnails_string(config.option(opt_key)->values); else if (opt_key == "bed_exclude_area") ret = get_thumbnails_string(config.option(opt_key)->values); else if (opt_key == "thumbnails") diff --git a/src/slic3r/GUI/ParamsDialog.cpp b/src/slic3r/GUI/ParamsDialog.cpp index db421a2d0ee..b4440a87593 100644 --- a/src/slic3r/GUI/ParamsDialog.cpp +++ b/src/slic3r/GUI/ParamsDialog.cpp @@ -52,6 +52,12 @@ ParamsDialog::ParamsDialog(wxWindow * parent) } #else Hide(); + if (!m_editing_filament_id.empty()) { + FilamentInfomation *filament_info = new FilamentInfomation(); + filament_info->filament_id = m_editing_filament_id; + wxQueueEvent(wxGetApp().plater(), new SimpleEvent(EVT_MODIFY_FILAMENT, filament_info)); + m_editing_filament_id.clear(); + } #endif wxGetApp().sidebar().finish_param_edit(); }); @@ -59,13 +65,16 @@ ParamsDialog::ParamsDialog(wxWindow * parent) //wxGetApp().UpdateDlgDarkUI(this); } -void ParamsDialog::Popup() +void ParamsDialog::Popup(bool just_edit) { wxGetApp().UpdateDlgDarkUI(this); #ifdef __WIN32__ Reparent(wxGetApp().mainframe); #endif Center(); + if (m_panel && m_panel->get_current_tab()) { + dynamic_cast(m_panel->get_current_tab())->set_just_edit(just_edit); + } Show(); } diff --git a/src/slic3r/GUI/ParamsDialog.hpp b/src/slic3r/GUI/ParamsDialog.hpp index 34ef20fc02e..df5388b1980 100644 --- a/src/slic3r/GUI/ParamsDialog.hpp +++ b/src/slic3r/GUI/ParamsDialog.hpp @@ -11,6 +11,15 @@ namespace Slic3r { namespace GUI { +wxDECLARE_EVENT(EVT_MODIFY_FILAMENT, SimpleEvent); + +class FilamentInfomation : public wxObject +{ +public: + std::string filament_id; + std::string filament_name; +}; + class ParamsPanel; class ParamsDialog : public DPIDialog @@ -20,12 +29,15 @@ class ParamsDialog : public DPIDialog ParamsPanel * panel() { return m_panel; } - void Popup(); + void Popup(bool just_edit = false); + + void set_editing_filament_id(std::string id) { m_editing_filament_id = id; } protected: void on_dpi_changed(const wxRect& suggested_rect) override; private: + std::string m_editing_filament_id; ParamsPanel * m_panel; wxWindowDisabler *m_winDisabler = nullptr; }; diff --git a/src/slic3r/GUI/ParamsPanel.cpp b/src/slic3r/GUI/ParamsPanel.cpp index 725c5fde06d..44b28636b9c 100644 --- a/src/slic3r/GUI/ParamsPanel.cpp +++ b/src/slic3r/GUI/ParamsPanel.cpp @@ -392,6 +392,10 @@ void ParamsPanel::create_layout() m_left_sizer->Add( m_tab_print, 0, wxEXPAND ); } + if (m_tab_print_plate) { + m_left_sizer->Add(m_tab_print_plate, 0, wxEXPAND); + } + if (m_tab_print_object) { m_left_sizer->Add( m_tab_print_object, 0, wxEXPAND ); } @@ -482,6 +486,7 @@ void ParamsPanel::refresh_tabs() } } if (m_top_panel) { + m_tab_print_plate = wxGetApp().get_plate_tab(); m_tab_print_object = wxGetApp().get_model_tab(); m_tab_print_part = wxGetApp().get_model_tab(true); m_tab_print_layer = wxGetApp().get_layer_tab(); @@ -558,6 +563,8 @@ void ParamsPanel::set_active_tab(wxPanel* tab) cur_tab = (Tab*)m_tab_print_layer; } else if (m_tab_print_object && ((TabPrintModel*) m_tab_print_object)->has_model_config()) { cur_tab = (Tab*) m_tab_print_object; + } else if (m_tab_print_plate && ((TabPrintPlate*)m_tab_print_plate)->has_model_config()) { + cur_tab = (Tab*)m_tab_print_plate; } Show(cur_tab != nullptr); wxGetApp().sidebar().show_object_list(m_mode_region->GetValue()); @@ -578,6 +585,7 @@ void ParamsPanel::set_active_tab(wxPanel* tab) {m_tab_print_object, m_staticline_print_object}, {m_tab_print_part, m_staticline_print_part}, {m_tab_print_layer, nullptr}, + {m_tab_print_plate, nullptr}, {m_tab_filament, m_staticline_filament}, {m_tab_printer, m_staticline_printer}})) { if (!t.first) continue; @@ -650,7 +658,7 @@ void ParamsPanel::msw_rescale() ((SwitchButton* )m_mode_region)->Rescale(); if (m_mode_view) ((SwitchButton* )m_mode_view)->Rescale(); - for (auto tab : {m_tab_print, m_tab_print_object, m_tab_print_part, m_tab_print_layer, m_tab_filament, m_tab_printer}) { + for (auto tab : {m_tab_print, m_tab_print_plate, m_tab_print_object, m_tab_print_part, m_tab_print_layer, m_tab_filament, m_tab_printer}) { if (tab) dynamic_cast(tab)->msw_rescale(); } //((Button*)m_export_to_file)->Rescale(); diff --git a/src/slic3r/GUI/ParamsPanel.hpp b/src/slic3r/GUI/ParamsPanel.hpp index 7e752aa335d..1a20ec7d206 100644 --- a/src/slic3r/GUI/ParamsPanel.hpp +++ b/src/slic3r/GUI/ParamsPanel.hpp @@ -90,6 +90,7 @@ class ParamsPanel : public wxPanel wxStaticLine* m_staticline_print { nullptr }; //wxBoxSizer* m_print_sizer { nullptr }; wxPanel* m_tab_print { nullptr }; + wxPanel* m_tab_print_plate { nullptr }; wxPanel* m_tab_print_object { nullptr }; wxStaticLine* m_staticline_print_object { nullptr }; wxPanel* m_tab_print_part { nullptr }; diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index edbb541a748..306939bba89 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -57,7 +57,15 @@ static const int PARTPLATE_ICON_GAP_Y = 5; static const int PARTPLATE_TEXT_OFFSET_X1 = 3; static const int PARTPLATE_TEXT_OFFSET_X2 = 1; static const int PARTPLATE_TEXT_OFFSET_Y = 1; +static const int PARTPLATE_PLATENAME_OFFSET_Y = 10; +const float WIPE_TOWER_DEFAULT_X_POS = 165.; +const float WIPE_TOWER_DEFAULT_Y_POS = 250.; // Max y + +const float I3_WIPE_TOWER_DEFAULT_X_POS = 0.; +const float I3_WIPE_TOWER_DEFAULT_Y_POS = 250.; // Max y + +std::array PlateTextureForeground = {0x0, 0xae, 0x42, 0xff}; namespace Slic3r { namespace GUI { @@ -270,16 +278,53 @@ PrintSequence PartPlate::get_print_seq() const return PrintSequence::ByDefault; } -PrintSequence PartPlate::get_real_print_seq() const +PrintSequence PartPlate::get_real_print_seq(bool* plate_same_as_global) const { + PrintSequence global_print_seq = PrintSequence::ByDefault; + auto curr_preset_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + if (curr_preset_config.has("print_sequence")) + global_print_seq = curr_preset_config.option>("print_sequence")->value; + PrintSequence curr_plate_seq = get_print_seq(); if (curr_plate_seq == PrintSequence::ByDefault) { - auto curr_preset_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; - if (curr_preset_config.has("print_sequence")) curr_plate_seq = curr_preset_config.option>("print_sequence")->value; + curr_plate_seq = global_print_seq; } + + if(plate_same_as_global) + *plate_same_as_global = (curr_plate_seq == global_print_seq); + return curr_plate_seq; } +bool PartPlate::has_spiral_mode_config() const +{ + std::string key = "spiral_mode"; + return m_config.has(key); +} + +bool PartPlate::get_spiral_vase_mode() const +{ + std::string key = "spiral_mode"; + if (m_config.has(key)) { + return m_config.opt_bool(key); + } + else { + DynamicPrintConfig* global_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config; + if (global_config->has(key)) + return global_config->opt_bool(key); + } + return false; +} + +void PartPlate::set_spiral_vase_mode(bool spiral_mode, bool as_global) +{ + std::string key = "spiral_mode"; + if (as_global) + m_config.erase(key); + else + m_config.set_key_value(key, new ConfigOptionBool(spiral_mode)); +} + bool PartPlate::valid_instance(int obj_id, int instance_id) { if ((obj_id >= 0) && (obj_id < m_model->objects.size())) @@ -1483,7 +1528,7 @@ std::vector PartPlate::get_used_extruders() return used_extruders; } -Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double d, int plate_extruder_size) const +Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double d, int plate_extruder_size, bool use_global_objects) const { Vec3d wipe_tower_size; @@ -1506,7 +1551,7 @@ Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, con return wipe_tower_size; for (int obj_idx = 0; obj_idx < m_model->objects.size(); obj_idx++) { - if (!contain_instance_totally(obj_idx, 0)) + if (!use_global_objects && !contain_instance_totally(obj_idx, 0)) continue; BoundingBoxf3 bbox = m_model->objects[obj_idx]->bounding_box(); @@ -1557,6 +1602,46 @@ Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, con return wipe_tower_size; } +arrangement::ArrangePolygon PartPlate::estimate_wipe_tower_polygon(const DynamicPrintConfig& config, int plate_index, int plate_extruder_size, bool use_global_objects) const +{ + float x = dynamic_cast(config.option("wipe_tower_x"))->get_at(plate_index); + float y = dynamic_cast(config.option("wipe_tower_y"))->get_at(plate_index); + float w = dynamic_cast(config.option("prime_tower_width"))->value; + //float a = dynamic_cast(config.option("wipe_tower_rotation_angle"))->value; + float v = dynamic_cast(config.option("prime_volume"))->value; + Vec3d wipe_tower_size = estimate_wipe_tower_size(config, w, v, plate_extruder_size, use_global_objects); + int plate_width=m_width, plate_depth=m_depth; + float depth = wipe_tower_size(1); + float margin = WIPE_TOWER_MARGIN, wp_brim_width = 0.f; + const ConfigOption* wipe_tower_brim_width_opt = config.option("prime_tower_brim_width"); + if (wipe_tower_brim_width_opt) { + wp_brim_width = wipe_tower_brim_width_opt->getFloat(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: wp_brim_width %1%") % wp_brim_width; + } + + x = std::clamp(x, margin, (float)plate_width - w - margin - wp_brim_width); + y = std::clamp(y, margin, (float)plate_depth - depth - margin - wp_brim_width); + + arrangement::ArrangePolygon wipe_tower_ap; + Polygon ap({ + {scaled(x - wp_brim_width), scaled(y - wp_brim_width)}, + {scaled(x + w + wp_brim_width), scaled(y - wp_brim_width)}, + {scaled(x + w + wp_brim_width), scaled(y + depth + wp_brim_width)}, + {scaled(x - wp_brim_width), scaled(y + depth + wp_brim_width)} + }); + wipe_tower_ap.bed_idx = plate_index; + wipe_tower_ap.setter = NULL; // do not move wipe tower + + wipe_tower_ap.poly.contour = std::move(ap); + wipe_tower_ap.translation = { scaled(0.f), scaled(0.f) }; + //wipe_tower_ap.rotation = a; + wipe_tower_ap.name = "WipeTower"; + wipe_tower_ap.is_virt_object = true; + wipe_tower_ap.is_wipe_tower = true; + + return wipe_tower_ap; +} + bool PartPlate::operator<(PartPlate& plate) const { int index = plate.get_index(); @@ -1587,7 +1672,7 @@ void PartPlate::clear(bool clear_sliced_result) /* size and position related functions*/ //set position and size -void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, int height, bool with_instance_move) +void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, int height, bool with_instance_move, bool do_clear) { bool size_changed = false; //size changed means the machine changed bool pos_changed = false; @@ -1605,7 +1690,7 @@ void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, int height return; } - if (with_instance_move) + if (with_instance_move && m_model) { for (std::set>::iterator it = obj_to_instance_set.begin(); it != obj_to_instance_set.end(); ++it) { int obj_id = it->first; @@ -1641,7 +1726,7 @@ void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, int height object->invalidate_bounding_box(); } } - else + else if (do_clear) { clear(); } @@ -2854,6 +2939,11 @@ void PartPlateList::init() m_plate_cols = 1; m_current_plate = 0; + if (m_plater) { + // In GUI mode + set_default_wipe_tower_pos_for_plate(0); + } + select_plate(0); unprintable_plate.set_index(1); @@ -2864,14 +2954,8 @@ void PartPlateList::init() Vec3d PartPlateList::compute_origin(int i, int cols) { Vec3d origin; - int row, col; - - row = i / cols; - col = i % cols; - - origin(0) = col * (m_plate_width * (1. + LOGICAL_PART_PLATE_GAP)); - origin(1) = -row * (m_plate_depth * (1. + LOGICAL_PART_PLATE_GAP)); - origin(2) = 0; + Vec2d pos = compute_shape_position(i, cols); + origin = Vec3d(pos.x(), pos.y(), 0); return origin; } @@ -3097,6 +3181,26 @@ void PartPlateList::release_icon_textures() } } +void PartPlateList::set_default_wipe_tower_pos_for_plate(int plate_idx) +{ + DynamicConfig & proj_cfg = wxGetApp().preset_bundle->project_config; + ConfigOptionFloats *wipe_tower_x = proj_cfg.opt("wipe_tower_x"); + ConfigOptionFloats *wipe_tower_y = proj_cfg.opt("wipe_tower_y"); + wipe_tower_x->values.resize(m_plate_list.size(), wipe_tower_x->values.front()); + wipe_tower_y->values.resize(m_plate_list.size(), wipe_tower_y->values.front()); + + auto printer_structure_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option>("printer_structure"); + // set the default position, the same with print config(left top) + ConfigOptionFloat wt_x_opt(WIPE_TOWER_DEFAULT_X_POS); + ConfigOptionFloat wt_y_opt(WIPE_TOWER_DEFAULT_Y_POS); + if (printer_structure_opt && printer_structure_opt->value == PrinterStructure::psI3) { + wt_x_opt = ConfigOptionFloat(I3_WIPE_TOWER_DEFAULT_X_POS); + wt_y_opt = ConfigOptionFloat(I3_WIPE_TOWER_DEFAULT_Y_POS); + } + dynamic_cast(proj_cfg.option("wipe_tower_x"))->set_at(&wt_x_opt, plate_idx, 0); + dynamic_cast(proj_cfg.option("wipe_tower_y"))->set_at(&wt_y_opt, plate_idx, 0); +} + //this may be happened after machine changed void PartPlateList::reset_size(int width, int depth, int height, bool reload_objects, bool update_shapes) { @@ -3109,7 +3213,7 @@ void PartPlateList::reset_size(int width, int depth, int height, bool reload_obj m_plate_width = width; m_plate_depth = depth; m_plate_height = height; - update_all_plates_pos_and_size(false, false); + update_all_plates_pos_and_size(false, false, true); if (update_shapes) { set_shapes(m_shape, m_exclude_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); } @@ -3261,11 +3365,7 @@ int PartPlateList::create_plate(bool adjust_position) // update wipe tower config if (m_plater) { // In GUI mode - DynamicConfig& proj_cfg = wxGetApp().preset_bundle->project_config; - ConfigOptionFloats* wipe_tower_x = proj_cfg.opt("wipe_tower_x"); - ConfigOptionFloats* wipe_tower_y = proj_cfg.opt("wipe_tower_y"); - wipe_tower_x->values.resize(m_plate_list.size(), wipe_tower_x->values.front()); - wipe_tower_y->values.resize(m_plate_list.size(), wipe_tower_y->values.front()); + set_default_wipe_tower_pos_for_plate(new_index); } unprintable_plate.set_index(new_index+1); @@ -3487,6 +3587,20 @@ std::vector PartPlateList::get_nonempty_plates_slic return nonempty_plates_slice_result; } +std::set PartPlateList::get_extruders(bool conside_custom_gcode) const +{ + int plate_count = get_plate_count(); + std::set extruder_ids; + + for (size_t i = 0; i < plate_count; i++) { + auto plate_extruders = m_plate_list[i]->get_extruders(conside_custom_gcode); + extruder_ids.insert(plate_extruders.begin(), plate_extruders.end()); + } + + return extruder_ids; +} + + //select plate int PartPlateList::select_plate(int index) { @@ -3599,7 +3713,7 @@ void PartPlateList::update_plate_cols() return; } -void PartPlateList::update_all_plates_pos_and_size(bool adjust_position, bool with_unprintable_move) +void PartPlateList::update_all_plates_pos_and_size(bool adjust_position, bool with_unprintable_move, bool switch_plate_type, bool do_clear) { Vec3d origin1, origin2; for (unsigned int i = 0; i < (unsigned int)m_plate_list.size(); ++i) @@ -3609,7 +3723,12 @@ void PartPlateList::update_all_plates_pos_and_size(bool adjust_position, bool wi //compute origin1 for PartPlate origin1 = compute_origin(i, m_plate_cols); - plate->set_pos_and_size(origin1, m_plate_width, m_plate_depth, m_plate_height, adjust_position); + plate->set_pos_and_size(origin1, m_plate_width, m_plate_depth, m_plate_height, adjust_position, do_clear); + + // set default wipe pos when switch plate + if (switch_plate_type && m_plater && plate->get_used_extruders().size() <= 0) { + set_default_wipe_tower_pos_for_plate(i); + } } origin2 = compute_origin_for_unprintable(); @@ -4133,7 +4252,7 @@ bool PartPlateList::preprocess_arrange_polygon_other_locked(int obj_index, int i arrange_polygon.col = i % m_plate_cols; arrange_polygon.translation(X) -= scaled(plate_stride_x() * arrange_polygon.col); arrange_polygon.translation(Y) += scaled(plate_stride_y() * arrange_polygon.row); - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": obj_id %1% instance_id %2% in plate %3%, locked %4%, row %5%, col %6%\n") % obj_index % instance_index % i % locked % arrange_polygon.row % arrange_polygon.col; + //BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": obj_id %1% instance_id %2% in plate %3%, locked %4%, row %5%, col %6%\n") % obj_index % instance_index % i % locked % arrange_polygon.row % arrange_polygon.col; return locked; } } @@ -4323,11 +4442,9 @@ void PartPlateList::postprocess_arrange_polygon(arrangement::ArrangePolygon& arr { // outarea for large object arrange_polygon.bed_idx = m_plate_list.size(); - BoundingBox apbox = get_extents(arrange_polygon.poly); + BoundingBox apbox = get_extents(arrange_polygon.transformed_poly()); // the item may have been rotated auto apbox_size = apbox.size(); - //arrange_polygon.translation(X) = scaled(0.5 * plate_stride_x()); - //arrange_polygon.translation(Y) = scaled(0.5 * plate_stride_y()); arrange_polygon.translation(X) = 0.5 * apbox_size[0]; arrange_polygon.translation(Y) = scaled(static_cast(m_plate_depth)) - 0.5 * apbox_size[1]; } @@ -4475,19 +4592,23 @@ bool PartPlateList::set_shapes(const Pointfs& shape, const Pointfs& exclude_area is_load_bedtype_textures = false;//reload textures calc_bounding_boxes(); - auto check_texture = [](const std::string& texture) { - boost::system::error_code ec; // so the exists call does not throw (e.g. after a permission problem) - return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(texture, ec); - }; - if (! texture_filename.empty() && ! check_texture(texture_filename)) { - BOOST_LOG_TRIVIAL(error) << "Unable to load bed texture: " << texture_filename; - } - else - m_logo_texture_filename = texture_filename; + update_logo_texture_filename(texture_filename); return true; } +void PartPlateList::update_logo_texture_filename(const std::string &texture_filename) +{ + auto check_texture = [](const std::string &texture) { + boost::system::error_code ec; // so the exists call does not throw (e.g. after a permission problem) + return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(texture, ec); + }; + if (!texture_filename.empty() && !check_texture(texture_filename)) { + BOOST_LOG_TRIVIAL(error) << "Unable to load bed texture: " << texture_filename; + } else + m_logo_texture_filename = texture_filename; +} + /*slice related functions*/ //update current slice context into backgroud slicing process void PartPlateList::update_slice_context_to_current_plate(BackgroundSlicingProcess& process) @@ -4574,6 +4695,30 @@ bool PartPlateList::is_all_slice_results_ready_for_print() const return res; } +//check whether all plates' slice result valid for export to file +bool PartPlateList::is_all_slice_result_ready_for_export() const +{ + bool res = false; + + for (unsigned int i = 0; i < (unsigned int) m_plate_list.size(); ++i) { + if (!m_plate_list[i]->empty()) { + if (m_plate_list[i]->is_all_instances_unprintable()) { + continue; + } + if (!m_plate_list[i]->is_slice_result_ready_for_print()) { + return false; + } + } + if (m_plate_list[i]->is_slice_result_ready_for_print()) { + if (!m_plate_list[i]->has_printable_instances()) { + return false; + } + res = true; + } + } + + return res; +} //check whether all plates ready for slice bool PartPlateList::is_all_plates_ready_for_slice() const @@ -4619,6 +4764,7 @@ int PartPlateList::rebuild_plates_after_deserialize(std::vector& previous_ partplate->printer_technology = this->printer_technology; } update_plate_cols(); + update_all_plates_pos_and_size(false, false, false, false); set_shapes(m_shape, m_exclude_areas, m_logo_texture_filename, m_height_to_lid, m_height_to_rod); for (unsigned int i = 0; i < (unsigned int)m_plate_list.size(); ++i) { diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index ced713a1f0d..4bf62680fe9 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -48,6 +48,15 @@ inline int compute_colum_count(int count) return cols; } + +extern const float WIPE_TOWER_DEFAULT_X_POS; +extern const float WIPE_TOWER_DEFAULT_Y_POS; // Max y + +extern const float I3_WIPE_TOWER_DEFAULT_X_POS; +extern const float I3_WIPE_TOWER_DEFAULT_Y_POS; // Max y + + + namespace Slic3r { class Model; @@ -224,8 +233,11 @@ class PartPlate : public ObjectBase // Get the real effective print sequence of current plate. // If curr_plate's print_seq is ByDefault, use the global sequence // @return PrintSequence::{ByLayer,ByObject} - PrintSequence get_real_print_seq() const; + PrintSequence get_real_print_seq(bool* plate_same_as_global=nullptr) const; + bool has_spiral_mode_config() const; + bool get_spiral_vase_mode() const; + void set_spiral_vase_mode(bool spiral_mode, bool as_global); //static const int plate_x_offset = 20; //mm //static const double plate_x_gap = 0.2; @@ -272,14 +284,16 @@ class PartPlate : public ObjectBase Vec3d get_center_origin(); /* size and position related functions*/ //set position and size - void set_pos_and_size(Vec3d& origin, int width, int depth, int height, bool with_instance_move); + void set_pos_and_size(Vec3d& origin, int width, int depth, int height, bool with_instance_move, bool do_clear = true); // BBS + Vec2d get_size() const { return Vec2d(m_width, m_depth); } ModelObjectPtrs get_objects() { return m_model->objects; } ModelInstance* get_instance(int obj_id, int instance_id); Vec3d get_origin() { return m_origin; } - Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double d, int plate_extruder_size = 0) const; + Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double d, int plate_extruder_size = 0, bool use_global_objects = false) const; + arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig & config, int plate_index, int plate_extruder_size = 0, bool use_global_objects = false) const; std::vector get_extruders(bool conside_custom_gcode = false) const; std::vector get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const; std::vector get_extruders_without_support(bool conside_custom_gcode = false) const; @@ -403,6 +417,12 @@ class PartPlate : public ObjectBase return result; } + // check whether plate's slice result valid for export to file + bool is_slice_result_ready_for_export() + { + return is_slice_result_ready_for_print() && has_printable_instances(); + } + //invalid sliced result void update_slice_result_valid_state(bool valid = false); @@ -544,6 +564,8 @@ class PartPlateList : public ObjectBase void generate_icon_textures(); void release_icon_textures(); + void set_default_wipe_tower_pos_for_plate(int plate_idx); + friend class cereal::access; friend class UndoRedo::StackImpl; friend class PartPlate; @@ -664,10 +686,13 @@ class PartPlateList : public ObjectBase std::vector get_nonempty_plates_slice_results(); + //compute the origin for printable plate with index i Vec3d get_current_plate_origin() { return compute_origin(m_current_plate, m_plate_cols); } Vec2d get_current_shape_position() { return compute_shape_position(m_current_plate, m_plate_cols); } Pointfs get_exclude_area() { return m_exclude_areas; } + std::set get_extruders(bool conside_custom_gcode = false) const; + //select plate int select_plate(int index); @@ -677,7 +702,7 @@ class PartPlateList : public ObjectBase //update the plate cols due to plate count change void update_plate_cols(); - void update_all_plates_pos_and_size(bool adjust_position = true, bool with_unprintable_move = true); + void update_all_plates_pos_and_size(bool adjust_position = true, bool with_unprintable_move = true, bool switch_plate_type = false, bool do_clear = true); //get the plate cols int get_plate_cols() { return m_plate_cols; } @@ -757,6 +782,8 @@ class PartPlateList : public ObjectBase bool intersects(const BoundingBoxf3 &bb); bool contains(const BoundingBoxf3 &bb); + const std::string &get_logo_texture_filename() { return m_logo_texture_filename; } + void update_logo_texture_filename(const std::string &texture_filename); /*slice related functions*/ //update current slice context into backgroud slicing process void update_slice_context_to_current_plate(BackgroundSlicingProcess& process); @@ -775,6 +802,7 @@ class PartPlateList : public ObjectBase bool is_all_slice_results_valid() const; bool is_all_slice_results_ready_for_print() const; bool is_all_plates_ready_for_slice() const; + bool is_all_slice_result_ready_for_export() const; void print() const; //get the all the sliced result diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.hpp b/src/slic3r/GUI/PhysicalPrinterDialog.hpp index ee88e34f7ca..93cd3f4aa90 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.hpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.hpp @@ -9,7 +9,6 @@ #include "GUI_Utils.hpp" #include "Widgets/RoundedRectangle.hpp" -class wxString; class wxTextCtrl; class wxStaticText; class ScalableButton; diff --git a/src/slic3r/GUI/PlateSettingsDialog.cpp b/src/slic3r/GUI/PlateSettingsDialog.cpp index 65d20fe5fb9..d45c93091d4 100644 --- a/src/slic3r/GUI/PlateSettingsDialog.cpp +++ b/src/slic3r/GUI/PlateSettingsDialog.cpp @@ -5,8 +5,8 @@ namespace Slic3r { namespace GUI { wxDEFINE_EVENT(EVT_SET_BED_TYPE_CONFIRM, wxCommandEvent); -PlateSettingsDialog::PlateSettingsDialog(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) -:DPIDialog(parent, id, title, pos, size, style) +PlateSettingsDialog::PlateSettingsDialog(wxWindow* parent, const wxString& title, bool only_first_layer_seq, const wxPoint& pos, const wxSize& size, long style) +:DPIDialog(parent, wxID_ANY, title, pos, size, style) { std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); @@ -140,6 +140,18 @@ PlateSettingsDialog::PlateSettingsDialog(wxWindow* parent, wxWindowID id, const CenterOnParent(); wxGetApp().UpdateDlgDarkUI(this); + + if (only_first_layer_seq) { + for (auto item : top_sizer->GetChildren()) { + if (item->GetWindow()) + item->GetWindow()->Show(false); + } + first_layer_txt->Show(); + m_first_layer_print_seq_choice->Show(); + m_drag_canvas->Show(); + Layout(); + Fit(); + } } PlateSettingsDialog::~PlateSettingsDialog() @@ -177,6 +189,21 @@ void PlateSettingsDialog::sync_first_layer_print_seq(int selection, const std::v } } +void PlateSettingsDialog::sync_spiral_mode(bool spiral_mode, bool as_global) +{ + if (m_spiral_mode_choice) { + if (as_global) { + m_spiral_mode_choice->SetSelection(0); + } + else { + if (spiral_mode) + m_spiral_mode_choice->SetSelection(1); + else + m_spiral_mode_choice->SetSelection(2); + } + } +} + wxString PlateSettingsDialog::to_bed_type_name(BedType bed_type) { switch (bed_type) { case btDefault: @@ -241,6 +268,12 @@ PlateNameEditDialog::PlateNameEditDialog(wxWindow *parent, wxWindowID id, const auto plate_name_txt = new wxStaticText(this, wxID_ANY, _L("Plate name")); plate_name_txt->SetFont(Label::Body_14); m_ti_plate_name = new TextInput(this, wxString::FromDouble(0.0), "", "", wxDefaultPosition, wxSize(FromDIP(240), -1), wxTE_PROCESS_ENTER); + m_ti_plate_name->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent &e) { + if (this->IsModal()) + EndModal(wxID_YES); + else + this->Close(); + }); top_sizer->Add(plate_name_txt, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); top_sizer->Add(m_ti_plate_name, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); m_ti_plate_name->GetTextCtrl()->SetMaxLength(250); @@ -263,9 +296,6 @@ PlateNameEditDialog::PlateNameEditDialog(wxWindow *parent, wxWindowID id, const m_button_ok->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); m_button_ok->SetCornerRadius(FromDIP(12)); m_button_ok->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { - wxCommandEvent evt(EVT_SET_BED_TYPE_CONFIRM, GetId()); - e.SetEventObject(this); - GetEventHandler()->ProcessEvent(evt); if (this->IsModal()) EndModal(wxID_YES); else @@ -313,6 +343,10 @@ void PlateNameEditDialog::on_dpi_changed(const wxRect &suggested_rect) wxString PlateNameEditDialog::get_plate_name() const { return m_ti_plate_name->GetTextCtrl()->GetValue(); } -void PlateNameEditDialog::set_plate_name(const wxString &name) { m_ti_plate_name->GetTextCtrl()->SetValue(name); } +void PlateNameEditDialog::set_plate_name(const wxString &name) { + m_ti_plate_name->GetTextCtrl()->SetValue(name); + m_ti_plate_name->GetTextCtrl()->SetFocus(); + m_ti_plate_name->GetTextCtrl()->SetInsertionPointEnd(); +} }} // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/PlateSettingsDialog.hpp b/src/slic3r/GUI/PlateSettingsDialog.hpp index d0a6b46dfd4..debad2a7f6f 100644 --- a/src/slic3r/GUI/PlateSettingsDialog.hpp +++ b/src/slic3r/GUI/PlateSettingsDialog.hpp @@ -22,8 +22,8 @@ class PlateSettingsDialog : public DPIDialog }; PlateSettingsDialog( wxWindow* parent, - wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, + bool only_first_layer_seq = false, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxCLOSE_BOX | wxCAPTION @@ -33,6 +33,7 @@ class PlateSettingsDialog : public DPIDialog void sync_bed_type(BedType type); void sync_print_seq(int print_seq = 0); void sync_first_layer_print_seq(int selection, const std::vector& seq = std::vector()); + void sync_spiral_mode(bool spiral_mode, bool as_global); wxString to_bed_type_name(BedType bed_type); wxString to_print_sequence_name(PrintSequence print_seq); void on_dpi_changed(const wxRect& suggested_rect) override; @@ -63,11 +64,23 @@ class PlateSettingsDialog : public DPIDialog std::vector get_first_layer_print_seq(); + int get_spiral_mode_choice() { + int choice = 0; + if (m_spiral_mode_choice != nullptr) + choice = m_spiral_mode_choice->GetSelection(); + return choice; + }; + + bool get_spiral_mode(){ + return false; + } + protected: DragCanvas* m_drag_canvas; ComboBox* m_first_layer_print_seq_choice { nullptr }; ComboBox* m_print_seq_choice { nullptr }; ComboBox* m_bed_type_choice { nullptr }; + ComboBox* m_spiral_mode_choice { nullptr }; Button* m_button_ok; Button* m_button_cancel; TextInput *m_ti_plate_name; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index a24eebaf07f..f3e05a93c24 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -158,6 +158,8 @@ #include "PhysicalPrinterDialog.hpp" #include "PrintHostDialogs.hpp" #include "PlateSettingsDialog.hpp" +#include "DailyTips.hpp" +#include "CreatePresetsDialog.hpp" using boost::optional; namespace fs = boost::filesystem; @@ -180,6 +182,7 @@ wxDEFINE_EVENT(EVT_EXPORT_FINISHED, wxCommandEvent); wxDEFINE_EVENT(EVT_IMPORT_MODEL_ID, wxCommandEvent); wxDEFINE_EVENT(EVT_DOWNLOAD_PROJECT, wxCommandEvent); wxDEFINE_EVENT(EVT_PUBLISH, wxCommandEvent); +wxDEFINE_EVENT(EVT_OPEN_PLATESETTINGSDIALOG, wxCommandEvent); // BBS: backup & restore wxDEFINE_EVENT(EVT_RESTORE_PROJECT, wxCommandEvent); wxDEFINE_EVENT(EVT_PRINT_FINISHED, wxCommandEvent); @@ -198,6 +201,8 @@ wxDEFINE_EVENT(EVT_GLCANVAS_COLOR_MODE_CHANGED, SimpleEvent); //BBS: print wxDEFINE_EVENT(EVT_PRINT_FROM_SDCARD_VIEW, SimpleEvent); +wxDEFINE_EVENT(EVT_CREATE_FILAMENT, SimpleEvent); +wxDEFINE_EVENT(EVT_MODIFY_FILAMENT, SimpleEvent); bool Plater::has_illegal_filename_characters(const wxString& wxs_name) { @@ -347,6 +352,8 @@ struct Sidebar::priv wxPanel* m_panel_project_title; ScalableButton* m_filament_icon = nullptr; Button * m_flushing_volume_btn = nullptr; + wxSearchCtrl* m_search_bar = nullptr; + Search::SearchObjectDialog* dia = nullptr; // BBS printer config StaticBox* m_panel_printer_title = nullptr; @@ -373,6 +380,9 @@ struct Sidebar::priv ~priv(); void show_preset_comboboxes(); + void on_search_update(); + void jump_to_object(ObjectDataViewModelNode* item); + void can_search(); #ifdef _WIN32 wxString btn_reslice_tip; @@ -413,6 +423,27 @@ void Sidebar::priv::show_preset_comboboxes() scrolled->Refresh(); } +void Sidebar::priv::on_search_update() +{ + m_object_list->assembly_plate_object_name(); + + wxString search_text = m_search_bar->GetValue(); + m_object_list->GetModel()->search_object(search_text); + dia->update_list(); +} + +void Sidebar::priv::jump_to_object(ObjectDataViewModelNode* item) +{ + m_object_list->selected_object(item); +} + +void Sidebar::priv::can_search() +{ + if (m_search_bar->IsShown()) { + m_search_bar->SetFocus(); + } +} + #ifdef _WIN32 using wxRichToolTipPopup = wxCustomBackgroundWindow; static wxRichToolTipPopup* get_rtt_popup(wxButton* btn) @@ -793,6 +824,7 @@ Sidebar::Sidebar(Plater *parent) wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent)); } })); + bSizer39->Add(p->m_flushing_volume_btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(5)); bSizer39->Hide(p->m_flushing_volume_btn); bSizer39->Add(FromDIP(10), 0, 0, 0, 0 ); @@ -811,6 +843,7 @@ Sidebar::Sidebar(Plater *parent) wxGetApp().plater()->on_filaments_change(filament_count); wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); + auto_calc_flushing_volumes(filament_count - 1); }); p->m_bpButton_add_filament = add_btn; @@ -935,13 +968,38 @@ Sidebar::Sidebar(Plater *parent) //add project content p->sizer_params = new wxBoxSizer(wxVERTICAL); + + p->m_search_bar = new wxSearchCtrl(p->scrolled, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + p->m_search_bar->ShowSearchButton(true); + p->m_search_bar->ShowCancelButton(true); + p->m_search_bar->SetDescriptiveText(_L("Search plate, object and part.")); + + p->m_search_bar->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent&) { + this->p->on_search_update(); + wxPoint pos = this->p->m_search_bar->ClientToScreen(wxPoint(0, 0)); + pos.y += this->p->m_search_bar->GetRect().height; + p->dia->SetPosition(pos); + p->dia->Popup(); + }); + p->m_search_bar->Bind(wxEVT_COMMAND_TEXT_UPDATED, [this](wxCommandEvent&) { + this->p->on_search_update(); + }); + p->m_search_bar->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) { + p->dia->Dismiss(); + e.Skip(); + }); + p->m_object_list = new ObjectList(p->scrolled); + + p->sizer_params->Add(p->m_search_bar, 0, wxALL | wxEXPAND, 0); p->sizer_params->Add(p->m_object_list, 1, wxEXPAND | wxTOP, 0); scrolled_sizer->Add(p->sizer_params, 2, wxEXPAND | wxLEFT, 0); p->m_object_list->Hide(); - + p->m_search_bar->Hide(); // Frequently Object Settings p->object_settings = new ObjectSettings(p->scrolled); + + p->dia = new Search::SearchObjectDialog(p->m_object_list, p->m_search_bar); #if !NEW_OBJECT_SETTING p->object_settings->Hide(); p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, 5 * em / 10); @@ -964,7 +1022,26 @@ Sidebar::Sidebar(Plater *parent) Sidebar::~Sidebar() {} -void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filament_idx) { +void Sidebar::create_printer_preset() +{ + CreatePrinterPresetDialog dlg(wxGetApp().mainframe); + int res = dlg.ShowModal(); + if (wxID_OK == res) { + wxGetApp().mainframe->update_side_preset_ui(); + update_ui_from_settings(); + update_all_preset_comboboxes(); + wxGetApp().load_current_presets(); + CreatePresetSuccessfulDialog success_dlg(wxGetApp().mainframe, SuccessType::PRINTER); + int res = success_dlg.ShowModal(); + if (res == wxID_OK) { + p->editing_filament = -1; + if (p->combo_printer->switch_to_tab()) p->editing_filament = 0; + } + } +} + +void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int filament_idx) +{ *combo = new PlaterPresetComboBox(p->m_panel_filament_content, Slic3r::Preset::TYPE_FILAMENT); (*combo)->set_filament_idx(filament_idx); @@ -1148,7 +1225,11 @@ void Sidebar::update_presets(Preset::Type preset_type) preset_bundle.set_filament_preset(p->editing_filament, name); } else if (filament_cnt == 1) { // Single filament printer, synchronize the filament presets. - preset_bundle.set_filament_preset(0, name); + Preset *preset = preset_bundle.filaments.find_preset(name, false); + if (preset) { + if (preset->is_compatible) preset_bundle.set_filament_preset(0, name); + } + } for (size_t i = 0; i < filament_cnt; i++) @@ -1187,9 +1268,16 @@ void Sidebar::update_presets(Preset::Type preset_type) printer_tab->update(); } + Preset& printer_preset = wxGetApp().preset_bundle->printers.get_edited_preset(); bool isBBL = preset_bundle.is_bbl_vendor(); wxGetApp().mainframe->show_calibration_button(!isBBL); + if (auto printer_structure_opt = printer_preset.config.option>("printer_structure")) { + wxGetApp().plater()->get_current_canvas3D()->get_arrange_settings().align_to_y_axis = (printer_structure_opt->value == PrinterStructure::psI3); + } + else + wxGetApp().plater()->get_current_canvas3D()->get_arrange_settings().align_to_y_axis = false; + break; } @@ -1408,10 +1496,12 @@ void Sidebar::on_filaments_change(size_t num_filaments) { PlaterPresetComboBox* choice/*{ nullptr }*/; init_filament_combo(&choice, i); + int last_selection = choices.back()->GetSelection(); choices.push_back(choice); // initialize selection choice->update(); + choice->SetSelection(last_selection); ++i; } @@ -1446,8 +1536,7 @@ std::map Sidebar::build_filament_ams_list(MachineObject if (!obj) return filament_ams_list; auto vt_tray = obj->vt_tray; - bool is_support_virtual_tray = obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_TYAY); - if (is_support_virtual_tray) { + if (obj->ams_support_virtual_tray) { DynamicPrintConfig vt_tray_config; vt_tray_config.set_key_value("filament_id", new ConfigOptionStrings{ vt_tray.setting_id }); vt_tray_config.set_key_value("tag_uid", new ConfigOptionStrings{ vt_tray.tag_uid }); @@ -1484,18 +1573,12 @@ void Sidebar::load_ams_list(std::string const &device, MachineObject* obj) { std::map filament_ams_list = build_filament_ams_list(obj); - if (!obj) { - p->ams_list_device = device; - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " clear list"; - wxGetApp().preset_bundle->filament_ams_list = filament_ams_list; - for (auto c : p->combos_filament) - c->update(); - return; - } - p->ams_list_device = device; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": %1% items") % filament_ams_list.size(); + if (wxGetApp().preset_bundle->filament_ams_list == filament_ams_list) + return; wxGetApp().preset_bundle->filament_ams_list = filament_ams_list; + for (auto c : p->combos_filament) c->update(); } @@ -1713,6 +1796,7 @@ void Sidebar::update_ui_from_settings() bool Sidebar::show_object_list(bool show) const { + p->m_search_bar->Show(show); if (!p->m_object_list->Show(show)) return false; if (!show) @@ -1740,7 +1824,86 @@ std::string& Sidebar::get_search_line() return p->searcher.search_string(); } -// Plater::DropTarget +void Sidebar::auto_calc_flushing_volumes(const int modify_id) { + auto& project_config = wxGetApp().preset_bundle->project_config; + auto& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector& init_matrix = (project_config.option("flush_volumes_matrix"))->values; + const std::vector& init_extruders = (project_config.option("flush_volumes_vector"))->values; + ConfigOption* extra_flush_volume_opt = printer_config.option("nozzle_volume"); + int extra_flush_volume = extra_flush_volume_opt ? (int)extra_flush_volume_opt->getFloat() : 0; + ConfigOptionFloat* flush_multi_opt = project_config.option("flush_multiplier"); + float flush_multiplier = flush_multi_opt ? flush_multi_opt->getFloat() : 1.f; + vector matrix = init_matrix; + int m_min_flush_volume = extra_flush_volume; + int m_max_flush_volume = Slic3r::g_max_flush_volume; + unsigned int m_number_of_extruders = (int)(sqrt(init_matrix.size()) + 0.001); + const std::vector extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); + vector m_colours; + for (const std::string& color : extruder_colours) { + m_colours.push_back(wxColor(color)); + } + if (modify_id >= 0 && modify_id < m_colours.size()) { + for (int i = 0; i < m_colours.size(); ++i) { + int from_idx = i; + if (from_idx != modify_id) { + const wxColour& from = m_colours[from_idx]; + bool is_from_support = is_support_filament(from_idx); + const wxColour& to = m_colours[modify_id]; + bool is_to_support = is_support_filament(modify_id); + int flushing_volume = 0; + if (is_to_support) { + flushing_volume = Slic3r::g_flush_volume_to_support; + } + else { + const wxColour& to = m_colours[modify_id]; + Slic3r::FlushVolCalculator calculator(m_min_flush_volume, m_max_flush_volume); + flushing_volume = calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue()); + if (is_from_support) { + flushing_volume = std::max(Slic3r::g_min_flush_volume_from_support, flushing_volume); + } + } + matrix[m_number_of_extruders * from_idx + modify_id] = flushing_volume; + } + int to_idx = i; + if (to_idx != modify_id) { + const wxColour& from = m_colours[modify_id]; + bool is_from_support = is_support_filament(modify_id); + const wxColour& to = m_colours[to_idx]; + bool is_to_support = is_support_filament(to_idx); + int flushing_volume = 0; + if (is_to_support) { + flushing_volume = Slic3r::g_flush_volume_to_support; + } + else { + const wxColour& to = m_colours[to_idx]; + Slic3r::FlushVolCalculator calculator(m_min_flush_volume, m_max_flush_volume); + flushing_volume = calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue()); + if (is_from_support) { + flushing_volume = std::max(Slic3r::g_min_flush_volume_from_support, flushing_volume); + } + } + matrix[m_number_of_extruders * modify_id + to_idx] = flushing_volume; + } + } + } + (project_config.option("flush_volumes_matrix"))->values = std::vector(matrix.begin(), matrix.end()); + + + wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); + + wxGetApp().plater()->update_project_dirty_from_presets(); + wxPostEvent(this, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, this)); +} + +void Sidebar::jump_to_object(ObjectDataViewModelNode* item) +{ + p->jump_to_object(item); +} + +void Sidebar::can_search() +{ + p->can_search(); +} class PlaterDropTarget : public wxFileDropTarget { @@ -2187,6 +2350,8 @@ struct Plater::priv void on_action_split_objects(SimpleEvent&); void on_action_split_volumes(SimpleEvent&); void on_action_layersediting(SimpleEvent&); + void on_create_filament(SimpleEvent &); + void on_modify_filament(SimpleEvent &); void on_object_select(SimpleEvent&); void on_right_click(RBtnEvent&); @@ -2414,6 +2579,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_PREVIEW_ONLY_MODE_HINT, &priv::show_preview_only_hint, this); this->q->Bind(EVT_GLCANVAS_COLOR_MODE_CHANGED, &priv::on_change_color_mode, this); this->q->Bind(wxEVT_SYS_COLOUR_CHANGED, &priv::on_apple_change_color_mode, this); + this->q->Bind(EVT_CREATE_FILAMENT, &priv::on_create_filament, this); + this->q->Bind(EVT_MODIFY_FILAMENT, &priv::on_modify_filament, this); view3D = new View3D(q, bed, &model, config, &background_process); //BBS: use partplater's gcode @@ -2471,6 +2638,12 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) q->Bind(EVT_SCHEDULE_BACKGROUND_PROCESS, [this](SimpleEvent&) { this->schedule_background_process(); }); // jump to found option from SearchDialog q->Bind(wxCUSTOMEVT_JUMP_TO_OPTION, [this](wxCommandEvent& evt) { sidebar->jump_to_option(evt.GetInt()); }); + q->Bind(wxCUSTOMEVT_JUMP_TO_OBJECT, [this](wxCommandEvent& evt) { + auto client_data = evt.GetClientData(); + ObjectDataViewModelNode* data = static_cast(client_data); + sidebar->jump_to_object(data); + } + ); } wxGLCanvas* view3D_canvas = view3D->get_wxglcanvas(); @@ -2615,6 +2788,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) assemble_canvas->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this); assemble_canvas->Bind(EVT_GLVIEWTOOLBAR_3D, [q](SimpleEvent&) { q->select_view_3D("3D"); }); assemble_canvas->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this); + assemble_canvas->Bind(EVT_GLCANVAS_FORCE_UPDATE, [this](SimpleEvent&) { update(); }); assemble_canvas->Bind(EVT_GLCANVAS_UNDO, [this](SimpleEvent&) { this->undo(); }); assemble_canvas->Bind(EVT_GLCANVAS_REDO, [this](SimpleEvent&) { this->redo(); }); } @@ -2642,10 +2816,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) q->Bind(EVT_GLCANVAS_PLATE_SELECT, &priv::on_plate_selected, this); q->Bind(EVT_DOWNLOAD_PROJECT, &priv::on_action_download_project, this); q->Bind(EVT_IMPORT_MODEL_ID, &priv::on_action_request_model_id, this); - q->Bind(EVT_PRINT_FINISHED, [q](wxCommandEvent &evt) { q->print_job_finished(evt); }); + q->Bind(EVT_PRINT_FINISHED, [q](wxCommandEvent& evt) { q->print_job_finished(evt); }); q->Bind(EVT_SEND_CALIBRATION_FINISHED, [q](wxCommandEvent& evt) { q->send_calibration_job_finished(evt); }); - q->Bind(EVT_SEND_FINISHED, [q](wxCommandEvent &evt) { q->send_job_finished(evt); }); - q->Bind(EVT_PUBLISH_FINISHED, [q](wxCommandEvent &evt) { q->publish_job_finished(evt);}); + q->Bind(EVT_SEND_FINISHED, [q](wxCommandEvent& evt) { q->send_job_finished(evt); }); + q->Bind(EVT_PUBLISH_FINISHED, [q](wxCommandEvent& evt) { q->publish_job_finished(evt);}); + q->Bind(EVT_OPEN_PLATESETTINGSDIALOG, [q](wxCommandEvent& evt) { q->open_platesettings_dialog(evt);}); //q->Bind(EVT_GLVIEWTOOLBAR_ASSEMBLE, [q](SimpleEvent&) { q->select_view_3D("Assemble"); }); } @@ -2687,6 +2862,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, [this](EjectDriveNotificationClickedEvent&) { this->q->eject_drive(); }); this->q->Bind(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, [this](ExportGcodeNotificationClickedEvent&) { this->q->export_gcode(true); }); this->q->Bind(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, [](PresetUpdateAvailableClickedEvent&) { wxGetApp().get_preset_updater()->on_update_notification_confirm(); }); + this->q->Bind(EVT_PRINTER_CONFIG_UPDATE_AVAILABLE_CLICKED, [](PrinterConfigUpdateAvailableClickedEvent&) { + wxGetApp().get_preset_updater()->do_printer_config_update(); + wxGetApp().getDeviceManager()->reload_printer_settings(); }); /* BBS do not handle removeable driver event */ this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this](RemovableDriveEjectEvent &evt) { @@ -2826,7 +3004,7 @@ void Plater::priv::update(unsigned int flags) void Plater::priv::select_view(const std::string& direction) { if (current_panel == view3D) { - BOOST_LOG_TRIVIAL(info) << "select view3D"; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << "select view3D"; view3D->select_view(direction); wxGetApp().update_ui_from_settings(); } @@ -2897,7 +3075,7 @@ void Plater::priv::apply_free_camera_correction(bool apply/* = true*/) void Plater::priv::select_view_3D(const std::string& name, bool no_slice) { if (name == "3D") { - BOOST_LOG_TRIVIAL(info) << "select view3D"; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << "select view3D"; if (q->only_gcode_mode() || q->using_exported_file()) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("goto preview page when loading gcode/exported_3mf"); } @@ -2988,6 +3166,53 @@ BoundingBox Plater::priv::scaled_bed_shape_bb() const return printable_area.bounding_box(); } +std::string read_binary_stl(const std::string& filename) { + std::string model_id; + std::ifstream file(filename, std::ios::binary); + if (!file) { + return model_id; + } + + try{ + // Read the first 80 bytes + char data[80]; + file.read(data, 80); + if (!file) { + file.close(); + return model_id; + } + + if (data[0] == '\0' || data[0] == ' ') { + file.close(); + return model_id; + } + + char magic[2] = { data[0], data[1] }; + if (magic[0] != 'M' || magic[1] != 'W') { + file.close(); + return model_id; + } + + if (data[2] != ' ') { + file.close(); + return model_id; + } + + char protocol_version[3] = { data[3], data[4], data[5] }; + + //version + if (protocol_version[0] == '1' && protocol_version[1] == '.' && protocol_version[2] == '0') { + model_id = std::string(&data[7], &data[80]); + } + + file.close(); + } + catch (...){ + } + return model_id; +} + + // BBS: backup & restore std::vector Plater::priv::load_files(const std::vector& input_files, LoadStrategy strategy, bool ask_multi) { @@ -3029,6 +3254,8 @@ std::vector Plater::priv::load_files(const std::vector& input_ auto *new_model = (!load_model || one_by_one) ? nullptr : new Slic3r::Model(); std::vector obj_idxs; + std::string designer_model_id; + int answer_convert_from_meters = wxOK_DEFAULT; int answer_convert_from_imperial_units = wxOK_DEFAULT; int tolal_model_count = 0; @@ -3196,31 +3423,45 @@ std::vector Plater::priv::load_files(const std::vector& input_ } } else if (load_config && (file_version > app_version)) { if (config_substitutions.unrecogized_keys.size() > 0) { - wxString text = wxString::Format(_L("The 3mf's version %s is newer than %s's version %s, Found following keys unrecognized:"), - file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string()); + wxString text = wxString::Format(_L("This slicer file version %s is newer than %s's version:"), + file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME)); text += "\n"; bool first = true; // std::string context = into_u8(text); wxString context = text; - for (auto &key : config_substitutions.unrecogized_keys) { - context += " -"; - context += key; - context += ";\n"; - first = false; + if (wxGetApp().app_config->get("user_mode") == "develop") { + for (auto &key : config_substitutions.unrecogized_keys) { + context += " -"; + context += key; + context += ";\n"; + first = false; + } } - wxString append = _L("You'd better upgrade your software.\n"); + wxString append = _L("Would you like to update your Bambu Studio software to enable all functionality in this slicer file?\n"); context += "\n\n"; // context += into_u8(append); context += append; - show_info(q, context, _L("Newer 3mf version")); + MessageDialog msg_window(q, context, wxString(SLIC3R_APP_FULL_NAME " - ") + _L("Newer 3mf version"), wxYES | wxNO | wxICON_INFORMATION); + auto res = msg_window.ShowModal(); + if (res == wxID_YES) { + wxGetApp().check_new_version(true, 1); + } else if (res == wxID_NO) { + show_info(q, _L("you can always update Bambu Studio at your convenience. The slicer file will now be loaded without full functionality.")); + } } else { //if the minor version is not matched if (file_version.min() != app_version.min()) { - wxString text = wxString::Format(_L("The 3mf's version %s is newer than %s's version %s, Suggest to upgrade your software."), - file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME), app_version.to_string()); + wxString text = wxString::Format(_L("This slicer file version %s is newer than %s's version.\n\nWould you like to update your Bambu Studio software to enable all functionality in this slicer file?"), + file_version.to_string(), std::string(SLIC3R_APP_FULL_NAME)); text += "\n"; - show_info(q, text, _L("Newer 3mf version")); + MessageDialog msg_window(q, text, wxString(SLIC3R_APP_FULL_NAME " - ") + _L("Newer 3mf version"), wxYES | wxNO | wxICON_INFORMATION); + auto res = msg_window.ShowModal(); + if (res == wxID_YES) { + wxGetApp().check_new_version(true, 1); + } else if (res == wxID_NO) { + show_info(q, _L("you can always update Bambu Studio at your convenience. The slicer file will now be loaded without full functionality.")); + } } } } else if (!load_config) { @@ -3340,23 +3581,44 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (!config.empty()) { Preset::normalize(config); PresetBundle *preset_bundle = wxGetApp().preset_bundle; - // BBS: first validate the printer - // TODO: remove it after released"" - bool validated = preset_bundle->validate_printers(filename.string(), config); - if (!validated) { - load_config = false; - load_old_project = true; - // select view to 3D - q->select_view_3D("3D"); - // select plate 0 as default - q->select_plate(0); - show_info(q, _L("The 3mf is not compatible, load geometry data only!"), _L("Incompatible 3mf")); - for (ModelObject *model_object : model.objects) { - model_object->config.reset(); - // Is there any modifier or advanced config data? - for (ModelVolume *model_volume : model_object->volumes) model_volume->config.reset(); + + auto choise = wxGetApp().app_config->get("no_warn_when_modified_gcodes"); + if (choise.empty() || choise != "true") { + // BBS: first validate the printer + // validate the system profiles + std::set modified_gcodes; + int validated = preset_bundle->validate_presets(filename.string(), config, modified_gcodes); + if (validated == VALIDATE_PRESETS_MODIFIED_GCODES) { + std::string warning_message; + warning_message += "\n"; + for (std::set::iterator it=modified_gcodes.begin(); it!=modified_gcodes.end(); ++it) + warning_message += "-" + *it + "\n"; + warning_message += "\n"; + //show_info(q, _L("The 3mf has following modified G-codes in filament or printer presets:") + warning_message+ _L("Please confirm that these modified G-codes are safe to prevent any damage to the machine!"), _L("Modified G-codes")); + + MessageDialog dlg(q, _L("The 3mf has following modified G-codes in filament or printer presets:") + warning_message+ _L("Please confirm that these modified G-codes are safe to prevent any damage to the machine!"), _L("Modified G-codes")); + dlg.show_dsa_button(); + auto res = dlg.ShowModal(); + if (dlg.get_checkbox_state()) + wxGetApp().app_config->set("no_warn_when_modified_gcodes", "true"); } - } else { + else if ((validated == VALIDATE_PRESETS_PRINTER_NOT_FOUND) || (validated == VALIDATE_PRESETS_FILAMENTS_NOT_FOUND)) { + std::string warning_message; + warning_message += "\n"; + for (std::set::iterator it=modified_gcodes.begin(); it!=modified_gcodes.end(); ++it) + warning_message += "-" + *it + "\n"; + warning_message += "\n"; + //show_info(q, _L("The 3mf has following customized filament or printer presets:") + warning_message + _L("Please confirm that the G-codes within these presets are safe to prevent any damage to the machine!"), _L("Customized Preset")); + MessageDialog dlg(q, _L("The 3mf has following customized filament or printer presets:") + from_u8(warning_message)+ _L("Please confirm that the G-codes within these presets are safe to prevent any damage to the machine!"), _L("Customized Preset")); + dlg.show_dsa_button(); + auto res = dlg.ShowModal(); + if (dlg.get_checkbox_state()) + wxGetApp().app_config->set("no_warn_when_modified_gcodes", "true"); + } + } + + //always load config + { preset_bundle->load_config_model(filename.string(), std::move(config), file_version); ConfigOption* bed_type_opt = preset_bundle->project_config.option("curr_bed_type"); @@ -3443,10 +3705,12 @@ std::vector Plater::priv::load_files(const std::vector& input_ std::vector project_presets; bool is_xxx; Semver file_version; + model = Slic3r::Model::read_from_file( path.string(), nullptr, nullptr, strategy, &plate_data, &project_presets, &is_xxx, &file_version, nullptr, - [this, &dlg, real_filename, &progress_percent, &file_percent, INPUT_FILES_RATIO, total_files, i](int current, int total, bool &cancel) + [this, &dlg, real_filename, &progress_percent, &file_percent, INPUT_FILES_RATIO, total_files, i, &designer_model_id](int current, int total, bool &cancel, std::string &mode_id) { + designer_model_id = mode_id; bool cont = true; float percent_float = (100.0f * (float)i / (float)total_files) + INPUT_FILES_RATIO * 100.0f * ((float)current / (float)total) / (float)total_files; BOOST_LOG_TRIVIAL(trace) << "load_stl_file: percent(float)=" << percent_float << ", curr = " << current << ", total = " << total; @@ -3471,6 +3735,11 @@ std::vector Plater::priv::load_files(const std::vector& input_ _L("Attention!")); }); + + if (designer_model_id.empty() && boost::algorithm::iends_with(path.string(), ".stl")) { + designer_model_id = read_binary_stl(path.string()); + } + if (type_any_amf && is_xxx) imperial_units = true; for (auto obj : model.objects) @@ -3765,6 +4034,10 @@ std::vector Plater::priv::load_files(const std::vector& input_ GLGizmoSimplify::add_simplify_suggestion_notification( obj_idxs, model.objects, *notification_manager); + //set designer_model_id + if (!designer_model_id.empty() && q->model().stl_design_id.empty()) { + q->model().stl_design_id = designer_model_id; + } if (tolal_model_count <= 0 && !q->m_exported_file) { dlg.Hide(); @@ -4028,6 +4301,20 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type) wxString out_path = dlg.GetPath(); fs::path path(into_path(out_path)); +#ifdef __WXMSW__ + if (path.extension() != output_file.extension()) { + out_path += output_file.extension().string(); + boost::system::error_code ec; + if (boost::filesystem::exists(into_u8(out_path), ec)) { + auto result = MessageBox(q->GetHandle(), + wxString::Format(_L("The file %s already exists\nDo you want to replace it?"), out_path), + _L("Comfirm Save As"), + MB_YESNO | MB_ICONWARNING); + if (result != IDYES) + return wxEmptyString; + } + } +#endif wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); return out_path; @@ -4212,6 +4499,7 @@ void Plater::priv::reset(bool apply_presets_change) clear_warnings(); set_project_filename(""); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " call set_project_filename: empty"; if (view3D->is_layers_editing_enabled()) view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting")); @@ -4797,7 +5085,6 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const { const std::string path = new_path.string(); wxBusyCursor wait; - wxBusyInfo info(_L("Replace from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas()); Model new_model; try { @@ -4818,6 +5105,8 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const return false; } + wxBusyInfo info(_L("Replace from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas()); + if (!snapshot.empty()) q->take_snapshot(snapshot); @@ -4936,7 +5225,7 @@ void Plater::priv::reload_from_disk() #if ENABLE_RELOAD_FROM_DISK_REWORK // collect selected reloadable ModelVolumes std::vector> selected_volumes = reloadable_volumes(model, get_selection()); - + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry, and reloadable volumes number is: " << selected_volumes.size(); // nothing to reload, return if (selected_volumes.empty()) return; @@ -5333,6 +5622,8 @@ void Plater::priv::reload_from_disk() for (size_t i = 0; i < model.objects.size(); ++i) { view3D->get_canvas3d()->update_instance_printable_state_for_object(i); } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " finish."; } void Plater::priv::reload_all_from_disk() @@ -5687,8 +5978,33 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) // So, use GetSelection() from event parameter int selection = evt.GetSelection(); + auto marker = reinterpret_cast(combo->GetClientData(selection)); + if (PresetComboBox::LabelItemType::LABEL_ITEM_WIZARD_ADD_PRINTERS == marker) { + sidebar->create_printer_preset(); + return; + } + auto idx = combo->get_filament_idx(); + // BBS:Save the plate parameters before switching + PartPlateList& old_plate_list = this->partplate_list; + PartPlate* old_plate = old_plate_list.get_selected_plate(); + Vec3d old_plate_pos = old_plate->get_center_origin(); + + // BBS: Save the model in the current platelist + std::vector > plate_object; + for (size_t i = 0; i < old_plate_list.get_plate_count(); ++i) { + PartPlate* plate = old_plate_list.get_plate(i); + std::vector obj_idxs; + for (int obj_idx = 0; obj_idx < model.objects.size(); obj_idx++) { + if (plate && plate->contain_instance(obj_idx, 0)) { + obj_idxs.emplace_back(obj_idx); + } + } + plate_object.emplace_back(obj_idxs); + } + + bool flag = is_support_filament(idx); //! Because of The MSW and GTK version of wxBitmapComboBox derived from wxComboBox, //! but the OSX version derived from wxOwnerDrawnCombo. //! So, to get selected string we do @@ -5704,8 +6020,11 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) wxGetApp().plater()->update_project_dirty_from_presets(); wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); dynamic_filament_list.update(); + bool flag_is_change = is_support_filament(idx); + if (flag != flag_is_change) { + sidebar->auto_calc_flushing_volumes(idx); + } } - bool select_preset = !combo->selection_is_changed_according_to_physical_printers(); // TODO: ? if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) { @@ -5735,6 +6054,21 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) * and for SLA presets they should be deleted */ wxGetApp().obj_list()->update_object_list_by_printer_technology(); + + // BBS:Model reset by plate center + PartPlateList& cur_plate_list = this->partplate_list; + PartPlate* cur_plate = cur_plate_list.get_curr_plate(); + Vec3d cur_plate_pos = cur_plate->get_center_origin(); + + if (old_plate_pos.x() != cur_plate_pos.x() || old_plate_pos.y() != cur_plate_pos.y()) { + for (int i = 0; i < plate_object.size(); ++i) { + view3D->select_object_from_idx(plate_object[i]); + this->sidebar->obj_list()->update_selections(); + view3D->center_selected_plate(i); + } + + view3D->deselect_all(); + } } #ifdef __WXMSW__ @@ -5883,7 +6217,11 @@ void Plater::priv::on_slicing_began() clear_warnings(); notification_manager->close_notification_of_type(NotificationType::SignDetected); notification_manager->close_notification_of_type(NotificationType::ExportFinished); + bool is_first_plate = m_cur_slice_plate == 0; + bool slice_all = q->m_only_gcode ? m_slice_all_only_has_gcode : m_slice_all; + bool need_change_dailytips = !(slice_all && !is_first_plate); notification_manager->set_slicing_progress_began(); + notification_manager->update_slicing_notif_dailytips(need_change_dailytips); } void Plater::priv::add_warning(const Slic3r::PrintStateBase::Warning& warning, size_t oid) { @@ -6450,6 +6788,10 @@ void Plater::priv::on_filament_color_changed(wxCommandEvent &event) { //q->update_all_plate_thumbnails(true); //q->get_preview_canvas3D()->update_plate_thumbnails(); + if (wxGetApp().app_config->get("auto_calculate") == "true") { + int modify_id = event.GetInt(); + sidebar->auto_calc_flushing_volumes(modify_id); + } } void Plater::priv::install_network_plugin(wxCommandEvent &event) @@ -6755,6 +7097,7 @@ wxString Plater::priv::get_project_name() //BBS void Plater::priv::set_project_name(const wxString& project_name) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " project is:" << project_name; m_project_name = project_name; //update topbar title wxGetApp().mainframe->SetTitle(m_project_name); @@ -6784,6 +7127,7 @@ void Plater::priv::set_project_filename(const wxString& filename) full_path.replace_extension(""); m_project_folder = full_path.parent_path(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " project folder is:" << m_project_folder.string(); //BBS wxString project_name = from_u8(full_path.filename().string()); @@ -7246,7 +7590,8 @@ bool Plater::priv::can_increase_instances() const int obj_idx = get_selected_object_idx(); return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) - && !sidebar->obj_list()->has_selected_cut_object(); + && !sidebar->obj_list()->has_selected_cut_object() + && std::all_of(model.objects[obj_idx]->instances.begin(), model.objects[obj_idx]->instances.end(), [](auto& inst) {return inst->printable; }); } bool Plater::priv::can_decrease_instances() const @@ -7295,6 +7640,35 @@ void Plater::priv::on_action_layersediting(SimpleEvent&) notification_manager->set_move_from_overlay(view3D->is_layers_editing_enabled()); } +void Plater::priv::on_create_filament(SimpleEvent &) +{ + CreateFilamentPresetDialog dlg(wxGetApp().mainframe); + int res = dlg.ShowModal(); + if (wxID_OK == res) { + wxGetApp().mainframe->update_side_preset_ui(); + update_ui_from_settings(); + sidebar->update_all_preset_comboboxes(); + CreatePresetSuccessfulDialog success_dlg(wxGetApp().mainframe, SuccessType::FILAMENT); + int res = success_dlg.ShowModal(); + } +} + +void Plater::priv::on_modify_filament(SimpleEvent &evt) +{ + FilamentInfomation *filament_info = static_cast(evt.GetEventObject()); + int res; + { + EditFilamentPresetDialog dlg(wxGetApp().mainframe, filament_info); + res = dlg.ShowModal(); + } + wxGetApp().mainframe->update_side_preset_ui(); + update_ui_from_settings(); + sidebar->update_all_preset_comboboxes(); + if (wxID_EDIT == res) { + wxGetApp().params_dialog()->Popup(true); + } +} + void Plater::priv::enter_gizmos_stack() { assert(m_undo_redo_stack_active == &m_undo_redo_stack_main); @@ -7850,6 +8224,7 @@ int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_ void Plater::load_project(wxString const& filename2, wxString const& originfile) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "filename is: " << filename2 << "and originfile is: " << originfile; auto filename = filename2; auto check = [&filename, this] (bool yes_or_no) { if (!yes_or_no && !wxGetApp().check_and_save_current_preset_changes(_L("Load project"), @@ -7915,15 +8290,20 @@ void Plater::load_project(wxString const& filename2, // if res is empty no data has been loaded if (!res.empty() && (load_restore || !(strategy & LoadStrategy::Silence))) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " call set_project_filename: " << load_restore ? originfile : filename; p->set_project_filename(load_restore ? originfile : filename); - if (load_restore && originfile.IsEmpty()) - p->set_project_name(_L("Untitled")); + if (load_restore && originfile.IsEmpty()) { + p->set_project_name(_L("Untitled")); + } + } else { - if (using_exported_file()) + if (using_exported_file()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " using ecported set project filename: " << filename; p->set_project_filename(filename); + } + } - // BBS set default 3D view and direction after loading project //p->select_view_3D("3D"); if (!m_exported_file) { @@ -7952,6 +8332,7 @@ void Plater::load_project(wxString const& filename2, wxGetApp().params_panel()->switch_to_object_if_has_object_configs(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " load project done"; m_loading_project = false; } @@ -7971,7 +8352,7 @@ int Plater::save_project(bool saveAs) return wxID_CANCEL; //BBS export 3mf without gcode - if (export_3mf(into_path(filename), SaveStrategy::SplitModel | SaveStrategy::ShareMesh) < 0) { + if (export_3mf(into_path(filename), SaveStrategy::SplitModel | SaveStrategy::ShareMesh | SaveStrategy::FullPathSources) < 0) { MessageDialog(this, _L("Failed to save the project.\nPlease check whether the folder exists online or if other programs open the project file."), _L("Save project"), wxOK | wxICON_WARNING).ShowModal(); return wxID_CANCEL; @@ -7980,6 +8361,7 @@ int Plater::save_project(bool saveAs) Slic3r::remove_backup(model(), false); p->set_project_filename(filename); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " call set_project_filename: " << filename; up_to_date(true, false); up_to_date(true, true); @@ -8002,6 +8384,8 @@ int Plater::save_project(bool saveAs) //BBS import model by model id void Plater::import_model_id(wxString download_info) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " download info: " << download_info; + wxString download_origin_url = download_info; wxString download_url; wxString filename; @@ -8041,7 +8425,7 @@ void Plater::import_model_id(wxString download_info) wxString msg; wxString dlg_title = _L("Importing Model"); - int percent = 1; + int percent = 0; ProgressDialog dlg(dlg_title, wxString(' ', 100) + "\n\n\n\n", 100, // range @@ -8306,7 +8690,6 @@ void Plater::calib_pa(const Calib_Params& params) const auto calib_pa_name = wxString::Format(L"Pressure Advance Test"); new_project(false, false, calib_pa_name); wxGetApp().mainframe->select_tab(size_t(MainFrame::tp3DEditor)); - switch (params.mode) { case CalibMode::Calib_PA_Line: add_model(false, Slic3r::resources_dir() + "/calib/pressure_advance/pressure_advance_test.stl"); @@ -8551,6 +8934,7 @@ void Plater::calib_flowrate(int pass) { _obj->config.set_key_value("wall_loops", new ConfigOptionInt(3)); _obj->config.set_key_value("only_one_wall_top", new ConfigOptionBool(true)); _obj->config.set_key_value("sparse_infill_density", new ConfigOptionPercent(35)); + _obj->config.set_key_value("min_width_top_surface", new ConfigOptionPercent(100)); _obj->config.set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); _obj->config.set_key_value("top_shell_layers", new ConfigOptionInt(5)); _obj->config.set_key_value("detect_thin_wall", new ConfigOptionBool(true)); @@ -8818,6 +9202,7 @@ void Plater::load_gcode() //BBS: remove GCodeViewer as seperate APP logic void Plater::load_gcode(const wxString& filename) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " entry and filename: " << filename; if (! is_gcode_file(into_u8(filename)) || (m_last_loaded_gcode == filename && m_only_gcode) ) @@ -8870,6 +9255,20 @@ void Plater::load_gcode(const wxString& filename) current_print.apply(this->model(), wxGetApp().preset_bundle->full_config()); + //BBS: add cost info when drag in gcode + auto& ps = current_result->print_statistics; + double total_cost = 0.0; + for (auto& volumes_map : { ps.volumes_per_extruder,ps.flush_per_filament ,ps.wipe_tower_volumes_per_extruder }) { + for (auto volume : volumes_map) { + size_t extruder_id = volume.first; + double density = current_result->filament_densities.at(extruder_id); + double cost = current_result->filament_costs.at(extruder_id); + double weight = volume.second * density * 0.001; + total_cost += weight * cost * 0.001; + } + } + current_print.print_statistics().total_cost = total_cost; + current_print.set_gcode_file_ready(); // show results @@ -8882,9 +9281,10 @@ void Plater::load_gcode(const wxString& filename) MessageDialog(this, _L("The selected file") + ":\n" + filename + "\n" + _L("does not contain valid gcode."), wxString(GCODEVIEWER_APP_NAME) + " - " + _L("Error occurs while loading G-code file"), wxCLOSE | wxICON_WARNING | wxCENTRE).ShowModal(); set_project_filename(DEFAULT_PROJECT_NAME); - } - else + } else { set_project_filename(filename); + } + } void Plater::reload_gcode_from_disk() @@ -9498,6 +9898,7 @@ int Plater::get_3mf_file_count(std::vector paths) void Plater::add_file() { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " entry"; wxArrayString input_files; wxGetApp().import_model(this, input_files); if (input_files.empty()) return; @@ -9538,7 +9939,13 @@ void Plater::add_file() case LoadFilesType::SingleOther: { Plater::TakeSnapshot snapshot(this, snapshot_label); - if (!load_files(paths, LoadStrategy::LoadModel, false).empty()) { wxGetApp().mainframe->update_title(); } + if (!load_files(paths, LoadStrategy::LoadModel, false).empty()) { + if (get_project_name() == _L("Untitled") && paths.size() > 0) { + p->set_project_filename(wxString::FromUTF8(paths[0].string())); + + } + wxGetApp().mainframe->update_title(); + } break; } case LoadFilesType::Multiple3MF: @@ -9554,6 +9961,9 @@ void Plater::add_file() case LoadFilesType::MultipleOther: { Plater::TakeSnapshot snapshot(this, snapshot_label); if (!load_files(paths, LoadStrategy::LoadModel, true).empty()) { + if (get_project_name() == _L("Untitled") && paths.size() > 0) { + p->set_project_filename(wxString::FromUTF8(paths[0].string())); + } wxGetApp().mainframe->update_title(); } break; @@ -9572,7 +9982,7 @@ void Plater::add_file() open_3mf_file(first_file[0]); load_files(tmf_file, LoadStrategy::LoadModel); - if (!load_files(other_file, LoadStrategy::LoadModel, false).empty()) { wxGetApp().mainframe->update_title(); } + if (!load_files(other_file, LoadStrategy::LoadModel, false).empty()) { wxGetApp().mainframe->update_title();} break; default:break; } @@ -10168,11 +10578,20 @@ TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, st // BBS export with/without boolean, however, stil merge mesh #define EXPORT_WITH_BOOLEAN 0 -void Plater::export_stl(bool extended, bool selection_only) +void Plater::export_stl(bool extended, bool selection_only, bool multi_stls) { if (p->model.objects.empty()) { return; } - wxString path = p->get_export_file(FT_STL); + wxString path; + if (multi_stls) { + wxDirDialog dlg(this, _L("Choose a directory"), from_u8(wxGetApp().app_config->get_last_dir()), + wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); + if (dlg.ShowModal() == wxID_OK) { + path = dlg.GetPath() + "/"; + } + } else { + path = p->get_export_file(FT_STL); + } if (path.empty()) { return; } const std::string path_u8 = into_u8(path); @@ -10295,6 +10714,14 @@ void Plater::export_stl(bool extended, bool selection_only) else mesh_to_export = mesh_to_export_sla; + auto get_save_file = [](std::string const & dir, std::string const & name) { + auto path = dir + name + ".stl"; + int n = 1; + while (boost::filesystem::exists(path)) + path = dir + name + "(" + std::to_string(n++) + ").stl"; + return path; + }; + TriangleMesh mesh; if (selection_only) { if (selection.is_single_full_object()) { @@ -10310,18 +10737,36 @@ void Plater::export_stl(bool extended, bool selection_only) if (model_object->instances.size() == 1) mesh.translate(-model_object->origin_translation.cast()); } - else if (selection.is_multiple_full_object()) { + else if (selection.is_multiple_full_object() && !multi_stls) { const std::set>& instances_idxs = p->get_selection().get_selected_object_instances(); for (const std::pair& i : instances_idxs) { ModelObject* object = p->model.objects[i.first]; mesh.merge(mesh_to_export(*object, i.second)); } } + else if (selection.is_multiple_full_object() && multi_stls) { + const std::set> &instances_idxs = p->get_selection().get_selected_object_instances(); + for (const std::pair &i : instances_idxs) { + ModelObject *object = p->model.objects[i.first]; + auto mesh = mesh_to_export(*object, i.second); + mesh.translate(-object->origin_translation.cast()); + + Slic3r::store_stl(get_save_file(path_u8, object->name).c_str(), &mesh, true); + } + return; + } } - else { + else if (!multi_stls) { for (const ModelObject* o : p->model.objects) { mesh.merge(mesh_to_export(*o, -1)); } + } else { + for (const ModelObject* o : p->model.objects) { + auto mesh = mesh_to_export(*o, -1); + mesh.translate(-o->origin_translation.cast()); + Slic3r::store_stl(get_save_file(path_u8, o->name).c_str(), &mesh, true); + } + return; } Slic3r::store_stl(path_u8.c_str(), &mesh, true); @@ -10469,9 +10914,17 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy // get type and color for platedata auto* filament_color = dynamic_cast(cfg.option("filament_colour")); + auto* nozzle_diameter_option = dynamic_cast(cfg.option("nozzle_diameter")); + std::string nozzle_diameter_str; + if (nozzle_diameter_option) + nozzle_diameter_str = nozzle_diameter_option->serialize(); + + std::string printer_model_id = preset_bundle.printers.get_edited_preset().get_printer_type(&preset_bundle); for (int i = 0; i < plate_data_list.size(); i++) { PlateData *plate_data = plate_data_list[i]; + plate_data->printer_model_id = printer_model_id; + plate_data->nozzle_diameters = nozzle_diameter_str; for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) { std::string display_filament_type; it->type = cfg.get_filament_type(display_filament_type, it->id); @@ -10518,6 +10971,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy if (!(store_params.strategy & SaveStrategy::Silence)) { // Success p->set_project_filename(path); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " call set_project_filename: " << path; } } else { @@ -10615,7 +11069,7 @@ void Plater::reslice() // Stop arrange and (or) optimize rotation tasks. this->stop_jobs(); - // regenerate CalibPressureAdvancePattern custom G-code to apply changes + // Orca: regenerate CalibPressureAdvancePattern custom G-code to apply changes if (model().calib_pa_pattern) { PresetBundle* preset_bundle = wxGetApp().preset_bundle; @@ -11680,7 +12134,7 @@ void Plater::clone_selection() long res = wxGetNumberFromUser("", _L("Clone"), _L("Number of copies:"), - 1, 0, 100, this); + 1, 0, 1000, this); wxString msg; if (res == -1) { msg = _L("Invalid number"); @@ -12013,6 +12467,73 @@ void Plater::validate_current_plate(bool& model_fits, bool& validate_error) return; } +void Plater::open_platesettings_dialog(wxCommandEvent& evt) { + int plate_index = evt.GetInt(); + PlateSettingsDialog dlg(this, _L("Plate Settings"), evt.GetString() == "only_first_layer_sequence"); + PartPlate* curr_plate = p->partplate_list.get_curr_plate(); + dlg.sync_bed_type(curr_plate->get_bed_type()); + + auto curr_print_seq = curr_plate->get_print_seq(); + if (curr_print_seq != PrintSequence::ByDefault) { + dlg.sync_print_seq(int(curr_print_seq) + 1); + } + else + dlg.sync_print_seq(0); + + auto first_layer_print_seq = curr_plate->get_first_layer_print_sequence(); + if (first_layer_print_seq.empty()) + dlg.sync_first_layer_print_seq(0); + else + dlg.sync_first_layer_print_seq(1, curr_plate->get_first_layer_print_sequence()); + + dlg.sync_spiral_mode(curr_plate->get_spiral_vase_mode(), !curr_plate->has_spiral_mode_config()); + + dlg.Bind(EVT_SET_BED_TYPE_CONFIRM, [this, plate_index, &dlg](wxCommandEvent& e) { + PartPlate* curr_plate = p->partplate_list.get_curr_plate(); + BedType old_bed_type = curr_plate->get_bed_type(); + auto bt_sel = BedType(dlg.get_bed_type_choice()); + if (old_bed_type != bt_sel) { + curr_plate->set_bed_type(bt_sel); + update_project_dirty_from_presets(); + set_plater_dirty(true); + } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("select bed type %1% for plate %2% at plate side") % bt_sel % plate_index; + + if (dlg.get_first_layer_print_seq_choice() != 0) + curr_plate->set_first_layer_print_sequence(dlg.get_first_layer_print_seq()); + else + curr_plate->set_first_layer_print_sequence({}); + + int ps_sel = dlg.get_print_seq_choice(); + if (ps_sel != 0) + curr_plate->set_print_seq(PrintSequence(ps_sel - 1)); + else + curr_plate->set_print_seq(PrintSequence::ByDefault); + + int spiral_sel = dlg.get_spiral_mode_choice(); + if (spiral_sel == 1) { + curr_plate->set_spiral_vase_mode(true, false); + } + else if (spiral_sel == 2) { + curr_plate->set_spiral_vase_mode(false, false); + } + else { + curr_plate->set_spiral_vase_mode(false, true); + } + + update_project_dirty_from_presets(); + set_plater_dirty(true); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("select print sequence %1% for plate %2% at plate side") % ps_sel % plate_index; + auto plate_config = *(curr_plate->config()); + wxGetApp().plater()->config_change_notification(plate_config, std::string("print_sequence")); + update(); + wxGetApp().obj_list()->update_selections(); + }); + dlg.set_plate_name(from_u8(curr_plate->get_plate_name())); + + dlg.ShowModal(); + curr_plate->set_plate_name(dlg.get_plate_name().ToUTF8().data()); +} //BBS: select Plate by hover_id int Plater::select_plate_by_hover_id(int hover_id, bool right_click, bool isModidyPlateName) @@ -12151,62 +12672,16 @@ int Plater::select_plate_by_hover_id(int hover_id, bool right_click, bool isModi } else if ((action == 5)&&(!right_click)) { - //set the plate type + // set the plate type ret = select_plate(plate_index); if (!ret) { - PlateSettingsDialog dlg(this, wxID_ANY, _L("Plate Settings")); - PartPlate* curr_plate = p->partplate_list.get_curr_plate(); - dlg.sync_bed_type(curr_plate->get_bed_type()); - - auto curr_print_seq = curr_plate->get_print_seq(); - if (curr_print_seq != PrintSequence::ByDefault) { - dlg.sync_print_seq(int(curr_print_seq) + 1); - } - else - dlg.sync_print_seq(0); - - auto first_layer_print_seq = curr_plate->get_first_layer_print_sequence(); - if (first_layer_print_seq.empty()) - dlg.sync_first_layer_print_seq(0); - else - dlg.sync_first_layer_print_seq(1, curr_plate->get_first_layer_print_sequence()); - - dlg.set_plate_name(from_u8(curr_plate->get_plate_name())); - - dlg.Bind(EVT_SET_BED_TYPE_CONFIRM, [this, plate_index, &dlg](wxCommandEvent& e) { - PartPlate *curr_plate = p->partplate_list.get_curr_plate(); - BedType old_bed_type = curr_plate->get_bed_type(); - auto bt_sel = BedType(dlg.get_bed_type_choice()); - if (old_bed_type != bt_sel) { - curr_plate->set_bed_type(bt_sel); - update_project_dirty_from_presets(); - set_plater_dirty(true); - } - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("select bed type %1% for plate %2% at plate side")%bt_sel %plate_index; - - if (dlg.get_first_layer_print_seq_choice() != 0) - curr_plate->set_first_layer_print_sequence(dlg.get_first_layer_print_seq()); - else - curr_plate->set_first_layer_print_sequence({}); - - int ps_sel = dlg.get_print_seq_choice(); - if (ps_sel != 0) - curr_plate->set_print_seq(PrintSequence(ps_sel - 1)); - else - curr_plate->set_print_seq(PrintSequence::ByDefault); - update_project_dirty_from_presets(); - set_plater_dirty(true); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("select print sequence %1% for plate %2% at plate side")%ps_sel %plate_index; - auto plate_config = *(curr_plate->config()); - wxGetApp().plater()->config_change_notification(plate_config, std::string("print_sequence")); - update(); - }); - dlg.ShowModal(); - curr_plate->set_plate_name(dlg.get_plate_name().ToUTF8().data()); + wxCommandEvent evt(EVT_OPEN_PLATESETTINGSDIALOG); + evt.SetInt(plate_index); + evt.SetEventObject(this); + wxPostEvent(this, evt); this->schedule_background_process(); - } - else { + } else { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "can not select plate %1%" << plate_index; ret = -1; } @@ -12221,12 +12696,11 @@ int Plater::select_plate_by_hover_id(int hover_id, bool right_click, bool isModi wxString curr_plate_name = from_u8(curr_plate->get_plate_name()); dlg.set_plate_name(curr_plate_name); - dlg.ShowModal(); - - wxString dlg_plate_name = dlg.get_plate_name(); - curr_plate->set_plate_name(dlg_plate_name.ToUTF8().data()); - - this->schedule_background_process(); + int result=dlg.ShowModal(); + if (result == wxID_YES) { + wxString dlg_plate_name = dlg.get_plate_name(); + curr_plate->set_plate_name(dlg_plate_name.ToUTF8().data()); + } } else { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "can not select plate %1%" << plate_index; ret = -1; @@ -12395,14 +12869,28 @@ bool Plater::show_publish_dialog(bool show) void Plater::post_process_string_object_exception(StringObjectException &err) { + PresetBundle* preset_bundle = wxGetApp().preset_bundle; if (err.type == StringExceptionType::STRING_EXCEPT_FILAMENT_NOT_MATCH_BED_TYPE) { try { int extruder_id = atoi(err.params[2].c_str()) - 1; - if (extruder_id < wxGetApp().preset_bundle->filament_presets.size()) { - std::string filament_name = wxGetApp().preset_bundle->filament_presets[extruder_id]; - for (auto filament : wxGetApp().preset_bundle->filaments) { - if (filament.name == filament_name) { - filament_name = filament.alias; + if (extruder_id < preset_bundle->filament_presets.size()) { + std::string filament_name = preset_bundle->filament_presets[extruder_id]; + for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) { + if (filament_it->name == filament_name) { + if (filament_it->is_system) { + filament_name = filament_it->alias; + } else { + auto preset = preset_bundle->filaments.get_preset_base(*filament_it); + if (!preset->alias.empty()) { + filament_name = preset->alias; + } else { + char target = '@'; + size_t pos = preset->name.find(target); + if (pos != std::string::npos) { + filament_name = preset->name.substr(0, pos - 1); + } + } + } break; } } @@ -12486,6 +12974,12 @@ NotificationManager * Plater::get_notification_manager() return p->notification_manager.get(); } +DailyTipsWindow* Plater::get_dailytips() const +{ + static DailyTipsWindow* dailytips_win = new DailyTipsWindow(); + return dailytips_win; +} + const NotificationManager * Plater::get_notification_manager() const { return p->notification_manager.get(); @@ -12632,7 +13126,7 @@ bool Plater::PopupMenu(wxMenu *menu, const wxPoint& pos) SuppressBackgroundProcessingUpdate sbpu; // When tracking a pop-up menu, postpone error messages from the slicing result. m_tracking_popup_menu = true; - bool out = this->wxPanel::PopupMenu(menu, pos); + bool out = wxGetApp().mainframe->PopupMenu(menu, pos); m_tracking_popup_menu = false; if (! m_tracking_popup_menu_error_message.empty()) { // Don't know whether the CallAfter is necessary, but it should not hurt. diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 809a3ed8017..5e9833ba564 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -42,6 +42,7 @@ #include "libslic3r/calib.hpp" #include "libslic3r/CutUtils.hpp" +#include "libslic3r/FlushVolCalc.hpp" #define FILAMENT_SYSTEM_COLORS_NUM 16 @@ -86,6 +87,7 @@ class ObjectList; class GLCanvas3D; class Mouse3DController; class NotificationManager; +class DailyTipsWindow; struct Camera; class GLToolbar; class PlaterPresetComboBox; @@ -102,6 +104,7 @@ enum class ActionButtonType : int; //BBS: add EVT_SLICING_UPDATE declare here wxDECLARE_EVENT(EVT_SLICING_UPDATE, Slic3r::SlicingStatusEvent); wxDECLARE_EVENT(EVT_PUBLISH, wxCommandEvent); +wxDECLARE_EVENT(EVT_OPEN_PLATESETTINGSDIALOG, wxCommandEvent); wxDECLARE_EVENT(EVT_REPAIR_MODEL, wxCommandEvent); wxDECLARE_EVENT(EVT_FILAMENT_COLOR_CHANGED, wxCommandEvent); wxDECLARE_EVENT(EVT_INSTALL_PLUGIN_NETWORKING, wxCommandEvent); @@ -110,7 +113,8 @@ wxDECLARE_EVENT(EVT_UPDATE_PLUGINS_WHEN_LAUNCH, wxCommandEvent); wxDECLARE_EVENT(EVT_PREVIEW_ONLY_MODE_HINT, wxCommandEvent); wxDECLARE_EVENT(EVT_GLCANVAS_COLOR_MODE_CHANGED, SimpleEvent); wxDECLARE_EVENT(EVT_PRINT_FROM_SDCARD_VIEW, SimpleEvent); - +wxDECLARE_EVENT(EVT_CREATE_FILAMENT, SimpleEvent); +wxDECLARE_EVENT(EVT_MODIFY_FILAMENT, SimpleEvent); const wxString DEFAULT_PROJECT_NAME = "Untitled"; @@ -125,6 +129,7 @@ class Sidebar : public wxPanel Sidebar &operator=(const Sidebar &) = delete; ~Sidebar(); + void create_printer_preset(); void init_filament_combo(PlaterPresetComboBox **combo, const int filament_idx); void remove_unused_filament_combos(const size_t current_extruder_count); void update_all_preset_comboboxes(); @@ -174,7 +179,9 @@ class Sidebar : public wxPanel void update_ui_from_settings(); bool show_object_list(bool show) const; void finish_param_edit(); - + void auto_calc_flushing_volumes(const int modify_id); + void jump_to_object(ObjectDataViewModelNode* item); + void can_search(); #ifdef _MSW_DARK_MODE void show_mode_sizer(bool show); #endif @@ -337,8 +344,13 @@ class Plater: public wxPanel bool is_selection_empty() const; void scale_selection_to_fit_print_volume(); void convert_unit(ConversionType conv_type); + // BBS: replace z with plane_points + void cut(size_t obj_idx, size_t instance_idx, std::array plane_points, ModelObjectCutAttributes attributes); + // BBS: segment model with CGAL + void segment(size_t obj_idx, size_t instance_idx, double smoothing_alpha=0.5, int segment_number=5); void apply_cut_object_to_model(size_t init_obj_idx, const ModelObjectPtrs& cut_objects); + void merge(size_t obj_idx, std::vector &vol_indeces); void send_to_printer(bool isall = false); void export_gcode(bool prefer_removable); @@ -346,7 +358,7 @@ class Plater: public wxPanel void send_gcode_finish(wxString name); void export_core_3mf(); static TriangleMesh combine_mesh_fff(const ModelObject& mo, int instance_id, std::function notify_func = {}); - void export_stl(bool extended = false, bool selection_only = false); + void export_stl(bool extended = false, bool selection_only = false, bool multi_stls = false); //BBS: remove amf //void export_amf(); //BBS add extra param for exporting 3mf silence @@ -385,6 +397,7 @@ class Plater: public wxPanel void print_job_finished(wxCommandEvent &evt); void send_job_finished(wxCommandEvent& evt); void publish_job_finished(wxCommandEvent& evt); + void open_platesettings_dialog(wxCommandEvent& evt); void on_change_color_mode(SimpleEvent& evt); void eject_drive(); @@ -593,6 +606,7 @@ class Plater: public wxPanel const NotificationManager* get_notification_manager() const; NotificationManager* get_notification_manager(); + DailyTipsWindow* get_dailytips() const; //BBS: show message in status bar void show_status_message(std::string s); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 64bf3c273f9..f28d13dbefd 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -30,6 +30,18 @@ WX_DEFINE_LIST(RadioSelectorList); wxDEFINE_EVENT(EVT_PREFERENCES_SELECT_TAB, wxCommandEvent); +class MyscrolledWindow : public wxScrolledWindow { +public: + MyscrolledWindow(wxWindow* parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxVSCROLL) : wxScrolledWindow(parent, id, pos, size, style) {} + + bool ShouldScrollToChildOnFocus(wxWindow* child) override { return false; } +}; + + wxBoxSizer *PreferencesDialog::create_item_title(wxString title, wxWindow *parent, wxString tooltip) { wxBoxSizer *m_sizer_title = new wxBoxSizer(wxHORIZONTAL); @@ -147,16 +159,19 @@ wxBoxSizer *PreferencesDialog::create_item_language_combobox( language_name = wxString::FromUTF8("\xED\x95\x9C\xEA\xB5\xAD\xEC\x96\xB4"); } else if (vlist[i] == wxLocale::GetLanguageInfo(wxLANGUAGE_RUSSIAN)) { - language_name = wxString::FromUTF8("\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9"); + language_name = wxString::FromUTF8("\xD0\xA0\xD1\x83\xD1\x81\xD1\x81\xD0\xBA\xD0\xB8\xD0\xB9"); + } + else if (vlist[i] == wxLocale::GetLanguageInfo(wxLANGUAGE_CZECH)) { + language_name = wxString::FromUTF8("\xC4\x8D\x65\xC5\xA1\x74\x69\x6E\x61"); } else if (vlist[i] == wxLocale::GetLanguageInfo(wxLANGUAGE_UKRAINIAN)) { - language_name = wxString::FromUTF8("Ukrainian"); + language_name = wxString::FromUTF8("\xC4\x8D\x65\xC5\xA1\x74\x69\x6E\x61"); } else if (vlist[i] == wxLocale::GetLanguageInfo(wxLANGUAGE_TURKISH)) { - language_name = wxString::FromUTF8("Turkish"); + language_name = wxString::FromUTF8("\xD1\x83\xD0\xBA\xD1\x80\xD0\xB0\xD1\x97\xD1\x9D\xD1\x81\xD1\x8C\xD0\xBA\xD0\xB0"); } - if (app_config->get(param) == vlist[i]->CanonicalName) { + if (language == vlist[i]->CanonicalName) { m_current_language_selected = i; } combobox->Append(language_name); @@ -465,6 +480,8 @@ wxBoxSizer *PreferencesDialog::create_item_backup_input(wxString title, wxWindow StateColor input_bg(std::pair(wxColour("#F0F0F1"), StateColor::Disabled), std::pair(*wxWHITE, StateColor::Enabled)); input->SetBackgroundColor(input_bg); input->GetTextCtrl()->SetValue(app_config->get(param)); + wxTextValidator validator(wxFILTER_DIGITS); + input->GetTextCtrl()->SetValidator(validator); auto second_title = new wxStaticText(parent, wxID_ANY, _L("Second"), wxDefaultPosition, DESIGN_TITLE_SIZE, 0); @@ -485,23 +502,22 @@ wxBoxSizer *PreferencesDialog::create_item_backup_input(wxString title, wxWindow e.Skip(); }); - input->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this, param, input](wxCommandEvent &e) { + std::function backup_interval = [this, param, input]() { m_backup_interval_time = input->GetTextCtrl()->GetValue(); app_config->set("backup_interval", std::string(m_backup_interval_time.mb_str())); app_config->save(); long backup_interval = 0; m_backup_interval_time.ToLong(&backup_interval); Slic3r::set_backup_interval(backup_interval); + }; + + input->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [backup_interval](wxCommandEvent &e) { + backup_interval(); e.Skip(); }); - input->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this, param, input](wxFocusEvent &e) { - m_backup_interval_time = input->GetTextCtrl()->GetValue(); - app_config->set("backup_interval", std::string(m_backup_interval_time.mb_str())); - app_config->save(); - long backup_interval = 0; - m_backup_interval_time.ToLong(&backup_interval); - Slic3r::set_backup_interval(backup_interval); + input->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [backup_interval](wxFocusEvent &e) { + backup_interval(); e.Skip(); }); @@ -620,7 +636,7 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxWindow *pa checkbox_title->SetFont(::Label::Body_13); auto size = checkbox_title->GetTextExtent(title); - checkbox_title->SetMinSize(wxSize(size.x + FromDIP(4), -1)); + checkbox_title->SetMinSize(wxSize(size.x + FromDIP(5), -1)); checkbox_title->Wrap(-1); m_sizer_checkbox->Add(checkbox_title, 0, wxALIGN_CENTER | wxALL, 3); @@ -683,8 +699,8 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxWindow *pa #endif // __WXMSW__ - if (param == "developer_mode") - { + if (param == "developer_mode") + { m_developer_mode_def = app_config->get("developer_mode"); if (m_developer_mode_def == "true") { Slic3r::GUI::wxGetApp().save_mode(comDevelop); @@ -693,7 +709,7 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxWindow *pa } } - // webview dump_vedio + // webview dump_vedio if (param == "internal_developer_mode") { m_internal_developer_mode_def = app_config->get("internal_developer_mode"); if (m_internal_developer_mode_def == "true") { @@ -832,6 +848,19 @@ PreferencesDialog::PreferencesDialog(wxWindow *parent, wxWindowID id, const wxSt SetBackgroundColour(*wxWHITE); create(); wxGetApp().UpdateDlgDarkUI(this); + Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event) { + try { + NetworkAgent* agent = GUI::wxGetApp().getAgent(); + if (agent) { + json j; + std::string value; + value = wxGetApp().app_config->get("auto_calculate"); + j["auto_flushing"] = value; + agent->track_event("preferences_changed", j.dump()); + } + } catch(...) {} + event.Skip(); + }); } void PreferencesDialog::create() @@ -846,7 +875,7 @@ void PreferencesDialog::create() auto main_sizer = new wxBoxSizer(wxVERTICAL); - m_scrolledWindow = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL); + m_scrolledWindow = new MyscrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL); m_scrolledWindow->SetScrollRate(5, 5); m_sizer_body = new wxBoxSizer(wxVERTICAL); @@ -983,6 +1012,7 @@ wxWindow* PreferencesDialog::create_general_page() auto item_show_splash_screen = create_item_checkbox(_L("Show splash screen"), page, _L("Show the splash screen during startup."), 50, "show_splash_screen"); auto item_hints = create_item_checkbox(_L("Show \"Tip of the day\" notification after start"), page, _L("If enabled, useful hints are displayed at startup."), 50, "show_hints"); + auto item_calc_mode = create_item_checkbox(_L("Flushing volumes: Auto-calculate everytime the color changed."), page, _L("If enabled, auto-calculate everytime the color changed."), 50, "auto_calculate"); auto title_presets = create_item_title(_L("Presets"), page, _L("Presets")); auto item_user_sync = create_item_checkbox(_L("Auto sync user presets(Printer/Filament/Process)"), page, _L("User Sync"), 50, "sync_user_preset"); auto item_system_sync = create_item_checkbox(_L("Update built-in Presets automatically."), page, _L("System Sync"), 50, "sync_system_preset"); @@ -1016,6 +1046,7 @@ wxWindow* PreferencesDialog::create_general_page() wxGetApp().app_config->set("save_project_choise", ""); }); // auto item_backup = create_item_switch(_L("Backup switch"), page, _L("Backup switch"), "units"); + auto item_gcodes_warning = create_item_checkbox(_L("No warnings when loading 3MF with modified G-codes"), page,_L("No warnings when loading 3MF with modified G-codes"), 50, "no_warn_when_modified_gcodes"); auto item_backup = create_item_checkbox(_L("Auto-Backup"), page,_L("Backup your project periodically for restoring from the occasional crash."), 50, "backup_switch"); auto item_backup_interval = create_item_backup_input(_L("every"), page, _L("The peroid of backup in seconds."), "backup_interval"); @@ -1044,6 +1075,7 @@ wxWindow* PreferencesDialog::create_general_page() sizer_page->Add(item_hints, 0, wxTOP, FromDIP(3)); sizer_page->Add(title_presets, 0, wxTOP | wxEXPAND, FromDIP(20)); sizer_page->Add(item_stealth_mode, 0, wxTOP, FromDIP(3)); + sizer_page->Add(item_calc_mode, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_user_sync, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_system_sync, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_save_presets, 0, wxTOP, FromDIP(3)); @@ -1068,6 +1100,7 @@ wxWindow* PreferencesDialog::create_general_page() sizer_page->Add(title_project, 0, wxTOP| wxEXPAND, FromDIP(20)); sizer_page->Add(item_max_recent_count, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_save_choise, 0, wxTOP, FromDIP(3)); + sizer_page->Add(item_gcodes_warning, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_backup, 0, wxTOP,FromDIP(3)); item_backup->Add(item_backup_interval, 0, wxLEFT, 0); @@ -1211,6 +1244,7 @@ wxWindow* PreferencesDialog::create_debug_page() debug_button->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { // success message box MessageDialog dialog(this, _L("save debug settings"), _L("DEBUG settings have saved successfully!"), wxNO_DEFAULT | wxYES_NO | wxICON_INFORMATION); + dialog.SetSize(400,-1); switch (dialog.ShowModal()) { case wxID_NO: { //if (m_developer_mode_def != app_config->get("developer_mode")) { diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index e3370d02db3..a417d47de99 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -41,6 +41,7 @@ class RadioSelector RadioBox *m_radiobox; bool m_selected = false; }; + WX_DECLARE_LIST(RadioSelector, RadioSelectorList); class CheckBox; class TextInput; @@ -61,7 +62,7 @@ class PreferencesDialog : public DPIDialog protected: wxBoxSizer * m_sizer_body; - wxScrolledWindow *m_scrolledWindow; + wxScrolledWindow* m_scrolledWindow; // bool m_settings_layout_changed {false}; bool m_seq_top_layer_only_changed{false}; diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index c58150b12a7..c0e59741b32 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -248,6 +248,7 @@ int PresetComboBox::update_ams_color() wxGetApp().plater()->on_config_change(new_cfg); //trigger the filament color changed wxCommandEvent *evt = new wxCommandEvent(EVT_FILAMENT_COLOR_CHANGED); + evt->SetInt(m_filament_idx); wxQueueEvent(wxGetApp().plater(), evt); return idx; } @@ -382,7 +383,7 @@ void PresetComboBox::add_ams_filaments(std::string selected, bool alias_name) std::string filament_id = tray.opt_string("filament_id", 0u); if (filament_id.empty()) continue; auto iter = std::find_if(filaments.begin(), filaments.end(), - [&filament_id](auto &f) { return f.is_compatible && f.is_system && f.filament_id == filament_id; }); + [&filament_id, this](auto &f) { return f.is_compatible && m_collection->get_preset_base(f) == &f && f.filament_id == filament_id; }); if (iter == filaments.end()) { auto filament_type = tray.opt_string("filament_type", 0u); if (!filament_type.empty()) { @@ -632,7 +633,7 @@ bool PresetComboBox::selection_is_changed_according_to_physical_printers() PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset_type) : PresetComboBox(parent, preset_type, wxSize(25 * wxGetApp().em_unit(), 30 * wxGetApp().em_unit() / 10)) { - GetDropDown().SetUseContentWidth(true); + GetDropDown().SetUseContentWidth(true,true); if (m_type == Preset::TYPE_FILAMENT) { @@ -699,6 +700,7 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset wxGetApp().plater()->on_config_change(cfg_new); wxCommandEvent *evt = new wxCommandEvent(EVT_FILAMENT_COLOR_CHANGED); + evt->SetInt(m_filament_idx); wxQueueEvent(wxGetApp().plater(), evt); } }); @@ -748,6 +750,10 @@ void PlaterPresetComboBox::OnSelect(wxCommandEvent &evt) auto marker = reinterpret_cast(this->GetClientData(selected_item)); if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) { this->SetSelection(m_last_selected); + if (LABEL_ITEM_WIZARD_ADD_PRINTERS == marker) { + evt.Skip(); + return; + } evt.StopPropagation(); if (marker == LABEL_ITEM_MARKER) return; @@ -1080,8 +1086,10 @@ void PlaterPresetComboBox::update() set_label_marker(Append(separator(L("Add/Remove filaments")), *bmp), LABEL_ITEM_WIZARD_FILAMENTS); else if (m_type == Preset::TYPE_SLA_MATERIAL) set_label_marker(Append(separator(L("Add/Remove materials")), *bmp), LABEL_ITEM_WIZARD_MATERIALS); - else - set_label_marker(Append(separator(L("Add/Remove printers")), *bmp), LABEL_ITEM_WIZARD_PRINTERS); + else { + set_label_marker(Append(separator(L("Select/Remove printers(system presets)")), *bmp), LABEL_ITEM_WIZARD_PRINTERS); + set_label_marker(Append(separator(L("Create printer")), *bmp), LABEL_ITEM_WIZARD_ADD_PRINTERS); + } } update_selection(); @@ -1385,7 +1393,7 @@ GUI::CalibrateFilamentComboBox::CalibrateFilamentComboBox(wxWindow *parent) : PlaterPresetComboBox(parent, Preset::TYPE_FILAMENT) { clr_picker->SetBackgroundColour(*wxWHITE); - clr_picker->SetBitmap(*get_extruder_color_icon("#FFFFFFFF", "", 20, 20)); + clr_picker->SetBitmap(*get_extruder_color_icon("#FFFFFFFF", "", FromDIP(20), FromDIP(20))); clr_picker->SetToolTip(""); clr_picker->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {}); } @@ -1403,7 +1411,7 @@ void GUI::CalibrateFilamentComboBox::load_tray(DynamicPrintConfig &config) m_filament_color = config.opt_string("filament_colour", 0u); m_filament_exist = config.opt_bool("filament_exist", 0u); wxColor clr(m_filament_color); - clr_picker->SetBitmap(*get_extruder_color_icon(m_filament_color, m_tray_name, 20, 20)); + clr_picker->SetBitmap(*get_extruder_color_icon(m_filament_color, m_tray_name, FromDIP(20), FromDIP(20))); #ifdef __WXOSX__ clr_picker->SetLabel(clr_picker->GetLabel()); // Let setBezelStyle: be called clr_picker->Refresh(); @@ -1412,7 +1420,7 @@ void GUI::CalibrateFilamentComboBox::load_tray(DynamicPrintConfig &config) SetValue(_L("Empty")); m_selected_preset = nullptr; m_is_compatible = false; - clr_picker->SetBitmap(*get_extruder_color_icon("#F0F0F0FF", m_tray_name, 20, 20)); + clr_picker->SetBitmap(*get_extruder_color_icon("#F0F0F0FF", m_tray_name, FromDIP(20), FromDIP(20))); } else { auto &filaments = m_collection->get_presets(); auto iter = std::find_if(filaments.begin(), filaments.end(), [this](auto &f) { @@ -1452,9 +1460,8 @@ void GUI::CalibrateFilamentComboBox::update() const Preset* selected_filament_preset = nullptr; - std::map nonsys_presets; - std::map project_embedded_presets; - std::map system_presets; + m_nonsys_presets.clear(); + m_system_presets.clear(); wxString selected_preset = m_selected_preset ? get_preset_name(*m_selected_preset) : GetValue(); @@ -1464,7 +1471,7 @@ void GUI::CalibrateFilamentComboBox::update() for (size_t i = presets.front().is_visible ? 0 : m_collection->num_default_presets(); i < presets.size(); ++i) { const Preset& preset = presets[i]; - auto name = get_preset_name(preset); + auto display_name = get_preset_name(preset); bool is_selected = m_selected_preset == &preset; if (m_preset_bundle->calibrate_filaments.empty()) { Thaw(); @@ -1482,27 +1489,28 @@ void GUI::CalibrateFilamentComboBox::update() wxBitmap* bmp = get_bmp(preset); assert(bmp); - if (preset.is_default || preset.is_system) - system_presets.emplace(name, bmp); - else if (preset.is_project_embedded) - project_embedded_presets.emplace(name, bmp); - else - nonsys_presets.emplace(name, bmp); + if (preset.is_default || preset.is_system) { + m_system_presets.emplace(display_name, std::make_pair( preset.name, bmp )); + } + else { + m_nonsys_presets.emplace(display_name, std::make_pair( preset.name, bmp )); + } + } - if (!nonsys_presets.empty()) + if (!m_nonsys_presets.empty()) { set_label_marker(Append(separator(L("User presets")), wxNullBitmap)); - for (std::map::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { - Append(it->first, *it->second); + for (auto it = m_nonsys_presets.begin(); it != m_nonsys_presets.end(); ++it) { + Append(it->first, *(it->second.second)); validate_selection(it->first == selected_preset); } } - if (!system_presets.empty()) + if (!m_system_presets.empty()) { set_label_marker(Append(separator(L("System presets")), wxNullBitmap)); - for (std::map::iterator it = system_presets.begin(); it != system_presets.end(); ++it) { - Append(it->first, *it->second); + for (auto it = m_system_presets.begin(); it != m_system_presets.end(); ++it) { + Append(it->first, *(it->second.second)); validate_selection(it->first == selected_preset); } } @@ -1513,19 +1521,39 @@ void GUI::CalibrateFilamentComboBox::update() SetToolTip(NULL); } +void GUI::CalibrateFilamentComboBox::msw_rescale() +{ + if (clr_picker) { + clr_picker->SetSize(FromDIP(20), FromDIP(20)); + clr_picker->SetBitmap(*get_extruder_color_icon(m_filament_color, m_tray_name, FromDIP(20), FromDIP(20))); + } + // BBS + if (edit_btn != nullptr) + edit_btn->msw_rescale(); +} + void GUI::CalibrateFilamentComboBox::OnSelect(wxCommandEvent &evt) { auto marker = reinterpret_cast(this->GetClientData(evt.GetSelection())); if (marker >= LABEL_ITEM_DISABLED && marker < LABEL_ITEM_MAX) { this->SetSelection(evt.GetSelection() + 1); + wxCommandEvent event(wxEVT_COMBOBOX); + event.SetInt(evt.GetSelection() + 1); + event.SetString(GetString(evt.GetSelection() + 1)); + wxPostEvent(this, event); return; } m_is_compatible = true; static_cast(m_parent)->Enable(true); - std::string selected_name = evt.GetString().ToUTF8().data(); - selected_name = Preset::remove_suffix_modified(selected_name); - std::string preset_name = m_collection->get_preset_name_by_alias(selected_name); + wxString display_name = evt.GetString(); + std::string preset_name; + if (m_system_presets.find(evt.GetString()) != m_system_presets.end()) { + preset_name = m_system_presets.at(display_name).first; + } + else if (m_nonsys_presets.find(evt.GetString()) != m_nonsys_presets.end()) { + preset_name = m_nonsys_presets.at(display_name).first; + } m_selected_preset = m_collection->find_preset(preset_name); // if the selected preset is null, do not send tray_change event diff --git a/src/slic3r/GUI/PresetComboBoxes.hpp b/src/slic3r/GUI/PresetComboBoxes.hpp index 4e13adc384f..4598b3dc327 100644 --- a/src/slic3r/GUI/PresetComboBoxes.hpp +++ b/src/slic3r/GUI/PresetComboBoxes.hpp @@ -45,6 +45,7 @@ class PresetComboBox : public ::ComboBox // BBS LABEL_ITEM_WIZARD_PRINTERS, LABEL_ITEM_WIZARD_FILAMENTS, LABEL_ITEM_WIZARD_MATERIALS, + LABEL_ITEM_WIZARD_ADD_PRINTERS, LABEL_ITEM_MAX, }; @@ -227,6 +228,7 @@ class CalibrateFilamentComboBox : public PlaterPresetComboBox void load_tray(DynamicPrintConfig & config); void update() override; + void msw_rescale() override; void OnSelect(wxCommandEvent &evt) override; const Preset* get_selected_preset() { return m_selected_preset; } std::string get_tray_name() { return m_tray_name; } @@ -243,6 +245,8 @@ class CalibrateFilamentComboBox : public PlaterPresetComboBox bool m_filament_exist{false}; bool m_is_compatible{true}; const Preset* m_selected_preset = nullptr; + std::map> m_nonsys_presets; + std::map> m_system_presets; }; } // namespace GUI diff --git a/src/slic3r/GUI/PrintOptionsDialog.cpp b/src/slic3r/GUI/PrintOptionsDialog.cpp index 04106abc6fd..9fee1c6fc75 100644 --- a/src/slic3r/GUI/PrintOptionsDialog.cpp +++ b/src/slic3r/GUI/PrintOptionsDialog.cpp @@ -61,6 +61,12 @@ PrintOptionsDialog::PrintOptionsDialog(wxWindow* parent) } evt.Skip(); }); + m_cb_filament_tangle->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent& evt) { + if (obj) { + obj->command_xcam_control_filament_tangle_detect(m_cb_filament_tangle->GetValue()); + } + evt.Skip(); + }); wxGetApp().UpdateDlgDarkUI(this); } @@ -88,7 +94,7 @@ void PrintOptionsDialog::update_ai_monitor_status() void PrintOptionsDialog::update_options(MachineObject* obj_) { if (!obj_) return; - if (obj_->is_function_supported(PrinterFunction::FUNC_AI_MONITORING)) { + if (obj_->is_support_ai_monitoring) { text_ai_monitoring->Show(); m_cb_ai_monitoring->Show(); text_ai_monitoring_caption->Show(); @@ -103,7 +109,7 @@ void PrintOptionsDialog::update_options(MachineObject* obj_) line1->Hide(); } - if (obj_->is_function_supported(PrinterFunction::FUNC_BUILDPLATE_MARKER_DETECT)) { + if (obj_->is_support_build_plate_marker_detect) { text_plate_mark->Show(); m_cb_plate_mark->Show(); text_plate_mark_caption->Show(); @@ -116,7 +122,7 @@ void PrintOptionsDialog::update_options(MachineObject* obj_) line2->Hide(); } - if (obj_->is_function_supported(PrinterFunction::FUNC_FIRSTLAYER_INSPECT)) { + if (obj_->is_support_first_layer_inspect) { text_first_layer->Show(); m_cb_first_layer->Show(); line3->Show(); @@ -127,7 +133,7 @@ void PrintOptionsDialog::update_options(MachineObject* obj_) line3->Hide(); } - if (obj_->is_function_supported(PrinterFunction::FUNC_AUTO_RECOVERY_STEP_LOSS)) { + if (obj_->is_support_auto_recovery_step_loss) { text_auto_recovery->Show(); m_cb_auto_recovery->Show(); line4->Show(); @@ -137,7 +143,7 @@ void PrintOptionsDialog::update_options(MachineObject* obj_) m_cb_auto_recovery->Hide(); line4->Hide(); } - if (obj_->is_function_supported(PrinterFunction::FUNC_PROMPT_SOUND)) { + if (obj_->is_support_prompt_sound) { text_sup_sound->Show(); m_cb_sup_sound->Show(); line5->Show(); @@ -147,6 +153,16 @@ void PrintOptionsDialog::update_options(MachineObject* obj_) m_cb_sup_sound->Hide(); line5->Hide(); } + if (obj_->is_support_filament_tangle_detect) { + text_filament_tangle->Show(); + m_cb_filament_tangle->Show(); + line6->Show(); + } + else { + text_filament_tangle->Hide(); + m_cb_filament_tangle->Hide(); + line6->Hide(); + } this->Freeze(); @@ -154,6 +170,7 @@ void PrintOptionsDialog::update_options(MachineObject* obj_) m_cb_plate_mark->SetValue(obj_->xcam_buildplate_marker_detector); m_cb_auto_recovery->SetValue(obj_->xcam_auto_recovery_step_loss); m_cb_sup_sound->SetValue(obj_->xcam_allow_prompt_sound); + m_cb_filament_tangle->SetValue(obj_->xcam_filament_tangle_detect); m_cb_ai_monitoring->SetValue(obj_->xcam_ai_monitoring); for (auto i = AiMonitorSensitivityLevel::LOW; i < LEVELS_NUM; i = (AiMonitorSensitivityLevel) (i + 1)) { @@ -202,6 +219,11 @@ wxBoxSizer* PrintOptionsDialog::create_settings_group(wxWindow* parent) ai_monitoring_level_list->Append(level_option); } + if (ai_monitoring_level_list->GetCount() > 0) { + ai_monitoring_level_list->SetSelection(0); + } + + line_sizer->Add(FromDIP(30), 0, 0, 0); line_sizer->Add(text_ai_monitoring_caption, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); line_sizer->Add( ai_monitoring_level_list, 0, wxEXPAND|wxALL, FromDIP(5) ); @@ -286,6 +308,23 @@ wxBoxSizer* PrintOptionsDialog::create_settings_group(wxWindow* parent) line5 = new StaticLine(parent, false); line5->SetLineColour(STATIC_BOX_LINE_COL); sizer->Add(line5, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20)); + sizer->Add(0, 0, 0, wxTOP, FromDIP(20)); + + //filament tangle detect + line_sizer = new wxBoxSizer(wxHORIZONTAL); + m_cb_filament_tangle = new CheckBox(parent); + text_filament_tangle = new wxStaticText(parent, wxID_ANY, _L("Fliament Tangle Detect")); + text_filament_tangle->SetFont(Label::Body_14); + line_sizer->Add(FromDIP(5), 0, 0, 0); + line_sizer->Add(m_cb_filament_tangle, 0, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + line_sizer->Add(text_filament_tangle, 1, wxALL | wxALIGN_CENTER_VERTICAL, FromDIP(5)); + sizer->Add(0, 0, 0, wxTOP, FromDIP(15)); + sizer->Add(line_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(18)); + line_sizer->Add(FromDIP(5), 0, 0, 0); + + line6 = new StaticLine(parent, false); + line6->SetLineColour(STATIC_BOX_LINE_COL); + sizer->Add(line6, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20)); ai_monitoring_level_list->Connect( wxEVT_COMBOBOX, wxCommandEventHandler(PrintOptionsDialog::set_ai_monitor_sensitivity), NULL, this ); diff --git a/src/slic3r/GUI/PrintOptionsDialog.hpp b/src/slic3r/GUI/PrintOptionsDialog.hpp index e348d64faf4..21865bda3c7 100644 --- a/src/slic3r/GUI/PrintOptionsDialog.hpp +++ b/src/slic3r/GUI/PrintOptionsDialog.hpp @@ -27,6 +27,7 @@ class PrintOptionsDialog : public DPIDialog CheckBox* m_cb_plate_mark; CheckBox* m_cb_auto_recovery; CheckBox* m_cb_sup_sound; + CheckBox* m_cb_filament_tangle; wxStaticText* text_first_layer; wxStaticText* text_ai_monitoring; wxStaticText* text_ai_monitoring_caption; @@ -35,11 +36,13 @@ class PrintOptionsDialog : public DPIDialog wxStaticText* text_plate_mark_caption; wxStaticText* text_auto_recovery; wxStaticText* text_sup_sound; + wxStaticText* text_filament_tangle; StaticLine* line1; StaticLine* line2; StaticLine* line3; StaticLine* line4; StaticLine* line5; + StaticLine* line6; wxBoxSizer* create_settings_group(wxWindow* parent); bool print_halt = false; diff --git a/src/slic3r/GUI/Printer/PrinterFileSystem.cpp b/src/slic3r/GUI/Printer/PrinterFileSystem.cpp index ca7718fabac..71483a6665e 100644 --- a/src/slic3r/GUI/Printer/PrinterFileSystem.cpp +++ b/src/slic3r/GUI/Printer/PrinterFileSystem.cpp @@ -19,6 +19,16 @@ //#define PRINTER_FILE_SYSTEM_TEST #endif +std::string last_system_error() { + return Slic3r::decode_path(std::error_code( +#ifdef _WIN32 + GetLastError(), +#else + errno, +#endif + std::system_category()).message().c_str()); +} + wxDEFINE_EVENT(EVT_STATUS_CHANGED, wxCommandEvent); wxDEFINE_EVENT(EVT_MODE_CHANGED, wxCommandEvent); wxDEFINE_EVENT(EVT_FILE_CHANGED, wxCommandEvent); @@ -31,6 +41,10 @@ wxDEFINE_EVENT(EVT_FILE_CALLBACK, wxCommandEvent); static wxBitmap default_thumbnail; static std::map error_messages = { + {PrinterFileSystem::ERROR_PIPE, L("Connection lost. Please retry.")}, + {PrinterFileSystem::ERROR_RES_BUSY, L("The device cannot handle more conversations. Please retry later.")}, + {PrinterFileSystem::FILE_NO_EXIST, L("File not exists.")}, + {PrinterFileSystem::FILE_CHECK_ERR, L("File checksum error. Please retry.")}, {PrinterFileSystem::FILE_TYPE_ERR, L("Not supported on the current printer version.")}, {PrinterFileSystem::STORAGE_UNAVAILABLE, L("Storage unavailable, insert SD card.")} }; @@ -146,8 +160,12 @@ void PrinterFileSystem::ListAllFiles() }, [this, type = m_file_type](int result, FileList list) { if (result != 0) { m_last_error = result; - m_status = Status::ListReady; + m_status = Status::Failed; + m_file_list.clear(); + BuildGroups(); + UpdateGroupSelect(); SendChangedEvent(EVT_STATUS_CHANGED, m_status, "", result); + SendChangedEvent(EVT_FILE_CHANGED); return 0; } if (type != m_file_type) @@ -220,6 +238,7 @@ struct PrinterFileSystem::Download : Progress std::string name; std::string path; std::string local_path; + std::string error; boost::filesystem::ofstream ofs; boost::uuids::detail::md5 boost_md5; }; @@ -252,6 +271,7 @@ void PrinterFileSystem::DownloadFiles(size_t index, std::string const &path) download->local_path = (boost::filesystem::path(path) / file.name).string(); file.download = download; } + boost::filesystem::create_directories(path); if ((m_task_flags & FF_DOWNLOAD) == 0) DownloadNextFile(); } @@ -492,6 +512,7 @@ void PrinterFileSystem::Start() void PrinterFileSystem::Retry() { boost::unique_lock l(m_mutex); + m_stopped = false; m_cond.notify_all(); } @@ -629,13 +650,22 @@ void PrinterFileSystem::DownloadNextFile() prog.total = resp["total"]; if (prog.size == 0) { download->ofs.open(download->local_path, std::ios::binary); - if (!download->ofs) return FILE_OPEN_ERR; + if (!download->ofs) { + download->error = last_system_error(); + wxLogWarning("PrinterFileSystem::DownloadNextFile open error: %s\n", wxString::FromUTF8(download->error)); + return FILE_OPEN_ERR; + } } if (download->total && (download->size != prog.size || download->total != prog.total)) { wxLogWarning("PrinterFileSystem::DownloadNextFile data error: %d != %d\n", download->size, prog.size); } // receive data download->ofs.write((char const *) data, size); + if (!download->ofs) { + download->error = last_system_error(); + wxLogWarning("PrinterFileSystem::DownloadNextFile write error: %s\n", wxString::FromUTF8(download->error)); + return FILE_READ_WRITE_ERR; + } download->boost_md5.process_bytes(data, size); prog.size += size; download->total = prog.total; @@ -688,7 +718,7 @@ void PrinterFileSystem::DownloadNextFile() else // FAILED file.download.reset(); if (&file_index.first == &m_file_list) - SendChangedEvent(EVT_DOWNLOAD, download->index, file.local_path, result); + SendChangedEvent(EVT_DOWNLOAD, download->index, result ? download->error : file.local_path, result); } } if (result != CONTINUE) DownloadNextFile(); @@ -819,6 +849,7 @@ void PrinterFileSystem::UpdateFocusThumbnail2(std::shared_ptr> if (!thumbnail.empty()) { arr.push_back(file.path + "#" + thumbnail); file.flags &= ~FF_THUMNAIL; + file.local_path.clear(); } } } @@ -845,6 +876,7 @@ void PrinterFileSystem::UpdateFocusThumbnail2(std::shared_ptr> } auto n = type == ModelMetadata ? std::string::npos : path.find_last_of('#'); // ModelMetadata is zipped without subpath auto path2 = n == std::string::npos ? path : path.substr(0, n); + auto subpath = n == std::string::npos ? path : path.substr(n + 1); auto iter = std::find_if(files->begin(), files->end(), [&path2](auto &f) { return f.path == path2; }); if (cont) { if (iter != files->end()) @@ -859,10 +891,12 @@ void PrinterFileSystem::UpdateFocusThumbnail2(std::shared_ptr> ParseThumbnail(file); } else { if (mimetype.empty()) { - if (!path.empty()) thumbnail = path; - auto n = thumbnail.find_last_of('.'); + if (subpath.empty()) subpath = thumbnail; + auto n = subpath.find_last_of('.'); if (n != std::string::npos) - mimetype = "image/" + thumbnail.substr(n + 1); + mimetype = "image/" + subpath.substr(n + 1); + else if (subpath == "thumbnail") + mimetype = "image/jpeg"; // default jpg } if (iter != files->end() && !iter->local_path.empty()) { iter->local_path += std::string((char *) data, size); @@ -966,7 +1000,7 @@ void PrinterFileSystem::FileRemoved(std::pair type, size_ m_group_flags.erase(m_group_flags.begin() + index2); } } - m_file_list.erase(m_file_list.begin() + index); + m_file_list.erase(file_index.first.begin() + index); } struct CallbackEvent : wxCommandEvent @@ -991,7 +1025,9 @@ void PrinterFileSystem::SendChangedEvent(wxEventType type, size_t index, std::st if (!str.empty()) event.SetString(wxString::FromUTF8(str.c_str())); else if (auto iter = error_messages.find(extra); iter != error_messages.end()) - event.SetString(wxString::FromUTF8(iter->second.c_str())); + event.SetString(_L(iter->second.c_str())); + else if (extra > CONTINUE && extra != ERROR_CANCEL) + event.SetString(wxString::Format(_L("Error code: %d"), int(extra))); event.SetExtraLong(extra); if (wxThread::IsMain()) ProcessEventLocally(event); @@ -1008,8 +1044,11 @@ void PrinterFileSystem::DumpLog(void * thiz, int, tchar const *msg) boost::uint32_t PrinterFileSystem::SendRequest(int type, json const &req, callback_t2 const &callback) { if (m_session.tunnel == nullptr) { - boost::unique_lock l(m_mutex); - m_cond.notify_all(); + { + boost::unique_lock l(m_mutex); + m_cond.notify_all(); + } + callback(ERROR_PIPE, json(), nullptr); return 0; } boost::uint32_t seq = m_sequence + m_callbacks.size(); @@ -1055,23 +1094,28 @@ void PrinterFileSystem::CancelRequests(std::vector const &seqs) void PrinterFileSystem::CancelRequests2(std::vector const &seqs) { - std::deque callbacks; + std::vector> callbacks; boost::unique_lock l(m_mutex); for (auto &f : seqs) { boost::uint32_t seq = f; seq -= m_sequence; - if (size_t(seq) >= m_callbacks.size()) continue; + if (size_t(seq) >= m_callbacks.size()) + continue; auto &c = m_callbacks[seq]; - if (c == nullptr) continue; - callbacks.push_back(c); - m_callbacks[seq] = callback_t2(); + if (c == nullptr) + continue; + callbacks.emplace_back(f, c); + c = nullptr; } while (!m_callbacks.empty() && m_callbacks.front() == nullptr) { m_callbacks.pop_front(); ++m_sequence; } l.unlock(); - for (auto &c : callbacks) c(ERROR_CANCEL, json(), nullptr); + for (auto &c : callbacks) { + wxLogInfo("PrinterFileSystem::CancelRequests2: %u\n", c.first); + c.second(ERROR_CANCEL, json(), nullptr); + } } void PrinterFileSystem::RecvMessageThread() @@ -1109,7 +1153,9 @@ void PrinterFileSystem::RecvMessageThread() if (n == 0) { HandleResponse(l, sample); } else if (n == Bambu_stream_end) { - Reconnect(l, 3); + if (m_status == ListSyncing) + m_stopped = true; + Reconnect(l, m_status == ListSyncing ? ERROR_RES_BUSY : ERROR_PIPE); } else if (n == Bambu_would_block) { m_cond.timed_wait(l, boost::posix_time::milliseconds(m_messages.empty() && m_callbacks.empty() ? 1000 : 20)); } else { @@ -1162,27 +1208,35 @@ void PrinterFileSystem::HandleResponse(boost::unique_lock &l, Bamb n(result, resp, json_end); l.lock(); } else { - seq -= m_sequence; - if (size_t(seq) >= m_callbacks.size()) return; - auto c = m_callbacks[seq]; + int seq2 = seq - m_sequence; + if (size_t(seq2) >= m_callbacks.size()) return; + auto c = m_callbacks[seq2]; if (c == nullptr) return; - seq += m_sequence; l.unlock(); - result = c(result, resp, json_end); + int result2 = c(result, resp, json_end); l.lock(); - if (result != CONTINUE) { - seq -= m_sequence; - m_callbacks[seq] = callback_t2(); - if (seq == 0) { + if (result2 != CONTINUE) { + int seq2 = seq - m_sequence; + m_callbacks[seq2] = callback_t2(); + if (seq2 == 0) { while (!m_callbacks.empty() && m_callbacks.front() == nullptr) { m_callbacks.pop_front(); ++m_sequence; } } + if (result == CONTINUE) { + l.unlock(); + CancelRequest(seq); + l.lock(); + } } } } +namespace Slic3r { namespace GUI { + extern wxString hide_passwd(wxString url, std::vector const &passwords); +}} + void PrinterFileSystem::Reconnect(boost::unique_lock &l, int result) { if (m_session.tunnel) { @@ -1224,7 +1278,7 @@ void PrinterFileSystem::Reconnect(boost::unique_lock &l, int resul wxLogMessage("PrinterFileSystem::Reconnect Initialize failed: %s", wxString::FromUTF8(url)); m_last_error = atoi(url.c_str()); } else { - wxLogMessage("PrinterFileSystem::Reconnect Initialized: %s", wxString::FromUTF8(url)); + wxLogMessage("PrinterFileSystem::Reconnect Initialized: %s", Slic3r::GUI::hide_passwd(wxString::FromUTF8(url), {"authkey=", "passwd="})); l.unlock(); m_status = Status::Connecting; wxLogMessage("PrinterFileSystem::Reconnect Connecting"); @@ -1259,7 +1313,7 @@ void PrinterFileSystem::Reconnect(boost::unique_lock &l, int resul #ifdef PRINTER_FILE_SYSTEM_TEST PostCallback([this] { SendChangedEvent(EVT_FILE_CHANGED); }); #else - PostCallback([this] { ListAllFiles(); }); + PostCallback([this] { m_task_flags = 0; ListAllFiles(); }); #endif } diff --git a/src/slic3r/GUI/Printer/PrinterFileSystem.h b/src/slic3r/GUI/Printer/PrinterFileSystem.h index 8caf720ce9f..d648b785b35 100644 --- a/src/slic3r/GUI/Printer/PrinterFileSystem.h +++ b/src/slic3r/GUI/Printer/PrinterFileSystem.h @@ -44,11 +44,13 @@ class PrinterFileSystem : public wxEvtHandler, public boost::enable_shared_from_ ERROR_JSON = 2, ERROR_PIPE = 3, ERROR_CANCEL = 4, + ERROR_RES_BUSY = 5, + FILE_NO_EXIST = 10, FILE_NAME_INVALID = 11, FILE_SIZE_ERR = 12, FILE_OPEN_ERR = 13, - FILE_READ_ERR = 14, + FILE_READ_WRITE_ERR = 14, FILE_CHECK_ERR = 15, FILE_TYPE_ERR = 16, STORAGE_UNAVAILABLE = 17, diff --git a/src/slic3r/GUI/Project.cpp b/src/slic3r/GUI/Project.cpp index 1d6e535bd71..aefffccc094 100644 --- a/src/slic3r/GUI/Project.cpp +++ b/src/slic3r/GUI/Project.cpp @@ -58,6 +58,7 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, main_sizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); m_browser->Bind(wxEVT_WEBVIEW_NAVIGATED, &ProjectPanel::on_navigated, this); m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ProjectPanel::OnScriptMessage, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_NAVIGATING, &ProjectPanel::onWebNavigating, this, m_browser->GetId()); Bind(EVT_PROJECT_RELOAD, &ProjectPanel::on_reload, this); @@ -68,6 +69,19 @@ ProjectPanel::ProjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, ProjectPanel::~ProjectPanel() {} + +void ProjectPanel::onWebNavigating(wxWebViewEvent& evt) +{ + wxString tmpUrl = evt.GetURL(); + //wxString NowUrl = m_browser->GetCurrentURL(); + + if (boost::starts_with(tmpUrl, "http://") || boost::starts_with(tmpUrl, "https://")) { + m_browser->Stop(); + evt.Veto(); + wxLaunchDefaultApplication(tmpUrl); + } +} + void ProjectPanel::on_reload(wxCommandEvent& evt) { boost::thread reload = boost::thread([this] { @@ -350,6 +364,7 @@ std::string ProjectPanel::formatBytes(unsigned long bytes) wxString ProjectPanel::to_base64(std::string file_path) { + std::ifstream imageFile(encode_path(file_path.c_str()), std::ios::binary); if (!imageFile) { return wxEmptyString; @@ -362,7 +377,7 @@ wxString ProjectPanel::to_base64(std::string file_path) std::string extension; size_t last_dot = file_path.find_last_of("."); - + if (last_dot != std::string::npos) { extension = file_path.substr(last_dot + 1); } diff --git a/src/slic3r/GUI/Project.hpp b/src/slic3r/GUI/Project.hpp index 0bde9eed955..70aa3348e0d 100644 --- a/src/slic3r/GUI/Project.hpp +++ b/src/slic3r/GUI/Project.hpp @@ -73,6 +73,7 @@ class ProjectPanel : public wxPanel ~ProjectPanel(); + void onWebNavigating(wxWebViewEvent& evt); void on_reload(wxCommandEvent& evt); void on_size(wxSizeEvent &event); void on_navigated(wxWebViewEvent& event); diff --git a/src/slic3r/GUI/ProjectDirtyStateManager.cpp b/src/slic3r/GUI/ProjectDirtyStateManager.cpp index 5d32ca34819..ab7f4cf45a4 100644 --- a/src/slic3r/GUI/ProjectDirtyStateManager.cpp +++ b/src/slic3r/GUI/ProjectDirtyStateManager.cpp @@ -35,12 +35,14 @@ void ProjectDirtyStateManager::update_from_presets() if (ConfigOption *color_option = wxGetApp().preset_bundle->project_config.option("filament_colour")) { auto colors = static_cast(color_option->clone()); m_presets_dirty |= m_initial_filament_presets_colors != colors->values; + delete colors; } } else { m_presets_dirty |= !m_initial_presets[type].empty() && m_initial_presets[type] != name; } } - + } else { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "project file name is empty"; } m_presets_dirty |= app.has_unsaved_preset_changes(); m_project_config_dirty = m_initial_project_config != app.preset_bundle->project_config; @@ -66,6 +68,7 @@ void ProjectDirtyStateManager::reset_initial_presets() if (ConfigOption *color_option = wxGetApp().preset_bundle->project_config.option("filament_colour")) { auto colors = static_cast(color_option->clone()); m_initial_filament_presets_colors = colors->values; + delete colors; } } else { m_initial_presets[type] = name; diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp index 02bfb7f9b11..05132945ceb 100644 --- a/src/slic3r/GUI/ReleaseNote.cpp +++ b/src/slic3r/GUI/ReleaseNote.cpp @@ -32,6 +32,7 @@ wxDEFINE_EVENT(EVT_ENTER_IP_ADDRESS, wxCommandEvent); wxDEFINE_EVENT(EVT_CLOSE_IPADDRESS_DLG, wxCommandEvent); wxDEFINE_EVENT(EVT_CHECK_IP_ADDRESS_FAILED, wxCommandEvent); wxDEFINE_EVENT(EVT_SECONDARY_CHECK_RETRY, wxCommandEvent); +wxDEFINE_EVENT(EVT_UPDATE_NOZZLE, wxCommandEvent); ReleaseNoteDialog::ReleaseNoteDialog(Plater *plater /*= nullptr*/) : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, _L("Release Note"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) @@ -287,7 +288,16 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) m_vebview_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430))); m_vebview_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430))); //m_vebview_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430))); - + m_vebview_release_note->Bind(wxEVT_WEBVIEW_NAVIGATING,[=](wxWebViewEvent& event){ + static bool load_url_first = false; + if(load_url_first){ + wxLaunchDefaultBrowser(url_line); + event.Veto(); + }else{ + load_url_first = true; + } + + }); fs::path ph(data_dir()); ph /= "resources/tooltip/releasenote.html"; @@ -304,9 +314,11 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) m_simplebook_release_note->AddPage(m_vebview_release_note, wxEmptyString, false); - m_remind_choice = new wxCheckBox( this, wxID_ANY, _L("Don't remind me of this version again"), wxDefaultPosition, wxDefaultSize, 0 ); - m_remind_choice->SetValue(false); - m_remind_choice->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &UpdateVersionDialog::alter_choice,this); + + m_bitmap_open_in_browser = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("open_in_browser", this, 12), wxDefaultPosition, wxDefaultSize, 0 ); + m_link_open_in_browser = new wxHyperlinkCtrl(this, wxID_ANY, "Open in browser", ""); + m_link_open_in_browser->SetFont(Label::Body_12); + auto sizer_button = new wxBoxSizer(wxHORIZONTAL); @@ -317,19 +329,33 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), std::pair(*wxWHITE, StateColor::Normal)); - m_button_ok = new Button(this, _L("OK")); - m_button_ok->SetBackgroundColor(btn_bg_green); - m_button_ok->SetBorderColor(*wxWHITE); - m_button_ok->SetTextColor(wxColour("#FFFFFE")); - m_button_ok->SetFont(Label::Body_12); - m_button_ok->SetSize(wxSize(FromDIP(58), FromDIP(24))); - m_button_ok->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); - m_button_ok->SetCornerRadius(FromDIP(12)); + m_button_download = new Button(this, _L("Download")); + m_button_download->SetBackgroundColor(btn_bg_green); + m_button_download->SetBorderColor(*wxWHITE); + m_button_download->SetTextColor(wxColour("#FFFFFE")); + m_button_download->SetFont(Label::Body_12); + m_button_download->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_download->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_download->SetCornerRadius(FromDIP(12)); - m_button_ok->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + m_button_download->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { EndModal(wxID_YES); }); + m_button_skip_version = new Button(this, _L("Skip this Version")); + m_button_skip_version->SetBackgroundColor(btn_bg_white); + m_button_skip_version->SetBorderColor(wxColour(38, 46, 48)); + m_button_skip_version->SetFont(Label::Body_12); + m_button_skip_version->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_skip_version->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_skip_version->SetCornerRadius(FromDIP(12)); + + m_button_skip_version->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + wxGetApp().set_skip_version(true); + EndModal(wxID_NO); + }); + + m_button_cancel = new Button(this, _L("Cancel")); m_button_cancel->SetBackgroundColor(btn_bg_white); m_button_cancel->SetBorderColor(wxColour(38, 46, 48)); @@ -343,10 +369,13 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) }); m_sizer_main->Add(m_line_top, 0, wxEXPAND | wxBOTTOM, 0); - - sizer_button->Add(m_remind_choice, 0, wxALL | wxEXPAND, FromDIP(5)); + + sizer_button->Add(m_bitmap_open_in_browser, 0, wxALIGN_CENTER | wxLEFT, FromDIP(7)); + sizer_button->Add(m_link_open_in_browser, 0, wxALIGN_CENTER| wxLEFT, FromDIP(3)); + //sizer_button->Add(m_remind_choice, 0, wxALL | wxEXPAND, FromDIP(5)); sizer_button->AddStretchSpacer(); - sizer_button->Add(m_button_ok, 0, wxALL, FromDIP(5)); + sizer_button->Add(m_button_download, 0, wxALL, FromDIP(5)); + sizer_button->Add(m_button_skip_version, 0, wxALL, FromDIP(5)); sizer_button->Add(m_button_cancel, 0, wxALL, FromDIP(5)); m_sizer_right->Add(m_text_up_info, 0, wxEXPAND | wxBOTTOM | wxTOP, FromDIP(15)); @@ -371,10 +400,6 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) UpdateVersionDialog::~UpdateVersionDialog() {} -void UpdateVersionDialog::alter_choice(wxCommandEvent& event) -{ - wxGetApp().set_skip_version(m_remind_choice->GetValue()); -} wxWebView* UpdateVersionDialog::CreateTipView(wxWindow* parent) { @@ -435,7 +460,8 @@ void UpdateVersionDialog::RunScript(std::string script) } void UpdateVersionDialog::on_dpi_changed(const wxRect &suggested_rect) { - m_button_ok->Rescale(); + m_button_download->Rescale(); + m_button_skip_version->Rescale(); m_button_cancel->Rescale(); } @@ -462,7 +488,7 @@ void UpdateVersionDialog::update_version_info(wxString release_note, wxString ve { //bbs check whether the web display is used bool use_web_link = false; - std::string url_line = ""; + url_line = ""; auto split_array = splitWithStl(release_note.ToStdString(), "###"); if (split_array.size() >= 3) { @@ -482,6 +508,7 @@ void UpdateVersionDialog::update_version_info(wxString release_note, wxString ve m_text_up_info->Hide(); m_simplebook_release_note->SetSelection(1); m_vebview_release_note->LoadURL(from_u8(url_line)); + m_link_open_in_browser->SetURL(url_line); } else { m_simplebook_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430))); @@ -651,6 +678,7 @@ SecondaryCheckDialog::SecondaryCheckDialog(wxWindow* parent, wxWindowID id, cons m_sizer_main->Add(m_sizer_right, 0, wxBOTTOM | wxEXPAND, FromDIP(5)); Bind(wxEVT_CLOSE_WINDOW, [this](auto& e) {this->on_hide();}); + Bind(wxEVT_ACTIVATE, [this](auto& e) { if (!e.GetActive()) this->RequestUserAttention(wxUSER_ATTENTION_ERROR); }); SetSizer(m_sizer_main); Layout(); @@ -872,9 +900,27 @@ ConfirmBeforeSendDialog::ConfirmBeforeSendDialog(wxWindow* parent, wxWindowID id m_button_cancel->Hide(); else m_button_cancel->Show(); + + m_button_update_nozzle = new Button(this, _L("Confirm and Update Nozzle")); + m_button_update_nozzle->SetBackgroundColor(btn_bg_white); + m_button_update_nozzle->SetBorderColor(wxColour(38, 46, 48)); + m_button_update_nozzle->SetFont(Label::Body_12); + m_button_update_nozzle->SetSize(wxSize(-1, FromDIP(24))); + m_button_update_nozzle->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_update_nozzle->SetCornerRadius(FromDIP(12)); + + m_button_update_nozzle->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { + wxCommandEvent evt(EVT_UPDATE_NOZZLE); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); + this->on_hide(); + }); + + m_button_update_nozzle->Hide(); sizer_button->AddStretchSpacer(); sizer_button->Add(m_button_ok, 0, wxALL, FromDIP(5)); + sizer_button->Add(m_button_update_nozzle, 0, wxALL, FromDIP(5)); sizer_button->Add(m_button_cancel, 0, wxALL, FromDIP(5)); sizer_button->Add(FromDIP(5),0, 0, 0); bottom_sizer->Add(sizer_button, 0, wxEXPAND | wxRIGHT | wxLEFT, 0); @@ -980,6 +1026,12 @@ void ConfirmBeforeSendDialog::on_dpi_changed(const wxRect& suggested_rect) rescale(); } +void ConfirmBeforeSendDialog::show_update_nozzle_button() +{ + m_button_update_nozzle->Show(true); + Layout(); +} + void ConfirmBeforeSendDialog::rescale() { m_button_ok->Rescale(); @@ -993,10 +1045,12 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); SetBackgroundColour(*wxWHITE); + m_result = -1; wxBoxSizer* m_sizer_body = new wxBoxSizer(wxVERTICAL); wxBoxSizer* m_sizer_main = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* m_sizer_main_left = new wxBoxSizer(wxVERTICAL); wxBoxSizer* m_sizer_main_right = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* m_sizer_msg = new wxBoxSizer(wxHORIZONTAL); auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1)); m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); @@ -1045,31 +1099,37 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) m_input_area->Add(0, 0, 0, wxLEFT, FromDIP(16)); m_input_area->Add(m_input_access_code, 0, wxALIGN_CENTER, 0); - m_error_msg = new Label(this, Label::Body_13, wxEmptyString, LB_AUTO_WRAP); - m_error_msg->SetForegroundColour(wxColour(208,27,27)); - m_error_msg->Hide(); + m_test_right_msg = new Label(this, Label::Body_13, wxEmptyString, LB_AUTO_WRAP); + m_test_right_msg->SetForegroundColour(wxColour(38, 166, 154)); + m_test_right_msg->Hide(); + + + m_test_wrong_msg = new Label(this, Label::Body_13, wxEmptyString, LB_AUTO_WRAP); + m_test_wrong_msg->SetForegroundColour(wxColour(208, 27, 27)); + m_test_wrong_msg->Hide(); m_tip3 = new Label(this, Label::Body_12, _L("Where to find your printer's IP and Access Code?"), LB_AUTO_WRAP); m_tip3->SetMinSize(wxSize(FromDIP(352), -1)); m_tip3->SetMaxSize(wxSize(FromDIP(352), -1)); - m_img_help1 = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("input_accesscode_help1", this, 198), wxDefaultPosition, wxSize(FromDIP(352), FromDIP(198)), 0); + m_tip4 = new Label(this, ::Label::Body_13, _L("Step 3: Ping the IP address to check for packet loss and latency."), LB_AUTO_WRAP); + m_tip4->SetMinSize(wxSize(FromDIP(352), -1)); + m_tip4->SetMaxSize(wxSize(FromDIP(352), -1)); - m_img_help2 = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("input_accesscode_help2", this, 118), wxDefaultPosition, wxSize(FromDIP(352), FromDIP(118)), 0); - - m_img_help1->Hide(); - m_img_help2->Hide(); + m_trouble_shoot = new wxHyperlinkCtrl(this, wxID_ANY, "How to trouble shooting", ""); + m_img_help = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("input_access_code_x1_en", this, 198), wxDefaultPosition, wxSize(FromDIP(352), -1), 0); + - auto sizer_button = new wxBoxSizer(wxHORIZONTAL); + auto m_sizer_button = new wxBoxSizer(wxHORIZONTAL); - StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + StateColor btn_bg_green(std::pair(wxColour(38, 166, 154), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), std::pair(*wxWHITE, StateColor::Normal)); - m_button_ok = new Button(this, _L("OK")); + m_button_ok = new Button(this, _L("Test")); m_button_ok->SetBackgroundColor(btn_bg_green); m_button_ok->SetBorderColor(*wxWHITE); m_button_ok->SetTextColor(wxColour(0xFFFFFE)); @@ -1081,7 +1141,7 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) m_button_ok->Bind(wxEVT_LEFT_DOWN, &InputIpAddressDialog::on_ok, this); - auto m_button_cancel = new Button(this, _L("Cancel")); + auto m_button_cancel = new Button(this, _L("Close")); m_button_cancel->SetBackgroundColor(btn_bg_white); m_button_cancel->SetBorderColor(wxColour(38, 46, 48)); m_button_cancel->SetFont(Label::Body_12); @@ -1093,9 +1153,11 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) on_cancel(); }); - sizer_button->AddStretchSpacer(); - sizer_button->Add(m_button_ok, 0, wxALL, FromDIP(5)); - sizer_button->Add(m_button_cancel, 0, wxALL, FromDIP(5)); + m_sizer_button->AddStretchSpacer(); + //m_sizer_button->Add(m_button_ok, 0, wxALL, FromDIP(5)); + m_sizer_button->Add(m_button_cancel, 0, wxALL, FromDIP(5)); + m_sizer_button->Layout(); + m_status_bar = std::make_shared(this); m_status_bar->get_panel()->Hide(); @@ -1103,12 +1165,14 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) auto m_step_icon_panel1 = new wxWindow(this, wxID_ANY); auto m_step_icon_panel2 = new wxWindow(this, wxID_ANY); - + m_step_icon_panel1->SetBackgroundColour(*wxWHITE); m_step_icon_panel2->SetBackgroundColour(*wxWHITE); + auto m_sizer_step_icon_panel1 = new wxBoxSizer(wxVERTICAL); auto m_sizer_step_icon_panel2 = new wxBoxSizer(wxVERTICAL); + m_img_step1 = new wxStaticBitmap(m_step_icon_panel1, wxID_ANY, create_scaled_bitmap("ip_address_step", this, 6), wxDefaultPosition, wxSize(FromDIP(6), FromDIP(6)), 0); @@ -1116,6 +1180,7 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) auto m_line_tips_left = new wxPanel(m_step_icon_panel1, wxID_ANY, wxDefaultPosition, wxSize(-1, 1)); m_line_tips_left->SetBackgroundColour(wxColour(0xEEEEEE)); m_img_step2 = new wxStaticBitmap(m_step_icon_panel2, wxID_ANY, create_scaled_bitmap("ip_address_step", this, 6), wxDefaultPosition, wxSize(FromDIP(6), FromDIP(6)), 0); + m_img_step3 = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("ip_address_step", this, 6), wxDefaultPosition, wxSize(FromDIP(6), FromDIP(6)), 0); m_sizer_step_icon_panel1->Add(m_img_step1, 0, wxALIGN_CENTER|wxALL, FromDIP(5)); @@ -1129,17 +1194,30 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) m_step_icon_panel2->Fit(); + m_sizer_step_icon_panel2->Add(m_img_step2, 0, wxALIGN_CENTER|wxALL, FromDIP(5)); + //m_sizer_step_icon_panel3->Add(m_img_step3, 0, wxALIGN_CENTER|wxALL, FromDIP(5)); m_step_icon_panel1->SetMinSize(wxSize(-1, m_tip1->GetBestSize().y)); m_step_icon_panel1->SetMaxSize(wxSize(-1, m_tip1->GetBestSize().y)); + m_sizer_msg->Add(0, 0, 0, wxALIGN_CENTER, FromDIP(20)); + m_sizer_msg->Add(m_img_step3, 0, wxALL, FromDIP(5)); + m_sizer_msg->Add(0, 0, 0, wxALIGN_CENTER, FromDIP(8)); + m_sizer_msg->Add(m_tip4, 0, wxALIGN_CENTER | wxEXPAND | wxLEFT, FromDIP(5)); + m_img_step3->Hide(); + m_tip4->Hide(); + m_sizer_msg->Layout(); + m_sizer_main_left->Add(m_step_icon_panel1, 0, wxEXPAND, 0); m_sizer_main_left->Add(0, 0, 0, wxTOP, FromDIP(20)); m_sizer_main_left->Add(m_line_tips_left, 1, wxEXPAND, 0); m_sizer_main_left->Add(0, 0, 0, wxTOP, FromDIP(20)); m_sizer_main_left->Add(m_step_icon_panel2, 0, wxEXPAND, 0); + m_sizer_main_left->Layout(); + + m_trouble_shoot->Hide(); m_sizer_main_right->Add(m_tip1, 0, wxRIGHT|wxEXPAND, FromDIP(18)); m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(20)); @@ -1147,19 +1225,19 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(20)); m_sizer_main_right->Add(m_tip2, 0, wxRIGHT|wxEXPAND, FromDIP(18)); m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(12)); + m_sizer_main_right->Add(m_tip3, 0, wxRIGHT | wxEXPAND, FromDIP(18)); + m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(4)); + m_sizer_main_right->Add(m_img_help, 0, 0, 0); + m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(12)); m_sizer_main_right->Add(m_input_tip_area, 0, wxRIGHT|wxEXPAND, FromDIP(18)); m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(4)); m_sizer_main_right->Add(m_input_area, 0, wxRIGHT|wxEXPAND, FromDIP(18)); - m_sizer_main_right->Add(m_error_msg, 0, wxRIGHT|wxEXPAND, FromDIP(18)); - m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(16)); - m_sizer_main_right->Add(m_tip3, 0, wxRIGHT|wxEXPAND, FromDIP(18)); - m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(4)); - m_sizer_main_right->Add(m_img_help1, 0, 0, 0); - m_sizer_main_right->Add(m_img_help2, 0, 0, 0); - - m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(30)); - m_sizer_main_right->Add(sizer_button, 1, wxRIGHT|wxEXPAND, FromDIP(18)); + m_sizer_main_right->Add(m_button_ok, 0, wxRIGHT, FromDIP(18)); + m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(4)); + m_sizer_main_right->Add(m_test_right_msg, 0, wxRIGHT|wxEXPAND, FromDIP(18)); + m_sizer_main_right->Add(m_test_wrong_msg, 0, wxRIGHT|wxEXPAND, FromDIP(18)); + m_sizer_main_right->Add(0, 0, 0, wxTOP, FromDIP(16)); m_sizer_main_right->Add(m_status_bar->get_panel(), 0,wxRIGHT|wxEXPAND, FromDIP(18)); m_sizer_main_right->Layout(); @@ -1171,7 +1249,15 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) m_sizer_body->Add(m_line_top, 0, wxEXPAND, 0); m_sizer_body->Add(0, 0, 0, wxTOP, FromDIP(20)); m_sizer_body->Add(m_sizer_main, 0, wxEXPAND, 0); - + m_sizer_body->Add(0, 0, 0, wxTOP, FromDIP(4)); + m_sizer_body->Add(m_sizer_msg, 0, wxLEFT|wxEXPAND, FromDIP(18)); + m_sizer_body->Add(0, 0, 0, wxTOP, FromDIP(4)); + m_sizer_body->Add(m_trouble_shoot, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(40)); + + m_sizer_body->Add(0, 0, 0, wxTOP, FromDIP(8)); + m_sizer_body->Add(m_sizer_button, 0, wxRIGHT | wxEXPAND, FromDIP(25)); + m_sizer_body->Layout(); + SetSizer(m_sizer_body); Layout(); Fit(); @@ -1187,6 +1273,7 @@ InputIpAddressDialog::InputIpAddressDialog(wxWindow* parent) EndModal(wxID_YES); }); Bind(wxEVT_CLOSE_WINDOW, [this](auto& e) {on_cancel();}); + } void InputIpAddressDialog::on_cancel() @@ -1197,7 +1284,11 @@ void InputIpAddressDialog::on_cancel() m_send_job->join(); } } - this->EndModal(wxID_CANCEL); + if (m_result == 0){ + this->EndModal(wxID_YES); + }else { + this->EndModal(wxID_CANCEL); + } } @@ -1212,15 +1303,11 @@ void InputIpAddressDialog::set_machine_obj(MachineObject* obj) m_input_ip->GetTextCtrl()->SetLabelText(m_obj->dev_ip); m_input_access_code->GetTextCtrl()->SetLabelText(m_obj->get_access_code()); - if (m_obj->printer_type == "C11" || m_obj->printer_type == "C12") { - m_img_help1->Hide(); - m_img_help2->Show(); - } - else if (m_obj->printer_type == "BL-P001" || m_obj->printer_type == "BL-P002") { - m_img_help1->Show(); - m_img_help2->Hide(); - } + std::string img_str = DeviceManager::get_printer_diagram_img(m_obj->printer_type); + auto diagram_bmp = create_scaled_bitmap(img_str + "_en", this, 198); + m_img_help->SetBitmap(diagram_bmp); + auto str_ip = m_input_ip->GetTextCtrl()->GetValue(); auto str_access_code = m_input_access_code->GetTextCtrl()->GetValue(); if (isIp(str_ip.ToStdString()) && str_access_code.Length() == 8) { @@ -1240,16 +1327,27 @@ void InputIpAddressDialog::set_machine_obj(MachineObject* obj) Fit(); } -void InputIpAddressDialog::update_error_msg(wxString msg) +void InputIpAddressDialog::update_test_msg(wxString msg,bool connected) { if (msg.empty()) { - m_error_msg->Hide(); + m_test_right_msg->Hide(); + m_test_wrong_msg->Hide(); } else { - m_error_msg->Show(); - m_error_msg->SetLabelText(msg); - m_error_msg->SetMinSize(wxSize(FromDIP(352), -1)); - m_error_msg->SetMaxSize(wxSize(FromDIP(352), -1)); + if(connected){ + m_test_right_msg->Show(); + m_test_right_msg->SetLabelText(msg); + m_test_right_msg->SetMinSize(wxSize(FromDIP(352), -1)); + m_test_right_msg->SetMaxSize(wxSize(FromDIP(352), -1)); + } + else{ + m_test_wrong_msg->Show(); + m_test_wrong_msg->SetLabelText(msg); + m_test_wrong_msg->SetMinSize(wxSize(FromDIP(352), -1)); + m_test_wrong_msg->SetMaxSize(wxSize(FromDIP(352), -1)); + } + + } Layout(); @@ -1274,12 +1372,19 @@ bool InputIpAddressDialog::isIp(std::string ipstr) void InputIpAddressDialog::on_ok(wxMouseEvent& evt) { + m_test_right_msg->Hide(); + m_test_wrong_msg->Hide(); + m_img_step3->Hide(); + m_tip4->Hide(); + m_trouble_shoot->Hide(); + Layout(); + Fit(); wxString ip = m_input_ip->GetTextCtrl()->GetValue(); wxString str_access_code = m_input_access_code->GetTextCtrl()->GetValue(); //check support function if (!m_obj) return; - if (!m_obj->is_function_supported(PrinterFunction::FUNC_SEND_TO_SDCARD)) { + if (!m_obj->is_support_send_to_sdcard) { wxString input_str = wxString::Format("%s|%s", ip, str_access_code); auto event = wxCommandEvent(EVT_ENTER_IP_ADDRESS); event.SetString(input_str); @@ -1333,8 +1438,8 @@ void InputIpAddressDialog::on_ok(wxMouseEvent& evt) m_send_job->set_check_mode(); m_send_job->set_project_name("verify_job"); - m_send_job->on_check_ip_address_fail([this]() { - this->check_ip_address_failed(); + m_send_job->on_check_ip_address_fail([this](int result) { + this->check_ip_address_failed(result); }); m_send_job->on_check_ip_address_success([this, ip, str_access_code]() { @@ -1343,24 +1448,37 @@ void InputIpAddressDialog::on_ok(wxMouseEvent& evt) event.SetString(input_str); event.SetEventObject(this); wxPostEvent(this, event); - - auto event_close = wxCommandEvent(EVT_CLOSE_IPADDRESS_DLG); - event_close.SetEventObject(this); - wxPostEvent(this, event_close); + m_result = 0; + + update_test_msg(_L("IP and Access Code Verified! You may close the window"), true); + }); m_send_job->start(); } -void InputIpAddressDialog::check_ip_address_failed() +void InputIpAddressDialog::check_ip_address_failed(int result) { auto evt = new wxCommandEvent(EVT_CHECK_IP_ADDRESS_FAILED); + evt->SetInt(result); wxQueueEvent(this, evt); } void InputIpAddressDialog::on_check_ip_address_failed(wxCommandEvent& evt) { - update_error_msg(_L("Error: IP or Access Code are not correct")); + m_result = evt.GetInt(); + if (m_result == -2) { + update_test_msg(_L("Connection failed, please double check IP and Access Code"), false); + } + else { + update_test_msg(_L("Connection failed! If your IP and Access Code is correct, \nplease move to step 3 for troubleshooting network issues"), false); + m_img_step3->Show(); + m_tip4->Show(); + //m_trouble_shoot->Show(); + Layout(); + Fit(); + } + m_button_ok->Enable(true); StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); diff --git a/src/slic3r/GUI/ReleaseNote.hpp b/src/slic3r/GUI/ReleaseNote.hpp index f6c9e27bd1b..04863aee639 100644 --- a/src/slic3r/GUI/ReleaseNote.hpp +++ b/src/slic3r/GUI/ReleaseNote.hpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "AmsMappingPopup.hpp" #include "GUI_Utils.hpp" @@ -40,8 +42,9 @@ namespace Slic3r { namespace GUI { wxDECLARE_EVENT(EVT_SECONDARY_CHECK_CONFIRM, wxCommandEvent); wxDECLARE_EVENT(EVT_SECONDARY_CHECK_CANCEL, wxCommandEvent); -wxDECLARE_EVENT(EVT_SECONDARY_CHECK_DONE, wxCommandEvent); wxDECLARE_EVENT(EVT_SECONDARY_CHECK_RETRY, wxCommandEvent); +wxDECLARE_EVENT(EVT_SECONDARY_CHECK_DONE, wxCommandEvent); +wxDECLARE_EVENT(EVT_UPDATE_NOZZLE, wxCommandEvent); class ReleaseNoteDialog : public DPIDialog { @@ -84,7 +87,6 @@ class UpdateVersionDialog : public DPIDialog void RunScript(std::string script); void on_dpi_changed(const wxRect& suggested_rect) override; void update_version_info(wxString release_note, wxString version); - void alter_choice(wxCommandEvent& event); std::vector splitWithStl(std::string str, std::string pattern); wxStaticBitmap* m_brand{nullptr}; @@ -94,9 +96,12 @@ class UpdateVersionDialog : public DPIDialog wxScrolledWindow* m_scrollwindows_release_note{nullptr}; wxBoxSizer * sizer_text_release_note{nullptr}; Label * m_staticText_release_note{nullptr}; - wxCheckBox* m_remind_choice; - Button* m_button_ok; + wxStaticBitmap* m_bitmap_open_in_browser; + wxHyperlinkCtrl* m_link_open_in_browser; + Button* m_button_skip_version; + Button* m_button_download; Button* m_button_cancel; + std::string url_line; }; class SecondaryCheckDialog : public DPIFrame @@ -171,16 +176,19 @@ class ConfirmBeforeSendDialog : public DPIDialog void on_show(); void on_hide(); void update_btn_label(wxString ok_btn_text, wxString cancel_btn_text); - wxString format_text(wxString str, int warp); void rescale(); - ~ConfirmBeforeSendDialog(); void on_dpi_changed(const wxRect& suggested_rect); + void show_update_nozzle_button(); + wxString format_text(wxString str, int warp); + + ~ConfirmBeforeSendDialog(); wxBoxSizer* m_sizer_main; wxScrolledWindow* m_vebview_release_note{ nullptr }; Label* m_staticText_release_note{ nullptr }; Button* m_button_ok; Button* m_button_cancel; + Button* m_button_update_nozzle; wxCheckBox* m_show_again_checkbox; bool not_show_again = false; std::string show_again_config_text = ""; @@ -196,6 +204,7 @@ class InputIpAddressDialog : public DPIDialog Label* m_tip1{ nullptr }; Label* m_tip2{ nullptr }; Label* m_tip3{ nullptr }; + Label* m_tip4{ nullptr }; InputIpAddressDialog(wxWindow* parent = nullptr); ~InputIpAddressDialog(); @@ -203,24 +212,26 @@ class InputIpAddressDialog : public DPIDialog Button* m_button_ok{ nullptr }; Label* m_tips_ip{ nullptr }; Label* m_tips_access_code{ nullptr }; - Label* m_error_msg{ nullptr }; + Label* m_test_right_msg{ nullptr }; + Label* m_test_wrong_msg{ nullptr }; TextInput* m_input_ip{ nullptr }; TextInput* m_input_access_code{ nullptr }; - wxStaticBitmap* m_img_help1{ nullptr }; - wxStaticBitmap* m_img_help2{ nullptr }; + wxStaticBitmap* m_img_help{ nullptr }; wxStaticBitmap* m_img_step1{ nullptr }; wxStaticBitmap* m_img_step2{ nullptr }; + wxStaticBitmap* m_img_step3{ nullptr }; + wxHyperlinkCtrl* m_trouble_shoot{ nullptr }; bool m_show_access_code{ false }; - + int m_result; std::shared_ptr m_send_job{nullptr}; std::shared_ptr m_status_bar; void on_cancel(); void update_title(wxString title); void set_machine_obj(MachineObject* obj); - void update_error_msg(wxString msg); + void update_test_msg(wxString msg, bool connected); bool isIp(std::string ipstr); - void check_ip_address_failed(); + void check_ip_address_failed(int result); void on_check_ip_address_failed(wxCommandEvent& evt); void on_ok(wxMouseEvent& evt); void on_text(wxCommandEvent& evt); diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index c7c0978b973..6184086dc0c 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -28,6 +28,7 @@ namespace Slic3r { wxDEFINE_EVENT(wxCUSTOMEVT_JUMP_TO_OPTION, wxCommandEvent); wxDEFINE_EVENT(wxCUSTOMEVT_EXIT_SEARCH, wxCommandEvent); +wxDEFINE_EVENT(wxCUSTOMEVT_JUMP_TO_OBJECT, wxCommandEvent); using GUI::from_u8; using GUI::into_u8; @@ -394,10 +395,11 @@ void OptionsSearcher::add_key(const std::string &opt_key, Preset::Type type, con // SearchItem //------------------------------------------ -SearchItem::SearchItem(wxWindow *parent, wxString text, int index, SearchDialog* sdialog) +SearchItem::SearchItem(wxWindow *parent, wxString text, int index, SearchDialog* sdialog, SearchObjectDialog* search_dialog) : wxWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(parent->GetSize().GetWidth(), 3 * GUI::wxGetApp().em_unit())) { m_sdialog = sdialog; + m_search_object_dialog = search_dialog; m_text = text; m_index = index; @@ -511,10 +513,19 @@ void SearchItem::on_mouse_left_up(wxMouseEvent &evt) //if (m_sdialog->prevent_list_events) return; // if (wxGetMouseState().LeftIsDown()) - m_sdialog->Die(); - wxCommandEvent event(wxCUSTOMEVT_JUMP_TO_OPTION); - event.SetInt(m_index); - wxPostEvent(GUI::wxGetApp().plater(), event); + if (m_sdialog) { + m_sdialog->Die(); + wxCommandEvent event(wxCUSTOMEVT_JUMP_TO_OPTION); + event.SetInt(m_index); + wxPostEvent(GUI::wxGetApp().plater(), event); + } + + if (m_search_object_dialog) { + m_search_object_dialog->Dismiss(); + wxCommandEvent event(wxCUSTOMEVT_JUMP_TO_OBJECT); + event.SetClientData(m_item); + wxPostEvent(GUI::wxGetApp().plater(), event); + } } //------------------------------------------ @@ -894,6 +905,121 @@ void SearchListModel::GetValueByRow(wxVariant &variant, unsigned int row, unsign } } +SearchObjectDialog::SearchObjectDialog(GUI::ObjectList* object_list, wxWindow* parent) + : PopupWindow(parent, wxBORDER_NONE), m_object_list(object_list) +{ + Freeze(); + SetBackgroundColour(wxColour(238, 238, 238)); + + em = GUI::wxGetApp().em_unit(); + + m_text_color = wxColour(38, 46, 48); + m_bg_color = wxColour(255, 255, 255); + m_thumb_color = wxColour(196, 196, 196); + + SetFont(GUI::wxGetApp().normal_font()); + SetSizeHints(wxDefaultSize, wxDefaultSize); + + m_sizer_border = new wxBoxSizer(wxVERTICAL); + m_sizer_main = new wxBoxSizer(wxVERTICAL); + m_sizer_body = new wxBoxSizer(wxVERTICAL); + + // border + m_border_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(POPUP_WIDTH * em, POPUP_HEIGHT * em), wxTAB_TRAVERSAL); + m_border_panel->SetBackgroundColour(m_bg_color); + + // client + m_client_panel = new wxPanel(m_border_panel, wxID_ANY, wxDefaultPosition, wxSize(POPUP_WIDTH * em, POPUP_HEIGHT * em), wxTAB_TRAVERSAL); + m_client_panel->SetBackgroundColour(m_bg_color); + + // scroll window + m_scrolledWindow = new ScrolledWindow(m_client_panel, wxID_ANY, wxDefaultPosition, wxSize(POPUP_WIDTH * em - (em + em / 2), POPUP_HEIGHT * em), wxVSCROLL, 6, 6); + m_scrolledWindow->SetMarginColor(m_bg_color); + m_scrolledWindow->SetScrollbarColor(m_thumb_color); + m_scrolledWindow->SetBackgroundColour(m_bg_color); + auto m_listsizer = new wxBoxSizer(wxVERTICAL); + auto m_listPanel = new wxWindow(m_scrolledWindow->GetPanel(), -1); + m_listPanel->SetBackgroundColour(m_bg_color); + m_listPanel->SetSize(wxSize(m_scrolledWindow->GetSize().GetWidth(), -1)); + + m_listPanel->SetSizer(m_listsizer); + m_listPanel->Fit(); + m_scrolledWindow->SetScrollbars(1, 1, 0, m_listPanel->GetSize().GetHeight()); + + m_sizer_body->Add(m_scrolledWindow, 0, wxEXPAND | wxALL, em); + + m_client_panel->SetSizer(m_sizer_body); + m_client_panel->Layout(); + m_sizer_body->Fit(m_client_panel); + m_sizer_main->Add(m_client_panel, 1, wxEXPAND, 0); + + m_border_panel->SetSizer(m_sizer_main); + m_border_panel->Layout(); + m_sizer_border->Add(m_border_panel, 1, wxEXPAND | wxALL, 1); + + SetSizer(m_sizer_border); + Layout(); + m_sizer_border->Fit(this); + Thaw(); + + GUI::wxGetApp().UpdateDarkUIWin(this); +} + +SearchObjectDialog::~SearchObjectDialog() {} + +void SearchObjectDialog::Popup(wxPoint position /*= wxDefaultPosition*/) +{ + update_list(); + PopupWindow::Popup(); +} + +void SearchObjectDialog::Dismiss() +{ + auto focus_window = this->GetParent()->HasFocus(); + if (!focus_window) + PopupWindow::Dismiss(); +} + +void SearchObjectDialog::update_list() +{ +#ifndef __WXGTK__ + Freeze(); +#endif + m_scrolledWindow->Destroy(); + + m_scrolledWindow = new ScrolledWindow(m_client_panel, wxID_ANY, wxDefaultPosition, wxSize(POPUP_WIDTH * em - (em + em / 2), POPUP_HEIGHT * em - em), wxVSCROLL, 6, 6); + m_scrolledWindow->SetMarginColor(StateColor::darkModeColorFor(m_bg_color)); + m_scrolledWindow->SetScrollbarColor(StateColor::darkModeColorFor(m_thumb_color)); + m_scrolledWindow->SetBackgroundColour(StateColor::darkModeColorFor(m_bg_color)); + + auto m_listsizer = new wxBoxSizer(wxVERTICAL); + auto m_listPanel = new wxWindow(m_scrolledWindow->GetPanel(), -1); + m_listPanel->SetBackgroundColour(StateColor::darkModeColorFor(m_bg_color)); + m_listPanel->SetSize(wxSize(m_scrolledWindow->GetSize().GetWidth(), -1)); + + const std::vector>& found = m_object_list->GetModel()->get_found_list(); + auto index = 0; + for (const auto& item : found) { + GUI::ObjectDataViewModelNode* data_item = item.first; + wxString data_str = item.second; + auto tmp = new SearchItem(m_listPanel, data_str, index, nullptr, this); + tmp->m_item = data_item; + m_listsizer->Add(tmp, 0, wxEXPAND, 0); + index++; + } + + m_listPanel->SetSizer(m_listsizer); + m_listPanel->Fit(); + m_scrolledWindow->SetScrollbars(1, 1, 0, m_listPanel->GetSize().GetHeight()); + + m_sizer_body->Add(m_scrolledWindow, 0, wxEXPAND | wxALL, em); + m_sizer_body->Fit(m_client_panel); + m_sizer_body->Layout(); +#ifndef __WXGTK__ + Thaw(); +#endif +} + } // namespace Search } // namespace Slic3r diff --git a/src/slic3r/GUI/Search.hpp b/src/slic3r/GUI/Search.hpp index 51f5030428f..8d20a14e1c6 100644 --- a/src/slic3r/GUI/Search.hpp +++ b/src/slic3r/GUI/Search.hpp @@ -14,6 +14,7 @@ #include #include +#include #include "wxExtensions.hpp" #include "GUI_Utils.hpp" @@ -21,12 +22,13 @@ #include "Widgets/ScrolledWindow.hpp" #include "Widgets/TextInput.hpp" #include "Widgets/PopupWindow.hpp" - +#include "GUI_ObjectList.hpp" namespace Slic3r { wxDECLARE_EVENT(wxCUSTOMEVT_JUMP_TO_OPTION, wxCommandEvent); wxDECLARE_EVENT(wxCUSTOMEVT_EXIT_SEARCH, wxCommandEvent); +wxDECLARE_EVENT(wxCUSTOMEVT_JUMP_TO_OBJECT, wxCommandEvent); namespace Search { @@ -154,14 +156,17 @@ class OptionsSearcher // SearchDialog //------------------------------------------ class SearchDialog; +class SearchObjectDialog; class SearchItem : public wxWindow { public: wxString m_text; int m_index; - SearchDialog *m_sdialog; + SearchDialog* m_sdialog{ nullptr }; + SearchObjectDialog* m_search_object_dialog{ nullptr }; + GUI::ObjectDataViewModelNode* m_item{ nullptr }; - SearchItem(wxWindow *parent, wxString text, int index, SearchDialog *sdialog); + SearchItem(wxWindow *parent, wxString text, int index, SearchDialog *sdialog = nullptr, SearchObjectDialog* search_dialog = nullptr); ~SearchItem(){}; wxSize DrawTextString(wxDC &dc, const wxString &text, const wxPoint &pt, bool bold); @@ -276,6 +281,40 @@ class SearchListModel : public wxDataViewVirtualListModel bool SetValueByRow(const wxVariant &variant, unsigned int row, unsigned int col) override { return false; } }; +class SearchObjectDialog : public PopupWindow +{ +public: + SearchObjectDialog(GUI::ObjectList* object_list, wxWindow* parent); + ~SearchObjectDialog(); + + void Popup(wxPoint position = wxDefaultPosition); + void Dismiss(); + + void update_list(); + +public: + GUI::ObjectList* m_object_list{ nullptr }; + + int em; + const int POPUP_WIDTH = 41; + const int POPUP_HEIGHT = 45; + + ScrolledWindow* m_scrolledWindow{ nullptr }; + + wxColour m_text_color; + wxColour m_bg_color; + wxColour m_thumb_color; + wxColour m_bold_color; + + wxBoxSizer* m_sizer_body{ nullptr }; + wxBoxSizer* m_sizer_main{ nullptr }; + wxBoxSizer* m_sizer_border{ nullptr }; + + wxWindow* m_border_panel{ nullptr }; + wxWindow* m_client_panel{ nullptr }; + wxWindow* m_listPanel{ nullptr }; +}; + } // namespace Search } // namespace Slic3r diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 1d581aef9b9..a2c25f9c407 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -41,7 +41,7 @@ wxDEFINE_EVENT(EVT_CLEAR_IPADDRESS, wxCommandEvent); #define LIST_REFRESH_INTERVAL 200 #define MACHINE_LIST_REFRESH_INTERVAL 2000 -#define WRAP_GAP FromDIP(10) +#define WRAP_GAP FromDIP(2) static wxString task_canceled_text = _L("Task canceled"); @@ -383,6 +383,7 @@ SelectMachinePopup::SelectMachinePopup(wxWindow *parent) #if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) m_sizer_search_bar = new wxBoxSizer(wxVERTICAL); m_search_bar = new wxSearchCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_search_bar->SetDescriptiveText(_L("Search")); m_search_bar->ShowSearchButton( true ); m_search_bar->ShowCancelButton( false ); m_sizer_search_bar->Add( m_search_bar, 1, wxALL| wxEXPAND, 1 ); @@ -430,19 +431,23 @@ void SelectMachinePopup::Popup(wxWindow *WXUNUSED(focus)) if (wxGetApp().is_user_login()) { if (!get_print_info_thread) { - get_print_info_thread = new boost::thread(Slic3r::create_thread([&] { + get_print_info_thread = new boost::thread(Slic3r::create_thread([this, token = std::weak_ptr(m_token)] { NetworkAgent* agent = wxGetApp().getAgent(); unsigned int http_code; std::string body; int result = agent->get_user_print_info(&http_code, &body); - if (result == 0) { - m_print_info = body; - } else { - m_print_info = ""; - } - wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); - event.SetEventObject(this); - wxPostEvent(this, event); + CallAfter([token, this, result, body]() { + if (token.expired()) {return;} + if (result == 0) { + m_print_info = body; + } + else { + m_print_info = ""; + } + wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); + event.SetEventObject(this); + wxPostEvent(this, event); + }); })); } } @@ -553,12 +558,6 @@ void SelectMachinePopup::update_other_devices() MachineObjectPanel* op = nullptr; if (i < m_other_list_machine_panel.size()) { op = m_other_list_machine_panel[i]->mPanel; - op->Show(); -#if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) - if (!search_for_printer(mobj)) { - op->Hide(); - } -#endif } else { op = new MachineObjectPanel(m_scrolledWindow, wxID_ANY); MachinePanel* mpanel = new MachinePanel(); @@ -567,6 +566,16 @@ void SelectMachinePopup::update_other_devices() m_other_list_machine_panel.push_back(mpanel); m_sizer_other_devices->Add(op, 0, wxEXPAND, 0); } +#if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) + if (!search_for_printer(mobj)) { + op->Hide(); + } + else { + op->Show(); + } +#else + op->Show(); +#endif i++; op->update_machine_info(mobj); @@ -683,11 +692,14 @@ void SelectMachinePopup::update_user_devices() MachineObjectPanel* op = nullptr; if (i < m_user_list_machine_panel.size()) { op = m_user_list_machine_panel[i]->mPanel; - op->Show(); #if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) if (!search_for_printer(mobj)) { op->Hide(); - } + } else { + op->Show(); + } +#else + op->Show(); #endif } else { op = new MachineObjectPanel(m_scrolledWindow, wxID_ANY); @@ -804,7 +816,7 @@ bool SelectMachinePopup::search_for_printer(MachineObject* obj) auto ip_it = ip.find(search_text); if ((name_it != std::string::npos)||(ip_it != std::string::npos)) { return true; - } + } return false; } @@ -868,9 +880,9 @@ void SelectMachinePopup::OnLeftUp(wxMouseEvent &event) static wxString MACHINE_BED_TYPE_STRING[BED_TYPE_COUNT] = { //_L("Auto"), _L("Bambu Cool Plate") + " / " + _L("PLA Plate"), - _L("Bambu Engineering Plate"), - _L("Bambu Smooth PEI Plate") + "/" + _L("High temperature Plate"), - _L("Bambu Textured PEI Plate")}; + _L("Bamabu Engineering Plate"), + _L("Bamabu Smooth PEI Plate") + "/" + _L("High temperature Plate"), + _L("Bamabu Textured PEI Plate")}; static std::string MachineBedTypeString[BED_TYPE_COUNT] = { //"auto", @@ -967,7 +979,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) rename_sizer_v = new wxBoxSizer(wxVERTICAL); rename_sizer_h = new wxBoxSizer(wxHORIZONTAL); - m_rename_text = new wxStaticText(m_rename_normal_panel, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, 0); + m_rename_text = new wxStaticText(m_rename_normal_panel, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END); m_rename_text->SetFont(::Label::Body_13); m_rename_text->SetMaxSize(wxSize(FromDIP(390), -1)); m_rename_button = new ScalableButton(m_rename_normal_panel, wxID_ANY, "ams_editable"); @@ -1082,10 +1094,10 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) wxBoxSizer* m_sizer_material_tips = new wxBoxSizer(wxHORIZONTAL); enable_ams_mapping = new ScalableBitmap(this, "enable_ams", 16); - auto img_amsmapping_tip = new wxStaticBitmap(m_scrollable_region, wxID_ANY, enable_ams_mapping->bmp(), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); + img_amsmapping_tip = new wxStaticBitmap(m_scrollable_region, wxID_ANY, enable_ams_mapping->bmp(), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); m_sizer_material_tips->Add(img_amsmapping_tip, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5)); - img_amsmapping_tip->Bind(wxEVT_ENTER_WINDOW, [this, img_amsmapping_tip](auto& e) { + img_amsmapping_tip->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { wxPoint img_pos = img_amsmapping_tip->ClientToScreen(wxPoint(0, 0)); wxPoint popup_pos(img_pos.x, img_pos.y + img_amsmapping_tip->GetRect().height); m_mapping_tutorial_popup.Position(popup_pos, wxSize(0, 0)); @@ -1102,7 +1114,6 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) img_amsmapping_tip->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { m_mapping_tutorial_popup.Dismiss(); }); - amsmapping_tip = img_amsmapping_tip; m_sizer_material = new wxGridSizer(0, 4, 0, FromDIP(5)); @@ -1125,8 +1136,8 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_ams_backup_tip->Hide(); img_ams_backup->Hide(); - m_ams_backup_tip->Bind(wxEVT_ENTER_WINDOW, [this, img_amsmapping_tip](auto& e) {SetCursor(wxCURSOR_HAND); }); - img_ams_backup->Bind(wxEVT_ENTER_WINDOW, [this, img_amsmapping_tip](auto& e) {SetCursor(wxCURSOR_HAND); }); + m_ams_backup_tip->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); }); + img_ams_backup->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); }); m_ams_backup_tip->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); }); img_ams_backup->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); }); @@ -1330,8 +1341,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0); - m_link_network_state = new Label(m_sw_print_failed_info, _L("Check the status of current system services")); - m_link_network_state->SetForegroundColour(0x009688); + m_link_network_state = new wxHyperlinkCtrl(m_sw_print_failed_info, wxID_ANY,_L("Check the status of current system services"),""); m_link_network_state->SetFont(::Label::Body_12); m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check();}); m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND);}); @@ -1423,13 +1433,13 @@ void SelectMachineDialog::init_bind() on_send_print(); } else if (e.GetInt() == -2 && (m_print_type == PrintFromType::FROM_SDCARD_VIEW)) { - show_status(PrintDialogStatus::PrintStatusSendingCanceled); + show_status(PrintDialogStatus::PrintStatusInit); prepare_mode(); MessageDialog msg_wingow(nullptr, _L("Printer local connection failed, please try again."), "", wxAPPLY | wxOK); msg_wingow.ShowModal(); } else if (e.GetInt() == 5 && (m_print_type == PrintFromType::FROM_SDCARD_VIEW)) { - show_status(PrintDialogStatus::PrintStatusSendingCanceled); + show_status(PrintDialogStatus::PrintStatusInit); prepare_mode(); DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); @@ -1544,12 +1554,12 @@ wxWindow *SelectMachineDialog::create_ams_checkbox(wxString title, wxWindow *par sizer_checkbox->Add(text, 0, wxALIGN_CENTER, 0); enable_ams = new ScalableBitmap(this, "enable_ams", 16); - img_ams_tip = new wxStaticBitmap(checkbox, wxID_ANY, enable_ams->bmp(), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); - sizer_checkbox->Add(img_ams_tip, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5)); + img_use_ams_tip = new wxStaticBitmap(checkbox, wxID_ANY, enable_ams->bmp(), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); + sizer_checkbox->Add(img_use_ams_tip, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5)); - img_ams_tip->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { - wxPoint img_pos = img_ams_tip->ClientToScreen(wxPoint(0, 0)); - wxPoint popup_pos(img_pos.x, img_pos.y + img_ams_tip->GetRect().height); + img_use_ams_tip->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { + wxPoint img_pos = img_use_ams_tip->ClientToScreen(wxPoint(0, 0)); + wxPoint popup_pos(img_pos.x, img_pos.y + img_use_ams_tip->GetRect().height); m_mapping_tip_popup.Position(popup_pos, wxSize(0, 0)); m_mapping_tip_popup.Popup(); @@ -1561,7 +1571,7 @@ wxWindow *SelectMachineDialog::create_ams_checkbox(wxString title, wxWindow *par } }); - img_ams_tip->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { + img_use_ams_tip->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { m_mapping_tip_popup.Dismiss(); }); @@ -1596,22 +1606,22 @@ wxWindow *SelectMachineDialog::create_item_checkbox(wxString title, wxWindow *pa sizer_check->Add(check, 0, wxBOTTOM | wxEXPAND | wxTOP, FromDIP(5)); - sizer_checkbox->Add(sizer_check, 0, wxEXPAND, FromDIP(5)); - sizer_checkbox->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(11)); - auto text = new wxStaticText(checkbox, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END); - text->SetFont(::Label::Body_13); + text->SetFont(::Label::Body_12); text->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#323A3C"))); text->Wrap(-1); - text->SetMinSize(wxSize(FromDIP(120), -1)); - text->SetMaxSize(wxSize(FromDIP(120), -1)); + text->SetMinSize(wxSize(FromDIP(140), -1)); + text->SetMaxSize(wxSize(FromDIP(140), -1)); + + sizer_checkbox->Add(sizer_check, 0, wxEXPAND, FromDIP(5)); + sizer_checkbox->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(7)); sizer_checkbox->Add(text, 0, wxALIGN_CENTER, 0); checkbox->SetSizer(sizer_checkbox); checkbox->Layout(); sizer_checkbox->Fit(checkbox); - checkbox->SetToolTip(tooltip); + check->SetToolTip(tooltip); text->SetToolTip(tooltip); @@ -1659,21 +1669,19 @@ wxWindow *SelectMachineDialog::create_item_checkbox(wxString title, wxWindow *pa void SelectMachineDialog::update_select_layout(MachineObject *obj) { - if (obj && obj->is_function_supported(PrinterFunction::FUNC_FLOW_CALIBRATION)) { + if (obj && obj->is_support_flow_calibration) { select_flow->Show(); } else { select_flow->Hide(); } - if (obj && obj->is_function_supported(PrinterFunction::FUNC_AUTO_LEVELING)) { + if (obj && obj->is_support_auto_leveling) { select_bed->Show(); } else { select_bed->Hide(); } - if (obj && obj->is_function_supported(PrinterFunction::FUNC_TIMELAPSE) - && obj->is_support_print_with_timelapse() - && is_show_timelapse()) { + if (obj && obj->is_support_timelapse && is_show_timelapse()) { select_timelapse->Show(); update_timelapse_enable_status(); } else { @@ -2020,7 +2028,6 @@ void SelectMachineDialog::show_status(PrintDialogStatus status, std::vectorEnable(); - // other if (status == PrintDialogStatus::PrintStatusInit) { update_print_status_msg(wxEmptyString, false, false); @@ -2170,7 +2177,7 @@ void SelectMachineDialog::show_status(PrintDialogStatus status, std::vectorEndModal(wxID_CANCEL); } -bool SelectMachineDialog::is_blocking_printing() +bool SelectMachineDialog::is_blocking_printing(MachineObject* obj_) { DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!dev) return true; - MachineObject* obj_ = dev->get_selected_machine(); - if (obj_ == nullptr) return true; - PresetBundle* preset_bundle = wxGetApp().preset_bundle; auto source_model = preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle); auto target_model = obj_->printer_type; @@ -2231,6 +2235,103 @@ bool SelectMachineDialog::is_blocking_printing() return false; } +bool SelectMachineDialog::is_same_nozzle_diameters(std::string& tag_nozzle_type, std::string& nozzle_diameter) +{ + bool is_same_nozzle_diameters = true; + + float preset_nozzle_diameters; + std::string preset_nozzle_type; + + DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev) return true; + + MachineObject* obj_ = dev->get_selected_machine(); + if (obj_ == nullptr) return true; + + try + { + PresetBundle* preset_bundle = wxGetApp().preset_bundle; + auto opt_nozzle_diameters = preset_bundle->printers.get_edited_preset().config.option("nozzle_diameter"); + + const ConfigOptionEnum* nozzle_type = preset_bundle->printers.get_edited_preset().config.option>("nozzle_type"); + + if (nozzle_type->value == NozzleType::ntHardenedSteel) { + preset_nozzle_type = "hardened_steel"; + } + else if (nozzle_type->value == NozzleType::ntStainlessSteel) { + preset_nozzle_type = "stainless_steel"; + } + + tag_nozzle_type = obj_->nozzle_type; + + auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders(); + if (opt_nozzle_diameters != nullptr) { + for (auto i = 0; i < extruders.size(); i++) { + auto extruder = extruders[i] - 1; + preset_nozzle_diameters = float(opt_nozzle_diameters->get_at(extruder)); + if (preset_nozzle_diameters != obj_->nozzle_diameter) { + is_same_nozzle_diameters = false; + } + } + } + + } + catch (...) + { + } + + //nozzle_type = preset_nozzle_type; + nozzle_diameter = wxString::Format("%.1f", preset_nozzle_diameters).ToStdString(); + + return is_same_nozzle_diameters; +} + +bool SelectMachineDialog::is_same_nozzle_type(std::string& filament_type, std::string& tag_nozzle_type) +{ + bool is_same_nozzle_type = true; + + DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev) return true; + + MachineObject* obj_ = dev->get_selected_machine(); + if (obj_ == nullptr) return true; + + + NozzleType nozzle_type = NozzleType::ntUndefine; + + if (obj_->nozzle_type == "stainless_steel") { + nozzle_type = NozzleType::ntStainlessSteel; + } + else if (obj_->nozzle_type == "hardened_steel") { + nozzle_type = NozzleType::ntHardenedSteel; + } + + auto printer_nozzle_hrc = Print::get_hrc_by_nozzle_type(nozzle_type); + + auto preset_bundle = wxGetApp().preset_bundle; + MaterialHash::iterator iter = m_materialList.begin(); + while (iter != m_materialList.end()) { + Material* item = iter->second; + MaterialItem* m = item->item; + auto filament_nozzle_hrc = preset_bundle->get_required_hrc_by_filament_type(m->m_material_name.ToStdString()); + + if (abs(filament_nozzle_hrc) > abs(printer_nozzle_hrc)) { + filament_type = m->m_material_name.ToStdString(); + BOOST_LOG_TRIVIAL(info) << "filaments hardness mismatch: filament = " << filament_type << " printer_nozzle_hrc = " << printer_nozzle_hrc; + is_same_nozzle_type = false; + tag_nozzle_type = "hardened_steel"; + return is_same_nozzle_type; + } + else { + tag_nozzle_type = obj_->nozzle_type; + } + + iter++; + } + + return is_same_nozzle_type; +} + bool SelectMachineDialog::is_same_printer_model() { bool result = true; @@ -2267,7 +2368,9 @@ void SelectMachineDialog::show_errors(wxString &info) void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) { + bool has_slice_warnings = false; + bool has_update_nozzle = false; DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!dev) return; @@ -2287,13 +2390,41 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) } + //check blacklist + for (auto i = 0; i < m_ams_mapping_result.size(); i++) { + + auto tid = m_ams_mapping_result[i].tray_id; + + std::string filament_type = boost::to_upper_copy(m_ams_mapping_result[i].type); + std::string filament_brand; + + for (auto fs : m_filaments) { + if (fs.id == m_ams_mapping_result[i].id) { + filament_brand = m_filaments[i].brand; + } + } + + bool in_blacklist = false; + std::string action; + std::string info; + + DeviceManager::check_filaments_in_blacklist(filament_brand, filament_type, in_blacklist, action, info); + + if (in_blacklist && action == "warning") { + wxString prohibited_error = wxString::FromUTF8(info); + + confirm_text.push_back(prohibited_error + "\n"); + has_slice_warnings = true; + } + } + PartPlate* plate = m_plater->get_partplate_list().get_curr_plate(); for (auto warning : plate->get_slice_result()->warnings) { if (warning.msg == BED_TEMP_TOO_HIGH_THAN_FILAMENT) { - if (obj_->is_printer_enclosed()) { - //confirm_text.push_back(Plater::get_slice_warning_string(warning) + "\n"); - //has_slice_warnings = true; + if ((obj_->get_printer_is_enclosed())){ + // confirm_text.push_back(Plater::get_slice_warning_string(warning) + "\n"); + // has_slice_warnings = true; } } else if (warning.msg == NOT_SUPPORT_TRADITIONAL_TIMELAPSE) { @@ -2320,6 +2451,7 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) //check for unidentified material auto mapping_result = m_mapping_popup.parse_ams_mapping(obj_->amsList); auto has_unknown_filament = false; + // check if ams mapping is has errors, tpu bool has_prohibited_filament = false; wxString prohibited_error = wxEmptyString; @@ -2334,19 +2466,19 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) for (auto fs : m_filaments) { if (fs.id == m_ams_mapping_result[i].id) { - filament_brand = boost::to_upper_copy(m_filaments[i].brand); + filament_brand = m_filaments[i].brand; } } - if (filament_type == "TPU") { - has_prohibited_filament = true; - prohibited_error = wxString::Format(_L("%s is not supported by AMS."), "TPU"); - }else if (filament_type == "PET-CF" && filament_brand == "BAMBULAB") { - has_prohibited_filament = true; - prohibited_error = wxString::Format(_L("%s is not supported by AMS."), "PET-CF"); - }else if (filament_type == "PA6-CF" && filament_brand == "BAMBULAB") { + bool in_blacklist = false; + std::string action; + std::string info; + + DeviceManager::check_filaments_in_blacklist(filament_brand, filament_type, in_blacklist, action, info); + + if (in_blacklist && action == "prohibition") { has_prohibited_filament = true; - prohibited_error = wxString::Format(_L("%s is not supported by AMS."), "PA6-CF"); + prohibited_error = wxString::FromUTF8(info); } for (auto miter : mapping_result) { @@ -2371,9 +2503,40 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) confirm_text.push_back(_L("There are some unknown filaments in the AMS mappings. Please check whether they are the required filaments. If they are okay, press \"Confirm\" to start printing.") + "\n"); } + std::string nozzle_diameter; + std::string filament_type; + std::string tag_nozzle_type; + + if (!obj_->nozzle_type.empty() && (m_print_type == PrintFromType::FROM_NORMAL)) { + if (!is_same_nozzle_diameters(tag_nozzle_type, nozzle_diameter)) { + has_slice_warnings = true; + has_update_nozzle = true; + + wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"),nozzle_diameter, ""); + wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj_->nozzle_diameter, ""); + + confirm_text.push_back(_L("Your nozzle diameter in preset is not consistent with memorized nozzle diameter. Did you change your nozzle lately?") + + "\n " + nozzle_in_preset + + "\n " + nozzle_in_printer + + "\n"); + } + else if (!is_same_nozzle_type(filament_type, tag_nozzle_type)){ + has_slice_warnings = true; + has_update_nozzle = true; + nozzle_diameter = wxString::Format("%.1f", obj_->nozzle_diameter).ToStdString(); + + wxString nozzle_in_preset = wxString::Format(_L("*Printing %s material with %s may cause nozzle damage"), filament_type, format_steel_name(obj_->nozzle_type)); + confirm_text.push_back(nozzle_in_preset + "\n"); + } + } + + if (has_slice_warnings) { wxString confirm_title = _L("Warning"); ConfirmBeforeSendDialog confirm_dlg(this, wxID_ANY, confirm_title); + + if(has_update_nozzle){confirm_dlg.show_update_nozzle_button();} + confirm_dlg.Bind(EVT_SECONDARY_CHECK_CONFIRM, [this, &confirm_dlg](wxCommandEvent& e) { confirm_dlg.on_hide(); if (m_print_type == PrintFromType::FROM_SDCARD_VIEW) { @@ -2382,7 +2545,18 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) else { this->on_send_print(); } + }); + confirm_dlg.Bind(EVT_UPDATE_NOZZLE, [this, obj_, tag_nozzle_type, nozzle_diameter, &confirm_dlg](wxCommandEvent& e) { + if (obj_ && !tag_nozzle_type.empty() && !nozzle_diameter.empty()) { + try + { + float diameter = std::stof(nozzle_diameter); + diameter = round(diameter * 10) / 10; + obj_->command_set_printer_nozzle(tag_nozzle_type, diameter); + } + catch (...) {} + } }); confirm_text.push_back(_L("Please click the confirm button if you still want to proceed with printing.") + "\n"); @@ -2413,6 +2587,18 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) } } +wxString SelectMachineDialog::format_steel_name(std::string name) +{ + if (name == "hardened_steel") { + return _L("Hardened Steel"); + } + else if (name == "stainless_steel") { + return _L("Stainless Steel"); + } + + return wxEmptyString; +} + void SelectMachineDialog::Enable_Auto_Refill(bool enable) { if (enable) { @@ -2516,7 +2702,6 @@ void SelectMachineDialog::on_send_print() } } - if (m_print_type == PrintFromType::FROM_NORMAL) { result = m_plater->send_gcode(m_print_plate_idx, [this](int export_stage, int current, int total, bool& cancel) { if (this->m_is_canceled) return; @@ -2565,7 +2750,7 @@ void SelectMachineDialog::on_send_print() m_print_job->m_local_use_ssl_for_mqtt = obj_->local_use_ssl_for_mqtt; #endif m_print_job->connection_type = obj_->connection_type(); - m_print_job->cloud_print_only = obj_->is_cloud_print_only; + m_print_job->cloud_print_only = obj_->is_support_cloud_print_only; if (m_print_type == PrintFromType::FROM_NORMAL) { BOOST_LOG_TRIVIAL(info) << "print_job: m_print_type = from_normal"; @@ -2588,11 +2773,11 @@ void SelectMachineDialog::on_send_print() if (input_str_arr.size() <= 1) { input_str_arr = wxGetApp().split_str(m_required_data_file_name, ".3mf"); if (input_str_arr.size() > 1) { - m_print_job->set_project_name(wxString(input_str_arr[0]).utf8_string()); + m_print_job->set_project_name(input_str_arr[0]); } } else { - m_print_job->set_project_name(wxString(input_str_arr[0]).utf8_string()); + m_print_job->set_project_name(input_str_arr[0]); } } @@ -2652,20 +2837,23 @@ void SelectMachineDialog::update_user_machine_list() { NetworkAgent* m_agent = wxGetApp().getAgent(); if (m_agent && m_agent->is_user_login()) { - boost::thread get_print_info_thread = Slic3r::create_thread([&] { + boost::thread get_print_info_thread = Slic3r::create_thread([this, token = std::weak_ptr(m_token)] { NetworkAgent* agent = wxGetApp().getAgent(); unsigned int http_code; std::string body; int result = agent->get_user_print_info(&http_code, &body); - if (result == 0) { - m_print_info = body; - } - else { - m_print_info = ""; - } - wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); - event.SetEventObject(this); - wxPostEvent(this, event); + CallAfter([token, this, result, body] { + if (token.expired()) {return;} + if (result == 0) { + m_print_info = body; + } + else { + m_print_info = ""; + } + wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); + event.SetEventObject(this); + wxPostEvent(this, event); + }); }); } else { wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); @@ -2716,7 +2904,7 @@ void SelectMachineDialog::on_set_finish_mapping(wxCommandEvent &evt) void SelectMachineDialog::on_print_job_cancel(wxCommandEvent &evt) { BOOST_LOG_TRIVIAL(info) << "print_job: canceled"; - show_status(PrintDialogStatus::PrintStatusSendingCanceled); + show_status(PrintDialogStatus::PrintStatusInit); // enter prepare mode prepare_mode(); } @@ -2902,6 +3090,18 @@ void SelectMachineDialog::on_rename_enter() } auto new_file_name = m_rename_input->GetTextCtrl()->GetValue(); + wxString temp; + int num = 0; + for (auto t : new_file_name) { + if (t == wxString::FromUTF8("\x20")) { + num++; + if (num == 1) temp += t; + } else { + num = 0; + temp += t; + } + } + new_file_name = temp; auto m_valid_type = Valid; wxString info_line; @@ -2973,12 +3173,15 @@ void SelectMachineDialog::on_timer(wxTimerEvent &event) if(!dev) return; MachineObject* obj_ = dev->get_selected_machine(); if(!obj_) return; - if (!obj_ - || obj_->amsList.empty() - || obj_->ams_exist_bits == 0 - || !obj_->ams_support_auto_switch_filament_flag - || !obj_->ams_auto_switch_filament_flag - || !obj_->is_function_supported(PrinterFunction::FUNC_FILAMENT_BACKUP) + + update_ams_check(obj_); + update_select_layout(obj_); + if (!obj_ + || obj_->amsList.empty() + || obj_->ams_exist_bits == 0 + || !obj_->is_support_filament_backup + || !obj_->is_support_show_filament_backup + || !obj_->ams_auto_switch_filament_flag || !m_checkbox_list["use_ams"]->GetValue() ) { if (m_ams_backup_tip->IsShown()) { m_ams_backup_tip->Hide(); @@ -3041,6 +3244,14 @@ void SelectMachineDialog::on_selection_changed(wxCommandEvent &event) }else if (dev->get_selected_machine()->dev_id != m_printer_last_select) { dev->set_selected_machine(m_printer_last_select, true); } + + // reset the timelapse check status for I3 structure + if (obj->get_printer_arch() == PrinterArch::ARCH_I3) { + m_checkbox_list["timelapse"]->SetValue(false); + AppConfig *config = wxGetApp().app_config; + if (config) config->set_str("print", "timelapse", "0"); + } + // Has changed machine unrecoverably GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj); update_select_layout(obj); @@ -3065,7 +3276,7 @@ void SelectMachineDialog::update_flow_cali_check(MachineObject* obj) auto bed_type = m_plater->get_partplate_list().get_curr_plate()->get_bed_type(true); auto show_cali_tips = true; - if (obj && obj->printer_type == "N1") { show_cali_tips = false; } + if (obj && obj->get_printer_arch() == PrinterArch::ARCH_I3) { show_cali_tips = false; } if (bed_type == BedType::btPTE) { set_flow_calibration_state(false, show_cali_tips); @@ -3077,12 +3288,14 @@ void SelectMachineDialog::update_flow_cali_check(MachineObject* obj) void SelectMachineDialog::update_ams_check(MachineObject* obj) { - if (obj && obj->is_function_supported(FUNC_USE_AMS) - && obj->ams_support_use_ams - && obj->has_ams()) { + if (obj && obj->ams_support_use_ams && obj->has_ams()) { select_use_ams->Show(); - if (obj->printer_type == "N1") {img_ams_tip->Hide();} - else {img_ams_tip->Show();} + if (obj->get_printer_ams_type() == "generic") { + img_use_ams_tip->Show(); + } + else { + img_use_ams_tip->Hide(); + } } else { select_use_ams->Hide(); } @@ -3157,9 +3370,9 @@ void SelectMachineDialog::update_show_status() } reset_timeout(); - update_ams_check(obj_); + //update_ams_check(obj_); - if (!obj_->is_function_supported(PrinterFunction::FUNC_PRINT_ALL) && m_print_plate_idx == PLATE_ALL_IDX) { + if (!obj_->is_support_print_all && m_print_plate_idx == PLATE_ALL_IDX) { show_status(PrintDialogStatus::PrintStatusNotSupportedPrintAll); return; } @@ -3199,7 +3412,7 @@ void SelectMachineDialog::update_show_status() } } - if (m_print_type == PrintFromType::FROM_NORMAL && is_blocking_printing()) { + if (m_print_type == PrintFromType::FROM_NORMAL && is_blocking_printing(obj_)) { show_status(PrintDialogStatus::PrintStatusUnsupportedPrinter); return; } @@ -3215,7 +3428,7 @@ void SelectMachineDialog::update_show_status() show_status(PrintDialogStatus::PrintStatusInPrinting); return; } - else if (!obj_->is_function_supported(PrinterFunction::FUNC_PRINT_WITHOUT_SD) && (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD)) { + else if (!obj_->is_support_print_without_sd && (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD)) { show_status(PrintDialogStatus::PrintStatusNoSdcard); return; } @@ -3249,6 +3462,7 @@ void SelectMachineDialog::update_show_status() } } + // do ams mapping if no ams result if (m_ams_mapping_result.empty()) { do_ams_mapping(obj_); @@ -3429,9 +3643,9 @@ void SelectMachineDialog::on_dpi_changed(const wxRect &suggested_rect) ams_editable->msw_rescale(); ams_editable_light->msw_rescale(); enable_ams_mapping->msw_rescale(); - amsmapping_tip->SetBitmap(enable_ams_mapping->bmp()); + img_amsmapping_tip->SetBitmap(enable_ams_mapping->bmp()); enable_ams->msw_rescale(); - img_ams_tip->SetBitmap(enable_ams->bmp()); + img_use_ams_tip->SetBitmap(enable_ams->bmp()); m_button_refresh->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE); m_button_refresh->SetCornerRadius(FromDIP(12)); @@ -3596,7 +3810,7 @@ void SelectMachineDialog::set_default() else if (m_print_type == PrintFromType::FROM_SDCARD_VIEW) { set_default_from_sdcard(); } - + Layout(); Fit(); } @@ -3624,27 +3838,38 @@ void SelectMachineDialog::set_default_normal() std::vector materials; std::vector brands; std::vector display_materials; + std::vector m_filaments_id; + auto preset_bundle = wxGetApp().preset_bundle; + for (auto filament_name : preset_bundle->filament_presets) { - for (auto iter = preset_bundle->filaments.lbegin(); iter != preset_bundle->filaments.end(); iter++) { - if (filament_name.compare(iter->name) == 0) { + for (int f_index = 0; f_index < preset_bundle->filaments.size(); f_index++) { + PresetCollection* filament_presets = &wxGetApp().preset_bundle->filaments; + Preset* preset = &filament_presets->preset(f_index); + + if (preset && filament_name.compare(preset->name) == 0) { std::string display_filament_type; - std::string filament_type = iter->config.get_filament_type(display_filament_type); + std::string filament_type = preset->config.get_filament_type(display_filament_type); + std::string m_filament_id=preset->filament_id; display_materials.push_back(display_filament_type); materials.push_back(filament_type); + m_filaments_id.push_back(m_filament_id); - if (iter->vendor && !iter->vendor->name.empty()) - brands.push_back(iter->vendor->name); - else - brands.push_back(""); + std::string m_vendor_name = ""; + auto vendor = dynamic_cast (preset->config.option("filament_vendor")); + if (vendor && (vendor->values.size() > 0)) { + std::string vendor_name = vendor->values[0]; + m_vendor_name = vendor_name; + } + brands.push_back(m_vendor_name); } } } //init MaterialItem auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders(); - + MaterialHash::iterator iter = m_materialList.begin(); while (iter != m_materialList.end()) { int id = iter->first; @@ -3673,11 +3898,6 @@ void SelectMachineDialog::set_default_normal() item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent& e) {}); item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent& e) { - - DeviceManager* dev_manager = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (!dev_manager) return; - MachineObject* curr_obj = dev_manager->get_selected_machine(); - MaterialHash::iterator iter = m_materialList.begin(); while (iter != m_materialList.end()) { int id = iter->first; @@ -3693,26 +3913,31 @@ void SelectMachineDialog::set_default_normal() auto mouse_pos = ClientToScreen(e.GetPosition()); wxPoint rect = item->ClientToScreen(wxPoint(0, 0)); + // update ams data + DeviceManager* dev_manager = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev_manager) return; + MachineObject* obj_ = dev_manager->get_selected_machine(); - if (curr_obj && curr_obj->is_support_ams_mapping()) { + if (obj_ && obj_->is_support_ams_mapping()) { if (m_mapping_popup.IsShown()) return; wxPoint pos = item->ClientToScreen(wxPoint(0, 0)); pos.y += item->GetRect().height; m_mapping_popup.Move(pos); - if (curr_obj->has_ams() && + if (obj_ && + obj_->has_ams() && m_checkbox_list["use_ams"]->GetValue() && - curr_obj->dev_id == m_printer_last_select) + obj_->dev_id == m_printer_last_select) { m_mapping_popup.set_parent_item(item); m_mapping_popup.set_current_filament_id(extruder); m_mapping_popup.set_tag_texture(materials[extruder]); - m_mapping_popup.update_ams_data(curr_obj->amsList); + m_mapping_popup.update_ams_data(obj_->amsList); m_mapping_popup.Popup(); } } - }); + }); Material* material_item = new Material(); material_item->id = extruder; @@ -3725,6 +3950,7 @@ void SelectMachineDialog::set_default_normal() info.id = extruder; info.type = materials[extruder]; info.brand = brands[extruder]; + info.filament_id=m_filaments_id[extruder]; info.color = wxString::Format("#%02X%02X%02X%02X", colour_rgb.Red(), colour_rgb.Green(), colour_rgb.Blue(), colour_rgb.Alpha()).ToStdString(); m_filaments.push_back(info); } @@ -3754,7 +3980,7 @@ void SelectMachineDialog::set_default_normal() auto dialogSize = this->GetSize(); #ifdef __WINDOWS__ - if (screenSize.y < dialogSize.y) { + if (screenSize.GetHeight() < dialogSize.GetHeight()) { m_need_adaptation_screen = true; m_scrollable_view->SetScrollRate(0, 5); m_scrollable_view->SetSize(wxSize(-1, FromDIP(220))); @@ -3778,7 +4004,12 @@ void SelectMachineDialog::set_default_normal() } char weight[64]; - ::sprintf(weight, " %.2f g", aprint_stats.total_weight); + if (wxGetApp().app_config->get("use_inches") == "1") { + ::sprintf(weight, " %.2f oz", aprint_stats.total_weight * 0.035274); + } + else { + ::sprintf(weight, " %.2f g", aprint_stats.total_weight); + } m_stext_time->SetLabel(time); m_stext_weight->SetLabel(weight); @@ -3910,7 +4141,7 @@ void SelectMachineDialog::set_default_from_sdcard() auto dialogSize = this->GetSize(); #ifdef __WINDOWS__ - if (screenSize.y < dialogSize.y) { + if (screenSize.GetHeight() < dialogSize.GetHeight()) { m_need_adaptation_screen = true; m_scrollable_view->SetScrollRate(0, 5); m_scrollable_view->SetSize(wxSize(-1, FromDIP(220))); @@ -4200,7 +4431,9 @@ void EditDevNameDialog::on_edit_name(wxCommandEvent &e) SetBackgroundStyle(wxBG_STYLE_CUSTOM); wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL); m_staticbitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize); + m_background_bitmap = ScalableBitmap(this,"thumbnail_grid",256); sizer->Add(m_staticbitmap, 1, wxEXPAND, 0); + Bind(wxEVT_PAINT, &ThumbnailPanel::OnPaint, this); SetSizer(sizer); Layout(); Fit(); @@ -4208,8 +4441,39 @@ void EditDevNameDialog::on_edit_name(wxCommandEvent &e) void ThumbnailPanel::set_thumbnail(wxImage img) { - wxBitmap bitmap(img); - m_staticbitmap->SetBitmap(bitmap); + m_bitmap = img; + //Paint the background bitmap to the thumbnail bitmap with wxMemoryDC + wxMemoryDC dc; + bitmap_with_background.Create(wxSize(m_bitmap.GetWidth(), m_bitmap.GetHeight())); + dc.SelectObject(bitmap_with_background); + dc.DrawBitmap(m_background_bitmap.bmp(), 0, 0); + dc.DrawBitmap(m_bitmap, 0, 0); + dc.SelectObject(wxNullBitmap); + + } + + void ThumbnailPanel::OnPaint(wxPaintEvent& event) { + + wxPaintDC dc(this); + render(dc); + } + + void ThumbnailPanel::render(wxDC& dc) { + + if (wxGetApp().dark_mode()) { + #ifdef __WXMSW__ + wxMemoryDC memdc; + wxBitmap bmp(GetSize()); + memdc.SelectObject(bmp); + memdc.DrawBitmap(bitmap_with_background, 0, 0); + dc.Blit(0, 0, GetSize().GetWidth(), GetSize().GetHeight(), &memdc, 0, 0); + #else + dc.DrawBitmap(bitmap_with_background, 0, 0); + #endif + } + else + dc.DrawBitmap(m_bitmap, 0, 0); + } ThumbnailPanel::~ThumbnailPanel() {} diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index ba3d8611b24..c8668edc64c 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -215,7 +215,8 @@ class SelectMachinePopup : public PopupWindow std::vector m_user_list_machine_panel; std::vector m_other_list_machine_panel; boost::thread* get_print_info_thread{ nullptr }; - std::string m_print_info; + std::shared_ptr m_token = std::make_shared(0); + std::string m_print_info = ""; bool m_dismiss { false }; std::map m_bind_machine_list; @@ -304,6 +305,7 @@ class SelectMachineDialog : public DPIDialog wxColour m_colour_bold_color{wxColour(38, 46, 48)}; StateColor m_btn_bg_enable; + std::shared_ptr m_token = std::make_shared(0); std::map m_checkbox_list; //std::map m_checkbox_state_list; std::vector m_bedtype_list; @@ -341,6 +343,7 @@ class SelectMachineDialog : public DPIDialog wxStaticBitmap* m_staticbitmap{ nullptr }; wxStaticBitmap* m_bitmap_last_plate{ nullptr }; wxStaticBitmap* m_bitmap_next_plate{ nullptr }; + wxStaticBitmap* img_amsmapping_tip{nullptr}; ThumbnailPanel* m_thumbnailPanel{ nullptr }; wxWindow* select_bed{ nullptr }; wxWindow* select_flow{ nullptr }; @@ -359,8 +362,8 @@ class SelectMachineDialog : public DPIDialog Label* m_st_txt_error_code{nullptr}; Label* m_st_txt_error_desc{nullptr}; Label* m_st_txt_extra_info{nullptr}; - Label * m_link_network_state; Label* m_ams_backup_tip{nullptr}; + wxHyperlinkCtrl* m_link_network_state{ nullptr }; wxSimplebook* m_rename_switch_panel{nullptr}; wxSimplebook* m_simplebook{nullptr}; wxStaticText* m_rename_text{nullptr}; @@ -384,9 +387,8 @@ class SelectMachineDialog : public DPIDialog ScalableBitmap * print_time{nullptr}; wxStaticBitmap * weightimg{nullptr}; ScalableBitmap * print_weight{nullptr}; - wxStaticBitmap * amsmapping_tip{nullptr}; ScalableBitmap * enable_ams_mapping{nullptr}; - wxStaticBitmap * img_ams_tip{nullptr}; + wxStaticBitmap * img_use_ams_tip{nullptr}; wxStaticBitmap * img_ams_backup{nullptr}; ScalableBitmap * enable_ams{nullptr}; @@ -448,7 +450,9 @@ class SelectMachineDialog : public DPIDialog bool has_timelapse_warning(); void update_timelapse_enable_status(); bool is_same_printer_model(); - bool is_blocking_printing(); + bool is_blocking_printing(MachineObject* obj_); + bool is_same_nozzle_diameters(std::string& tag_nozzle_type, std::string& nozzle_diameter); + bool is_same_nozzle_type(std::string& filament_type, std::string& tag_nozzle_type); bool has_tips(MachineObject* obj); bool is_timeout(); int update_print_required_data(Slic3r::DynamicPrintConfig config, Slic3r::Model model, Slic3r::PlateDataPtrs plate_data_list, std::string file_name, std::string file_path); @@ -458,6 +462,7 @@ class SelectMachineDialog : public DPIDialog bool get_ams_mapping_result(std::string& mapping_array_str, std::string& ams_mapping_info); PrintFromType get_print_type() {return m_print_type;}; + wxString format_steel_name(std::string name); wxString format_text(wxString &m_msg); wxWindow* create_ams_checkbox(wxString title, wxWindow* parent, wxString tooltip); wxWindow* create_item_checkbox(wxString title, wxWindow* parent, wxString tooltip, std::string param); @@ -496,7 +501,7 @@ class EditDevNameDialog : public DPIDialog class ThumbnailPanel : public wxPanel { public: - wxBitmap * m_bitmap{nullptr}; + wxBitmap m_bitmap; wxStaticBitmap *m_staticbitmap{nullptr}; ThumbnailPanel(wxWindow * parent, @@ -509,6 +514,10 @@ class ThumbnailPanel : public wxPanel void PaintBackground(wxDC &dc); void OnEraseBackground(wxEraseEvent &event); void set_thumbnail(wxImage img); + void render(wxDC &dc); +private: + ScalableBitmap m_background_bitmap; + wxBitmap bitmap_with_background; }; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 9e385ab54c9..aef47ed6d07 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -418,6 +418,22 @@ void Selection::add_curr_plate() this->set_bounding_boxes_dirty(); } +void Selection::add_object_from_idx(std::vector& object_idxs) { + if (!m_valid) + return; + + m_mode = Instance; + clear(); + + for (int obj_idx = 0; obj_idx < object_idxs.size(); obj_idx++) { + std::vector volume_idxs = get_volume_idxs_from_object(object_idxs[obj_idx]); + do_add_volumes(volume_idxs); + } + + update_type(); + this->set_bounding_boxes_dirty(); +} + void Selection::remove_curr_plate() { if (!m_valid) @@ -446,10 +462,12 @@ void Selection::remove_curr_plate() void Selection::clone(int numbers) { - if (numbers > 0) - wxGetApp().plater()->take_snapshot(std::string("Selection-clone!")); + if (numbers <= 0) + return; + + wxGetApp().plater()->take_snapshot(std::string("Selection-clone")); + copy_to_clipboard(); for (int i = 0; i < numbers; i++) { - copy_to_clipboard(); paste_from_clipboard(); } } @@ -468,6 +486,20 @@ void Selection::center() return; } +void Selection::center_plate(const int plate_idx) { + + PartPlate* plate = wxGetApp().plater()->get_partplate_list().get_plate(plate_idx); + + + Vec3d src_pos = this->get_bounding_box().center(); + Vec3d tar_pos = plate->get_center_origin(); + Vec3d distance = Vec3d(tar_pos.x() - src_pos.x(), tar_pos.y() - src_pos.y(), 0); + + this->move_to_center(distance); + wxGetApp().plater()->get_view3D_canvas3D()->do_move(L("Move Object")); + return; +} + //BBS void Selection::set_printable(bool printable) { @@ -905,7 +937,7 @@ void Selection::translate(const Vec3d& displacement, bool local) Vec3d tower_size = v.bounding_box().size(); Vec3d tower_origin = m_cache.volumes_data[i].get_volume_position(); Vec3d actual_displacement = displacement; - const double margin = 15.f; + const double margin = WIPE_TOWER_MARGIN; if (!local) actual_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement; @@ -2802,7 +2834,7 @@ void Selection::paste_objects_from_clipboard() { const ModelObject *src_object = src_objects[i]; ModelObject* dst_object = m_model->add_object(*src_object); - + // BBS: find an empty cell to put the copied object BoundingBoxf3 bbox = src_object->instance_convex_hull_bounding_box(0); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index e130cb18bea..233fb4aa521 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -219,9 +219,11 @@ class Selection //BBS void add_curr_plate(); + void add_object_from_idx(std::vector& object_idxs); void remove_curr_plate(); void clone(int numbers = 1); void center(); + void center_plate(const int plate_idx); void set_printable(bool printable); void add_all(); @@ -280,7 +282,6 @@ class Selection const IndicesList& get_volume_idxs() const { return m_list; } const GLVolume* get_volume(unsigned int volume_idx) const; const GLVolume* get_first_volume() const { return get_volume(*m_list.begin()); } - const ObjectIdxsToInstanceIdxsMap& get_content() const { return m_cache.content; } unsigned int volumes_count() const { return (unsigned int)m_list.size(); } diff --git a/src/slic3r/GUI/SendSystemInfoDialog.cpp b/src/slic3r/GUI/SendSystemInfoDialog.cpp index b93c00f767a..73de9101c42 100644 --- a/src/slic3r/GUI/SendSystemInfoDialog.cpp +++ b/src/slic3r/GUI/SendSystemInfoDialog.cpp @@ -438,7 +438,7 @@ static std::string generate_system_info_json() ); #endif // __WXGTK__ data_node.put("SystemLanguage", sys_language); - data_node.put("TranslationLanguage: ", wxGetApp().app_config->get("language")); + data_node.put("TranslationLanguage: ", wxGetApp().current_language_code_safe()); pt::ptree hw_node; diff --git a/src/slic3r/GUI/SendToPrinter.cpp b/src/slic3r/GUI/SendToPrinter.cpp index 9ce0de27dbf..4f6a2e7ecee 100644 --- a/src/slic3r/GUI/SendToPrinter.cpp +++ b/src/slic3r/GUI/SendToPrinter.cpp @@ -107,6 +107,20 @@ void SendToPrinterDialog::on_rename_enter() } auto new_file_name = m_rename_input->GetTextCtrl()->GetValue(); + + wxString temp; + int num = 0; + for (auto t : new_file_name) { + if (t == wxString::FromUTF8("\x20")) { + num++; + if (num == 1) temp += t; + } else { + num = 0; + temp += t; + } + } + new_file_name = temp; + auto m_valid_type = Valid; wxString info_line; @@ -380,8 +394,7 @@ SendToPrinterDialog::SendToPrinterDialog(Plater *plater) sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0); - m_link_network_state = new Label(m_sw_print_failed_info, _L("Check the status of current system services")); - m_link_network_state->SetForegroundColour(0x009688); + m_link_network_state = new wxHyperlinkCtrl(m_sw_print_failed_info, wxID_ANY,_L("Check the status of current system services"),""); m_link_network_state->SetFont(::Label::Body_12); m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); }); m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND); }); @@ -422,7 +435,7 @@ SendToPrinterDialog::SendToPrinterDialog(Plater *plater) rename_sizer_v = new wxBoxSizer(wxVERTICAL); rename_sizer_h = new wxBoxSizer(wxHORIZONTAL); - m_rename_text = new wxStaticText(m_rename_normal_panel, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, 0); + m_rename_text = new wxStaticText(m_rename_normal_panel, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END); m_rename_text->SetForegroundColour(*wxBLACK); m_rename_text->SetFont(::Label::Body_13); m_rename_text->SetMaxSize(wxSize(FromDIP(390), -1)); @@ -565,25 +578,27 @@ void SendToPrinterDialog::show_print_failed_info(bool show, int code, wxString d void SendToPrinterDialog::prepare_mode() { - m_is_in_sending_mode = false; - if (m_send_job) { - m_send_job->join(); - } + m_is_in_sending_mode = false; + m_comboBox_printer->Enable(); + if (m_send_job) { + m_send_job->join(); + } - if (wxIsBusy()) - wxEndBusyCursor(); - Enable_Send_Button(true); + if (wxIsBusy()) + wxEndBusyCursor(); + Enable_Send_Button(true); show_print_failed_info(false); m_status_bar->reset(); - if (m_simplebook->GetSelection() != 0) { - m_simplebook->SetSelection(0); - } + if (m_simplebook->GetSelection() != 0) { + m_simplebook->SetSelection(0); + } } void SendToPrinterDialog::sending_mode() { m_is_in_sending_mode = true; + m_comboBox_printer->Disable(); if (m_simplebook->GetSelection() != 1){ m_simplebook->SetSelection(1); Layout(); @@ -781,7 +796,7 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) enable_prepare_mode = false; - m_send_job->on_check_ip_address_fail([this]() { + m_send_job->on_check_ip_address_fail([this](int result) { wxCommandEvent* evt = new wxCommandEvent(EVT_CLEAR_IPADDRESS); wxQueueEvent(this, evt); wxGetApp().show_ip_address_enter_dialog(); @@ -809,20 +824,23 @@ void SendToPrinterDialog::update_user_machine_list() { NetworkAgent* m_agent = wxGetApp().getAgent(); if (m_agent && m_agent->is_user_login()) { - boost::thread get_print_info_thread = Slic3r::create_thread([&] { + boost::thread get_print_info_thread = Slic3r::create_thread([this, token = std::weak_ptr(m_token)] { NetworkAgent* agent = wxGetApp().getAgent(); unsigned int http_code; std::string body; int result = agent->get_user_print_info(&http_code, &body); - if (result == 0) { - m_print_info = body; - } - else { - m_print_info = ""; - } - wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); - event.SetEventObject(this); - wxPostEvent(this, event); + CallAfter([token, this, result, body] { + if (token.expired()) {return;} + if (result == 0) { + m_print_info = body; + } + else { + m_print_info = ""; + } + wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); + event.SetEventObject(this); + wxPostEvent(this, event); + }); }); } else { wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); @@ -1026,7 +1044,7 @@ void SendToPrinterDialog::update_show_status() if (!obj_->is_info_ready()) { if (is_timeout()) { - (PrintDialogStatus::PrintStatusReadingTimeout); + show_status(PrintDialogStatus::PrintStatusReadingTimeout); return; } else { @@ -1039,12 +1057,6 @@ void SendToPrinterDialog::update_show_status() reset_timeout(); - bool is_suppt = obj_->is_function_supported(PrinterFunction::FUNC_SEND_TO_SDCARD); - if (!is_suppt) { - show_status(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard); - return; - } - // reading done if (obj_->is_in_upgrading()) { show_status(PrintDialogStatus::PrintStatusInUpgrading); @@ -1063,12 +1075,16 @@ void SendToPrinterDialog::update_show_status() return; } - if (obj_->dev_ip.empty()) { - show_status(PrintDialogStatus::PrintStatusNotOnTheSameLAN); + + if (!obj_->is_support_send_to_sdcard) { + show_status(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard); + return; + } + + if (!m_is_in_sending_mode) { + show_status(PrintDialogStatus::PrintStatusReadingFinished); return; } - - show_status(PrintDialogStatus::PrintStatusReadingFinished); } void SendToPrinterDialog::Enable_Refresh_Button(bool en) @@ -1317,7 +1333,11 @@ void SendToPrinterDialog::set_default() } char weight[64]; - ::sprintf(weight, " %.2f g", aprint_stats.total_weight); + if (wxGetApp().app_config->get("use_inches") == "1") { + ::sprintf(weight, " %.2f oz", aprint_stats.total_weight*0.035274); + }else{ + ::sprintf(weight, " %.2f g", aprint_stats.total_weight); + } m_stext_time->SetLabel(time); m_stext_weight->SetLabel(weight); diff --git a/src/slic3r/GUI/SendToPrinter.hpp b/src/slic3r/GUI/SendToPrinter.hpp index 33f198d1a80..6b348c66569 100644 --- a/src/slic3r/GUI/SendToPrinter.hpp +++ b/src/slic3r/GUI/SendToPrinter.hpp @@ -95,7 +95,7 @@ class SendToPrinterDialog : public DPIDialog Label* m_st_txt_error_code{ nullptr }; Label* m_st_txt_error_desc{ nullptr }; Label* m_st_txt_extra_info{ nullptr }; - Label * m_link_network_state; + wxHyperlinkCtrl* m_link_network_state{ nullptr }; StateColor btn_bg_enable; wxBoxSizer* rename_sizer_v{ nullptr }; wxBoxSizer* rename_sizer_h{ nullptr }; @@ -114,7 +114,7 @@ class SendToPrinterDialog : public DPIDialog wxTimer* m_refresh_timer{ nullptr }; std::shared_ptr m_status_bar; wxScrolledWindow* m_sw_print_failed_info{nullptr}; - + std::shared_ptr m_token = std::make_shared(0); public: SendToPrinterDialog(Plater* plater = nullptr); diff --git a/src/slic3r/GUI/SlicingProgressNotification.cpp b/src/slic3r/GUI/SlicingProgressNotification.cpp new file mode 100644 index 00000000000..1ba866076df --- /dev/null +++ b/src/slic3r/GUI/SlicingProgressNotification.cpp @@ -0,0 +1,490 @@ +#include "SlicingProgressNotification.hpp" + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include + +namespace Slic3r { namespace GUI { + +namespace { + inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) + { + if (fading_out) + ImGui::PushStyleColor(idx, ImVec4(col.x, col.y, col.z, col.w * current_fade_opacity)); + else + ImGui::PushStyleColor(idx, col); + } +} + +void NotificationManager::SlicingProgressNotification::on_change_color_mode(bool is_dark) +{ + PopNotification::on_change_color_mode(is_dark); + m_dailytips_panel->on_change_color_mode(is_dark); +} + +void NotificationManager::SlicingProgressNotification::init() +{ + if (m_sp_state == SlicingProgressState::SP_PROGRESS) { + PopNotification::init(); + if (m_endlines.empty()) { + m_endlines.push_back(0); + } + if (m_lines_count >= 2) { + m_lines_count = 3; + m_multiline = true; + while (m_endlines.size() < 3) + m_endlines.push_back(m_endlines.back()); + } + else { + m_lines_count = 2; + m_endlines.push_back(m_endlines.back()); + m_multiline = false; + } + if (m_state == EState::Shown) + m_state = EState::NotFading; + } + else { + PopNotification::init(); + } + +} + +bool NotificationManager::SlicingProgressNotification::set_progress_state(float percent) +{ + if (percent < 0.f) + return true;//set_progress_state(SlicingProgressState::SP_CANCELLED); + else if (percent >= 1.f) { + m_before_complete_start = GLCanvas3D::timestamp_now(); + return set_progress_state(SlicingProgressState::SP_COMPLETED); + } + else + return set_progress_state(SlicingProgressState::SP_PROGRESS, percent); +} + +bool NotificationManager::SlicingProgressNotification::set_progress_state(NotificationManager::SlicingProgressNotification::SlicingProgressState state, float percent/* = 0.f*/) +{ + switch (state) + { + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: + m_state = EState::Hidden; + set_percentage(-1); + m_has_print_info = false; + set_export_possible(false); + m_sp_state = state; + return true; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_BEGAN: + m_state = EState::Hidden; + set_percentage(-1); + m_has_print_info = false; + set_export_possible(false); + m_sp_state = state; + m_current_fade_opacity = 1; + return true; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: + if ((m_sp_state != SlicingProgressState::SP_BEGAN && m_sp_state != SlicingProgressState::SP_PROGRESS) || percent < m_percentage) + return false; + set_percentage(percent); + m_sp_state = state; + m_current_fade_opacity = 1; + return true; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: + set_percentage(-1); + m_has_print_info = false; + set_export_possible(false); + m_sp_state = state; + return true; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: + if (m_sp_state != SlicingProgressState::SP_BEGAN && m_sp_state != SlicingProgressState::SP_PROGRESS) + return false; + set_percentage(1); + m_has_print_info = false; + // m_export_possible is important only for SP_PROGRESS state, thus we can reset it here + set_export_possible(false); + m_sp_state = state; + return true; + default: + break; + } + return false; +} + +void NotificationManager::SlicingProgressNotification::set_status_text(const std::string& text) +{ + switch (m_sp_state) + { + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: + m_state = EState::Hidden; + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: + { + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text + "." }; + update(data); + m_state = EState::NotFading; + } + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: + { + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text }; + update(data); + m_state = EState::Shown; + } + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: + { + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, _u8L("Slice ok.") }; + update(data); + m_state = EState::Shown; + } + break; + default: + break; + } +} + +void NotificationManager::SlicingProgressNotification::set_print_info(const std::string& info) +{ + if (m_sp_state != SlicingProgressState::SP_COMPLETED) { + set_progress_state (SlicingProgressState::SP_COMPLETED); + } else { + m_has_print_info = true; + m_print_info = info; + } +} + +void NotificationManager::SlicingProgressNotification::set_sidebar_collapsed(bool collapsed) +{ + m_sidebar_collapsed = collapsed; + if (m_sp_state == SlicingProgressState::SP_COMPLETED && collapsed) + m_state = EState::NotFading; +} + +void NotificationManager::SlicingProgressNotification::on_cancel_button() +{ + if (m_cancel_callback){ + if (!m_cancel_callback()) { + set_progress_state(SlicingProgressState::SP_NO_SLICING); + } + } +} + +int NotificationManager::SlicingProgressNotification::get_duration() +{ + if (m_sp_state == SlicingProgressState::SP_CANCELLED) + return 3; + else if (m_sp_state == SlicingProgressState::SP_COMPLETED) + return 3; + else + return 0; +} + +bool NotificationManager::SlicingProgressNotification::update_state(bool paused, const int64_t delta) +{ + bool ret = PopNotification::update_state(paused, delta); + if (m_sp_state == SlicingProgressState::SP_COMPLETED) + ret = true; + + // sets Estate to hidden + if (get_state() == PopNotification::EState::ClosePending || get_state() == PopNotification::EState::Finished) + set_progress_state(SlicingProgressState::SP_NO_SLICING); + return ret; +} + +void NotificationManager::SlicingProgressNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin) +{ + if (m_state == EState::Unknown || m_state == PopNotification::EState::Hovered) + init(); + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + float scale = imgui.get_font_size() / 15.0f; + + bool fading_pop = false; + if (m_state == EState::FadingOut) { + push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity); + push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, m_current_fade_opacity); + push_style_color(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered), true, m_current_fade_opacity); + fading_pop = true; + } + use_bbl_theme(); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8 * scale, 0)); + // for debug + //ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, m_WindowRadius / 4); + //m_is_dark ? push_style_color(ImGuiCol_Border, { 62 / 255.f, 62 / 255.f, 69 / 255.f, 1.f }, true, m_current_fade_opacity) : push_style_color(ImGuiCol_Border, m_CurrentColor, true, m_current_fade_opacity); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + push_style_color(ImGuiCol_Border, { 0, 0, 0, 0 }, true, m_current_fade_opacity); + + Size cnv_size = canvas.get_canvas_size(); + + //m_window_width = 600.f * scale; + //if (m_sp_state == SlicingProgressNotification::SlicingProgressState::SP_COMPLETED || m_sp_state == SlicingProgressNotification::SlicingProgressState::SP_CANCELLED) + // m_window_width = m_line_height * 25; + const ImVec2 progress_child_window_padding = ImVec2(15.f, 0.f) * scale; + const ImVec2 dailytips_child_window_padding = m_dailytips_panel->is_expanded() ? ImVec2(15.f, 10.f) * scale : ImVec2(15.f, 0.f) * scale; + const ImVec2 bottom_padding = ImVec2(0.f, 0.f) * scale; + const float progress_panel_width = (m_window_width - 2 * progress_child_window_padding.x); + const float progress_panel_height = (58.0f * scale); + const float dailytips_panel_width = (m_window_width - 2 * dailytips_child_window_padding.x); + const float gcodeviewer_height = wxGetApp().plater()->get_preview_canvas3D()->get_gcode_viewer().get_legend_height(); + //const float dailytips_panel_height = std::min(380.0f * scale, std::max(90.0f, (cnv_size.get_height() - gcodeviewer_height - progress_panel_height - dailytips_child_window_padding.y - initial_y - m_line_height * 4))); + const float dailytips_panel_height = 380.0f * scale; + + float right_gap = right_margin + (move_from_overlay ? overlay_width + m_line_height * 5 : 0); + m_window_pos = ImVec2((float)cnv_size.get_width() - right_gap - m_window_width, (float)cnv_size.get_height() - m_top_y); + imgui.set_next_window_pos(m_window_pos.x, m_window_pos.y, ImGuiCond_Always, 0.0f, 0.0f); + m_window_height = progress_panel_height + m_dailytips_panel->get_size().y + progress_child_window_padding.y + dailytips_child_window_padding.y + bottom_padding.y; + m_top_y = initial_y + m_window_height; + ImGui::SetNextWindowSizeConstraints(ImVec2(m_window_width, m_window_height), ImVec2(m_window_width, m_window_height)); + + // name of window indentifies window - has to be unique string + if (m_id == 0) + m_id = m_id_provider.allocate_id(); + std::string name = "!!Ntfctn" + std::to_string(m_id); + int window_flags = ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoScrollbar | + ImGuiWindowFlags_NoScrollWithMouse; + int child_window_flags = ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_NoScrollbar | + ImGuiWindowFlags_NoScrollWithMouse; + if (imgui.begin(name, window_flags)) { + ImGuiWindow* parent_window = ImGui::GetCurrentWindow(); + + //if (m_sp_state == SlicingProgressState::SP_CANCELLED || m_sp_state == SlicingProgressState::SP_COMPLETED) { + // ImVec2 button_size = ImVec2(38.f, 38.f) * scale; + // float button_right_margin_x = 3.0f * scale; + // ImVec2 button_pos = m_window_pos + ImVec2(m_window_width - button_size.x - button_right_margin_x, (m_window_height - button_size.y) / 2.0f); + // float text_left_margin_x = 15.0f * scale; + // ImVec2 text_pos = m_window_pos + ImVec2(text_left_margin_x, m_window_height / 2.0f - m_line_height * 1.2f); + // ImVec2 view_dailytips_text_pos = m_window_pos + ImVec2(text_left_margin_x, m_window_height / 2.0f + m_line_height * 0.2f); + + // bbl_render_left_sign(imgui, m_window_width, m_window_height, m_window_pos.x + m_window_width, m_window_pos.y); + // render_text(text_pos); + // render_close_button(button_pos, button_size); + // render_show_dailytips(view_dailytips_text_pos); + //} + + if (m_sp_state == SlicingProgressState::SP_CANCELLED || m_sp_state == SlicingProgressState::SP_PROGRESS || m_sp_state == SlicingProgressState::SP_COMPLETED) { + std::string child_name = "##SlicingProgressPanel" + std::to_string(parent_window->ID); + + ImGui::SetNextWindowPos(parent_window->Pos + progress_child_window_padding); + if (ImGui::BeginChild(child_name.c_str(), ImVec2(progress_panel_width, progress_panel_height), false, child_window_flags)) { + ImVec2 child_window_pos = ImGui::GetWindowPos(); + ImVec2 button_size = ImVec2(38.f, 38.f) * scale; + ImVec2 button_pos = child_window_pos + ImVec2(progress_panel_width - button_size.x, (progress_panel_height - button_size.y) / 2.0f); + float margin_x = 8.0f * scale; + ImVec2 progress_bar_pos = child_window_pos + ImVec2(0, progress_panel_height / 2.0f); + ImVec2 progress_bar_size = ImVec2(progress_panel_width - button_size.x - margin_x, 4.0f * scale); + ImVec2 text_pos = ImVec2(progress_bar_pos.x, progress_bar_pos.y - m_line_height * 1.2f); + + render_text(text_pos); + render_close_button(button_pos, button_size); + if (m_sp_state == SlicingProgressState::SP_PROGRESS) { + render_bar(progress_bar_pos, progress_bar_size); + render_cancel_button(button_pos, button_size); + } + } + ImGui::EndChild(); + + // Separator Line + ImVec2 separator_min = ImVec2(ImGui::GetCursorScreenPos().x + progress_child_window_padding.x, ImGui::GetCursorScreenPos().y); + ImVec2 separator_max = ImVec2(ImGui::GetCursorScreenPos().x + progress_child_window_padding.x + progress_panel_width, ImGui::GetCursorScreenPos().y); + ImGui::GetCurrentWindow()->DrawList->AddLine(separator_min, separator_max, ImColor(238, 238, 238, (int)(255 * m_current_fade_opacity))); + + child_name = "##DailyTipsPanel" + std::to_string(parent_window->ID); + ImVec2 dailytips_pos = ImGui::GetCursorScreenPos() + dailytips_child_window_padding; + ImVec2 dailytips_size = ImVec2(dailytips_panel_width, dailytips_panel_height); + m_dailytips_panel->set_position(dailytips_pos); + m_dailytips_panel->set_size(dailytips_size); + m_dailytips_panel->set_fade_opacity(m_current_fade_opacity); + ImGui::SetNextWindowPos(dailytips_pos); + if (ImGui::BeginChild(child_name.c_str(), ImVec2(dailytips_panel_width, dailytips_panel_height), false, child_window_flags)) { + render_dailytips_panel(dailytips_pos, dailytips_size); + } + ImGui::EndChild(); + } + + if (ImGui::IsMouseHoveringRect(ImGui::GetWindowPos(), ImGui::GetWindowPos() + ImGui::GetWindowSize(), true)) { + set_hovered(); + } + } + imgui.end(); + + + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(1); + restore_default_theme(); + if (fading_pop) + ImGui::PopStyleColor(3); +} + +void Slic3r::GUI::NotificationManager::SlicingProgressNotification::render_text(const ImVec2& pos) +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + float scale = imgui.get_font_size() / 15.0f; + ImVec2 icon_size = ImVec2(38.f, 38.f) * scale; + if (m_sp_state == SlicingProgressState::SP_COMPLETED) { + // complete icon + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + ImGui::SetCursorScreenPos(pos); + std::wstring icon_text; + icon_text = ImGui::CompleteIcon; + imgui.button(icon_text.c_str()); + + ImGui::PopStyleColor(5); + + // complete text + imgui.push_bold_font(); + ImGui::SetCursorScreenPos(ImVec2(pos.x + icon_size.x + ImGui::CalcTextSize(" ").x, pos.y + (icon_size.y - m_line_height) / 2)); + imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); + imgui.pop_bold_font(); + return; + } + if (m_sp_state == SlicingProgressState::SP_CANCELLED) { + imgui.push_bold_font(); + ImGui::SetCursorScreenPos(ImVec2(pos.x + ImGui::CalcTextSize(" ").x, pos.y + (icon_size.y - m_line_height) / 2)); + imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); + imgui.pop_bold_font(); + } + if(m_sp_state == SlicingProgressState::SP_PROGRESS) { + //one line text + ImGui::SetCursorScreenPos(pos); + imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); + } +} + +void Slic3r::GUI::NotificationManager::SlicingProgressNotification::render_bar(const ImVec2& pos, const ImVec2& size) +{ + if (m_sp_state != SlicingProgressState::SP_PROGRESS) + return; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + + ImColor progress_color = ImColor(0, 150, 136, (int)(255 * m_current_fade_opacity)); + ImColor bg_color = ImColor(217, 217, 217, (int)(255 * m_current_fade_opacity)); + + ImVec2 lineStart = pos; + ImVec2 lineEnd = lineStart + size; + ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineEnd.y); + ImGui::GetWindowDrawList()->AddRectFilled(lineStart, lineEnd, bg_color); + ImGui::GetWindowDrawList()->AddRectFilled(lineStart, midPoint, progress_color); + + // percentage text + ImVec2 text_pos = ImVec2(pos.x, pos.y + size.y + m_line_height * 0.2f); + std::string text; + std::stringstream stream; + stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "%"; + text = stream.str(); + ImGui::SetCursorScreenPos(text_pos); + imgui.text(text.c_str()); +} + +void NotificationManager::SlicingProgressNotification::render_dailytips_panel(const ImVec2& pos, const ImVec2& size) +{ + m_dailytips_panel->render(); +} + +void NotificationManager::SlicingProgressNotification::render_show_dailytips(const ImVec2& pos) +{ + if (m_sp_state != SlicingProgressState::SP_COMPLETED && m_sp_state != SlicingProgressState::SP_CANCELLED) + return; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImColor(31, 142, 234).Value); + + ImGui::SetCursorScreenPos(pos); + std::wstring button_text; + button_text = ImGui::OpenArrowIcon; + imgui.button(_L("View all Daily tips") + " " + button_text); + //click behavior + if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) + { + //underline + ImVec2 lineEnd = ImGui::GetItemRectMax(); + lineEnd.x -= ImGui::CalcTextSize("A").x / 2; + lineEnd.y -= 2; + ImVec2 lineStart = lineEnd; + lineStart.x = ImGui::GetItemRectMin().x; + ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, ImColor(31, 142, 234)); + + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + on_show_dailytips(); + } + + ImGui::PopStyleColor(4); +} + +void NotificationManager::SlicingProgressNotification::on_show_dailytips() +{ + wxGetApp().plater()->get_dailytips()->open(); +} + +void Slic3r::GUI::NotificationManager::SlicingProgressNotification::render_cancel_button(const ImVec2& pos, const ImVec2& size) +{ + if (m_sp_state == SlicingProgressState::SP_PROGRESS) { + ImGuiWrapper& imgui = *wxGetApp().imgui(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + ImVec2 button_size = size; + ImVec2 button_pos = pos; + ImGui::SetCursorScreenPos(button_pos); + + std::wstring button_text; + button_text = ImGui::CancelButton; + if (ImGui::IsMouseHoveringRect(button_pos, button_pos + button_size, true)) + { + button_text = ImGui::CancelHoverButton; + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + on_cancel_button(); + } + imgui.button(button_text.c_str()); + + ImGui::PopStyleColor(5); + } +} + +void NotificationManager::SlicingProgressNotification::render_close_button(const ImVec2& pos, const ImVec2& size) +{ + if (m_sp_state == SlicingProgressState::SP_CANCELLED || m_sp_state == SlicingProgressState::SP_COMPLETED) { + ImGuiWrapper& imgui = *wxGetApp().imgui(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + ImVec2 button_size = size; + ImVec2 button_pos = pos; + ImGui::SetCursorScreenPos(button_pos); + + std::wstring button_text; + button_text = m_is_dark ? ImGui::CloseNotifDarkButton : ImGui::CloseNotifButton; + if (ImGui::IsMouseHoveringRect(button_pos, button_pos + button_size, true)) + { + button_text = m_is_dark ? ImGui::CloseNotifHoverDarkButton : ImGui::CloseNotifHoverButton; + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + close(); + } + imgui.button(button_text.c_str()); + + ImGui::PopStyleColor(5); + } +} + +}} \ No newline at end of file diff --git a/src/slic3r/GUI/SlicingProgressNotification.hpp b/src/slic3r/GUI/SlicingProgressNotification.hpp new file mode 100644 index 00000000000..44f2bbd32ba --- /dev/null +++ b/src/slic3r/GUI/SlicingProgressNotification.hpp @@ -0,0 +1,87 @@ +#ifndef slic3r_GUI_SlicingProgressNotification_hpp_ +#define slic3r_GUI_SlicingProgressNotification_hpp_ + +#include "DailyTips.hpp" +#include "NotificationManager.hpp" + +namespace Slic3r { namespace GUI { + + +class NotificationManager::SlicingProgressNotification : public NotificationManager::PopNotification +{ +public: + // Inner state of notification, Each state changes bahaviour of the notification + enum class SlicingProgressState + { + SP_NO_SLICING, // hidden + SP_BEGAN, // still hidden but allows to go to SP_PROGRESS state. This prevents showing progress after slicing was canceled. + SP_PROGRESS, // never fades outs, no close button, has cancel button + SP_CANCELLED, // fades after 10 seconds, simple message + //SP_BEFORE_COMPLETED, // to keep displaying DailyTips for 3 seconds + SP_COMPLETED // Has export hyperlink and print info, fades after 20 sec if sidebar is shown, otherwise no fade out + }; + SlicingProgressNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, std::function callback) + : PopNotification(n, id_provider, evt_handler) + , m_cancel_callback(callback) + , m_dailytips_panel(new DailyTipsPanel(true, DailyTipsLayout::Vertical)) + { + set_progress_state(SlicingProgressState::SP_NO_SLICING); + } + void set_percentage(float percent) { m_percentage = percent; } + DailyTipsPanel* get_dailytips_panel() { return m_dailytips_panel; } + SlicingProgressState get_progress_state() { return m_sp_state; } + // sets text of notification - call after setting progress state + void set_status_text(const std::string& text); + // sets cancel button callback + void set_cancel_callback(std::function callback) { m_cancel_callback = callback; } + bool has_cancel_callback() const { return m_cancel_callback != nullptr; } + // sets SlicingProgressState, negative percent means canceled, returns true if state was set succesfully. + bool set_progress_state(float percent); + // sets SlicingProgressState, percent is used only at progress state. Returns true if state was set succesfully. + bool set_progress_state(SlicingProgressState state, float percent = 0.f); + // sets additional string of print info and puts notification into Completed state. + void set_print_info(const std::string& info); + // sets fading if in Completed state. + void set_sidebar_collapsed(bool collapsed); + // Calls inherited update_state and ensures Estate goes to hidden not closing. + bool update_state(bool paused, const int64_t delta) override; + // Switch between technology to provide correct text. + void set_fff(bool b) { m_is_fff = b; } + void set_export_possible(bool b) { m_export_possible = b; } + void on_change_color_mode(bool is_dark) override; +protected: + void init() override; + void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin) override; + /* PARAMS: pos is relative to screen */ + void render_text(const ImVec2& pos); + void render_bar(const ImVec2& pos, const ImVec2& size); + void render_cancel_button(const ImVec2& pos, const ImVec2& size); + void render_close_button(const ImVec2& pos, const ImVec2& size); + void render_dailytips_panel(const ImVec2& pos, const ImVec2& size); + void render_show_dailytips(const ImVec2& pos); + + void on_show_dailytips(); + void on_cancel_button(); + int get_duration() override; + +protected: + ImVec2 m_window_pos; + float m_percentage{ 0.0f }; + int64_t m_before_complete_start; + // if returns false, process was already canceled + std::function m_cancel_callback; + SlicingProgressState m_sp_state{ SlicingProgressState::SP_PROGRESS }; + bool m_sidebar_collapsed{ false }; + // if true, it is possible show export hyperlink in state SP_PROGRESS + bool m_export_possible{ false }; + DailyTipsPanel* m_dailytips_panel{ nullptr }; + + /* currently not used */ + bool m_has_print_info{ false }; + std::string m_print_info; + bool m_is_fff{ true }; +}; + +}} + +#endif \ No newline at end of file diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 3cfc14528ed..e4fed1aac6c 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -8,6 +8,7 @@ #include "BitmapCache.hpp" #include "GUI_App.hpp" +#include "MainFrame.hpp" #include "MsgDialog.hpp" #include "slic3r/Utils/Http.hpp" @@ -80,6 +81,8 @@ static std::vector message_containing_retry{ "07FF 8011", "07FF 8012", "07FF 8013", + "12FF 8007" + }; static std::vector message_containing_done{ @@ -109,6 +112,7 @@ static wxImage fail_image; #define TASK_BUTTON_SIZE2 (wxSize(-1, FromDIP(24))) #define Z_BUTTON_SIZE (wxSize(FromDIP(52), FromDIP(52))) #define MISC_BUTTON_PANEL_SIZE (wxSize(FromDIP(136), FromDIP(55))) +#define MISC_BUTTON_1FAN_SIZE (wxSize(FromDIP(132), FromDIP(51))) #define MISC_BUTTON_2FAN_SIZE (wxSize(FromDIP(66), FromDIP(51))) #define MISC_BUTTON_3FAN_SIZE (wxSize(FromDIP(44), FromDIP(51))) #define TEMP_CTRL_MIN_SIZE (wxSize(FromDIP(122), FromDIP(52))) @@ -143,6 +147,9 @@ PrintingTaskPanel::PrintingTaskPanel(wxWindow* parent, PrintingTaskType type) m_type = type; create_panel(this); SetBackgroundColour(*wxWHITE); + m_bitmap_background = ScalableBitmap(this, "thumbnail_grid", m_bitmap_thumbnail->GetSize().y); + + m_bitmap_thumbnail->Bind(wxEVT_PAINT, &PrintingTaskPanel::paint, this); } PrintingTaskPanel::~PrintingTaskPanel() @@ -159,7 +166,7 @@ void PrintingTaskPanel::create_panel(wxWindow* parent) m_staticText_printing = new wxStaticText(m_panel_printing_title, wxID_ANY ,_L("Printing Progress")); m_staticText_printing->Wrap(-1); - m_staticText_printing->SetFont(PAGE_TITLE_FONT); + //m_staticText_printing->SetFont(PAGE_TITLE_FONT); m_staticText_printing->SetForegroundColour(PAGE_TITLE_FONT_COL); bSizer_printing_title->Add(m_staticText_printing, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, PAGE_TITLE_LEFT_MARGIN); @@ -170,8 +177,8 @@ void PrintingTaskPanel::create_panel(wxWindow* parent) bSizer_printing_title->Fit(m_panel_printing_title); m_bitmap_thumbnail = new wxStaticBitmap(parent, wxID_ANY, m_thumbnail_placeholder.bmp(), wxDefaultPosition, TASK_THUMBNAIL_SIZE, 0); - - + m_bitmap_thumbnail->SetMaxSize(TASK_THUMBNAIL_SIZE); + m_bitmap_thumbnail->SetMinSize(TASK_THUMBNAIL_SIZE); wxBoxSizer *bSizer_subtask_info = new wxBoxSizer(wxVERTICAL); wxBoxSizer *bSizer_task_name = new wxBoxSizer(wxVERTICAL); @@ -179,6 +186,7 @@ void PrintingTaskPanel::create_panel(wxWindow* parent) wxPanel* task_name_panel = new wxPanel(parent); m_staticText_subtask_value = new wxStaticText(task_name_panel, wxID_ANY, _L("N/A"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT | wxST_ELLIPSIZE_END); + m_staticText_subtask_value->SetMaxSize(wxSize(FromDIP(600), -1)); m_staticText_subtask_value->Wrap(-1); #ifdef __WXOSX_MAC__ m_staticText_subtask_value->SetFont(::Label::Body_13); @@ -204,10 +212,9 @@ void PrintingTaskPanel::create_panel(wxWindow* parent) m_staticText_consumption_of_weight->Wrap(-1); bSizer_task_name_hor->Add(m_staticText_subtask_value, 1, wxALL | wxEXPAND, 0); - bSizer_task_name_hor->Add(0, 0, 1, wxEXPAND, 0); bSizer_task_name_hor->Add(m_bitmap_static_use_time, 0, wxALIGN_CENTER_VERTICAL, 0); bSizer_task_name_hor->Add(m_staticText_consumption_of_time, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, FromDIP(3)); - bSizer_task_name_hor->Add(0, 0, 0, wxLEFT, FromDIP(20)); + bSizer_task_name_hor->Add(0, 0, 0, wxLEFT, FromDIP(10)); bSizer_task_name_hor->Add(m_bitmap_static_use_weight, 0, wxALIGN_CENTER_VERTICAL, 0); bSizer_task_name_hor->Add(m_staticText_consumption_of_weight, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(3)); bSizer_task_name_hor->Add(0, 0, 0, wxRIGHT, FromDIP(10)); @@ -227,6 +234,7 @@ void PrintingTaskPanel::create_panel(wxWindow* parent) m_printing_stage_value = new wxStaticText(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT | wxST_ELLIPSIZE_END); m_printing_stage_value->Wrap(-1); + m_printing_stage_value->SetMaxSize(wxSize(FromDIP(800),-1)); #ifdef __WXOSX_MAC__ m_printing_stage_value->SetFont(::Label::Body_11); #else @@ -455,8 +463,8 @@ void PrintingTaskPanel::create_panel(wxWindow* parent) m_request_failed_info->SetForegroundColour(*wxRED); m_request_failed_info->SetFont(::Label::Body_10); static_request_failed_panel_sizer->Add(m_request_failed_info, 0, wxEXPAND | wxALL, FromDIP(10)); - StateColor btn_bg_green(std::pair(AMS_CONTROL_DISABLE_COLOUR, StateColor::Disabled), std::pair(wxColour(27, 136, 68), StateColor::Pressed), - std::pair(wxColour(61, 203, 115), StateColor::Hovered), std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); + StateColor btn_bg_green(std::pair(AMS_CONTROL_DISABLE_COLOUR, StateColor::Disabled), std::pair(wxColour(0, 137, 123), StateColor::Pressed), + std::pair(wxColour(38, 166, 154), StateColor::Hovered), std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); StateColor btn_bd_green(std::pair(AMS_CONTROL_WHITE_COLOUR, StateColor::Disabled), std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Enabled)); m_button_market_retry = new Button(m_request_failed_panel, _L("Retry")); m_button_market_retry->SetBackgroundColor(btn_bg_green); @@ -543,6 +551,20 @@ void PrintingTaskPanel::create_panel(wxWindow* parent) parent->Fit(); } +void PrintingTaskPanel::paint(wxPaintEvent&) +{ + wxPaintDC dc(m_bitmap_thumbnail); + if (wxGetApp().dark_mode()) + dc.DrawBitmap(m_bitmap_background.bmp(), 0, 0); + dc.DrawBitmap(m_thumbnail_bmp_display, wxPoint(0, 0)); + dc.SetTextForeground(*wxBLACK); + dc.SetFont(Label::Body_12); + if (m_plate_index >= 0) { + wxString plate_id_str = wxString::Format("%d", m_plate_index); + dc.DrawText(plate_id_str, wxPoint(4, 4)); + } +} + void PrintingTaskPanel::set_has_reted_text(bool has_rated) { if (has_rated) { @@ -558,7 +580,7 @@ void PrintingTaskPanel::msw_rescale() { m_panel_printing_title->SetSize(wxSize(-1, FromDIP(PAGE_TITLE_HEIGHT))); m_printing_sizer->SetMinSize(wxSize(PAGE_MIN_WIDTH, -1)); - m_staticText_printing->SetMinSize(wxSize(PAGE_TITLE_TEXT_WIDTH, PAGE_TITLE_HEIGHT)); + //m_staticText_printing->SetMinSize(wxSize(PAGE_TITLE_TEXT_WIDTH, PAGE_TITLE_HEIGHT)); m_gauge_progress->SetHeight(PROGRESSBAR_HEIGHT); m_gauge_progress->Rescale(); m_button_abort->msw_rescale(); @@ -597,7 +619,8 @@ void PrintingTaskPanel::show_error_msg(wxString msg) void PrintingTaskPanel::reset_printing_value() { - m_bitmap_thumbnail->SetBitmap(m_thumbnail_placeholder.bmp()); + this->set_thumbnail_img(m_thumbnail_placeholder.bmp()); + this->set_plate_index(-1); } void PrintingTaskPanel::enable_pause_resume_button(bool enable, std::string type) @@ -747,16 +770,28 @@ void PrintingTaskPanel::show_profile_info(bool show, wxString profile /*= wxEmpt } } +void PrintingTaskPanel::set_thumbnail_img(const wxBitmap& bmp) +{ + m_thumbnail_bmp_display = bmp; +} + +void PrintingTaskPanel::set_plate_index(int plate_idx) +{ + m_plate_index = plate_idx; +} + void PrintingTaskPanel::market_scoring_show() { m_score_staticline->Show(); m_score_subtask_info->Show(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " show market scoring page"; } void PrintingTaskPanel::market_scoring_hide() { m_score_staticline->Hide(); m_score_subtask_info->Hide(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " hide market scoring page"; } void PrintingTaskPanel::set_star_count(int star_count) @@ -902,7 +937,7 @@ wxBoxSizer *StatusBasePanel::create_monitoring_page() m_staticText_monitoring = new Label(m_panel_monitoring_title, _L("Camera")); m_staticText_monitoring->Wrap(-1); - m_staticText_monitoring->SetFont(PAGE_TITLE_FONT); + //m_staticText_monitoring->SetFont(PAGE_TITLE_FONT); m_staticText_monitoring->SetForegroundColour(PAGE_TITLE_FONT_COL); bSizer_monitoring_title->Add(m_staticText_monitoring, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, PAGE_TITLE_LEFT_MARGIN); @@ -1000,7 +1035,7 @@ wxBoxSizer *StatusBasePanel::create_machine_control_page(wxWindow *parent) wxBoxSizer *bSizer_control_title = new wxBoxSizer(wxHORIZONTAL); m_staticText_control = new Label(m_panel_control_title,_L("Control")); m_staticText_control->Wrap(-1); - m_staticText_control->SetFont(PAGE_TITLE_FONT); + //m_staticText_control->SetFont(PAGE_TITLE_FONT); m_staticText_control->SetForegroundColour(PAGE_TITLE_FONT_COL); StateColor btn_bg_green(std::pair(AMS_CONTROL_DISABLE_COLOUR, StateColor::Disabled), std::pair(wxColour(0, 137, 123), StateColor::Pressed), @@ -1132,7 +1167,7 @@ wxBoxSizer *StatusBasePanel::create_temp_control(wxWindow *parent) sizer->Add(line, 0, wxEXPAND | wxLEFT | wxRIGHT, 12); wxWindowID frame_id = wxWindow::NewControlId(); - m_tempCtrl_chamber = new TempInput(parent, frame_id, TEMP_BLANK_STR, TEMP_BLANK_STR, wxString("monitor_frame_temp"), wxString("monitor_frame_temp"), wxDefaultPosition, + m_tempCtrl_chamber = new TempInput(parent, frame_id, TEMP_BLANK_STR, TEMP_BLANK_STR, wxString("monitor_frame_temp"), wxString("monitor_frame_temp_active"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER); m_tempCtrl_chamber->SetReadOnly(true); m_tempCtrl_chamber->SetMinTemp(nozzle_chamber_range[0]); @@ -1259,14 +1294,14 @@ wxBoxSizer *StatusBasePanel::create_misc_control(wxWindow *parent) m_fan_panel->SetBackgroundColor(parent->GetBackgroundColour()); }); - m_switch_block_fan = new wxPanel(m_fan_panel); - m_switch_block_fan->SetBackgroundColour(parent->GetBackgroundColour()); + //m_switch_block_fan = new wxPanel(m_fan_panel); + //m_switch_block_fan->SetBackgroundColour(parent->GetBackgroundColour()); fan_line_sizer->Add(0, 0, 0, wxLEFT, FromDIP(2)); fan_line_sizer->Add(m_switch_nozzle_fan, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM , FromDIP(2)); fan_line_sizer->Add(m_switch_printing_fan, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(2)); fan_line_sizer->Add(m_switch_cham_fan, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM , FromDIP(2)); - fan_line_sizer->Add(m_switch_block_fan, 1, wxEXPAND | wxTOP | wxBOTTOM , FromDIP(2)); + //fan_line_sizer->Add(m_switch_block_fan, 1, wxEXPAND | wxTOP | wxBOTTOM , FromDIP(2)); fan_line_sizer->Add(0, 0, 0, wxLEFT, FromDIP(2)); m_fan_panel->SetSizer(fan_line_sizer); @@ -1390,6 +1425,7 @@ wxBoxSizer *StatusBasePanel::create_bed_control(wxWindow *parent) m_staticText_z_tip = new wxStaticText(panel, wxID_ANY, _L("Bed"), wxDefaultPosition, wxDefaultSize, 0); m_staticText_z_tip->SetFont(::Label::Body_13); + if (wxGetApp().app_config->get("language") == "de_DE") m_staticText_z_tip->SetFont(::Label::Body_11); m_staticText_z_tip->Wrap(-1); m_staticText_z_tip->SetForegroundColour(TEXT_LIGHT_FONT_COL); bSizer_z_ctrl->Add(m_staticText_z_tip, 0, wxBOTTOM | wxALIGN_CENTER_HORIZONTAL, FromDIP(5)); @@ -1540,24 +1576,23 @@ void StatusPanel::update_camera_state(MachineObject* obj) } //recording - if (obj->is_function_supported(PrinterFunction::FUNC_RECORDING)) { - if (m_last_recording != (obj->is_recording() ? 1: 0)) { - if (obj->is_recording()) { - m_bitmap_recording_img->SetBitmap(m_bitmap_recording_on.bmp()); - } else { - m_bitmap_recording_img->SetBitmap(m_bitmap_recording_off.bmp()); - } - m_last_recording = obj->is_recording() ? 1 : 0; + if (m_last_recording != (obj->is_recording() ? 1 : 0)) { + if (obj->is_recording()) { + m_bitmap_recording_img->SetBitmap(m_bitmap_recording_on.bmp()); } - if (!m_bitmap_recording_img->IsShown()) - m_bitmap_recording_img->Show(); - } else { - if (m_bitmap_recording_img->IsShown()) - m_bitmap_recording_img->Hide(); + else { + m_bitmap_recording_img->SetBitmap(m_bitmap_recording_off.bmp()); + } + m_last_recording = obj->is_recording() ? 1 : 0; } + if (!m_bitmap_recording_img->IsShown()) + m_bitmap_recording_img->Show(); + + /*if (m_bitmap_recording_img->IsShown()) + m_bitmap_recording_img->Hide();*/ //timelapse - if (obj->is_function_supported(PrinterFunction::FUNC_TIMELAPSE)) { + if (obj->is_support_timelapse) { if (m_last_timelapse != (obj->is_timelapse() ? 1: 0)) { if (obj->is_timelapse()) { m_bitmap_timelapse_img->SetBitmap(m_bitmap_timelapse_on.bmp()); @@ -1574,7 +1609,7 @@ void StatusPanel::update_camera_state(MachineObject* obj) } //vcamera - if (obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_CAMERA)) { + if (obj->virtual_camera) { if (m_last_vcamera != (m_media_play_ctrl->IsStreaming() ? 1: 0)) { if (m_media_play_ctrl->IsStreaming()) { m_bitmap_vcamera_img->SetBitmap(m_bitmap_vcamera_on.bmp()); @@ -1873,14 +1908,20 @@ void StatusPanel::on_webrequest_state(wxWebRequestEvent &evt) wxImage img(*evt.GetResponse().GetStream()); img_list.insert(std::make_pair(m_request_url, img)); wxImage resize_img = img.Scale(m_project_task_panel->get_bitmap_thumbnail()->GetSize().x, m_project_task_panel->get_bitmap_thumbnail()->GetSize().y, wxIMAGE_QUALITY_HIGH); - m_project_task_panel->get_bitmap_thumbnail()->SetBitmap(resize_img); + m_project_task_panel->set_thumbnail_img(resize_img); + if (obj) { + m_project_task_panel->set_plate_index(obj->m_plate_index); + } else { + m_project_task_panel->set_plate_index(-1); + } task_thumbnail_state = ThumbnailState::TASK_THUMBNAIL; break; } case wxWebRequest::State_Failed: case wxWebRequest::State_Cancelled: case wxWebRequest::State_Unauthorized: { - m_project_task_panel->get_bitmap_thumbnail()->SetBitmap(m_thumbnail_brokenimg.bmp()); + m_project_task_panel->set_thumbnail_img(m_thumbnail_brokenimg.bmp()); + m_project_task_panel->set_plate_index(-1); task_thumbnail_state = ThumbnailState::BROKEN_IMG; break; } @@ -1936,8 +1977,11 @@ void StatusPanel::update(MachineObject *obj) m_project_task_panel->Thaw(); #if !BBL_RELEASE_TO_PUBLIC + auto delay1 = std::chrono::duration_cast(obj->last_update_time - std::chrono::system_clock::now()).count(); + auto delay2 = std::chrono::duration_cast(obj->last_push_time - std::chrono::system_clock::now()).count(); + auto delay = wxString::Format(" %ld/%ld", delay1, delay2); m_staticText_timelapse - ->SetLabel(obj->is_lan_mode_printer() ? "Local Mqtt" : obj->is_tunnel_mqtt ? "Tunnel Mqtt" : "Cloud Mqtt"); + ->SetLabel((obj->is_lan_mode_printer() ? "Local Mqtt" : obj->is_tunnel_mqtt ? "Tunnel Mqtt" : "Cloud Mqtt") + delay); m_bmToggleBtn_timelapse ->Enable(!obj->is_lan_mode_printer()); m_bmToggleBtn_timelapse @@ -1965,19 +2009,17 @@ void StatusPanel::update(MachineObject *obj) } // update calibration status - if (calibration_dlg == nullptr) { - calibration_dlg = new CalibrationDialog(); - calibration_dlg->update_machine_obj(obj); - } else { + if (calibration_dlg != nullptr) { calibration_dlg->update_machine_obj(obj); + calibration_dlg->update_cali(obj); } - calibration_dlg->update_cali(obj); + - if (obj->is_function_supported(PrinterFunction::FUNC_FIRSTLAYER_INSPECT) - || obj->is_function_supported(PrinterFunction::FUNC_AI_MONITORING) - || obj->is_function_supported(PrinterFunction::FUNC_BUILDPLATE_MARKER_DETECT) - || obj->is_function_supported(PrinterFunction::FUNC_AUTO_RECOVERY_STEP_LOSS)) { + if (obj->is_support_first_layer_inspect + || obj->is_support_ai_monitoring + || obj->is_support_build_plate_marker_detect + || obj->is_support_auto_recovery_step_loss) { m_options_btn->Show(); if (print_options_dlg) { print_options_dlg->update_machine_obj(obj); @@ -1988,12 +2030,17 @@ void StatusPanel::update(MachineObject *obj) } //support edit chamber temp - if (obj->is_function_supported(PrinterFunction::FUNC_CHAMBER_TEMP)) { + if (obj->is_support_chamber_edit) { m_tempCtrl_chamber->SetReadOnly(false); m_tempCtrl_chamber->Enable(); + wxCursor cursor(wxCURSOR_IBEAM); + m_tempCtrl_chamber->GetTextCtrl()->SetCursor(cursor); } else { m_tempCtrl_chamber->SetReadOnly(true); + wxCursor cursor(wxCURSOR_ARROW); + m_tempCtrl_chamber->GetTextCtrl()->SetCursor(cursor); + if (obj->get_printer_series() == PrinterSeries::SERIES_X1) { m_tempCtrl_chamber->SetTagTemp(TEMP_BLANK_STR); }if (obj->get_printer_series() == PrinterSeries::SERIES_P1P) @@ -2002,7 +2049,8 @@ void StatusPanel::update(MachineObject *obj) m_tempCtrl_chamber->GetTextCtrl()->SetValue(TEMP_BLANK_STR); } - m_tempCtrl_chamber->Disable(); + //m_tempCtrl_chamber->Disable(); + } if (!obj->dev_connection_type.empty()) { @@ -2076,6 +2124,7 @@ void StatusPanel::show_error_message(MachineObject* obj, wxString msg, std::stri }); m_print_error_dlg->on_show(); + wxGetApp().mainframe->RequestUserAttention(wxUSER_ATTENTION_ERROR); } } @@ -2204,9 +2253,8 @@ void StatusPanel::update_temp_ctrl(MachineObject *obj) } m_tempCtrl_nozzle->SetCurrTemp((int) obj->nozzle_temp); - int nozzle_max_temp = 0; - if (DeviceManager::get_nozzle_max_temperature(obj->printer_type, nozzle_max_temp)) { - if (m_tempCtrl_nozzle) m_tempCtrl_nozzle->SetMaxTemp(nozzle_max_temp); + if (obj->nozzle_max_temperature > -1) { + if (m_tempCtrl_nozzle) m_tempCtrl_nozzle->SetMaxTemp(obj->nozzle_max_temperature); } else { if (m_tempCtrl_nozzle) m_tempCtrl_nozzle->SetMaxTemp(nozzle_temp_range[1]); @@ -2266,8 +2314,8 @@ void StatusPanel::update_misc_ctrl(MachineObject *obj) // update extruder icon update_extruder_status(obj); - bool is_suppt_aux_fun = obj->is_function_supported(PrinterFunction::FUNC_AUX_FAN); - bool is_suppt_cham_fun = obj->is_function_supported(PrinterFunction::FUNC_CHAMBER_FAN); + bool is_suppt_aux_fun = obj->is_support_aux_fan; + bool is_suppt_cham_fun = obj->is_support_chamber_fan; //update cham fan if (m_current_support_cham_fan != is_suppt_cham_fun) { @@ -2308,6 +2356,12 @@ void StatusPanel::update_misc_ctrl(MachineObject *obj) m_misc_ctrl_sizer->Layout(); } + if (!is_suppt_aux_fun && !is_suppt_cham_fun) { + m_switch_nozzle_fan->SetMinSize(MISC_BUTTON_1FAN_SIZE); + m_switch_nozzle_fan->SetMaxSize(MISC_BUTTON_1FAN_SIZE); + m_misc_ctrl_sizer->Layout(); + } + // nozzle fan if (m_switch_nozzle_fan_timeout > 0) { @@ -2403,15 +2457,20 @@ void StatusPanel::update_ams(MachineObject *obj) } if (m_filament_setting_dlg) { m_filament_setting_dlg->obj = obj; } - if (obj->is_high_printer_type() && last_cali_version != obj->cali_version) { + if ( (obj->get_printer_series() == PrinterSeries::SERIES_X1) && last_cali_version != obj->cali_version) { last_cali_version = obj->cali_version; CalibUtils::emit_get_PA_calib_info(obj->nozzle_diameter, ""); } - bool is_support_virtual_tray = obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_TYAY); - bool is_support_filament_backup = obj->is_function_supported(PrinterFunction::FUNC_FILAMENT_BACKUP); + bool is_support_virtual_tray = obj->ams_support_virtual_tray; + bool is_support_filament_backup = obj->is_support_filament_backup; AMSModel ams_mode = AMSModel::GENERIC_AMS; + if (obj) { + if (obj->get_printer_ams_type() == "f1") { ams_mode = AMSModel::EXTRA_AMS; } + else if(obj->get_printer_ams_type() == "generic") { ams_mode = AMSModel::GENERIC_AMS; } + } + if (!obj || !obj->is_connected() || obj->amsList.empty() @@ -2426,17 +2485,15 @@ void StatusPanel::update_ams(MachineObject *obj) BOOST_LOG_TRIVIAL(trace) << "machine object" << obj->dev_name << " was disconnected, set show_ams_group is false"; } - - if (obj->printer_type == "N1") { ams_mode = AMSModel::EXTRA_AMS; } - m_ams_control->SetAmsModel(AMSModel::NO_AMS, ams_mode); + m_ams_control->SetAmsModel(AMSModel::NO_AMS, ams_mode); show_ams_group(false); + m_ams_control->show_auto_refill(false); } else { - if (obj->printer_type == "N1") { ams_mode = AMSModel::EXTRA_AMS; } - m_ams_control->SetAmsModel(ams_mode, ams_mode); + m_ams_control->SetAmsModel(ams_mode, ams_mode); show_ams_group(true); m_ams_control->show_auto_refill(true); } @@ -2746,9 +2803,11 @@ void StatusPanel::update_basic_print_data(bool def) void StatusPanel::update_model_info() { auto get_subtask_fn = [this](BBLModelTask* subtask) { - if (obj && obj->subtask_id_ == subtask->task_id) { - obj->set_modeltask(subtask); - } + CallAfter([this, subtask]() { + if (obj && obj->subtask_id_ == subtask->task_id) { + obj->set_modeltask(subtask); + } + }); }; @@ -2937,7 +2996,12 @@ void StatusPanel::update_cloud_subtask(MachineObject *obj) if (it != img_list.end()) { img = it->second; wxImage resize_img = img.Scale(m_project_task_panel->get_bitmap_thumbnail()->GetSize().x, m_project_task_panel->get_bitmap_thumbnail()->GetSize().y); - m_project_task_panel->get_bitmap_thumbnail()->SetBitmap(resize_img); + m_project_task_panel->set_thumbnail_img(resize_img); + if (this->obj) { + m_project_task_panel->set_plate_index(obj->m_plate_index); + } else { + m_project_task_panel->set_plate_index(-1); + } task_thumbnail_state = ThumbnailState::TASK_THUMBNAIL; BOOST_LOG_TRIVIAL(trace) << "web_request: use cache image"; } else { @@ -2972,7 +3036,6 @@ void StatusPanel::reset_printing_values() m_project_task_panel->update_stage_value(wxEmptyString, 0); m_project_task_panel->update_progress_percent(NA_STR, wxEmptyString); - m_project_task_panel->market_scoring_hide(); m_project_task_panel->get_request_failed_panel()->Hide(); update_basic_print_data(false); @@ -3076,7 +3139,7 @@ void StatusPanel::axis_ctrl_e_hint(bool up_down) { if (ctrl_e_hint_dlg == nullptr) { ctrl_e_hint_dlg = new SecondaryCheckDialog(this->GetParent(), wxID_ANY, _L("Warning"), SecondaryCheckDialog::ButtonStyle::CONFIRM_AND_CANCEL, wxDefaultPosition, wxDefaultSize, wxCLOSE_BOX | wxCAPTION, true); - ctrl_e_hint_dlg->update_text(_L("Please heat the nozzle to above 170 degree before loading filament.")); + ctrl_e_hint_dlg->update_text(_L("Please heat the nozzle to above 170 degree before loading or unloading filament.")); ctrl_e_hint_dlg->show_again_config_text = std::string("not_show_ectrl_hint"); } if (up_down) { @@ -3267,7 +3330,7 @@ void StatusPanel::on_ams_setting_click(SimpleEvent &event) if (obj) { m_ams_setting_dlg->update_insert_material_read_mode(obj->ams_insert_flag); m_ams_setting_dlg->update_starting_read_mode(obj->ams_power_on_flag); - m_ams_setting_dlg->update_image(obj->printer_type == "N1"?"generic":"f1"); + m_ams_setting_dlg->update_ams_img(DeviceManager::get_printer_ams_img(obj->printer_type)); std::string ams_id = m_ams_control->GetCurentShowAms(); if (obj->amsList.size() == 0) { /* wxString txt = _L("AMS settings are not supported for external spool"); @@ -3278,7 +3341,7 @@ void StatusPanel::on_ams_setting_click(SimpleEvent &event) try { int ams_id_int = atoi(ams_id.c_str()); m_ams_setting_dlg->ams_id = ams_id_int; - m_ams_setting_dlg->ams_support_remain = obj->ams_support_remain; + m_ams_setting_dlg->ams_support_remain = obj->is_support_update_remain; m_ams_setting_dlg->Show(); } catch (...) { @@ -3344,6 +3407,12 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) { // update params if (!m_filament_setting_dlg) m_filament_setting_dlg = new AMSMaterialsSetting((wxWindow *) this, wxID_ANY); + + int current_position_x = m_ams_control->GetScreenPosition().x; + int current_position_y = m_ams_control->GetScreenPosition().y - FromDIP(40); + auto drect = wxDisplay(GetParent()).GetGeometry().GetHeight() - FromDIP(50); + current_position_y = current_position_y + m_filament_setting_dlg->GetSize().GetHeight() > drect ? drect - m_filament_setting_dlg->GetSize().GetHeight() : current_position_y; + if (obj) { m_filament_setting_dlg->obj = obj; std::string ams_id = m_ams_control->GetCurentAms(); @@ -3357,7 +3426,7 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) wxString n_val; k_val = wxString::Format("%.3f", obj->vt_tray.k); n_val = wxString::Format("%.3f", obj->vt_tray.n); - m_filament_setting_dlg->Move(wxPoint(m_ams_control->GetScreenPosition().x, m_ams_control->GetScreenPosition().y - FromDIP(40))); + m_filament_setting_dlg->Move(wxPoint(current_position_x, current_position_y)); m_filament_setting_dlg->Popup(wxEmptyString, wxEmptyString, wxEmptyString, wxEmptyString, k_val, n_val); } else { std::string tray_id = event.GetString().ToStdString(); // m_ams_control->GetCurrentCan(ams_id); @@ -3405,7 +3474,8 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) } } } - m_filament_setting_dlg->Move(wxPoint(m_ams_control->GetScreenPosition().x, m_ams_control->GetScreenPosition().y - FromDIP(40))); + + m_filament_setting_dlg->Move(wxPoint(current_position_x, current_position_y)); m_filament_setting_dlg->Popup(filament, sn_number, temp_min, temp_max, k_val, n_val); } catch (...) { @@ -3419,6 +3489,12 @@ void StatusPanel::on_ext_spool_edit(wxCommandEvent &event) { // update params if (!m_filament_setting_dlg) m_filament_setting_dlg = new AMSMaterialsSetting((wxWindow*)this, wxID_ANY); + + int current_position_x = m_ams_control->GetScreenPosition().x; + int current_position_y = m_ams_control->GetScreenPosition().y - FromDIP(40); + auto drect = wxDisplay(GetParent()).GetGeometry().GetHeight() - FromDIP(50); + current_position_y = current_position_y + m_filament_setting_dlg->GetSize().GetHeight() > drect ? drect - m_filament_setting_dlg->GetSize().GetHeight() : current_position_y; + if (obj) { m_filament_setting_dlg->obj = obj; try { @@ -3450,7 +3526,7 @@ void StatusPanel::on_ext_spool_edit(wxCommandEvent &event) temp_min = obj->vt_tray.nozzle_temp_min; } - m_filament_setting_dlg->Move(wxPoint(m_ams_control->GetScreenPosition().x, m_ams_control->GetScreenPosition().y - FromDIP(40))); + m_filament_setting_dlg->Move(wxPoint(current_position_x,current_position_y)); m_filament_setting_dlg->Popup(filament, sn_number, temp_min, temp_max, k_val, n_val); } catch (...) { @@ -3706,8 +3782,8 @@ void StatusPanel::on_nozzle_fan_switch(wxCommandEvent &event) m_fan_control_popup = new FanControlPopup(this); if (obj) { - m_fan_control_popup->show_cham_fan(obj->is_function_supported(PrinterFunction::FUNC_CHAMBER_FAN)); - m_fan_control_popup->show_aux_fan(obj->is_function_supported(PrinterFunction::FUNC_AUX_FAN)); + m_fan_control_popup->show_cham_fan(obj->is_support_chamber_fan); + m_fan_control_popup->show_aux_fan(obj->is_support_aux_fan); } auto pos = m_switch_nozzle_fan->GetScreenPosition(); @@ -3836,9 +3912,11 @@ void StatusPanel::on_start_calibration(wxCommandEvent &event) if (calibration_dlg == nullptr) { calibration_dlg = new CalibrationDialog(); calibration_dlg->update_machine_obj(obj); + calibration_dlg->update_cali(obj); calibration_dlg->ShowModal(); } else { calibration_dlg->update_machine_obj(obj); + calibration_dlg->update_cali(obj); calibration_dlg->ShowModal(); } } @@ -3915,11 +3993,6 @@ void StatusPanel::show_status(int status) void StatusPanel::set_hold_count(int& count) { - if (obj) { - if (obj->is_U0_firmware()) { - count = COMMAND_TIMEOUT_U0; - } - } count = COMMAND_TIMEOUT; } @@ -3988,10 +4061,11 @@ void StatusPanel::msw_rescale() m_project_task_panel->init_bitmaps(); m_project_task_panel->msw_rescale(); m_panel_monitoring_title->SetSize(wxSize(-1, FromDIP(PAGE_TITLE_HEIGHT))); - m_staticText_monitoring->SetMinSize(wxSize(PAGE_TITLE_TEXT_WIDTH, PAGE_TITLE_HEIGHT)); + //m_staticText_monitoring->SetMinSize(wxSize(PAGE_TITLE_TEXT_WIDTH, PAGE_TITLE_HEIGHT)); m_bmToggleBtn_timelapse->Rescale(); m_panel_control_title->SetSize(wxSize(-1, FromDIP(PAGE_TITLE_HEIGHT))); - m_staticText_control->SetMinSize(wxSize(-1, PAGE_TITLE_HEIGHT)); + //m_staticText_control->SetMinSize(wxSize(-1, PAGE_TITLE_HEIGHT)); + m_media_play_ctrl->msw_rescale(); m_bpButton_xy->SetBitmap(m_bitmap_axis_home); m_bpButton_xy->SetMinSize(AXIS_MIN_SIZE); m_bpButton_xy->SetSize(AXIS_MIN_SIZE); @@ -4324,10 +4398,8 @@ wxBoxSizer* ScoreDialog::get_comment_text_sizer() { void ScoreDialog::create_comment_text(const wxString& comment) { m_comment_text = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(492), FromDIP(104)), wxTE_MULTILINE); - if (wxGetApp().dark_mode()) { - m_comment_text->SetForegroundColour(wxColor(*wxWHITE)); - } else - m_comment_text->SetForegroundColour(wxColor(*wxBLACK)); + m_comment_text->SetBackgroundColour(wxColor(*wxWHITE)); + if (!comment.empty()) { m_comment_text->SetValue(comment); } @@ -4429,7 +4501,7 @@ wxBoxSizer *ScoreDialog::get_button_sizer() wxBoxSizer *bSizer_button = new wxBoxSizer(wxHORIZONTAL); bSizer_button->Add(0, 0, 1, wxEXPAND, 0); - StateColor btn_bg_green(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); m_button_ok = new Button(this, _L("Submit")); diff --git a/src/slic3r/GUI/StatusPanel.hpp b/src/slic3r/GUI/StatusPanel.hpp index adbaa8010ee..fba9dc2f0fe 100644 --- a/src/slic3r/GUI/StatusPanel.hpp +++ b/src/slic3r/GUI/StatusPanel.hpp @@ -34,7 +34,6 @@ class StepIndicator; -#define COMMAND_TIMEOUT_U0 15 #define COMMAND_TIMEOUT 5 namespace Slic3r { @@ -161,8 +160,10 @@ class PrintingTaskPanel : public wxPanel private: MachineObject* m_obj; ScalableBitmap m_thumbnail_placeholder; + wxBitmap m_thumbnail_bmp_display; ScalableBitmap m_bitmap_use_time; ScalableBitmap m_bitmap_use_weight; + ScalableBitmap m_bitmap_background; wxPanel * m_panel_printing_title; wxPanel* m_staticline; @@ -184,6 +185,7 @@ class PrintingTaskPanel : public wxPanel wxStaticText * m_has_rated_prompt; wxStaticText * m_request_failed_info; wxStaticBitmap* m_bitmap_thumbnail; + int m_plate_index { -1 }; wxStaticBitmap* m_bitmap_static_use_time; wxStaticBitmap* m_bitmap_static_use_weight; ScalableButton* m_button_pause_resume; @@ -222,6 +224,8 @@ class PrintingTaskPanel : public wxPanel void update_layers_num(bool show, wxString num = wxEmptyString); void show_priting_use_info(bool show, wxString time = wxEmptyString, wxString weight = wxEmptyString); void show_profile_info(bool show, wxString profile = wxEmptyString); + void set_thumbnail_img(const wxBitmap& bmp); + void set_plate_index(int plate_idx = -1); void market_scoring_show(); void market_scoring_hide(); @@ -239,6 +243,7 @@ class PrintingTaskPanel : public wxPanel bool get_star_count_dirty() { return m_star_count_dirty; } void set_star_count_dirty(bool dirty) { m_star_count_dirty = dirty; } void set_has_reted_text(bool has_rated); + void paint(wxPaintEvent&); }; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 94eb6e45798..2bb94cfccf5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -345,10 +345,12 @@ void Tab::create_preset_tab() m_main_sizer = new wxBoxSizer( wxVERTICAL ); m_top_sizer = new wxBoxSizer( wxHORIZONTAL ); + + m_top_sizer->Add(m_undo_btn, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 5); // BBS: model config if (m_presets_choice) { m_presets_choice->Reparent(m_top_panel); - m_top_sizer->Add(m_presets_choice, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 10); + m_top_sizer->Add(m_presets_choice, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 8); } else { m_top_sizer->AddSpacer(10); m_top_sizer->AddStretchSpacer(1); @@ -359,7 +361,6 @@ void Tab::create_preset_tab() m_top_sizer->Add( m_undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL); m_top_sizer->AddSpacer(8); #endif - m_top_sizer->Add( m_undo_btn, 0, wxALIGN_CENTER_VERTICAL); m_top_sizer->Add( m_btn_save_preset, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 8 ); m_top_sizer->Add( m_btn_delete_preset, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 8 ); m_top_sizer->Add( m_btn_search, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 8 ); @@ -936,8 +937,14 @@ void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool void Tab::update_changed_tree_ui() { - if (m_options_list.empty()) + if (m_options_list.empty()) { + if (m_type == Preset::Type::TYPE_PLATE) { + for (auto page : m_pages) { + page->m_is_nonsys_values = false; + } + } return; + } auto cur_item = m_tabctrl->GetFirstVisibleItem(); if (cur_item < 0 || !m_tabctrl->IsVisible(cur_item)) return; @@ -1421,6 +1428,23 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) } } + if (opt_key == "print_sequence" && m_config->opt_enum("print_sequence") == PrintSequence::ByObject) { + auto printer_structure_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option>("printer_structure"); + if (printer_structure_opt && printer_structure_opt->value == PrinterStructure::psI3) { + wxString msg_text = _(L("Timelapse is not supported because Print sequence is set to \"By object\".")); + msg_text += "\n\n" + _(L("Still print by object?")); + + MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO); + auto answer = dialog.ShowModal(); + if (answer == wxID_NO) { + DynamicPrintConfig new_conf = *m_config; + new_conf.set_key_value("print_sequence", new ConfigOptionEnum(PrintSequence::ByLayer)); + m_config_manipulation.apply(m_config, &new_conf); + wxGetApp().plater()->update(); + } + } + } + // BBS set support style to default when support type changes // Orca: do this only in simple mode if (opt_key == "support_type" && m_mode == comSimple) { @@ -1489,6 +1513,33 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) } } + if(opt_key=="layer_height"){ + auto min_layer_height_from_nozzle=wxGetApp().preset_bundle->full_config().option("min_layer_height")->values; + auto max_layer_height_from_nozzle=wxGetApp().preset_bundle->full_config().option("max_layer_height")->values; + auto layer_height_floor = *std::min_element(min_layer_height_from_nozzle.begin(), min_layer_height_from_nozzle.end()); + auto layer_height_ceil = *std::max_element(max_layer_height_from_nozzle.begin(), max_layer_height_from_nozzle.end()); + bool exceed_minimum_flag = m_config->opt_float("layer_height") < layer_height_floor; + bool exceed_maximum_flag = m_config->opt_float("layer_height") > layer_height_ceil; + + if (exceed_maximum_flag || exceed_minimum_flag) { + wxString msg_text = _(L("Layer height exceeds the limit in Printer Settings -> Extruder -> Layer height limits ,this may cause printing quality issues.")); + msg_text += "\n\n" + _(L("Adjust to the set range automatically? \n")); + MessageDialog dialog(wxGetApp().plater(), msg_text, "", wxICON_WARNING | wxYES | wxNO); + dialog.SetButtonLabel(wxID_YES, _L("Adjust")); + dialog.SetButtonLabel(wxID_NO, _L("Ignore")); + auto answer = dialog.ShowModal(); + auto new_conf = *m_config; + if (answer == wxID_YES) { + if (exceed_maximum_flag) + new_conf.set_key_value("layer_height", new ConfigOptionFloat(layer_height_ceil)); + if (exceed_minimum_flag) + new_conf.set_key_value("layer_height",new ConfigOptionFloat(layer_height_floor)); + m_config_manipulation.apply(m_config, &new_conf); + } + wxGetApp().plater()->update(); + } + } + // BBS #if 0 if (opt_key == "extruders_count") @@ -1830,6 +1881,7 @@ void Tab::update_frequently_changed_parameters() update_wiping_button_visibility(); } } + //BBS: BBS new parameter list void TabPrint::build() { @@ -1864,9 +1916,9 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Precision"), L"param_precision"); optgroup->append_single_option_line("slice_closing_radius"); optgroup->append_single_option_line("resolution"); - optgroup->append_single_option_line("enable_arc_fitting"); - optgroup->append_single_option_line("xy_hole_compensation"); - optgroup->append_single_option_line("xy_contour_compensation"); + optgroup->append_single_option_line("enable_arc_fitting", "acr-move"); + optgroup->append_single_option_line("xy_hole_compensation", "xy-hole-contour-compensation"); + optgroup->append_single_option_line("xy_contour_compensation", "xy-hole-contour-compensation"); optgroup->append_single_option_line("elefant_foot_compensation"); optgroup->append_single_option_line("elefant_foot_compensation_layers"); optgroup->append_single_option_line("precise_outer_wall"); @@ -1875,7 +1927,7 @@ void TabPrint::build() optgroup->append_single_option_line("hole_to_polyhole_twisted"); optgroup = page->new_optgroup(L("Ironing"), L"param_ironing"); - optgroup->append_single_option_line("ironing_type"); + optgroup->append_single_option_line("ironing_type", "parameter/ironing"); optgroup->append_single_option_line("ironing_pattern"); optgroup->append_single_option_line("ironing_speed"); optgroup->append_single_option_line("ironing_flow"); @@ -1883,7 +1935,7 @@ void TabPrint::build() optgroup->append_single_option_line("ironing_angle"); optgroup = page->new_optgroup(L("Wall generator"), L"param_wall"); - optgroup->append_single_option_line("wall_generator"); + optgroup->append_single_option_line("wall_generator", "wall-generator"); optgroup->append_single_option_line("wall_transition_angle"); optgroup->append_single_option_line("wall_transition_filter_deviation"); optgroup->append_single_option_line("wall_transition_length"); @@ -1893,8 +1945,9 @@ void TabPrint::build() optgroup->append_single_option_line("min_feature_size"); optgroup = page->new_optgroup(L("Advanced"), L"param_advanced"); - optgroup->append_single_option_line("wall_infill_order"); optgroup->append_single_option_line("print_flow_ratio"); + optgroup->append_single_option_line("wall_sequence"); + optgroup->append_single_option_line("is_infill_first"); optgroup->append_single_option_line("bridge_flow"); optgroup->append_single_option_line("internal_bridge_flow"); optgroup->append_single_option_line("bridge_density"); @@ -1955,8 +2008,8 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Other layers speed"), L"param_speed", 15); optgroup->append_single_option_line("outer_wall_speed"); optgroup->append_single_option_line("inner_wall_speed"); - optgroup->append_single_option_line("small_perimeter_threshold"); optgroup->append_single_option_line("small_perimeter_speed"); + optgroup->append_single_option_line("small_perimeter_threshold"); optgroup->append_single_option_line("sparse_infill_speed"); optgroup->append_single_option_line("internal_solid_infill_speed"); optgroup->append_single_option_line("top_surface_speed"); @@ -2029,6 +2082,7 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Support filament"), L"param_support_filament"); optgroup->append_single_option_line("support_filament", "support#support-filament"); optgroup->append_single_option_line("support_interface_filament", "support#support-filament"); + optgroup->append_single_option_line("support_interface_not_for_body", "support#support-filament"); //optgroup = page->new_optgroup(L("Options for support material and raft")); @@ -2111,6 +2165,9 @@ void TabPrint::build() optgroup->append_single_option_line("fuzzy_skin_thickness"); optgroup->append_single_option_line("fuzzy_skin_first_layer"); + optgroup = page->new_optgroup(L("Advanced"), L"advanced"); + // optgroup->append_single_option_line("mmu_segmented_region_max_width"); + optgroup->append_single_option_line("mmu_segmented_region_interlocking_depth"); optgroup = page->new_optgroup(L("G-code output"), L"param_gcode"); optgroup->append_single_option_line("reduce_infill_retraction"); @@ -2194,8 +2251,8 @@ void TabPrint::toggle_options() auto support_type = m_config->opt_enum("support_type"); if (auto choice = dynamic_cast(field)) { auto def = print_config_def.get("support_style"); - std::vector enum_set_normal = {0, 1, 2}; - std::vector enum_set_tree = {0, 3, 4, 5, 6}; + std::vector enum_set_normal = {smsDefault, smsGrid, smsSnug }; + std::vector enum_set_tree = { smsDefault, smsTreeSlim, smsTreeStrong, smsTreeHybrid, smsOrganic }; auto & set = is_tree(support_type) ? enum_set_tree : enum_set_normal; auto & opt = const_cast(field->m_opt); auto cb = dynamic_cast(choice->window); @@ -2372,6 +2429,33 @@ void TabPrintModel::update_model_config() // except those than all equal on m_config->apply_only(local_config, local_keys); m_config_manipulation.apply_null_fff_config(m_config, m_null_keys, m_object_configs); + + if (m_type == Preset::Type::TYPE_PLATE) { + // Reset m_config manually because there's no corresponding config in m_parent_tab->m_config + for (auto plate_item : m_object_configs) { + const DynamicPrintConfig& plate_config = plate_item.second->get(); + BedType plate_bed_type = (BedType)0; + PrintSequence plate_print_seq = (PrintSequence)0; + if (!plate_config.has("curr_bed_type")) { + // same as global + DynamicConfig& global_cfg = wxGetApp().preset_bundle->project_config; + if (global_cfg.has("curr_bed_type")) { + BedType global_bed_type = global_cfg.opt_enum("curr_bed_type"); + m_config->set_key_value("curr_bed_type", new ConfigOptionEnum(global_bed_type)); + } + } + if (!plate_config.has("first_layer_print_sequence")) { + // same as global + m_config->set_key_value("first_layer_sequence_choice", new ConfigOptionEnum(flsAuto)); + } + else { + replace(m_all_keys.begin(), m_all_keys.end(), std::string("first_layer_print_sequence"), std::string("first_layer_sequence_choice")); + m_config->set_key_value("first_layer_sequence_choice", new ConfigOptionEnum(flsCutomize)); + } + notify_changed(plate_item.first); + } + } + } toggle_options(); if (m_active_page) @@ -2492,6 +2576,179 @@ void TabPrintModel::update_custom_dirty() } //BBS: GUI refactor +static const std::vector plate_keys = { "curr_bed_type", "first_layer_print_sequence", "first_layer_sequence_choice", "print_sequence"/*, "spiral_mode"*/}; +TabPrintPlate::TabPrintPlate(ParamsPanel* parent) : + TabPrintModel(parent, plate_keys) +{ + m_parent_tab = wxGetApp().get_tab(Preset::TYPE_PRINT); + m_type = Preset::TYPE_PLATE; + m_keys = concat(m_keys, plate_keys); +} + +void TabPrintPlate::build() +{ + m_presets = &m_prints; + load_initial_data(); + + m_config->option("curr_bed_type", true); + if (m_preset_bundle->project_config.has("curr_bed_type")) { + BedType global_bed_type = m_preset_bundle->project_config.opt_enum("curr_bed_type"); + global_bed_type = BedType(global_bed_type - 1); + m_config->set_key_value("curr_bed_type", new ConfigOptionEnum(global_bed_type)); + } + m_config->option("first_layer_sequence_choice", true); + m_config->option("first_layer_print_sequence", true); + + auto page = add_options_page(L("Plate Settings"), "empty"); + auto optgroup = page->new_optgroup(""); + optgroup->append_single_option_line("curr_bed_type"); + optgroup->append_single_option_line("print_sequence"); + optgroup->append_single_option_line("first_layer_sequence_choice"); + // hidden + //optgroup->append_single_option_line("spiral_mode"); + for (auto& line : const_cast&>(optgroup->get_lines())) { + line.undo_to_sys = true; + } + optgroup->have_sys_config = [this] { m_back_to_sys = true; return true; }; +} + +void TabPrintPlate::reset_model_config() +{ + if (m_object_configs.empty()) return; + wxGetApp().plater()->take_snapshot(std::string("Reset Options")); + for (auto plate_item : m_object_configs) { + auto rmkeys = intersect(m_keys, plate_item.second->keys()); + for (auto& k : rmkeys) { + plate_item.second->erase(k); + } + auto plate = dynamic_cast(plate_item.first); + plate->reset_bed_type(); + plate->set_print_seq(PrintSequence::ByDefault); + plate->set_first_layer_print_sequence({}); + plate->set_spiral_vase_mode(false, true); + notify_changed(plate_item.first); + } + update_model_config(); + wxGetApp().mainframe->on_config_changed(m_config); +} + +void TabPrintPlate::on_value_change(const std::string& opt_key, const boost::any& value) +{ + auto k = opt_key; + if (m_config_manipulation.is_applying()) { + return; + } + if (!has_key(k)) + return; + if (!m_object_configs.empty()) + wxGetApp().plater()->take_snapshot((boost::format("Change Option %s") % k).str()); + bool set = true; + if (m_back_to_sys) { + for (auto plate_item : m_object_configs) { + plate_item.second->erase(k); + auto plate = dynamic_cast(plate_item.first); + if (k == "curr_bed_type") + plate->reset_bed_type(); + if (k == "print_sequence") + plate->set_print_seq(PrintSequence::ByDefault); + if (k == "first_layer_sequence_choice") + plate->set_first_layer_print_sequence({}); + if (k == "spiral_mode") + plate->set_spiral_vase_mode(false, true); + } + m_all_keys.erase(std::remove(m_all_keys.begin(), m_all_keys.end(), k), m_all_keys.end()); + } + else if (set) { + for (auto plate_item : m_object_configs) { + plate_item.second->apply_only(*m_config, { k }); + auto plate = dynamic_cast(plate_item.first); + BedType bed_type; + PrintSequence print_seq; + FirstLayerSeq first_layer_seq_choice; + if (k == "curr_bed_type") { + bed_type = m_config->opt_enum("curr_bed_type"); + plate->set_bed_type(BedType(bed_type)); + } + if (k == "print_sequence") { + print_seq = m_config->opt_enum("print_sequence"); + plate->set_print_seq(print_seq); + } + if (k == "first_layer_sequence_choice") { + first_layer_seq_choice = m_config->opt_enum("first_layer_sequence_choice"); + if (first_layer_seq_choice == FirstLayerSeq::flsAuto) { + plate->set_first_layer_print_sequence({}); + } + else if (first_layer_seq_choice == FirstLayerSeq::flsCutomize) { + const DynamicPrintConfig& plate_config = plate_item.second->get(); + if (!plate_config.has("first_layer_print_sequence")) { + std::vector initial_sequence; + for (int i = 0; i < wxGetApp().filaments_cnt(); i++) { + initial_sequence.push_back(i + 1); + } + plate->set_first_layer_print_sequence(initial_sequence); + } + wxCommandEvent evt(EVT_OPEN_PLATESETTINGSDIALOG); + evt.SetInt(plate->get_index()); + evt.SetString("only_first_layer_sequence"); + evt.SetEventObject(wxGetApp().plater()); + //wxGetApp().plater()->GetEventHandler()->ProcessEvent(evt); + wxPostEvent(wxGetApp().plater(), evt); + } + } + if (k == "spiral_mode") { + plate->set_spiral_vase_mode(m_config->opt_bool("spiral_mode"), false); + } + } + m_all_keys = concat(m_all_keys, { k }); + } + if (m_back_to_sys || set) update_changed_ui(); + m_back_to_sys = false; + for (auto plate_item : m_object_configs) { + plate_item.second->touch(); + notify_changed(plate_item.first); + } + + wxGetApp().params_panel()->notify_object_config_changed(); + update(); +} + +void TabPrintPlate::notify_changed(ObjectBase* object) +{ + auto plate = dynamic_cast(object); + auto objects_list = wxGetApp().obj_list(); + wxDataViewItemArray items; + objects_list->GetSelections(items); + for (auto item : items) { + if (objects_list->GetModel()->GetItemType(item) == itPlate) { + ObjectDataViewModelNode* node = static_cast(item.GetID()); + if (node) + node->set_action_icon(!m_all_keys.empty()); + } + } +} + +void TabPrintPlate::update_custom_dirty() +{ + for (auto k : m_null_keys) + m_options_list[k] = 0; + for (auto k : m_all_keys) { + if (k == "first_layer_sequence_choice") { + if (m_config->opt_enum("first_layer_sequence_choice") != FirstLayerSeq::flsAuto) { + m_options_list[k] &= ~osInitValue; + } + } + if (k == "curr_bed_type") { + DynamicConfig& global_cfg = wxGetApp().preset_bundle->project_config; + if (global_cfg.has("curr_bed_type")) { + BedType global_bed_type = global_cfg.opt_enum("curr_bed_type"); + if (m_config->opt_enum("curr_bed_type") != global_bed_type) { + m_options_list[k] &= ~osInitValue; + } + } + } + m_options_list[k] &= ~osSystemValue; + } +} TabPrintObject::TabPrintObject(ParamsPanel* parent) : TabPrintModel(parent, concat(PrintObjectConfig().keys(), PrintRegionConfig().keys())) @@ -2583,6 +2840,12 @@ static void validate_custom_gcode_cb(Tab* tab, const wxString& title, const t_co tab->on_value_change(opt_key, value); } +static void validate_custom_gcode_cb(Tab* tab, ConfigOptionsGroupShp opt_group, const t_config_option_key& opt_key, const boost::any& value) { + tab->validate_custom_gcodes_was_shown = !Tab::validate_custom_gcode(opt_group->title, boost::any_cast(value)); + tab->update_dirty(); + tab->on_value_change(opt_key, value); +} + void TabFilament::add_filament_overrides_page() { //BBS @@ -3147,7 +3410,6 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("thumbnails_format"); optgroup->append_single_option_line("use_relative_e_distances"); optgroup->append_single_option_line("use_firmware_retraction"); - optgroup->append_single_option_line("scan_first_layer"); // optgroup->append_single_option_line("spaghetti_detector"); optgroup->append_single_option_line("machine_load_filament_time"); optgroup->append_single_option_line("machine_unload_filament_time"); @@ -3194,6 +3456,17 @@ void TabPrinter::build_fff() option.opt.is_code = true; option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); + + optgroup = page->new_optgroup(L("Printing by object G-code"), L"param_gcode", 0); + optgroup->m_on_change = [this, optgroup](const t_config_option_key &opt_key, const boost::any &value) { + validate_custom_gcode_cb(this, optgroup, opt_key, value); + }; + option = optgroup->get_option("printing_by_object_gcode"); + option.opt.full_width = true; + option.opt.is_code = true; + option.opt.height = gcode_field_height; // 150; + optgroup->append_single_option_line(option); + optgroup = page->new_optgroup(L("Before layer change G-code"),"param_gcode", 0); optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { @@ -3579,6 +3852,8 @@ if (is_marlin_flavor) optgroup->append_single_option_line("retraction_length", "", extruder_idx); optgroup->append_single_option_line("retract_restart_extra", "", extruder_idx); optgroup->append_single_option_line("z_hop", "", extruder_idx); + optgroup->append_single_option_line("retract_lift_above", "", extruder_idx); + optgroup->append_single_option_line("retract_lift_below", "", extruder_idx); optgroup->append_single_option_line("z_hop_types", "", extruder_idx); optgroup->append_single_option_line("retraction_speed", "", extruder_idx); optgroup->append_single_option_line("deretraction_speed", "", extruder_idx); @@ -4221,6 +4496,9 @@ bool Tab::select_preset(std::string preset_name, bool delete_current /*=false*/, } BOOST_LOG_TRIVIAL(info) << boost::format("before delete action, canceled %1%, delete_current %2%") %canceled %delete_current; + bool delete_third_printer = false; + std::vector filament_presets; + std::vector process_presets; if (! canceled && delete_current) { // Delete the file and select some other reasonable preset. // It does not matter which preset will be made active as the preset will be re-selected from the preset_name variable. @@ -4228,11 +4506,22 @@ bool Tab::select_preset(std::string preset_name, bool delete_current /*=false*/, try { //BBS delete preset Preset ¤t_preset = m_presets->get_selected_preset(); + + // Obtain compatible filament and process presets for printers + if (m_preset_bundle && m_presets->get_preset_base(current_preset) == ¤t_preset && printer_tab && !current_preset.is_system) { + delete_third_printer = true; + for (const Preset &preset : m_preset_bundle->filaments.get_presets()) { + if (preset.is_compatible && !preset.is_default) { filament_presets.push_back(preset); } + } + for (const Preset &preset : m_preset_bundle->prints.get_presets()) { + if (preset.is_compatible && !preset.is_default) { process_presets.push_back(preset); } + } + } if (!current_preset.setting_id.empty()) { - BOOST_LOG_TRIVIAL(info) << "delete preset = " << current_preset.name << ", setting_id = " << current_preset.setting_id; - m_presets->set_sync_info_and_save(current_preset.name, current_preset.setting_id, "delete"); + m_presets->set_sync_info_and_save(current_preset.name, current_preset.setting_id, "delete", 0); wxGetApp().delete_preset_from_cloud(current_preset.setting_id); } + BOOST_LOG_TRIVIAL(info) << "delete preset = " << current_preset.name << ", setting_id = " << current_preset.setting_id; BOOST_LOG_TRIVIAL(info) << boost::format("will delete current preset..."); m_presets->delete_current_preset(); } catch (const std::exception & ex) { @@ -4311,6 +4600,39 @@ bool Tab::select_preset(std::string preset_name, bool delete_current /*=false*/, wxGetApp().plater()->sidebar().on_filaments_change(m_preset_bundle->filament_presets.size()); } load_current_preset(); + + if (delete_third_printer) { + wxGetApp().CallAfter([filament_presets, process_presets]() { + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + std::string old_filament_name = preset_bundle->filaments.get_edited_preset().name; + std::string old_process_name = preset_bundle->prints.get_edited_preset().name; + + for (const Preset &preset : filament_presets) { + if (!preset.setting_id.empty()) { + preset_bundle->filaments.set_sync_info_and_save(preset.name, preset.setting_id, "delete", 0); + wxGetApp().delete_preset_from_cloud(preset.setting_id); + } + BOOST_LOG_TRIVIAL(info) << "delete filament preset = " << preset.name << ", setting_id = " << preset.setting_id; + preset_bundle->filaments.delete_preset(preset.name); + } + + for (const Preset &preset : process_presets) { + if (!preset.setting_id.empty()) { + preset_bundle->prints.set_sync_info_and_save(preset.name, preset.setting_id, "delete", 0); + wxGetApp().delete_preset_from_cloud(preset.setting_id); + } + BOOST_LOG_TRIVIAL(info) << "delete print preset = " << preset.name << ", setting_id = " << preset.setting_id; + preset_bundle->prints.delete_preset(preset.name); + } + + preset_bundle->update_compatible(PresetSelectCompatibleType::Always); + preset_bundle->filaments.select_preset_by_name(old_filament_name, true); + preset_bundle->prints.select_preset_by_name(old_process_name, true); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " old filament name is:" << old_filament_name << " old process name is: " << old_process_name; + + }); + } + } if (technology_changed) @@ -4671,8 +4993,10 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach, bool save_to_proje if (name.empty()) { SavePresetDialog dlg(m_parent, m_type, detach ? _u8L("Detached") : ""); - if (dlg.ShowModal() != wxID_OK) - return; + if (!m_just_edit) { + if (dlg.ShowModal() != wxID_OK) + return; + } name = dlg.get_name(); //BBS: add project embedded preset relate logic save_to_project = dlg.get_save_to_project_selection(m_type); @@ -4781,12 +5105,52 @@ void Tab::delete_preset() std::string action = _utf8(L("Delete")); //std::string action = current_preset.is_external ? _utf8(L("remove")) : _utf8(L("delete")); // TRN remove/delete + wxString msg; + bool confirm_delete_third_party_printer = false; + bool is_base_preset = false; + if (m_presets->get_preset_base(current_preset) == ¤t_preset) { //root preset + is_base_preset = true; + if (current_preset.type == Preset::Type::TYPE_PRINTER && !current_preset.is_system) { //Customize third-party printers + Preset ¤t_preset = m_presets->get_selected_preset(); + int filament_preset_num = 0; + int process_preset_num = 0; + for (const Preset &preset : m_preset_bundle->filaments.get_presets()) { + if (preset.is_compatible && !preset.is_default) { filament_preset_num++; } + } + for (const Preset &preset : m_preset_bundle->prints.get_presets()) { + if (preset.is_compatible && !preset.is_default) { process_preset_num++; } + } + + DeleteConfirmDialog + dlg(parent(), wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Delete"), + wxString::Format(_L("%d Filament Preset and %d Process Preset is attached to this printer. Those presets would be deleted if the printer is deleted."), + filament_preset_num, process_preset_num)); + int res = dlg.ShowModal(); + if (res != wxID_OK) return; + confirm_delete_third_party_printer = true; + } + int count = 0; + wxString presets; + for (auto &preset2 : *m_presets) + if (preset2.inherits() == current_preset.name) { + ++count; + presets += "\n - " + preset2.name; + } + if (count > 0) { + msg = _L("Presets inherited by other presets can not be deleted!"); + msg += "\n"; + msg += _L_PLURAL("The following presets inherit this preset.", + "The following preset inherits this preset.", count); + wxString title = from_u8((boost::format(_utf8(L("%1% Preset"))) % action).str()); // action + _(L(" Preset")); + MessageDialog(parent(), msg + presets, title, wxOK | wxICON_ERROR).ShowModal(); + return; + } + } BOOST_LOG_TRIVIAL(info) << boost::format("delete preset %1%, setting_id %2%, user_id %3%, base_id %4%, sync_info %5%, type %6%") %current_preset.name%current_preset.setting_id%current_preset.user_id%current_preset.base_id%current_preset.sync_info %Preset::get_type_string(m_type); PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers; - wxString msg; if (m_type == Preset::TYPE_PRINTER && !physical_printers.empty()) { @@ -4824,16 +5188,20 @@ void Tab::delete_preset() } } - msg += from_u8((boost::format(_u8L("Are you sure to %1% the selected preset?")) % action).str()); + if (is_base_preset && (current_preset.type == Preset::Type::TYPE_FILAMENT) && action == _utf8(L("Delete"))) { + msg += from_u8(_u8L("Are you sure to delete the selected preset? \nIf the preset corresponds to a filament currently in use on your printer, please reset the filament information for that slot.")); + } else { + msg += from_u8((boost::format(_u8L("Are you sure to %1% the selected preset?")) % action).str()); + } //BBS: add project embedded preset logic and refine is_external action = _utf8(L("Delete")); //action = current_preset.is_external ? _utf8(L("Remove")) : _utf8(L("Delete")); // TRN Remove/Delete wxString title = from_u8((boost::format(_utf8(L("%1% Preset"))) % action).str()); //action + _(L(" Preset")); - if (current_preset.is_default || + if (current_preset.is_default || !(confirm_delete_third_party_printer || //wxID_YES != wxMessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal()) - wxID_YES != MessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal()) + wxID_YES == MessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal())) return; // if we just delete preset from the physical printer @@ -5002,8 +5370,8 @@ wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent) auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL); - btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) - { + btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) { + bool is_configed_by_BBL = PresetUtils::system_printer_bed_model(m_preset_bundle->printers.get_edited_preset()).size() > 0; BedShapeDialog dlg(this); dlg.build_dialog(*m_config->option("printable_area"), *m_config->option("bed_custom_texture"), @@ -5084,6 +5452,18 @@ bool Tab::validate_custom_gcodes() return valid; } +void Tab::set_just_edit(bool just_edit) +{ + m_just_edit = just_edit; + if (just_edit) { + m_presets_choice->Disable(); + m_btn_delete_preset->Disable(); + } else { + m_presets_choice->Enable(); + m_btn_delete_preset->Enable(); + } +} + void Tab::compatible_widget_reload(PresetDependencies &deps) { Field* field = this->get_field(deps.key_condition); diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 586573f181a..eb63667a126 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -179,6 +179,9 @@ class Tab: public wxPanel */ bool m_is_default_preset {false}; + // just be used for edit filament dialog + bool m_just_edit{false}; + ScalableButton* m_undo_btn; ScalableButton* m_undo_to_sys_btn; //ScalableButton* m_question_btn; @@ -405,6 +408,7 @@ class Tab: public wxPanel static bool validate_custom_gcode(const wxString& title, const std::string& gcode); bool validate_custom_gcodes(); bool validate_custom_gcodes_was_shown{ false }; + void set_just_edit(bool just_edit); protected: void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const std::string& path, widget_t widget); @@ -477,7 +481,7 @@ class TabPrintModel : public TabPrint virtual void update_custom_dirty() override; protected: - std::vector const m_keys; + std::vector m_keys; PresetCollection m_prints; Tab * m_parent_tab; std::map m_object_configs; @@ -486,6 +490,22 @@ class TabPrintModel : public TabPrint bool m_back_to_sys = false; }; + +class TabPrintPlate : public TabPrintModel +{ +public: + //BBS: GUI refactor + TabPrintPlate(ParamsPanel* parent); + ~TabPrintPlate() {} + void build() override; + void reset_model_config() override; + +protected: + virtual void on_value_change(const std::string& opt_key, const boost::any& value) override; + virtual void notify_changed(ObjectBase* object) override; + virtual void update_custom_dirty() override; +}; + class TabPrintObject : public TabPrintModel { public: diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index a04152f004e..0432ec38bc0 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1501,15 +1501,33 @@ void UnsavedChangesDialog::update_list() for (auto g = 0; g < class_g_list[gname].size(); g++) { //first group - // if (g == 0) { - // auto citem_title = new wxStaticText(citem, wxID_ANY, gname, wxDefaultPosition, wxDefaultSize, 0); - // //citem_title->SetForegroundColour(GREY900); - // auto block_title = new wxWindow(citem, wxID_ANY, wxDefaultPosition, wxSize(0, 0)); + if (g == 0) { + auto panel_item = new wxWindow(m_scrolledWindow, -1, wxDefaultPosition, wxSize(-1, UNSAVE_CHANGE_DIALOG_ITEM_HEIGHT)); + panel_item->SetBackgroundColour(GREY200); - // - // sizer_citem->Add(block_title, 0, wxEXPAND | wxLEFT, 20); - // sizer_citem->Add(citem_title, 0, wxALL, (list_item_height - citem_title->GetSize().GetHeight()) / 2); - //} + wxBoxSizer *sizer_item = new wxBoxSizer(wxHORIZONTAL); + + auto panel_left = new wxPanel(panel_item, wxID_ANY, wxDefaultPosition, wxSize(UNSAVE_CHANGE_DIALOG_FIRST_VALUE_WIDTH, -1), wxTAB_TRAVERSAL); + panel_left->SetBackgroundColour(GREY200); + + wxBoxSizer *sizer_left_v = new wxBoxSizer(wxVERTICAL); + + auto text_left = new wxStaticText(panel_left, wxID_ANY, gname, wxDefaultPosition, wxSize(-1, -1), 0); + text_left->SetFont(::Label::Head_13); + text_left->Wrap(-1); + text_left->SetForegroundColour(GREY700); + text_left->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); + + sizer_left_v->Add(text_left, 0, wxLEFT, 37); + + panel_left->SetSizer(sizer_left_v); + panel_left->Layout(); + sizer_item->Add(panel_left, 0, wxALIGN_CENTER, 0); + + panel_item->SetSizer(sizer_item); + panel_item->Layout(); + m_listsizer->Add(panel_item, 0, wxEXPAND, 0); + } auto data = class_g_list[gname][g]; @@ -1529,7 +1547,7 @@ void UnsavedChangesDialog::update_list() text_left->SetForegroundColour(GREY700); text_left->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); - sizer_left_v->Add(text_left, 0, wxLEFT, 37 ); + sizer_left_v->Add(text_left, 0, wxLEFT, 51 ); panel_left->SetSizer(sizer_left_v); panel_left->Layout(); diff --git a/src/slic3r/GUI/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 1ff4a56fe07..d78136a0940 100644 --- a/src/slic3r/GUI/UpdateDialogs.cpp +++ b/src/slic3r/GUI/UpdateDialogs.cpp @@ -132,10 +132,11 @@ MsgUpdateConfig::MsgUpdateConfig(const std::vector &updates, bool force_ m_sizer_right->Add(0, 0, 1, wxTOP, FromDIP(15)); - auto m_scrollwindw_release_note = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(560), FromDIP(430))); - m_scrollwindw_release_note->SetScrollRate(5, 5); + auto m_scrollwindw_release_note = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(560), FromDIP(430)),wxVSCROLL); + m_scrollwindw_release_note->SetScrollRate(0, 5); m_scrollwindw_release_note->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); - m_scrollwindw_release_note->SetMaxSize(wxSize(FromDIP(540), FromDIP(410))); + m_scrollwindw_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430))); + m_scrollwindw_release_note->SetWindowStyle(wxVSCROLL); auto sizer_button = new wxBoxSizer(wxHORIZONTAL); sizer_button->Add(0, 0, 1, wxEXPAND, 5); @@ -200,8 +201,11 @@ MsgUpdateConfig::MsgUpdateConfig(const std::vector &updates, bool force_ // BBS: use changelog string instead of url if (!update.comment.empty()) { flex->Add(new wxStaticText(m_scrollwindw_release_note, wxID_ANY, _(L("Description:"))), 0, wxALIGN_RIGHT); - auto *update_comment = new wxStaticText(m_scrollwindw_release_note, wxID_ANY, from_u8(update.comment)); - update_comment->Wrap(FromDIP(242) * wxGetApp().em_unit()); + auto *update_comment = new Label(m_scrollwindw_release_note,std::string("")); + update_comment->SetLabel(from_u8(update.comment)); + update_comment->SetMaxSize(wxSize(FromDIP(545), -1)); + update_comment->SetMinSize(wxSize(FromDIP(545), -1)); + update_comment->Wrap(FromDIP(450)); flex->Add(update_comment); } diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index f83becd0e06..8b800e4e3a5 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -309,7 +309,12 @@ void MachineInfoPanel::init_bitmaps() m_img_printer = ScalableBitmap(this, "printer_thumbnail", 160); m_img_monitor_ams = ScalableBitmap(this, "monitor_upgrade_ams", 200); m_img_ext = ScalableBitmap(this, "monitor_upgrade_ext", 200); - m_img_extra_ams = ScalableBitmap(this, "monitor_upgrade_f1", 160); + if (wxGetApp().dark_mode()) { + m_img_extra_ams = ScalableBitmap(this, "extra_icon_dark", 160); + } + else { + m_img_extra_ams = ScalableBitmap(this, "extra_icon", 160); + } upgrade_green_icon = ScalableBitmap(this, "monitor_upgrade_online", 5); upgrade_gray_icon = ScalableBitmap(this, "monitor_upgrade_offline", 5); upgrade_yellow_icon = ScalableBitmap(this, "monitor_upgrade_busy", 5); @@ -342,10 +347,20 @@ void MachineInfoPanel::Update_printer_img(MachineObject* obj) { if (!obj) {return;} auto img = obj->get_printer_thumbnail_img_str(); - if (wxGetApp().dark_mode()) {img += "_dark";} + if (wxGetApp().dark_mode()) { + img += "_dark"; + m_img_extra_ams = ScalableBitmap(this, "extra_icon_dark", 160); + } + else { + m_img_extra_ams = ScalableBitmap(this, "extra_icon", 160); + + } m_img_printer = ScalableBitmap(this, img, 160); m_printer_img->SetBitmap(m_img_printer.bmp()); m_printer_img->Refresh(); + m_extra_ams_img->SetBitmap(m_img_extra_ams.bmp()); + m_extra_ams_img->Refresh(); + } void MachineInfoPanel::update(MachineObject* obj) diff --git a/src/slic3r/GUI/WebGuideDialog.cpp b/src/slic3r/GUI/WebGuideDialog.cpp index 4606e9184ff..8e71a0ecf1b 100644 --- a/src/slic3r/GUI/WebGuideDialog.cpp +++ b/src/slic3r/GUI/WebGuideDialog.cpp @@ -27,6 +27,7 @@ #include #include #include +#include "CreatePresetsDialog.hpp" using namespace nlohmann; @@ -34,6 +35,42 @@ namespace Slic3r { namespace GUI { json m_ProfileJson; +static wxString update_custom_filaments() +{ + json m_Res = json::object(); + m_Res["command"] = "update_custom_filaments"; + m_Res["sequence_id"] = "2000"; + json m_CustomFilaments = json::array(); + PresetBundle * preset_bundle = wxGetApp().preset_bundle; + std::map> temp_filament_id_to_presets = preset_bundle->filaments.get_filament_presets(); + + std::vector> need_sort; + for (std::pair> filament_id_to_presets : temp_filament_id_to_presets) { + std::string filament_id = filament_id_to_presets.first; + if (filament_id.empty()) continue; + for (const Preset *preset : filament_id_to_presets.second) { + if (preset->is_system || filament_id.empty() || "null" == filament_id || filament_id.size() != 8 || filament_id[0] != 'P') break; + auto filament_vendor = dynamic_cast (const_cast(preset)->config.option("filament_vendor",false)); + if(filament_vendor&&filament_vendor->values.size()&&filament_vendor->values[0] == "Generic") break; + std::string preset_name = preset->name; + size_t index_at = preset_name.find(" @"); + if (std::string::npos != index_at) { preset_name = preset_name.substr(0, index_at); } + need_sort.push_back(std::make_pair(preset_name, preset->filament_id)); + break; + } + } + std::sort(need_sort.begin(), need_sort.end(), [](const std::pair &a, const std::pair &b) { return a.first < b.first; }); + json temp_j; + for (std::pair &filament_name_to_id : need_sort) { + temp_j["name"] = filament_name_to_id.first; + temp_j["id"] = filament_name_to_id.second; + m_CustomFilaments.push_back(temp_j); + } + m_Res["data"] = m_CustomFilaments; + wxString strJS = wxString::Format("HandleStudio(%s)", wxString::FromUTF8(m_Res.dump(-1, ' ', false, json::error_handler_t::ignore))); + return strJS; +} + GuideFrame::GuideFrame(GUI_App *pGUI, long style) : DPIDialog((wxWindow *) (pGUI->mainframe), wxID_ANY, "OrcaSlicer", wxDefaultPosition, wxDefaultSize, style), m_appconfig_new() @@ -322,6 +359,17 @@ void GuideFrame::OnScriptMessage(wxWebViewEvent &evt) wxGetApp().CallAfter([this,strJS] { RunScript(strJS); }); } + else if (strCmd == "request_custom_filaments") { + wxString strJS = update_custom_filaments(); + wxGetApp().CallAfter([this, strJS] { RunScript(strJS); }); + } + else if (strCmd == "create_custom_filament") { + this->EndModal(wxID_OK); + wxQueueEvent(wxGetApp().plater(), new SimpleEvent(EVT_CREATE_FILAMENT)); + } else if (strCmd == "modify_custom_filament") { + m_editing_filament_id = j["id"]; + this->EndModal(wxID_EDIT); + } else if (strCmd == "save_userguide_models") { json MSelected = j["data"]; @@ -738,19 +786,20 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle BOOST_LOG_TRIVIAL(info) << "No bundles need to be installed from resource directory"; } - if (remove_bundles.size() > 0) { - //remove unused bundles - for (const auto &it : remove_bundles) { - auto vendor_file = vendor_dir/(it + ".json"); - auto sub_dir = vendor_dir/(it); - if (fs::exists(vendor_file)) - fs::remove(vendor_file); - if (fs::exists(sub_dir)) - fs::remove_all(sub_dir); - } - } else { - BOOST_LOG_TRIVIAL(info) << "No bundles need to be removed"; - } + // Not remove, because these bundles may be updated + //if (remove_bundles.size() > 0) { + // //remove unused bundles + // for (const auto &it : remove_bundles) { + // auto vendor_file = vendor_dir/(it + ".json"); + // auto sub_dir = vendor_dir/(it); + // if (fs::exists(vendor_file)) + // fs::remove(vendor_file); + // if (fs::exists(sub_dir)) + // fs::remove_all(sub_dir); + // } + //} else { + // BOOST_LOG_TRIVIAL(info) << "No bundles need to be removed"; + //} std::string preferred_model; std::string preferred_variant; @@ -866,6 +915,12 @@ bool GuideFrame::run() } else return false; + } else if (result == wxID_EDIT) { + this->Close(); + FilamentInfomation *filament_info = new FilamentInfomation(); + filament_info->filament_id = m_editing_filament_id; + wxQueueEvent(wxGetApp().plater(), new SimpleEvent(EVT_MODIFY_FILAMENT, filament_info)); + return false; } else return false; diff --git a/src/slic3r/GUI/WebGuideDialog.hpp b/src/slic3r/GUI/WebGuideDialog.hpp index f941f7916b1..ff66f5cb34d 100644 --- a/src/slic3r/GUI/WebGuideDialog.hpp +++ b/src/slic3r/GUI/WebGuideDialog.hpp @@ -124,6 +124,7 @@ class GuideFrame : public DPIDialog wxString m_response_js; wxString m_bbl_user_agent; + std::string m_editing_filament_id; }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/WebUserLoginDialog.cpp b/src/slic3r/GUI/WebUserLoginDialog.cpp index f91b86a8bb3..b95aa50b5f0 100644 --- a/src/slic3r/GUI/WebUserLoginDialog.cpp +++ b/src/slic3r/GUI/WebUserLoginDialog.cpp @@ -44,67 +44,94 @@ ZUserLogin::ZUserLogin() : wxDialog((wxWindow *) (wxGetApp().mainframe), wxID_AN SetBackgroundColour(*wxWHITE); // Url NetworkAgent* agent = wxGetApp().getAgent(); - if (!agent) return; - std::string host_url = agent->get_bambulab_host(); - TargetUrl = host_url + "/sign-in"; - m_networkOk = false; - - wxString strlang = wxGetApp().current_language_code_safe(); - if (strlang != "") { - strlang.Replace("_", "-"); - TargetUrl = host_url + "/" + strlang + "/sign-in"; - } - - BOOST_LOG_TRIVIAL(info) << "login url = " << TargetUrl.ToStdString(); + if (!agent) { + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + SetBackgroundColour(*wxWHITE); - m_bbl_user_agent = wxString::Format("BBL-Slicer/v%s", SLIC3R_VERSION); + wxBoxSizer* m_sizer_main = new wxBoxSizer(wxVERTICAL); + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1)); + m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); + m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0); - // set the frame icon + auto* m_message = new wxStaticText(this, wxID_ANY, _L("Bambu Network plug-in not detected."), wxDefaultPosition, wxDefaultSize, 0); + m_message->SetForegroundColour(*wxBLACK); + m_message->Wrap(FromDIP(360)); - // Create the webview - m_browser = WebView::CreateWebView(this, TargetUrl); - if (m_browser == nullptr) { - wxLogError("Could not init m_browser"); - return; + auto m_download_hyperlink = new wxHyperlinkCtrl(this, wxID_ANY, _L("Click here to download it."), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE); + m_download_hyperlink->Bind(wxEVT_HYPERLINK, [this](wxCommandEvent& event) { + this->Close(); + wxGetApp().ShowDownNetPluginDlg(); + }); + m_sizer_main->Add(m_message, 0, wxALIGN_CENTER | wxALL, FromDIP(15)); + m_sizer_main->Add(m_download_hyperlink, 0, wxALIGN_CENTER | wxALL, FromDIP(10)); + m_sizer_main->Add(0, 0, 1, wxBOTTOM, 10); + + SetSizer(m_sizer_main); + m_sizer_main->SetSizeHints(this); + Layout(); + Fit(); + CentreOnParent(); } - m_browser->Hide(); - m_browser->SetSize(0, 0); - - // Log backend information - // wxLogMessage(wxWebView::GetBackendVersionInfo().ToString()); - // wxLogMessage("Backend: %s Version: %s", - // m_browser->GetClassInfo()->GetClassName(),wxWebView::GetBackendVersionInfo().ToString()); - // wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); - - // Connect the webview events - Bind(wxEVT_WEBVIEW_NAVIGATING, &ZUserLogin::OnNavigationRequest, this, m_browser->GetId()); - Bind(wxEVT_WEBVIEW_NAVIGATED, &ZUserLogin::OnNavigationComplete, this, m_browser->GetId()); - Bind(wxEVT_WEBVIEW_LOADED, &ZUserLogin::OnDocumentLoaded, this, m_browser->GetId()); - Bind(wxEVT_WEBVIEW_ERROR, &ZUserLogin::OnError, this, m_browser->GetId()); - Bind(wxEVT_WEBVIEW_NEWWINDOW, &ZUserLogin::OnNewWindow, this, m_browser->GetId()); - Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &ZUserLogin::OnTitleChanged, this, m_browser->GetId()); - Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &ZUserLogin::OnFullScreenChanged, this, m_browser->GetId()); - Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ZUserLogin::OnScriptMessage, this, m_browser->GetId()); - - // Connect the idle events - // Bind(wxEVT_IDLE, &ZUserLogin::OnIdle, this); - // Bind(wxEVT_CLOSE_WINDOW, &ZUserLogin::OnClose, this); - - // UI - SetTitle( _L("Login")); - // Set a more sensible size for web browsing - wxSize pSize = FromDIP(wxSize(650, 840)); - SetSize(pSize); - - int screenheight = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y, NULL); - int screenwidth = wxSystemSettings::GetMetric(wxSYS_SCREEN_X, NULL); - int MaxY = (screenheight - pSize.y) > 0 ? (screenheight - pSize.y) / 2 : 0; - wxPoint tmpPT((screenwidth - pSize.x) / 2, MaxY); - Move(tmpPT); - - //Param - m_AutotestToken = ""; + else { + std::string host_url = agent->get_bambulab_host(); + TargetUrl = host_url + "/sign-in"; + m_networkOk = false; + + wxString strlang = wxGetApp().current_language_code_safe(); + if (strlang != "") { + strlang.Replace("_", "-"); + TargetUrl = host_url + "/" + strlang + "/sign-in"; + } + + BOOST_LOG_TRIVIAL(info) << "login url = " << TargetUrl.ToStdString(); + m_bbl_user_agent = wxString::Format("BBL-Slicer/v%s", SLIC3R_VERSION); + + // set the frame icon + + // Create the webview + m_browser = WebView::CreateWebView(this, TargetUrl); + if (m_browser == nullptr) { + wxLogError("Could not init m_browser"); + return; + } + m_browser->Hide(); + m_browser->SetSize(0, 0); + + // Log backend information + // wxLogMessage(wxWebView::GetBackendVersionInfo().ToString()); + // wxLogMessage("Backend: %s Version: %s", + // m_browser->GetClassInfo()->GetClassName(),wxWebView::GetBackendVersionInfo().ToString()); + // wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); + + // Connect the webview events + Bind(wxEVT_WEBVIEW_NAVIGATING, &ZUserLogin::OnNavigationRequest, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_NAVIGATED, &ZUserLogin::OnNavigationComplete, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_LOADED, &ZUserLogin::OnDocumentLoaded, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_ERROR, &ZUserLogin::OnError, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_NEWWINDOW, &ZUserLogin::OnNewWindow, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &ZUserLogin::OnTitleChanged, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &ZUserLogin::OnFullScreenChanged, this, m_browser->GetId()); + Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ZUserLogin::OnScriptMessage, this, m_browser->GetId()); + + // Connect the idle events + // Bind(wxEVT_IDLE, &ZUserLogin::OnIdle, this); + // Bind(wxEVT_CLOSE_WINDOW, &ZUserLogin::OnClose, this); + + // UI + SetTitle(_L("Login")); + // Set a more sensible size for web browsing + wxSize pSize = FromDIP(wxSize(650, 840)); + SetSize(pSize); + + int screenheight = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y, NULL); + int screenwidth = wxSystemSettings::GetMetric(wxSYS_SCREEN_X, NULL); + int MaxY = (screenheight - pSize.y) > 0 ? (screenheight - pSize.y) / 2 : 0; + wxPoint tmpPT((screenwidth - pSize.x) / 2, MaxY); + Move(tmpPT); + } wxGetApp().UpdateDlgDarkUI(this); } diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index 2319187bc28..538ecf1e47d 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -90,12 +91,14 @@ WebViewPanel::WebViewPanel(wxWindow *parent) topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); // Log backend information + /* m_browser->GetUserAgent() may lead crash if (wxGetApp().get_mode() == comDevelop) { wxLogMessage(wxWebView::GetBackendVersionInfo().ToString()); wxLogMessage("Backend: %s Version: %s", m_browser->GetClassInfo()->GetClassName(), wxWebView::GetBackendVersionInfo().ToString()); wxLogMessage("User Agent: %s", m_browser->GetUserAgent()); } + */ // Create the Tools menu m_tools_menu = new wxMenu(); @@ -452,8 +455,17 @@ void WebViewPanel::SendDesignStaffpick(bool on) void WebViewPanel::OpenModelDetail(std::string id, NetworkAgent *agent) { std::string url; - if ((agent ? agent->get_model_mall_detail_url(&url, id) : get_model_mall_detail_url(&url, id)) == 0) - wxLaunchDefaultBrowser(url); + if ((agent ? agent->get_model_mall_detail_url(&url, id) : get_model_mall_detail_url(&url, id)) == 0) + { + if (url.find("?") != std::string::npos) + { + url += "&from=bambustudio"; + } else { + url += "?from=bambustudio"; + } + + wxLaunchDefaultBrowser(url); + } } void WebViewPanel::SendLoginInfo() @@ -528,6 +540,12 @@ void WebViewPanel::OnNavigationRequest(wxWebViewEvent& evt) const wxString &url = evt.GetURL(); if (url.StartsWith("File://") || url.StartsWith("file://")) { if (!url.Contains("/web/homepage/index.html")) { + auto file = wxURL::Unescape(wxURL(url).GetPath()); +#ifdef _WIN32 + if (file.StartsWith('/')) + file = file.Mid(1); +#endif + wxGetApp().plater()->load_files(wxArrayString{1, &file}); evt.Veto(); return; } diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index be6dafee473..eb7367cb8dd 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -83,7 +83,7 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo wxColour(255, 255, 255); } - if (obj->get_printer_series() == PrinterSeries::SERIES_X1) { + if (obj->get_printer_series() == PrinterSeries::SERIES_X1 && it->second->is_tray_info_ready()) { CalibUtils::get_pa_k_n_value_by_cali_idx(obj, it->second->cali_idx, info.k, info.n); } else { @@ -480,11 +480,11 @@ void AMSextruder::doRender(wxDC& dc) if (m_vams_loading) { - if (m_current_colur.Alpha() == 0) { dc.SetPen(wxPen(*wxBLACK, 6, wxSOLID)); } + if (m_current_colur.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxSOLID)); } else { dc.SetPen(wxPen(m_current_colur, 6, wxSOLID)); } dc.DrawRoundedRectangle(-size.x / 2, size.y * 0.1, size.x, size.y, 4); - if (m_current_colur == *wxWHITE && !wxGetApp().dark_mode()) { + if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxSOLID)); dc.DrawRoundedRectangle(-size.x / 2 - FromDIP(3), size.y * 0.1 + FromDIP(3), size.x, size.y, 3); dc.DrawRoundedRectangle(-size.x / 2 + FromDIP(3), size.y * 0.1 - FromDIP(3), size.x, size.y, 5); @@ -492,11 +492,11 @@ void AMSextruder::doRender(wxDC& dc) } if (m_ams_loading && !m_none_ams_mode) { - if (m_current_colur.Alpha() == 0) {dc.SetPen(wxPen(*wxBLACK, 6, wxSOLID));} + if (m_current_colur.Alpha() == 0) {dc.SetPen(wxPen(*wxWHITE, 6, wxSOLID));} else {dc.SetPen(wxPen(m_current_colur, 6, wxSOLID));} dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - if (m_current_colur == *wxWHITE && !wxGetApp().dark_mode()) { + if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxSOLID)); dc.DrawLine(size.x / 2 - FromDIP(4), -1, size.x / 2 - FromDIP(3), size.y * 0.6 - 1); dc.DrawLine(size.x / 2 + FromDIP(3), -1, size.x / 2 + FromDIP(3), size.y * 0.6 - 1); @@ -505,11 +505,11 @@ void AMSextruder::doRender(wxDC& dc) } else { if (m_ams_loading) { - if (m_current_colur.Alpha() == 0) { dc.SetPen(wxPen(*wxBLACK, 6, wxSOLID)); } + if (m_current_colur.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxSOLID)); } else { dc.SetPen(wxPen(m_current_colur, 6, wxSOLID)); } dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - if (m_current_colur == *wxWHITE && !wxGetApp().dark_mode()) { + if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxSOLID)); dc.DrawLine(size.x / 2 - FromDIP(4), -1, size.x / 2 - FromDIP(3), size.y * 0.6 - 1); dc.DrawLine(size.x / 2 + FromDIP(3), -1, size.x / 2 + FromDIP(3), size.y * 0.6 - 1); @@ -583,7 +583,7 @@ void AMSVirtualRoad::doRender(wxDC& dc) wxSize size = GetSize(); if (m_vams_loading) { - if (m_current_color.Alpha() == 0) { dc.SetPen(wxPen(*wxBLACK, 6, wxSOLID)); } + if (m_current_color.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxSOLID)); } else { dc.SetPen(wxPen(m_current_color, 6, wxSOLID)); } } else { @@ -593,7 +593,7 @@ void AMSVirtualRoad::doRender(wxDC& dc) dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); dc.DrawRoundedRectangle(size.x / 2, -size.y / 1.1 + FromDIP(1), size.x, size.y, 4); - if (m_current_color == *wxWHITE && !wxGetApp().dark_mode()) { + if ((m_current_color == *wxWHITE || m_current_color.Alpha() == 0) && !wxGetApp().dark_mode()) { dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxSOLID)); dc.DrawRoundedRectangle(size.x / 2 - FromDIP(3), -size.y / 1.1 + FromDIP(4), size.x, size.y, 5); dc.DrawRoundedRectangle(size.x / 2 + FromDIP(3), -size.y / 1.1 - FromDIP(2), size.x, size.y, 3); @@ -866,8 +866,15 @@ void AMSLib::render_generic_text(wxDC &dc) if (m_info.material_name.empty() /*&& m_info.material_state != AMSCanType::AMS_CAN_TYPE_VIRTUAL*/) { auto tsize = dc.GetMultiLineTextExtent("?"); auto pot = wxPoint(0, 0); - pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 - FromDIP(9)); + + if (m_obj && show_k_value) { + pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 - FromDIP(9)); + } + else { + pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 + FromDIP(3)); + } dc.DrawText(L("?"), pot); + } else { auto tsize = dc.GetMultiLineTextExtent(m_info.material_name); @@ -1406,7 +1413,7 @@ void AMSRoad::doRender(wxDC &dc) // mode none // if (m_pass_rode_mode.size() == 1 && m_pass_rode_mode[0] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) return; - if (m_road_color.Alpha() == 0) {dc.SetPen(wxPen(*wxBLACK, m_passroad_width, wxSOLID));} + if (m_road_color.Alpha() == 0) {dc.SetPen(wxPen(*wxWHITE, m_passroad_width, wxSOLID));} else {dc.SetPen(wxPen(m_road_color, m_passroad_width, wxSOLID));} dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); @@ -1681,15 +1688,16 @@ void AMSItem::doRender(wxDC &dc) if (!wxWindow::IsEnabled()) { border_colour = AMS_CONTROL_DISABLE_COLOUR; } if (m_hover) { - dc.SetPen(wxPen(border_colour, 1)); + dc.SetPen(wxPen(border_colour, 2)); dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); + dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 3); + } if (m_selected) { - dc.SetPen(wxPen(border_colour, 1)); + dc.SetPen(wxPen(border_colour, 2)); dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); + dc.DrawRoundedRectangle(1, 1, size.x-1, size.y-1, 3); } } @@ -2421,33 +2429,39 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons wxBoxSizer *m_sizer_button = new wxBoxSizer(wxVERTICAL); wxBoxSizer *m_sizer_button_area = new wxBoxSizer(wxHORIZONTAL); - /*m_button_extrusion_cali = new Button(m_button_area, _L("Cali")); - m_button_extrusion_cali->SetToolTip(_L("Calibration of extrusion")); - m_button_extrusion_cali->SetBackgroundColor(btn_bg_green); - m_button_extrusion_cali->SetBorderColor(btn_bd_green); - m_button_extrusion_cali->SetTextColor(btn_text_green); - m_button_extrusion_cali->SetFont(Label::Body_13); - if (wxGetApp().app_config->get("language") == "de_DE") m_button_extrusion_cali->SetFont(Label::Body_9); - if (wxGetApp().app_config->get("language") == "fr_FR") m_button_extrusion_cali->SetFont(Label::Body_9);*/ - m_button_extruder_feed = new Button(m_button_area, _L("Load Filament")); + m_button_extruder_feed->SetFont(Label::Body_13); + m_button_extruder_feed->SetBackgroundColor(btn_bg_green); m_button_extruder_feed->SetBorderColor(btn_bd_green); m_button_extruder_feed->SetTextColor(btn_text_green); - m_button_extruder_feed->SetFont(Label::Body_13); + + if (wxGetApp().app_config->get("language") == "de_DE") m_button_extruder_feed->SetFont(Label::Body_9); if (wxGetApp().app_config->get("language") == "fr_FR") m_button_extruder_feed->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "ru_RU") m_button_extruder_feed->SetLabel("Load"); + if (wxGetApp().app_config->get("language") == "nl_NL") m_button_extruder_feed->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "hu_HU") m_button_extruder_feed->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "ja_JP") m_button_extruder_feed->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "sv_SE") m_button_extruder_feed->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "cs_CZ") m_button_extruder_feed->SetFont(Label::Body_9); m_button_extruder_back = new Button(m_button_area, _L("Unload Filament")); m_button_extruder_back->SetBackgroundColor(btn_bg_white); m_button_extruder_back->SetBorderColor(btn_bd_white); m_button_extruder_back->SetTextColor(btn_text_white); m_button_extruder_back->SetFont(Label::Body_13); + if (wxGetApp().app_config->get("language") == "de_DE") m_button_extruder_back->SetFont(Label::Body_9); if (wxGetApp().app_config->get("language") == "fr_FR") m_button_extruder_back->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "ru_RU") m_button_extruder_back->SetLabel("Unload"); + if (wxGetApp().app_config->get("language") == "nl_NL") m_button_extruder_back->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "hu_HU") m_button_extruder_back->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "ja_JP") m_button_extruder_back->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "sv_SE") m_button_extruder_back->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "cs_CZ") m_button_extruder_back->SetFont(Label::Body_9); m_sizer_button_area->Add(0, 0, 1, wxEXPAND, 0); - //m_sizer_button_area->Add(m_button_extrusion_cali, 0, wxLEFT, FromDIP(5)); m_sizer_button_area->Add(m_button_extruder_back, 0, wxLEFT, FromDIP(6)); m_sizer_button_area->Add(m_button_extruder_feed, 0, wxLEFT, FromDIP(6)); @@ -2524,7 +2538,8 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_vams_sizer = new wxBoxSizer(wxVERTICAL); m_sizer_vams_tips = new wxBoxSizer(wxHORIZONTAL); - auto m_vams_tip = new wxStaticText(m_amswin, wxID_ANY, _L("Ext Spool")); + auto m_vams_tip = new wxStaticText(m_amswin, wxID_ANY, _L("Ext Spool"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END); + m_vams_tip->SetMaxSize(wxSize(FromDIP(66), -1)); m_vams_tip->SetFont(::Label::Body_12); m_vams_tip->SetBackgroundColour(*wxWHITE); m_img_vams_tip = new wxStaticBitmap(m_amswin, wxID_ANY, create_scaled_bitmap("enable_ams", this, 16), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); @@ -2575,8 +2590,9 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_tip_right_top->Wrap(AMS_STEP_SIZE.x); - m_tip_load_info = new wxStaticText(tip_right, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_tip_load_info = new ::Label(tip_right, wxEmptyString); m_tip_load_info->SetFont(::Label::Body_13); + m_tip_load_info->SetBackgroundColour(*wxWHITE); m_tip_load_info->SetForegroundColour(AMS_CONTROL_GRAY700); m_sizer_right_tip->Add(m_tip_right_top, 0, 0, 0); @@ -2619,6 +2635,13 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_button_guide->SetFont(Label::Body_13); if (wxGetApp().app_config->get("language") == "de_DE") m_button_guide->SetFont(Label::Body_9); if (wxGetApp().app_config->get("language") == "fr_FR") m_button_guide->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "ru_RU") m_button_guide->SetLabel("Guide"); + if (wxGetApp().app_config->get("language") == "nl_NL") m_button_guide->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "hu_HU") m_button_guide->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "ja_JP") m_button_guide->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "sv_SE") m_button_guide->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "cs_CZ") m_button_guide->SetFont(Label::Body_9); + m_button_guide->SetCornerRadius(FromDIP(12)); m_button_guide->SetBorderColor(btn_bd_white); m_button_guide->SetTextColor(btn_text_white); @@ -2629,6 +2652,13 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_button_retry->SetFont(Label::Body_13); if (wxGetApp().app_config->get("language") == "de_DE") m_button_retry->SetFont(Label::Body_9); if (wxGetApp().app_config->get("language") == "fr_FR") m_button_retry->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "ru_RU") m_button_retry->SetLabel("Retry"); + if (wxGetApp().app_config->get("language") == "nl_NL") m_button_retry->SetLabel("Retry"); + if (wxGetApp().app_config->get("language") == "hu_HU") m_button_retry->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "ja_JP") m_button_retry->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "sv_SE") m_button_retry->SetFont(Label::Body_9); + if (wxGetApp().app_config->get("language") == "cs_CZ") m_button_retry->SetFont(Label::Body_9); + m_button_retry->SetCornerRadius(FromDIP(12)); m_button_retry->SetBorderColor(btn_bd_white); m_button_retry->SetTextColor(btn_text_white); @@ -2731,7 +2761,6 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons UpdateStepCtrl(false); - //m_button_extrusion_cali->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(AMSControl::on_extrusion_cali), NULL, this); m_button_extruder_feed->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(AMSControl::on_filament_load), NULL, this); m_button_extruder_back->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(AMSControl::on_filament_unload), NULL, this); @@ -2777,8 +2806,6 @@ void AMSControl::on_retry() void AMSControl::init_scaled_buttons() { - //m_button_extrusion_cali->SetMinSize(wxSize(-1, FromDIP(24))); - //m_button_extrusion_cali->SetCornerRadius(FromDIP(12)); m_button_extruder_feed->SetMinSize(wxSize(-1, FromDIP(24))); m_button_extruder_feed->SetCornerRadius(FromDIP(12)); m_button_extruder_back->SetMinSize(wxSize(-1, FromDIP(24))); @@ -2818,9 +2845,6 @@ wxColour AMSControl::GetCanColour(std::string amsid, std::string canid) void AMSControl::SetActionState(bool button_status[]) { - /*if (button_status[ActionButton::ACTION_BTN_CALI]) m_button_extrusion_cali->Enable(); - else m_button_extrusion_cali->Disable();*/ - if (button_status[ActionButton::ACTION_BTN_LOAD]) m_button_extruder_feed->Enable(); else m_button_extruder_feed->Disable(); @@ -2828,7 +2852,7 @@ void AMSControl::SetActionState(bool button_status[]) else m_button_extruder_back->Disable(); } -void AMSControl::EnterNoneAMSMode(bool support_vt_load) +void AMSControl::EnterNoneAMSMode() { m_vams_lib->m_ams_model = m_ext_model; if(m_is_none_ams_mode == AMSModel::NO_AMS) return; @@ -2840,11 +2864,9 @@ void AMSControl::EnterNoneAMSMode(bool support_vt_load) m_extruder->no_ams_mode(true); m_button_ams_setting->Hide(); m_button_guide->Hide(); - m_button_extruder_feed->Show(); m_button_extruder_back->Show(); - ShowFilamentTip(false); m_amswin->Layout(); m_amswin->Fit(); @@ -2891,7 +2913,7 @@ void AMSControl::EnterExtraAMSMode() m_vams_lib->m_ams_model = AMSModel::EXTRA_AMS; - m_ams_tip->SetLabel(_L("AMS")); + m_ams_tip->SetLabel(wxEmptyString); m_img_vams_tip->SetBitmap(create_scaled_bitmap("enable_ams_disable", this, 16)); m_img_vams_tip->Disable(); m_img_amsmapping_tip->SetBitmap(create_scaled_bitmap("enable_ams_disable", this, 16)); @@ -2968,7 +2990,6 @@ void AMSControl::msw_rescale() m_extruder->msw_rescale(); m_vams_extra_road->msw_rescale(); - //m_button_extrusion_cali->SetMinSize(wxSize(-1, FromDIP(24))); m_button_extruder_feed->SetMinSize(wxSize(-1, FromDIP(24))); m_button_extruder_back->SetMinSize(wxSize(-1, FromDIP(24))); m_button_ams_setting->SetMinSize(wxSize(FromDIP(25), FromDIP(24))); @@ -3003,8 +3024,6 @@ void AMSControl::UpdateStepCtrl(bool is_extrusion) m_filament_unload_step->DeleteAllItems(); m_filament_vt_load_step->DeleteAllItems(); - - if (m_ams_model == AMSModel::GENERIC_AMS || m_ext_model == AMSModel::GENERIC_AMS) { if (is_extrusion) { m_filament_load_step->AppendItem(FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_HEAT_NOZZLE]); @@ -3091,7 +3110,7 @@ void AMSControl::Reset() std::vector ams_info{ams1, ams2, ams3, ams4}; std::vector::iterator it; - UpdateAms(ams_info, false, true); + UpdateAms(ams_info, true); m_current_show_ams = ""; m_current_ams = ""; m_current_senect = ""; @@ -3179,7 +3198,7 @@ void AMSControl::reset_vams() } -void AMSControl::UpdateAms(std::vector info, bool keep_selection, bool is_reset) +void AMSControl::UpdateAms(std::vector info, bool is_reset) { std::string curr_ams_id = GetCurentAms(); std::string curr_can_id = GetCurrentCan(curr_ams_id); @@ -3238,6 +3257,10 @@ void AMSControl::UpdateAms(std::vector info, bool keep_selection, bool SwitchAms(info[0].ams_id); } } + + if (m_ams_model == AMSModel::NO_AMS && !m_vams_lib->is_selected()) { + m_vams_lib->OnSelected(); + } } void AMSControl::AddAmsItems(AMSinfo info) @@ -3429,9 +3452,10 @@ void AMSControl::ShowFilamentTip(bool hasams) m_tip_right_top->Hide(); m_tip_load_info->SetLabelText(wxEmptyString); } - m_sizer_right_tip->Layout(); - m_tip_load_info->Wrap(AMS_STEP_SIZE.x); + m_tip_load_info->SetMinSize(AMS_STEP_SIZE); + m_tip_load_info->Wrap(AMS_STEP_SIZE.x - FromDIP(5)); + m_sizer_right_tip->Layout(); } bool AMSControl::Enable(bool enable) @@ -3445,7 +3469,7 @@ bool AMSControl::Enable(bool enable) AmsCansWindow *cans = m_ams_cans_list[i]; cans->amsCans->Enable(enable); } - //m_button_extrusion_cali->Enable(enable); + m_button_extruder_feed->Enable(enable); m_button_extruder_back->Enable(enable); m_button_ams_setting->Enable(enable); diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index 75c362d2a14..67f0c0ce18a 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -38,7 +38,7 @@ namespace Slic3r { namespace GUI { enum AMSModel { NO_AMS = 0, GENERIC_AMS = 1, - EXTRA_AMS = 2 + EXTRA_AMS = 2 }; enum ActionButton { @@ -431,7 +431,7 @@ class AMSItem : public wxWindow protected: wxSize m_cube_size; wxColour m_background_colour = {AMS_CONTROL_DEF_BLOCK_BK_COLOUR}; - int m_padding = {6}; + int m_padding = {7}; int m_space = {5}; bool m_hover = {false}; bool m_selected = {false}; @@ -591,7 +591,7 @@ class AMSControl : public wxSimplebook wxSimplebook *m_simplebook_bottom = {nullptr}; wxStaticText *m_tip_right_top = {nullptr}; - wxStaticText *m_tip_load_info = {nullptr}; + Label *m_tip_load_info = {nullptr}; wxStaticText *m_text_calibration_percent = {nullptr}; wxWindow * m_none_ams_panel = {nullptr}; wxWindow * m_panel_top = {nullptr}; @@ -627,7 +627,6 @@ class AMSControl : public wxSimplebook ScalableBitmap m_button_ams_setting_normal; ScalableBitmap m_button_ams_setting_hover; ScalableBitmap m_button_ams_setting_press; - Button *m_button_extrusion_cali= {nullptr}; Button *m_button_guide = {nullptr}; Button *m_button_retry = {nullptr}; wxWindow* m_button_area = {nullptr}; @@ -651,7 +650,7 @@ class AMSControl : public wxSimplebook void SetAmsModel(AMSModel mode, AMSModel ext_mode) {m_ams_model = mode; m_ext_model = ext_mode;}; void SetActionState(bool button_status[]); - void EnterNoneAMSMode(bool support_vt_load = false); + void EnterNoneAMSMode(); void EnterGenericAMSMode(); void EnterExtraAMSMode(); @@ -669,7 +668,7 @@ class AMSControl : public wxSimplebook void UpdateStepCtrl(bool is_extrusion_exist); void CreateAms(); - void UpdateAms(std::vector info, bool keep_selection = true, bool is_reset = false); + void UpdateAms(std::vector info, bool is_reset = true); void AddAms(AMSinfo info); void AddAmsItems(AMSinfo info); void AddExtraAms(AMSinfo info); diff --git a/src/slic3r/GUI/Widgets/DropDown.cpp b/src/slic3r/GUI/Widgets/DropDown.cpp index a9728ee7e93..03f8f366b04 100644 --- a/src/slic3r/GUI/Widgets/DropDown.cpp +++ b/src/slic3r/GUI/Widgets/DropDown.cpp @@ -141,11 +141,12 @@ void DropDown::SetSelectorBackgroundColor(StateColor const &color) paintNow(); } -void DropDown::SetUseContentWidth(bool use) +void DropDown::SetUseContentWidth(bool use, bool limit_max_content_width) { if (use_content_width == use) return; use_content_width = use; + this->limit_max_content_width = limit_max_content_width; need_sync = true; messureSize(); } @@ -350,6 +351,13 @@ void DropDown::messureSize() szContent.x = x; } rowSize = szContent; + if (limit_max_content_width) { + wxSize parent_size = GetParent()->GetSize(); + if (rowSize.x > parent_size.x * 2) { + rowSize.x = 2 * parent_size.x; + szContent = rowSize; + } + } szContent.y *= std::min((size_t)15, texts.size()); szContent.y += texts.size() > 15 ? rowSize.y / 2 : 0; wxWindow::SetSize(szContent); diff --git a/src/slic3r/GUI/Widgets/DropDown.hpp b/src/slic3r/GUI/Widgets/DropDown.hpp index e2a6cb4930c..4ff909c8450 100644 --- a/src/slic3r/GUI/Widgets/DropDown.hpp +++ b/src/slic3r/GUI/Widgets/DropDown.hpp @@ -22,6 +22,7 @@ class DropDown : public PopupWindow double radius = 0; bool use_content_width = false; + bool limit_max_content_width = false; bool align_icon = false; bool text_off = false; @@ -74,7 +75,7 @@ class DropDown : public PopupWindow void SetSelectorBackgroundColor(StateColor const &color); - void SetUseContentWidth(bool use); + void SetUseContentWidth(bool use, bool limit_max_content_width = false); void SetAlignIcon(bool align); diff --git a/src/slic3r/GUI/Widgets/FanControl.cpp b/src/slic3r/GUI/Widgets/FanControl.cpp index dc8a061c536..222362e9171 100644 --- a/src/slic3r/GUI/Widgets/FanControl.cpp +++ b/src/slic3r/GUI/Widgets/FanControl.cpp @@ -576,7 +576,7 @@ void FanControlPopup::show_aux_fan(bool support_aux_fun) void FanControlPopup::update_fan_data(MachineObject::FanType type, MachineObject* obj) { - m_is_suppt_cham_fun = obj->is_function_supported(PrinterFunction::FUNC_CHAMBER_FAN); + m_is_suppt_cham_fun = obj->is_support_chamber_fan; show_cham_fan(m_is_suppt_cham_fun); if (type == MachineObject::FanType::COOLING_FAN && obj->cooling_fan_speed >= 0) { diff --git a/src/slic3r/GUI/Widgets/Label.cpp b/src/slic3r/GUI/Widgets/Label.cpp index b57a62e4773..8ac96e90382 100644 --- a/src/slic3r/GUI/Widgets/Label.cpp +++ b/src/slic3r/GUI/Widgets/Label.cpp @@ -52,6 +52,7 @@ wxFont Label::Body_12; wxFont Label::Body_11; wxFont Label::Body_10; wxFont Label::Body_9; +wxFont Label::Body_8; void Label::initSysFont() { @@ -96,6 +97,7 @@ void Label::initSysFont() Body_11 = Label::sysFont(11, false); Body_10 = Label::sysFont(10, false); Body_9 = Label::sysFont(9, false); + Body_8 = Label::sysFont(8, false); } class WXDLLIMPEXP_CORE wxTextWrapper2 diff --git a/src/slic3r/GUI/Widgets/Label.hpp b/src/slic3r/GUI/Widgets/Label.hpp index 1de18ff964a..ea15128ec77 100644 --- a/src/slic3r/GUI/Widgets/Label.hpp +++ b/src/slic3r/GUI/Widgets/Label.hpp @@ -52,6 +52,7 @@ class Label : public wxStaticText static wxFont Body_10; static wxFont Body_11; static wxFont Body_9; + static wxFont Body_8; static void initSysFont(); diff --git a/src/slic3r/GUI/Widgets/SideTools.cpp b/src/slic3r/GUI/Widgets/SideTools.cpp index 05458f4b26d..c226b39e6c1 100644 --- a/src/slic3r/GUI/Widgets/SideTools.cpp +++ b/src/slic3r/GUI/Widgets/SideTools.cpp @@ -92,6 +92,18 @@ bool SideToolsPanel::is_in_interval() void SideToolsPanel::msw_rescale() { + m_printing_img.msw_rescale(); + m_arrow_img.msw_rescale(); + + m_none_printing_img.msw_rescale(); + m_none_arrow_img.msw_rescale(); + m_none_add_img.msw_rescale(); + + m_wifi_none_img.msw_rescale(); + m_wifi_weak_img.msw_rescale(); + m_wifi_middle_img.msw_rescale(); + m_wifi_strong_img.msw_rescale(); + Refresh(); } @@ -314,10 +326,9 @@ SideTools::SideTools(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxBoxSizer* sizer_error_desc = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* sizer_extra_info = new wxBoxSizer(wxHORIZONTAL); - m_link_network_state = new Label(m_side_error_panel, _L("Check cloud service status"), wxALIGN_CENTER_HORIZONTAL | wxST_ELLIPSIZE_END); + m_link_network_state = new wxHyperlinkCtrl(m_side_error_panel, wxID_ANY,_L("Check the status of current system services"),"",wxDefaultPosition,wxDefaultSize,wxALIGN_CENTER_HORIZONTAL | wxST_ELLIPSIZE_END); m_link_network_state->SetMinSize(wxSize(FromDIP(220), -1)); m_link_network_state->SetMaxSize(wxSize(FromDIP(220), -1)); - m_link_network_state->SetForegroundColour(0x009688); m_link_network_state->SetFont(::Label::Body_12); m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); }); m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND); }); diff --git a/src/slic3r/GUI/Widgets/SideTools.hpp b/src/slic3r/GUI/Widgets/SideTools.hpp index aff920cb0d5..4f1cf7c6670 100644 --- a/src/slic3r/GUI/Widgets/SideTools.hpp +++ b/src/slic3r/GUI/Widgets/SideTools.hpp @@ -98,8 +98,8 @@ class SideTools : public wxPanel private: SideToolsPanel* m_side_tools{ nullptr }; - Tabbook* m_tabpanel{ nullptr }; - Label* m_link_network_state{ nullptr }; + Tabbook* m_tabpanel{ nullptr }; + wxHyperlinkCtrl* m_link_network_state{ nullptr }; Label* m_st_txt_error_code{ nullptr }; Label* m_st_txt_error_desc{ nullptr }; Label* m_st_txt_extra_info{ nullptr }; diff --git a/src/slic3r/GUI/Widgets/StaticBox.cpp b/src/slic3r/GUI/Widgets/StaticBox.cpp index 6fde9bb3a31..00855eddf9f 100644 --- a/src/slic3r/GUI/Widgets/StaticBox.cpp +++ b/src/slic3r/GUI/Widgets/StaticBox.cpp @@ -143,7 +143,11 @@ void StaticBox::render(wxDC& dc) wxSize size = GetSize(); if (size.x <= 0 || size.y <= 0) return; - wxMemoryDC memdc; + wxMemoryDC memdc(&dc); + if (!memdc.IsOk()) { + doRender(dc); + return; + } wxBitmap bmp(size.x, size.y); memdc.SelectObject(bmp); //memdc.Blit({0, 0}, size, &dc, {0, 0}); diff --git a/src/slic3r/GUI/Widgets/TempInput.cpp b/src/slic3r/GUI/Widgets/TempInput.cpp index 1311fe60d7e..2cf961fa3be 100644 --- a/src/slic3r/GUI/Widgets/TempInput.cpp +++ b/src/slic3r/GUI/Widgets/TempInput.cpp @@ -117,7 +117,7 @@ void TempInput::Create(wxWindow *parent, wxString text, wxString label, wxString } }); text_ctrl->SetFont(Label::Body_13); - text_ctrl->SetForegroundColour(text_color.colorForStates(StateColor::Normal)); + text_ctrl->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK)); if (!normal_icon.IsEmpty()) { this->normal_icon = ScalableBitmap(this, normal_icon.ToStdString(), 16); } if (!actice_icon.IsEmpty()) { this->actice_icon = ScalableBitmap(this, actice_icon.ToStdString(), 16); } this->degree_icon = ScalableBitmap(this, "degree", 16); diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 55d47c1b84c..607b64fc392 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -14,6 +14,7 @@ #include + using namespace Slic3r::GUI; int scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit() / 10; } @@ -32,9 +33,11 @@ static const wxColour g_text_color = wxColour(107, 107, 107, 255); #define ROW_END_PADDING FromDIP(21) #define BTN_SIZE wxSize(FromDIP(58), FromDIP(24)) #define BTN_GAP FromDIP(20) -#define TEXT_BEG_PADDING FromDIP(41) +#define TEXT_BEG_PADDING FromDIP(30) #define MAX_FLUSH_VALUE 999 -#define MIN_WIPING_DIALOG_WIDTH FromDIP(400) +#define MIN_WIPING_DIALOG_WIDTH FromDIP(300) +#define TIP_MESSAGES_PADDING FromDIP(8) + static void update_ui(wxWindow* window) @@ -289,6 +292,36 @@ wxBoxSizer* WipingDialog::create_btn_sizer(long flags) return btn_sizer; } + +wxBoxSizer* WipingPanel::create_calc_btn_sizer(wxWindow* parent) { + auto btn_sizer = new wxBoxSizer(wxHORIZONTAL); + StateColor calc_btn_bg( + std::pair(wxColour(0, 137, 123), StateColor::Pressed), + std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal) + ); + + StateColor calc_btn_bd( + std::pair(wxColour(0, 150, 136), StateColor::Normal) + ); + + StateColor calc_btn_text( + std::pair(wxColour(255, 255, 254), StateColor::Normal) + ); + + Button* calc_btn = new Button(parent, _L("Re-calculate")); + calc_btn->SetFont(Label::Body_13); + calc_btn->SetMinSize(wxSize(FromDIP(75), FromDIP(24))); + calc_btn->SetCornerRadius(FromDIP(12)); + calc_btn->SetBackgroundColor(calc_btn_bg); + calc_btn->SetBorderColor(calc_btn_bd); + calc_btn->SetTextColor(calc_btn_text); + calc_btn->SetFocus(); + btn_sizer->Add(calc_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, BTN_GAP); + calc_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { calc_flushing_volumes(); }); + + return btn_sizer; +} void WipingDialog::on_dpi_changed(const wxRect &suggested_rect) { for (auto button_item : m_button_list) @@ -321,21 +354,28 @@ WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, c wxDefaultSize, wxDEFAULT_DIALOG_STYLE /* | wxRESIZE_BORDER*/) { + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % Slic3r::resources_dir()).str(); + SetIcon(wxIcon(Slic3r::encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1)); + m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); + this->SetBackgroundColour(*wxWHITE); this->SetMinSize(wxSize(MIN_WIPING_DIALOG_WIDTH, -1)); + m_panel_wiping = new WipingPanel(this, matrix, extruders, extruder_colours, nullptr, extra_flush_volume, flush_multiplier); auto main_sizer = new wxBoxSizer(wxVERTICAL); - + main_sizer->Add(m_line_top, 0, wxEXPAND, 0); + // set min sizer width according to extruders count auto sizer_width = (int)((sqrt(matrix.size()) + 2.8)*ITEM_WIDTH()); sizer_width = sizer_width > MIN_WIPING_DIALOG_WIDTH ? sizer_width : MIN_WIPING_DIALOG_WIDTH; main_sizer->SetMinSize(wxSize(sizer_width, -1)); - main_sizer->Add(m_panel_wiping, 1, wxEXPAND | wxALL, 0); - auto btn_sizer = create_btn_sizer(wxOK | wxCANCEL |wxRESET); + auto btn_sizer = create_btn_sizer(wxOK | wxCANCEL); main_sizer->Add(btn_sizer, 0, wxBOTTOM | wxRIGHT | wxEXPAND, BTN_GAP); SetSizer(main_sizer); main_sizer->SetSizeHints(this); @@ -352,9 +392,13 @@ WipingDialog::WipingDialog(wxWindow* parent, const std::vector& matrix, c this->FindWindowById(wxID_CANCEL, this)->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { EndModal(wxCANCEL); }); } + + /* if (this->FindWindowById(wxID_RESET, this)) { this->FindWindowById(wxID_RESET, this)->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { m_panel_wiping->calc_flushing_volumes(); }); } + */ + this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); }); this->Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& e) { if (e.GetKeyCode() == WXK_ESCAPE) { @@ -389,6 +433,7 @@ void WipingPanel::create_panels(wxWindow* parent, const int num) { for (int j = 0; j < num; ++j) { edit_boxes[j][i]->Reparent(panel); edit_boxes[j][i]->SetBackgroundColour(panel->GetBackgroundColour()); + edit_boxes[j][i]->SetFont(::Label::Body_13); sizer->AddSpacer(EDIT_BOXES_GAP); sizer->Add(edit_boxes[j][i], 0, wxALIGN_CENTER_VERTICAL, 0); } @@ -412,7 +457,8 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con Slic3r::decode_color(color, rgb); m_colours.push_back(wxColor(rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar())); } - + auto sizer_width = (int)((sqrt(matrix.size())) * ITEM_WIDTH() + (sqrt(matrix.size()) + 1) * HEADER_BEG_PADDING); + sizer_width = sizer_width > MIN_WIPING_DIALOG_WIDTH ? sizer_width : MIN_WIPING_DIALOG_WIDTH; // Create two switched panels with their own sizers m_sizer_simple = new wxBoxSizer(wxVERTICAL); m_sizer_advanced = new wxBoxSizer(wxVERTICAL); @@ -420,6 +466,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con m_page_advanced = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); m_page_simple->SetSizer(m_sizer_simple); m_page_advanced->SetSizer(m_sizer_advanced); + m_page_advanced->SetBackgroundColour(*wxWHITE); update_ui(m_page_simple); update_ui(m_page_advanced); @@ -472,6 +519,30 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con } // BBS + m_sizer_advanced->AddSpacer(FromDIP(10)); + auto tip_message_panel = new wxPanel(m_page_advanced, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + tip_message_panel->SetBackgroundColour(wxColour(238, 238, 238)); + auto message_sizer = new wxBoxSizer(wxVERTICAL); + tip_message_panel->SetSizer(message_sizer); + { + wxString message = _L("Studio would re-calculate your flushing volumes everytime the filaments color changed. You could disable the auto-calculate in Bambu Studio > Preferences"); + m_tip_message_label = new Label(tip_message_panel, wxEmptyString); + wxClientDC dc(tip_message_panel); + wxString multiline_message; + m_tip_message_label->split_lines(dc, sizer_width, message, multiline_message); + m_tip_message_label->SetLabel(multiline_message); + m_tip_message_label->SetFont(Label::Body_13); + message_sizer->Add(m_tip_message_label, 0, wxEXPAND | wxALL, TIP_MESSAGES_PADDING); + } + m_sizer_advanced->Add(tip_message_panel, 0, wxEXPAND | wxRIGHT | wxLEFT, TABLE_BORDER); + bool is_show = wxGetApp().app_config->get("auto_calculate") == "true"; + tip_message_panel->Show(is_show); + m_sizer_advanced->AddSpacer(FromDIP(10)); + auto calc_btn_sizer = create_calc_btn_sizer(m_page_advanced); + m_sizer_advanced->Add(calc_btn_sizer, 0, wxEXPAND | wxLEFT, FromDIP(30)); + + //m_sizer_advanced->AddSpacer(FromDIP(10)); + m_sizer_advanced->AddSpacer(FromDIP(5)); header_line_panel = new wxPanel(m_page_advanced, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); header_line_panel->SetBackgroundColour(wxColour(238, 238, 238)); auto header_line_sizer = new wxBoxSizer(wxHORIZONTAL); @@ -488,28 +559,15 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con header_line_sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, HEADER_VERT_PADDING); } header_line_sizer->AddSpacer(HEADER_END_PADDING); - - m_sizer_advanced->Add(header_line_panel, 0, wxEXPAND | wxTOP | wxRIGHT | wxLEFT, TABLE_BORDER); - + + m_sizer_advanced->Add(header_line_panel, 0, wxEXPAND | wxRIGHT | wxLEFT, TABLE_BORDER); + create_panels(m_page_advanced, m_number_of_extruders); - m_sizer_advanced->AddSpacer(BTN_SIZE.y); + //m_sizer_advanced->AddSpacer(BTN_SIZE.y); // BBS: for tunning flush volumes { - wxBoxSizer* param_sizer = new wxBoxSizer(wxHORIZONTAL); - - wxStaticText* flush_multiplier_title = new wxStaticText(m_page_advanced, wxID_ANY, _L("Multiplier")); - param_sizer->Add(flush_multiplier_title); - param_sizer->AddSpacer(FromDIP(5)); - m_flush_multiplier_ebox = new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(50), -1), wxTE_PROCESS_ENTER); - char flush_multi_str[32] = { 0 }; - snprintf(flush_multi_str, sizeof(flush_multi_str), "%.2f", flush_multiplier); - m_flush_multiplier_ebox->SetValue(flush_multi_str); - param_sizer->Add(m_flush_multiplier_ebox); - param_sizer->AddStretchSpacer(1); - m_sizer_advanced->Add(param_sizer, 0, wxEXPAND | wxLEFT, TEXT_BEG_PADDING); - auto multi_desc_label = new wxStaticText(m_page_advanced, wxID_ANY, _(L("Flushing volume (mm³) for each filament pair.")), wxDefaultPosition, wxDefaultSize, 0); multi_desc_label->SetForegroundColour(g_text_color); m_sizer_advanced->Add(multi_desc_label, 0, wxEXPAND | wxLEFT, TEXT_BEG_PADDING); @@ -539,10 +597,23 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector& matrix, con this->update_warning_texts(); e.Skip(); }; - m_flush_multiplier_ebox->Bind(wxEVT_TEXT_ENTER, on_apply_text_modify); - m_flush_multiplier_ebox->Bind(wxEVT_KILL_FOCUS, on_apply_text_modify); m_sizer_advanced->AddSpacer(10); + + wxBoxSizer* param_sizer = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* flush_multiplier_title = new wxStaticText(m_page_advanced, wxID_ANY, _L("Multiplier")); + param_sizer->Add(flush_multiplier_title, 0, wxALIGN_CENTER | wxALL, 0); + param_sizer->AddSpacer(FromDIP(5)); + m_flush_multiplier_ebox = new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(50), -1), wxTE_PROCESS_ENTER); + char flush_multi_str[32] = { 0 }; + snprintf(flush_multi_str, sizeof(flush_multi_str), "%.2f", flush_multiplier); + m_flush_multiplier_ebox->SetValue(flush_multi_str); + param_sizer->Add(m_flush_multiplier_ebox, 0, wxALIGN_CENTER | wxALL, 0); + param_sizer->AddStretchSpacer(1); + m_sizer_advanced->Add(param_sizer, 0, wxEXPAND | wxLEFT, TEXT_BEG_PADDING); + + m_flush_multiplier_ebox->Bind(wxEVT_TEXT_ENTER, on_apply_text_modify); + m_flush_multiplier_ebox->Bind(wxEVT_KILL_FOCUS, on_apply_text_modify); } this->update_warning_texts(); diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index 4d038d378db..71548eea3ba 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -11,6 +11,7 @@ #include "RammingChart.hpp" class Button; +class Label; class RammingPanel : public wxPanel { @@ -52,6 +53,7 @@ class WipingPanel : public wxPanel { void create_panels(wxWindow* parent, const int num); void calc_flushing_volumes(); void msw_rescale(); + wxBoxSizer* create_calc_btn_sizer(wxWindow* parent); float get_flush_multiplier() { @@ -81,6 +83,8 @@ class WipingPanel : public wxPanel { wxBoxSizer* m_sizer_advanced = nullptr; wxGridSizer* m_gridsizer_advanced = nullptr; wxButton* m_widget_button = nullptr; + Label* m_tip_message_label = nullptr; + std::vector icon_list1; std::vector icon_list2; @@ -104,7 +108,6 @@ class WipingDialog : public Slic3r::GUI::DPIDialog int extra_flush_volume, float flush_multiplier); std::vector get_matrix() const { return m_output_matrix; } std::vector get_extruders() const { return m_output_extruders; } - wxBoxSizer* create_btn_sizer(long flags); float get_flush_multiplier() diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 8186f4dfc20..186455f0cd9 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -55,6 +55,104 @@ std::string get_calib_mode_name(CalibMode cali_mode, int stage) } } +static wxString to_wstring_name(std::string name) +{ + if (name == "hardened_steel") { + return _L("Hardened Steel"); + } else if (name == "stainless_steel") { + return _L("Stainless Steel"); + } + + return wxEmptyString; +} + +static bool is_same_nozzle_diameters(const DynamicPrintConfig &full_config, const MachineObject *obj, wxString& error_msg) +{ + if (obj == nullptr) + return true; + + try { + std::string nozzle_type; + const ConfigOptionEnum * config_nozzle_type = full_config.option>("nozzle_type"); + if (config_nozzle_type->value == NozzleType::ntHardenedSteel) { + nozzle_type = "hardened_steel"; + } else if (config_nozzle_type->value == NozzleType::ntStainlessSteel) { + nozzle_type = "stainless_steel"; + } + + auto opt_nozzle_diameters = full_config.option("nozzle_diameter"); + if (opt_nozzle_diameters != nullptr) { + float preset_nozzle_diameter = opt_nozzle_diameters->get_at(0); + if (preset_nozzle_diameter != obj->nozzle_diameter) { + wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"), wxString::Format("%.1f", preset_nozzle_diameter).ToStdString(), to_wstring_name(nozzle_type)); + wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj->nozzle_diameter, to_wstring_name(obj->nozzle_type)); + + error_msg = _L("Your nozzle diameter in preset is not consistent with memorized nozzle diameter. Did you change your nozzle lately?") + "\n " + nozzle_in_preset + + "\n " + nozzle_in_printer + "\n"; + return false; + } + } + + } catch (...) {} + + return true; +} + +static bool is_same_nozzle_type(const DynamicPrintConfig &full_config, const MachineObject *obj, wxString& error_msg) +{ + if (obj == nullptr) + return true; + + NozzleType nozzle_type = NozzleType::ntUndefine; + + if (obj->nozzle_type == "stainless_steel") { + nozzle_type = NozzleType::ntStainlessSteel; + } else if (obj->nozzle_type == "hardened_steel") { + nozzle_type = NozzleType::ntHardenedSteel; + } + + int printer_nozzle_hrc = Print::get_hrc_by_nozzle_type(nozzle_type); + if (full_config.has("required_nozzle_HRC")) { + int filament_nozzle_hrc = full_config.opt_int("required_nozzle_HRC", 0); + if (abs(filament_nozzle_hrc) > abs(printer_nozzle_hrc)) { + BOOST_LOG_TRIVIAL(info) << "filaments hardness mismatch: printer_nozzle_hrc = " << printer_nozzle_hrc << ", filament_nozzle_hrc = " << filament_nozzle_hrc; + std::string filament_type = full_config.opt_string("filament_type", 0); + error_msg = wxString::Format(_L("*Printing %s material with %s may cause nozzle damage"), filament_type, to_wstring_name(obj->nozzle_type)); + error_msg += "\n"; + return false; + } + } + + return true; +} + +static bool check_nozzle_diameter_and_type(const DynamicPrintConfig &full_config, wxString& error_msg) +{ + DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev) { + error_msg = _L("Need select printer"); + return false; + } + + MachineObject *obj = dev->get_selected_machine(); + if (obj == nullptr) { + error_msg = _L("Need select printer"); + return false; + } + + // P1P/S + if (obj->nozzle_type.empty()) + return true; + + if (!is_same_nozzle_diameters(full_config, obj, error_msg)) + return false; + + if (!is_same_nozzle_type(full_config, obj, error_msg)) + return false; + + return true; +} + CalibMode CalibUtils::get_calib_mode_by_name(const std::string name, int& cali_stage) { if (name == "pa_line_calib_mode") { @@ -94,13 +192,14 @@ bool CalibUtils::validate_input_k_value(wxString k_text, float* output_value) double k_value = 0.0; try { - k_text.ToDouble(&k_value); + if(!k_text.ToDouble(&k_value)) + return false; } catch (...) { ; } - if (k_value < 0 || k_value > 0.5) { + if (k_value < 0 || k_value > 0.3) { *output_value = default_k; return false; } @@ -176,6 +275,16 @@ static void read_model_from_file(const std::string& input_file, Model& model) object->ensure_on_bed(); } +std::array get_cut_plane_points(const BoundingBoxf3 &bbox, const double &cut_height) +{ + std::array plane_pts; + plane_pts[0] = Vec3d(bbox.min(0), bbox.min(1), cut_height); + plane_pts[1] = Vec3d(bbox.max(0), bbox.min(1), cut_height); + plane_pts[2] = Vec3d(bbox.max(0), bbox.max(1), cut_height); + plane_pts[3] = Vec3d(bbox.min(0), bbox.max(1), cut_height); + return plane_pts; +} + void CalibUtils::calib_PA(const X1CCalibInfos& calib_infos, int mode, wxString& error_message) { DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); @@ -404,7 +513,7 @@ void CalibUtils::calib_flowrate(int pass, const CalibInfo &calib_info, wxString for (auto _obj : model.objects) { _obj->ensure_on_bed(); _obj->config.set_key_value("wall_loops", new ConfigOptionInt(3)); - // _obj->config.set_key_value("top_one_wall_type", new ConfigOptionEnum(TopOneWallType::Topmost)); + _obj->config.set_key_value("only_one_wall_top", new ConfigOptionBool(true)); _obj->config.set_key_value("sparse_infill_density", new ConfigOptionPercent(35)); _obj->config.set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); _obj->config.set_key_value("top_shell_layers", new ConfigOptionInt(5)); @@ -812,6 +921,16 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f plate_size[1] = bedfs[2].y() - bedfs[0].y(); plate_size[2] = print_height; + if (params.mode == CalibMode::Calib_PA_Line) { + double space_y = 3.5; + int max_line_nums = int(plate_size[1] - 10) / space_y; + int count = std::llround(std::ceil((params.end - params.start) / params.step)); + if (count > max_line_nums) { + error_message = _L("Unable to calibrate: maybe because the set calibration value range is too large, or the step is too small"); + return; + } + } + if (params.mode == CalibMode::Calib_PA_Pattern) { ModelInstance *instance = model->objects[0]->instances[0]; Vec3d offset = model->calib_pa_pattern->get_start_offset() + @@ -861,6 +980,9 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f // return; //} + if (!check_nozzle_diameter_and_type(full_config, error_message)) + return; + fff_print->process(); part_plate->update_slice_result_valid_state(true); @@ -898,7 +1020,7 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f const ModelVolume &model_volume = *model_object.volumes[volume_idx]; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, false, true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, "volume", false, true); glvolume_collection.volumes.back()->set_render_color(new_color); glvolume_collection.volumes.back()->set_color(new_color); //glvolume_collection.volumes.back()->printable = model_instance.printable; @@ -1000,7 +1122,8 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess error_message = _L("The printer is busy on other print job"); return; } - else if (!obj_->is_function_supported(PrinterFunction::FUNC_PRINT_WITHOUT_SD) && (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD)) { + + else if (!obj_->is_support_print_without_sd && (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD)) { error_message = _L("An SD card needs to be inserted before printing."); return; } @@ -1026,7 +1149,7 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess #endif print_job->connection_type = obj_->connection_type(); - print_job->cloud_print_only = obj_->is_cloud_print_only; + print_job->cloud_print_only = obj_->is_support_cloud_print_only; PrintPrepareData job_data; job_data.is_from_plater = false; diff --git a/src/slic3r/Utils/FileHelp.cpp b/src/slic3r/Utils/FileHelp.cpp new file mode 100644 index 00000000000..c272112c732 --- /dev/null +++ b/src/slic3r/Utils/FileHelp.cpp @@ -0,0 +1,26 @@ +#include "FileHelp.hpp" +#include +#include +namespace Slic3r { + namespace Utils { + +bool is_file_too_large(std::string file_path, bool &try_ok) +{ + try { + uintmax_t fileSizeBytes = boost::filesystem::file_size(file_path); + double fileSizeMB = static_cast(fileSizeBytes) / 1024 / 1024; + try_ok = true; + if (fileSizeMB > STL_SVG_MAX_FILE_SIZE_MB) { return true; } + } catch (boost::filesystem::filesystem_error &e) { + try_ok = false; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " error message: " << e.what(); + } + return false; +} + +void slash_to_back_slash(std::string &file_path) { + std::regex regex("\\\\"); + file_path = std::regex_replace(file_path, regex, "/"); +} + +}} // namespace Slic3r::Utils \ No newline at end of file diff --git a/src/slic3r/Utils/FileHelp.hpp b/src/slic3r/Utils/FileHelp.hpp new file mode 100644 index 00000000000..6642354f23a --- /dev/null +++ b/src/slic3r/Utils/FileHelp.hpp @@ -0,0 +1,13 @@ +#ifndef file_help_hpp_ +#define file_help_hpp_ +#include + +#define STL_SVG_MAX_FILE_SIZE_MB 3 +namespace Slic3r { + namespace Utils { + +bool is_file_too_large(std::string file_path, bool &try_ok); +void slash_to_back_slash(std::string& file_path);// "//" to "\" + } +} +#endif // file_help_hpp_ diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 97279dddcf8..099fd616862 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -176,6 +176,7 @@ Http::priv::priv(const std::string &url) #ifdef __WINDOWS__ ::curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_2); #endif + ::curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); } diff --git a/src/slic3r/Utils/MacDarkMode.mm b/src/slic3r/Utils/MacDarkMode.mm index e539053c1df..58ff02ff5d1 100644 --- a/src/slic3r/Utils/MacDarkMode.mm +++ b/src/slic3r/Utils/MacDarkMode.mm @@ -97,6 +97,7 @@ void WKWebView_setTransparentBackground(void * web) { WKWebView * webView = (WKWebView*)web; [webView layer].backgroundColor = [NSColor clearColor].CGColor; + [webView registerForDraggedTypes: @[NSFilenamesPboardType]]; } void openFolderForFile(wxString const & file) @@ -110,6 +111,54 @@ void openFolderForFile(wxString const & file) @end +/* WKWebView */ +@implementation WKWebView (DragDrop) + ++ (void) load +{ + Method draggingEntered = class_getInstanceMethod([WKWebView class], @selector(draggingEntered:)); + Method draggingEntered2 = class_getInstanceMethod([WKWebView class], @selector(draggingEntered2:)); + method_exchangeImplementations(draggingEntered, draggingEntered2); + + Method draggingUpdated = class_getInstanceMethod([WKWebView class], @selector(draggingUpdated:)); + Method draggingUpdated2 = class_getInstanceMethod([WKWebView class], @selector(draggingUpdated2:)); + method_exchangeImplementations(draggingUpdated, draggingUpdated2); + + Method prepareForDragOperation = class_getInstanceMethod([WKWebView class], @selector(prepareForDragOperation:)); + Method prepareForDragOperation2 = class_getInstanceMethod([WKWebView class], @selector(prepareForDragOperation2:)); + method_exchangeImplementations(prepareForDragOperation, prepareForDragOperation2); + + Method performDragOperation = class_getInstanceMethod([WKWebView class], @selector(performDragOperation:)); + Method performDragOperation2 = class_getInstanceMethod([WKWebView class], @selector(performDragOperation2:)); + method_exchangeImplementations(performDragOperation, performDragOperation2); +} + +- (NSDragOperation)draggingEntered2:(id)sender +{ + return NSDragOperationCopy; +} + +- (NSDragOperation)draggingUpdated2:(id)sender +{ + return NSDragOperationCopy; +} + +- (BOOL)prepareForDragOperation2:(id)info +{ + return TRUE; +} + +- (BOOL)performDragOperation2:(id)info +{ + NSURL* url = [NSURL URLFromPasteboard:[info draggingPasteboard]]; + NSString * path = [url path]; + url = [NSURL fileURLWithPath: path]; + [self loadFileURL:url allowingReadAccessToURL:url]; + return TRUE; +} + +@end + /* textColor for NSTextField */ @implementation NSTextField (textColor) diff --git a/src/slic3r/Utils/NetworkAgent.cpp b/src/slic3r/Utils/NetworkAgent.cpp index 0cc2ac7da8f..5f1933567e0 100644 --- a/src/slic3r/Utils/NetworkAgent.cpp +++ b/src/slic3r/Utils/NetworkAgent.cpp @@ -43,6 +43,7 @@ func_set_on_printer_connected_fn NetworkAgent::set_on_printer_connected_fn_pt func_set_on_server_connected_fn NetworkAgent::set_on_server_connected_fn_ptr = nullptr; func_set_on_http_error_fn NetworkAgent::set_on_http_error_fn_ptr = nullptr; func_set_get_country_code_fn NetworkAgent::set_get_country_code_fn_ptr = nullptr; +func_set_on_subscribe_failure_fn NetworkAgent::set_on_subscribe_failure_fn_ptr = nullptr; func_set_on_message_fn NetworkAgent::set_on_message_fn_ptr = nullptr; func_set_on_local_connect_fn NetworkAgent::set_on_local_connect_fn_ptr = nullptr; func_set_on_local_message_fn NetworkAgent::set_on_local_message_fn_ptr = nullptr; @@ -80,6 +81,7 @@ func_get_user_presets NetworkAgent::get_user_presets_ptr = nullptr func_request_setting_id NetworkAgent::request_setting_id_ptr = nullptr; func_put_setting NetworkAgent::put_setting_ptr = nullptr; func_get_setting_list NetworkAgent::get_setting_list_ptr = nullptr; +func_get_setting_list2 NetworkAgent::get_setting_list2_ptr = nullptr; func_delete_setting NetworkAgent::delete_setting_ptr = nullptr; func_get_studio_info_url NetworkAgent::get_studio_info_url_ptr = nullptr; func_set_extra_http_header NetworkAgent::set_extra_http_header_ptr = nullptr; @@ -114,12 +116,12 @@ func_put_rating_picture_oss NetworkAgent::put_rating_picture_oss_ptr = n func_get_model_mall_rating_result NetworkAgent::get_model_mall_rating_result_ptr = nullptr; -NetworkAgent::NetworkAgent() +NetworkAgent::NetworkAgent(std::string log_dir) { if (create_agent_ptr) { - network_agent = create_agent_ptr(); + network_agent = create_agent_ptr(log_dir); } - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", this %1%, network_agent=%2%, create_agent_ptr=%3%")%this %network_agent %create_agent_ptr; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", this %1%, network_agent=%2%, create_agent_ptr=%3%, log_dir=%4%")%this %network_agent %create_agent_ptr %log_dir; } NetworkAgent::~NetworkAgent() @@ -200,6 +202,7 @@ int NetworkAgent::initialize_network_module(bool using_backup) set_on_server_connected_fn_ptr = reinterpret_cast(get_network_function("bambu_network_set_on_server_connected_fn")); set_on_http_error_fn_ptr = reinterpret_cast(get_network_function("bambu_network_set_on_http_error_fn")); set_get_country_code_fn_ptr = reinterpret_cast(get_network_function("bambu_network_set_get_country_code_fn")); + set_on_subscribe_failure_fn_ptr = reinterpret_cast(get_network_function("bambu_network_set_on_subscribe_failure_fn")); set_on_message_fn_ptr = reinterpret_cast(get_network_function("bambu_network_set_on_message_fn")); set_on_local_connect_fn_ptr = reinterpret_cast(get_network_function("bambu_network_set_on_local_connect_fn")); set_on_local_message_fn_ptr = reinterpret_cast(get_network_function("bambu_network_set_on_local_message_fn")); @@ -236,7 +239,8 @@ int NetworkAgent::initialize_network_module(bool using_backup) get_user_presets_ptr = reinterpret_cast(get_network_function("bambu_network_get_user_presets")); request_setting_id_ptr = reinterpret_cast(get_network_function("bambu_network_request_setting_id")); put_setting_ptr = reinterpret_cast(get_network_function("bambu_network_put_setting")); - get_setting_list_ptr = reinterpret_cast(get_network_function("bambu_network_get_setting_list")); + get_setting_list_ptr = reinterpret_cast(get_network_function("bambu_network_get_setting_list")); + get_setting_list2_ptr = reinterpret_cast(get_network_function("bambu_network_get_setting_list2")); delete_setting_ptr = reinterpret_cast(get_network_function("bambu_network_delete_setting")); get_studio_info_url_ptr = reinterpret_cast(get_network_function("bambu_network_get_studio_info_url")); set_extra_http_header_ptr = reinterpret_cast(get_network_function("bambu_network_set_extra_http_header")); @@ -311,6 +315,7 @@ int NetworkAgent::unload_network_module() set_on_server_connected_fn_ptr = nullptr; set_on_http_error_fn_ptr = nullptr; set_get_country_code_fn_ptr = nullptr; + set_on_subscribe_failure_fn_ptr = nullptr; set_on_message_fn_ptr = nullptr; set_on_local_connect_fn_ptr = nullptr; set_on_local_message_fn_ptr = nullptr; @@ -348,6 +353,7 @@ int NetworkAgent::unload_network_module() request_setting_id_ptr = nullptr; put_setting_ptr = nullptr; get_setting_list_ptr = nullptr; + get_setting_list2_ptr = nullptr; delete_setting_ptr = nullptr; get_studio_info_url_ptr = nullptr; set_extra_http_header_ptr = nullptr; @@ -593,6 +599,17 @@ int NetworkAgent::set_get_country_code_fn(GetCountryCodeFn fn) return ret; } +int NetworkAgent::set_on_subscribe_failure_fn(GetSubscribeFailureFn fn) +{ + int ret = 0; + if (network_agent && set_on_subscribe_failure_fn_ptr) { + ret = set_on_subscribe_failure_fn_ptr(network_agent, fn); + if (ret) + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%") % network_agent % ret; + } + return ret; +} + int NetworkAgent::set_on_message_fn(OnMessageFn fn) { int ret = 0; @@ -974,8 +991,19 @@ int NetworkAgent::get_setting_list(std::string bundle_version, ProgressFn pro_fn int ret = 0; if (network_agent && get_setting_list_ptr) { ret = get_setting_list_ptr(network_agent, bundle_version, pro_fn, cancel_fn); - if (ret) - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, bundle_version=%3%")%network_agent %ret %bundle_version ; + if (ret) BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, bundle_version=%3%") % network_agent % ret % bundle_version; + } + return ret; +} + +int NetworkAgent::get_setting_list2(std::string bundle_version, CheckFn chk_fn, ProgressFn pro_fn, WasCancelledFn cancel_fn) +{ + int ret = 0; + if (network_agent && get_setting_list2_ptr) { + ret = get_setting_list2_ptr(network_agent, bundle_version, chk_fn, pro_fn, cancel_fn); + if (ret) BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, bundle_version=%3%") % network_agent % ret % bundle_version; + } else { + ret = get_setting_list(bundle_version, pro_fn, cancel_fn); } return ret; } diff --git a/src/slic3r/Utils/NetworkAgent.hpp b/src/slic3r/Utils/NetworkAgent.hpp index 0db3a08684d..60998c77375 100644 --- a/src/slic3r/Utils/NetworkAgent.hpp +++ b/src/slic3r/Utils/NetworkAgent.hpp @@ -8,93 +8,93 @@ using namespace BBL; namespace Slic3r { typedef bool (*func_check_debug_consistent)(bool is_debug); -typedef std::string(*func_get_version)(void); -typedef void* (*func_create_agent)(void); -typedef int (*func_destroy_agent)(void* agent); -typedef int (*func_init_log)(void* agent); -typedef int (*func_set_config_dir)(void* agent, std::string config_dir); -typedef int (*func_set_cert_file)(void* agent, std::string folder, std::string filename); -typedef int (*func_set_country_code)(void* agent, std::string country_code); -typedef int (*func_start)(void* agent); -typedef int (*func_set_on_ssdp_msg_fn)(void* agent, OnMsgArrivedFn fn); -typedef int (*func_set_on_user_login_fn)(void* agent, OnUserLoginFn fn); -typedef int (*func_set_on_printer_connected_fn)(void* agent, OnPrinterConnectedFn fn); -typedef int (*func_set_on_server_connected_fn)(void* agent, OnServerConnectedFn fn); -typedef int (*func_set_on_http_error_fn)(void* agent, OnHttpErrorFn fn); -typedef int (*func_set_get_country_code_fn)(void* agent, GetCountryCodeFn fn); -typedef int (*func_set_on_message_fn)(void* agent, OnMessageFn fn); -typedef int (*func_set_on_local_connect_fn)(void* agent, OnLocalConnectedFn fn); -typedef int (*func_set_on_local_message_fn)(void* agent, OnMessageFn fn); -typedef int (*func_set_queue_on_main_fn)(void* agent, QueueOnMainFn fn); -typedef int (*func_connect_server)(void* agent); -typedef bool (*func_is_server_connected)(void* agent); -typedef int (*func_refresh_connection)(void* agent); -typedef int (*func_start_subscribe)(void* agent, std::string module); -typedef int (*func_stop_subscribe)(void* agent, std::string module); -typedef int (*func_send_message)(void* agent, std::string dev_id, std::string json_str, int qos); -typedef int (*func_connect_printer)(void* agent, std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl); -typedef int (*func_disconnect_printer)(void* agent); -typedef int (*func_send_message_to_printer)(void* agent, std::string dev_id, std::string json_str, int qos); -typedef bool (*func_start_discovery)(void* agent, bool start, bool sending); -typedef int (*func_change_user)(void* agent, std::string user_info); -typedef bool (*func_is_user_login)(void* agent); -typedef int (*func_user_logout)(void* agent); -typedef std::string(*func_get_user_id)(void* agent); -typedef std::string(*func_get_user_name)(void* agent); -typedef std::string(*func_get_user_avatar)(void* agent); -typedef std::string(*func_get_user_nickanme)(void* agent); -typedef std::string(*func_build_login_cmd)(void* agent); -typedef std::string(*func_build_logout_cmd)(void* agent); -typedef std::string(*func_build_login_info)(void* agent); -typedef int (*func_bind)(void* agent, std::string dev_ip, std::string dev_id, std::string sec_link, std::string timezone, bool improved, OnUpdateStatusFn update_fn); -typedef int (*func_unbind)(void* agent, std::string dev_id); -typedef std::string(*func_get_bambulab_host)(void* agent); -typedef std::string(*func_get_user_selected_machine)(void* agent); -typedef int (*func_set_user_selected_machine)(void* agent, std::string dev_id); -typedef int (*func_start_print)(void* agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); -typedef int (*func_start_local_print_with_record)(void* agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); -typedef int (*func_start_send_gcode_to_sdcard)(void* agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); -typedef int (*func_start_local_print)(void* agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn); -typedef int (*func_get_user_presets)(void* agent, std::map>* user_presets); -typedef std::string(*func_request_setting_id)(void* agent, std::string name, std::map* values_map, unsigned int* http_code); -typedef int (*func_put_setting)(void* agent, std::string setting_id, std::string name, std::map* values_map, unsigned int* http_code); -typedef int (*func_get_setting_list)(void* agent, std::string bundle_version, ProgressFn pro_fn, WasCancelledFn cancel_fn); -typedef int (*func_get_setting_list2)(void* agent, std::string bundle_version, CheckFn chk_fn, ProgressFn pro_fn, WasCancelledFn cancel_fn); -typedef int (*func_delete_setting)(void* agent, std::string setting_id); -typedef std::string(*func_get_studio_info_url)(void* agent); -typedef int (*func_set_extra_http_header)(void* agent, std::map extra_headers); -typedef int (*func_get_my_message)(void* agent, int type, int after, int limit, unsigned int* http_code, std::string* http_body); -typedef int (*func_check_user_task_report)(void* agent, int* task_id, bool* printable); -typedef int (*func_check_user_report)(void* agent, int* task_id, bool* printable, std::string* report_url); -typedef int (*func_get_user_print_info)(void* agent, unsigned int* http_code, std::string* http_body); -typedef int (*func_get_printer_firmware)(void* agent, std::string dev_id, unsigned* http_code, std::string* http_body); -typedef int (*func_get_task_plate_index)(void* agent, std::string task_id, int* plate_index); -typedef int (*func_get_user_info)(void* agent, int* identifier); -typedef int (*func_request_bind_ticket)(void* agent, std::string* ticket); -typedef int (*func_get_subtask_info)(void* agent, std::string subtask_id, std::string* task_json, unsigned int* http_code, std::string* http_body); -typedef int (*func_get_slice_info)(void* agent, std::string project_id, std::string profile_id, int plate_index, std::string* slice_json); -typedef int (*func_query_bind_status)(void* agent, std::vector query_list, unsigned int* http_code, std::string* http_body); -typedef int (*func_modify_printer_name)(void* agent, std::string dev_id, std::string dev_name); -typedef int (*func_get_camera_url)(void* agent, std::string dev_id, std::function callback); -typedef int (*func_get_design_staffpick)(void* agent, int offset, int limit, std::function callback); -typedef int (*func_start_pubilsh)(void* agent, PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out); -typedef int (*func_get_profile_3mf)(void* agent, BBLProfile* profile); -typedef int (*func_get_model_publish_url)(void* agent, std::string* url); -typedef int (*func_get_subtask)(void* agent, BBLModelTask* task, OnGetSubTaskFn getsub_fn); -typedef int (*func_get_model_mall_home_url)(void* agent, std::string* url); -typedef int (*func_get_model_mall_detail_url)(void* agent, std::string* url, std::string id); -typedef int (*func_get_my_profile)(void* agent, std::string token, unsigned int* http_code, std::string* http_body); -typedef int (*func_track_enable)(void* agent, bool enable); -typedef int (*func_track_event)(void* agent, std::string evt_key, std::string content); -typedef int (*func_track_header)(void* agent, std::string header); -typedef int (*func_track_update_property)(void* agent, std::string name, std::string value, std::string type); -typedef int (*func_track_get_property)(void* agent, std::string name, std::string& value, std::string type); +typedef std::string (*func_get_version)(void); +typedef void* (*func_create_agent)(std::string log_dir); +typedef int (*func_destroy_agent)(void *agent); +typedef int (*func_init_log)(void *agent); +typedef int (*func_set_config_dir)(void *agent, std::string config_dir); +typedef int (*func_set_cert_file)(void *agent, std::string folder, std::string filename); +typedef int (*func_set_country_code)(void *agent, std::string country_code); +typedef int (*func_start)(void *agent); +typedef int (*func_set_on_ssdp_msg_fn)(void *agent, OnMsgArrivedFn fn); +typedef int (*func_set_on_user_login_fn)(void *agent, OnUserLoginFn fn); +typedef int (*func_set_on_printer_connected_fn)(void *agent, OnPrinterConnectedFn fn); +typedef int (*func_set_on_server_connected_fn)(void *agent, OnServerConnectedFn fn); +typedef int (*func_set_on_http_error_fn)(void *agent, OnHttpErrorFn fn); +typedef int (*func_set_get_country_code_fn)(void *agent, GetCountryCodeFn fn); +typedef int (*func_set_on_subscribe_failure_fn)(void *agent, GetSubscribeFailureFn fn); +typedef int (*func_set_on_message_fn)(void *agent, OnMessageFn fn); +typedef int (*func_set_on_local_connect_fn)(void *agent, OnLocalConnectedFn fn); +typedef int (*func_set_on_local_message_fn)(void *agent, OnMessageFn fn); +typedef int (*func_set_queue_on_main_fn)(void *agent, QueueOnMainFn fn); +typedef int (*func_connect_server)(void *agent); +typedef bool (*func_is_server_connected)(void *agent); +typedef int (*func_refresh_connection)(void *agent); +typedef int (*func_start_subscribe)(void *agent, std::string module); +typedef int (*func_stop_subscribe)(void *agent, std::string module); +typedef int (*func_send_message)(void *agent, std::string dev_id, std::string json_str, int qos); +typedef int (*func_connect_printer)(void *agent, std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl); +typedef int (*func_disconnect_printer)(void *agent); +typedef int (*func_send_message_to_printer)(void *agent, std::string dev_id, std::string json_str, int qos); +typedef bool (*func_start_discovery)(void *agent, bool start, bool sending); +typedef int (*func_change_user)(void *agent, std::string user_info); +typedef bool (*func_is_user_login)(void *agent); +typedef int (*func_user_logout)(void *agent); +typedef std::string (*func_get_user_id)(void *agent); +typedef std::string (*func_get_user_name)(void *agent); +typedef std::string (*func_get_user_avatar)(void *agent); +typedef std::string (*func_get_user_nickanme)(void *agent); +typedef std::string (*func_build_login_cmd)(void *agent); +typedef std::string (*func_build_logout_cmd)(void *agent); +typedef std::string (*func_build_login_info)(void *agent); +typedef int (*func_bind)(void *agent, std::string dev_ip, std::string dev_id, std::string sec_link, std::string timezone, bool improved, OnUpdateStatusFn update_fn); +typedef int (*func_unbind)(void *agent, std::string dev_id); +typedef std::string (*func_get_bambulab_host)(void *agent); +typedef std::string (*func_get_user_selected_machine)(void *agent); +typedef int (*func_set_user_selected_machine)(void *agent, std::string dev_id); +typedef int (*func_start_print)(void *agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); +typedef int (*func_start_local_print_with_record)(void *agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); +typedef int (*func_start_send_gcode_to_sdcard)(void *agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); +typedef int (*func_start_local_print)(void *agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn); +typedef int (*func_get_user_presets)(void *agent, std::map>* user_presets); +typedef std::string (*func_request_setting_id)(void *agent, std::string name, std::map* values_map, unsigned int* http_code); +typedef int (*func_put_setting)(void *agent, std::string setting_id, std::string name, std::map* values_map, unsigned int* http_code); +typedef int (*func_get_setting_list)(void *agent, std::string bundle_version, ProgressFn pro_fn, WasCancelledFn cancel_fn); +typedef int (*func_get_setting_list2)(void *agent, std::string bundle_version, CheckFn chk_fn, ProgressFn pro_fn, WasCancelledFn cancel_fn); +typedef int (*func_delete_setting)(void *agent, std::string setting_id); +typedef std::string (*func_get_studio_info_url)(void *agent); +typedef int (*func_set_extra_http_header)(void *agent, std::map extra_headers); +typedef int (*func_get_my_message)(void *agent, int type, int after, int limit, unsigned int* http_code, std::string* http_body); +typedef int (*func_check_user_task_report)(void *agent, int* task_id, bool* printable); +typedef int (*func_get_user_print_info)(void *agent, unsigned int* http_code, std::string* http_body); +typedef int (*func_get_printer_firmware)(void *agent, std::string dev_id, unsigned* http_code, std::string* http_body); +typedef int (*func_get_task_plate_index)(void *agent, std::string task_id, int* plate_index); +typedef int (*func_get_user_info)(void *agent, int* identifier); +typedef int (*func_request_bind_ticket)(void *agent, std::string* ticket); +typedef int (*func_get_subtask_info)(void *agent, std::string subtask_id, std::string* task_json, unsigned int* http_code, std::string *http_body); +typedef int (*func_get_slice_info)(void *agent, std::string project_id, std::string profile_id, int plate_index, std::string* slice_json); +typedef int (*func_query_bind_status)(void *agent, std::vector query_list, unsigned int* http_code, std::string* http_body); +typedef int (*func_modify_printer_name)(void *agent, std::string dev_id, std::string dev_name); +typedef int (*func_get_camera_url)(void *agent, std::string dev_id, std::function callback); +typedef int (*func_get_design_staffpick)(void *agent, int offset, int limit, std::function callback); +typedef int (*func_start_pubilsh)(void *agent, PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out); +typedef int (*func_get_profile_3mf)(void *agent, BBLProfile* profile); +typedef int (*func_get_model_publish_url)(void *agent, std::string* url); +typedef int (*func_get_subtask)(void *agent, BBLModelTask* task, OnGetSubTaskFn getsub_fn); +typedef int (*func_get_model_mall_home_url)(void *agent, std::string* url); +typedef int (*func_get_model_mall_detail_url)(void *agent, std::string* url, std::string id); +typedef int (*func_get_my_profile)(void *agent, std::string token, unsigned int *http_code, std::string *http_body); +typedef int (*func_track_enable)(void *agent, bool enable); +typedef int (*func_track_event)(void *agent, std::string evt_key, std::string content); +typedef int (*func_track_header)(void *agent, std::string header); +typedef int (*func_track_update_property)(void *agent, std::string name, std::string value, std::string type); +typedef int (*func_track_get_property)(void *agent, std::string name, std::string& value, std::string type); typedef int (*func_put_model_mall_rating_url)( - void* agent, int rating_id, int score, std::string content, std::vector images, unsigned int& http_code, std::string& http_error); -typedef int (*func_get_oss_config)(void* agent, std::string& config, std::string country_code, unsigned int& http_code, std::string& http_error); + void *agent, int rating_id, int score, std::string content, std::vector images, unsigned int &http_code, std::string &http_error); +typedef int (*func_get_oss_config)(void *agent, std::string &config, std::string country_code, unsigned int &http_code, std::string &http_error); typedef int (*func_put_rating_picture_oss)( - void* agent, std::string& config, std::string& pic_oss_path, std::string model_id, int profile_id, unsigned int& http_code, std::string& http_error); -typedef int (*func_get_model_mall_rating_result)(void* agent, int job_id, std::string& rating_result, unsigned int& http_code, std::string& http_error); + void *agent, std::string &config, std::string &pic_oss_path, std::string model_id, int profile_id, unsigned int &http_code, std::string &http_error); +typedef int (*func_get_model_mall_rating_result)(void *agent, int job_id, std::string &rating_result, unsigned int &http_code, std::string &http_error); //the NetworkAgent class @@ -111,7 +111,7 @@ class NetworkAgent #endif static std::string get_version(); static void* get_network_function(const char* name); - NetworkAgent(); + NetworkAgent(std::string log_dir); ~NetworkAgent(); int init_log(); @@ -125,6 +125,7 @@ class NetworkAgent int set_on_server_connected_fn(OnServerConnectedFn fn); int set_on_http_error_fn(OnHttpErrorFn fn); int set_get_country_code_fn(GetCountryCodeFn fn); + int set_on_subscribe_failure_fn(GetSubscribeFailureFn fn); int set_on_message_fn(OnMessageFn fn); int set_on_local_connect_fn(OnLocalConnectedFn fn); int set_on_local_message_fn(OnMessageFn fn); @@ -149,7 +150,7 @@ class NetworkAgent std::string build_login_cmd(); std::string build_logout_cmd(); std::string build_login_info(); - int bind(std::string dev_ip, std::string dev_id, std::string sec_link, std::string timezone, bool improved, OnUpdateStatusFn update_fn); + int bind(std::string dev_ip, std::string dev_id, std::string sec_link, std::string timezone, bool improved, OnUpdateStatusFn update_fn); int unbind(std::string dev_id); std::string get_bambulab_host(); std::string get_user_selected_machine(); @@ -168,7 +169,6 @@ class NetworkAgent int set_extra_http_header(std::map extra_headers); int get_my_message(int type, int after, int limit, unsigned int* http_code, std::string* http_body); int check_user_task_report(int* task_id, bool* printable); - int check_user_report(int* task_id, bool* printable, std::string* report_url); int get_user_print_info(unsigned int* http_code, std::string* http_body); int get_printer_firmware(std::string dev_id, unsigned* http_code, std::string* http_body); int get_task_plate_index(std::string task_id, int* plate_index); @@ -192,14 +192,14 @@ class NetworkAgent int track_header(std::string header); int track_update_property(std::string name, std::string value, std::string type = "string"); int track_get_property(std::string name, std::string& value, std::string type = "string"); - int put_model_mall_rating(int design_id, int score, std::string content, std::vector images, unsigned int& http_code, std::string& http_error); - int get_oss_config(std::string& config, std::string country_code, unsigned int& http_code, std::string& http_error); - int put_rating_picture_oss(std::string& config, std::string& pic_oss_path, std::string model_id, int profile_id, unsigned int& http_code, std::string& http_error); - int get_model_mall_rating_result(int job_id, std::string& rating_result, unsigned int& http_code, std::string& http_error); + int put_model_mall_rating(int design_id, int score, std::string content, std::vector images, unsigned int &http_code, std::string &http_error); + int get_oss_config(std::string &config, std::string country_code, unsigned int &http_code, std::string &http_error); + int put_rating_picture_oss(std::string &config, std::string &pic_oss_path, std::string model_id, int profile_id, unsigned int &http_code, std::string &http_error); + int get_model_mall_rating_result(int job_id, std::string &rating_result, unsigned int &http_code, std::string &http_error); bool get_track_enable() { return enable_track; } private: bool enable_track = false; - void* network_agent{ nullptr }; + void* network_agent { nullptr }; static func_check_debug_consistent check_debug_consistent_ptr; static func_get_version get_version_ptr; @@ -216,6 +216,7 @@ class NetworkAgent static func_set_on_server_connected_fn set_on_server_connected_fn_ptr; static func_set_on_http_error_fn set_on_http_error_fn_ptr; static func_set_get_country_code_fn set_get_country_code_fn_ptr; + static func_set_on_subscribe_failure_fn set_on_subscribe_failure_fn_ptr; static func_set_on_message_fn set_on_message_fn_ptr; static func_set_on_local_connect_fn set_on_local_connect_fn_ptr; static func_set_on_local_message_fn set_on_local_message_fn_ptr; @@ -259,7 +260,6 @@ class NetworkAgent static func_set_extra_http_header set_extra_http_header_ptr; static func_get_my_message get_my_message_ptr; static func_check_user_task_report check_user_task_report_ptr; - static func_check_user_report check_user_report_ptr; static func_get_user_print_info get_user_print_info_ptr; static func_get_printer_firmware get_printer_firmware_ptr; static func_get_task_plate_index get_task_plate_index_ptr; diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 2168890975e..a69cc4828ae 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -179,6 +179,8 @@ struct PresetUpdater::priv bool has_waiting_updates { false }; Updates waiting_updates; + bool has_waiting_printer_updates { false }; + Updates waiting_printer_updates; struct Resource { @@ -202,11 +204,13 @@ struct PresetUpdater::priv void sync_config(std::string http_url, const VendorMap vendors); void sync_tooltip(std::string http_url, std::string language); void sync_plugins(std::string http_url, std::string plugin_version); - bool get_cached_plugins_version(std::string& cached_version); + void sync_printer_config(std::string http_url); + bool get_cached_plugins_version(std::string &cached_version); //BBS: refine preset update logic bool install_bundles_rsrc(std::vector bundles, bool snapshot) const; void check_installed_vendor_profiles() const; + Updates get_printer_config_updates(bool update = false) const; Updates get_config_updates(const Semver& old_slic3r_version) const; bool perform_updates(Updates &&updates, bool snapshot = true) const; void set_waiting_updates(Updates u); @@ -224,6 +228,7 @@ PresetUpdater::priv::priv() set_download_prefs(GUI::wxGetApp().app_config); // Install indicies from resources. Only installs those that are either missing or older than in resources. check_installed_vendor_profiles(); + perform_updates(get_printer_config_updates(), false); // Load indices from the cache directory. //index_db = Index::load_db(); } @@ -836,7 +841,7 @@ void PresetUpdater::priv::sync_tooltip(std::string http_url, std::string languag } } -//return true means there are plugins files +// return true means there are plugins files bool PresetUpdater::priv::get_cached_plugins_version(std::string& cached_version) { std::string data_dir_str = data_dir(); @@ -980,6 +985,69 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_ } } +void PresetUpdater::priv::sync_printer_config(std::string http_url) +{ + std::string curr_version = SLIC3R_VERSION; + std::string using_version = curr_version.substr(0, 6) + "00.00"; + + std::string cached_version; + std::string data_dir_str = data_dir(); + boost::filesystem::path data_dir_path(data_dir_str); + auto config_folder = data_dir_path / "printers"; + auto cache_folder = data_dir_path / "ota" / "printers"; + + try { + boost::filesystem::load_string_file(config_folder / "version.txt", curr_version); + boost::algorithm::trim(curr_version); + } catch (...) {} + try { + boost::filesystem::load_string_file(cache_folder / "version.txt", cached_version); + boost::algorithm::trim(cached_version); + } catch (...) {} + if (!cached_version.empty()) { + bool need_delete_cache = false; + Semver current_semver = curr_version; + Semver cached_semver = cached_version; + + if ((cached_semver.maj() != current_semver.maj()) || (cached_semver.min() != current_semver.min())) { + need_delete_cache = true; + BOOST_LOG_TRIVIAL(info) << boost::format("cached printer config version %1% not match with current %2%") % cached_version % curr_version; + } else if (cached_semver.patch() <= current_semver.patch()) { + need_delete_cache = true; + BOOST_LOG_TRIVIAL(info) << boost::format("cached printer config version %1% not newer than current %2%") % cached_version % curr_version; + } else { + using_version = cached_version; + } + + if (need_delete_cache) { + boost::system::error_code ec; + boost::filesystem::remove_all(cache_folder, ec); + cached_version = curr_version; + } + } + + try { + std::map resources{{"slicer/printer/bbl", {using_version, "", "", cache_folder.string()}}}; + sync_resources(http_url, resources, false, cached_version, "printer.json"); + } catch (std::exception &e) { + BOOST_LOG_TRIVIAL(warning) << format("[BBL Updater] sync_printer_config: %1%", e.what()); + } + + bool result = false; + try { + boost::filesystem::load_string_file(cache_folder / "version.txt", cached_version); + boost::algorithm::trim(cached_version); + result = true; + } catch (...) {} + if (result) { + BOOST_LOG_TRIVIAL(info) << format("[BBL Updater] found new printer config: %1%, prompt to update", cached_version); + waiting_printer_updates = get_printer_config_updates(true); + if (waiting_printer_updates.updates.size() > 0) { + has_waiting_printer_updates = true; + GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::BBLPrinterConfigUpdateAvailable); + } + } +} bool PresetUpdater::priv::install_bundles_rsrc(std::vector bundles, bool snapshot) const { @@ -1076,6 +1144,53 @@ void PresetUpdater::priv::check_installed_vendor_profiles() const install_bundles_rsrc(bundles, false); } +Updates PresetUpdater::priv::get_printer_config_updates(bool update) const +{ + std::string data_dir_str = data_dir(); + boost::filesystem::path data_dir_path(data_dir_str); + boost::filesystem::path resc_dir_path(resources_dir()); + auto config_folder = data_dir_path / "printers"; + auto resc_folder = (update ? cache_path : resc_dir_path) / "printers"; + std::string curr_version; + std::string resc_version; + try { + boost::filesystem::load_string_file(resc_folder / "version.txt", resc_version); + boost::algorithm::trim(resc_version); + } catch (...) {} + try { + boost::filesystem::load_string_file(config_folder / "version.txt", curr_version); + boost::algorithm::trim(curr_version); + } catch (...) {} + + if (!curr_version.empty()) { + Semver curr_ver = curr_version; + Semver resc_ver = resc_version; + + bool version_match = ((resc_ver.maj() == curr_ver.maj()) && (resc_ver.min() == curr_ver.min())); + + if (!version_match || (curr_ver < resc_ver)) { + BOOST_LOG_TRIVIAL(info) << "[BBL Updater]:found newer version " << resc_version << " from resource, old version " << curr_version; + } else { + return {}; + } + } + Updates updates; + Version version; + version.config_version = resc_version; + std::string change_log; + if (update) { + std::string changelog_file = (resc_folder / "printer.json").string(); + try { + boost::nowide::ifstream ifs(changelog_file); + json j; + ifs >> j; + version.comment = j["description"]; + } catch (...) {} + } + updates.updates.emplace_back(std::move(resc_folder), std::move(config_folder), version, "bbl", change_log, version.comment, false, true); + return updates; +} + // Generates a list of bundle updates that are to be performed. // Version of slic3r that was running the last time and which was read out from PrusaSlicer.ini is provided // as a parameter. @@ -1270,7 +1385,8 @@ void PresetUpdater::sync(std::string http_url, std::string language, std::string } if (p->cancel) return; - this->p->sync_plugins(http_url, plugin_version); + this->p->sync_plugins(http_url, plugin_version); + this->p->sync_printer_config(http_url); //if (p->cancel) // return; //remove the tooltip currently @@ -1459,6 +1575,30 @@ void PresetUpdater::on_update_notification_confirm() } } +void PresetUpdater::do_printer_config_update() +{ + if (!p->has_waiting_printer_updates) + return; + BOOST_LOG_TRIVIAL(info) << "Update of printer configs available. Asking for confirmation ..."; + + std::vector updates_msg; + for (const auto &update : p->waiting_printer_updates.updates) { + std::string changelog = update.change_log; + updates_msg.emplace_back(update.vendor, update.version.config_version, update.descriptions, std::move(changelog)); + } + + GUI::MsgUpdateConfig dlg(updates_msg); + + const auto res = dlg.ShowModal(); + if (res == wxID_OK) { + BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update"; + if (p->perform_updates(std::move(p->waiting_printer_updates))) + p->has_waiting_printer_updates = false; + } else { + BOOST_LOG_TRIVIAL(info) << "User refused the update"; + } +} + bool PresetUpdater::version_check_enabled() const { return p->enabled_version_check; diff --git a/src/slic3r/Utils/PresetUpdater.hpp b/src/slic3r/Utils/PresetUpdater.hpp index 306c0549fa4..6d6e4cd94d5 100644 --- a/src/slic3r/Utils/PresetUpdater.hpp +++ b/src/slic3r/Utils/PresetUpdater.hpp @@ -57,6 +57,7 @@ class PresetUpdater bool install_bundles_rsrc(std::vector bundles, bool snapshot = true) const; void on_update_notification_confirm(); + void do_printer_config_update(); bool version_check_enabled() const; diff --git a/src/slic3r/Utils/bambu_networking.hpp b/src/slic3r/Utils/bambu_networking.hpp index a533da2bb91..b91b4d382ca 100644 --- a/src/slic3r/Utils/bambu_networking.hpp +++ b/src/slic3r/Utils/bambu_networking.hpp @@ -3,6 +3,10 @@ #include #include +#include + +extern std::string g_log_folder; +extern std::string g_log_start_time; namespace BBL { @@ -33,8 +37,8 @@ namespace BBL { #define BAMBU_NETWORK_ERR_NO_CORRESPONDING_BUCKET -24 #define BAMBU_NETWORK_ERR_GET_INSTANCE_ID_FAILED -25 - //bind error -#define BAMBU_NETWORK_ERR_BIND_CREATE_SOCKET_FAILED -1010 //failed to create socket +//bind error +#define BAMBU_NETWORK_ERR_BIND_CREATE_SOCKET_FAILED -1010 //failed to create socket #define BAMBU_NETWORK_ERR_BIND_SOCKET_CONNECT_FAILED -1020 //failed to socket connect #define BAMBU_NETWORK_ERR_BIND_PUBLISH_LOGIN_REQUEST -1030 //failed to publish login request #define BAMBU_NETWORK_ERR_BIND_GET_PRINTER_TICKET_TIMEOUT -1040 //timeout to get ticket from printer @@ -58,17 +62,17 @@ namespace BBL { #define BAMBU_NETWORK_ERR_PRINT_WR_UPLOAD_3MF_TO_OSS_FAILED -2110 //failed to upload 3mf to oss #define BAMBU_NETWORK_ERR_PRINT_WR_POST_TASK_FAILED -2120 //failed to post task #define BAMBU_NETWORK_ERR_PRINT_WR_UPLOAD_FTP_FAILED -2130 //failed to upload to ftp -#define BAMBU_NETWORK_ERR_PRINT_WR_GET_USER_UPLOAD_FAILED -2140 //failed to get_user_upload +#define BAMBU_NETWORK_ERR_PRINT_WR_GET_USER_UPLOAD_FAILED -2140 //failed to get_user_upload //start_print error -#define BAMBU_NETWORK_ERR_PRINT_SP_REQUEST_PROJECT_ID_FAILED -3010 //failed to request project id +#define BAMBU_NETWORK_ERR_PRINT_SP_REQUEST_PROJECT_ID_FAILED -3010 //failed to request project id #define BAMBU_NETWORK_ERR_PRINT_SP_CHECK_MD5_FAILED -3020 //failed to check md5 for upload 3mf to oss #define BAMBU_NETWORK_ERR_PRINT_SP_UPLOAD_3MF_CONFIG_TO_OSS_FAILED -3030 //failed to upload 3mf config to oss #define BAMBU_NETWORK_ERR_PRINT_SP_PUT_NOTIFICATION_FAILED -3040 //failed to put notification #define BAMBU_NETWORK_ERR_PRINT_SP_GET_NOTIFICATION_TIMEOUT -3050 //timeout to get notification #define BAMBU_NETWORK_ERR_PRINT_SP_GET_NOTIFICATION_FAILED -3060 //failed to get notification #define BAMBU_NETWORK_ERR_PRINT_SP_FILE_NOT_EXIST -3070 //3mf file is not exists -#define BAMBU_NETWORK_ERR_PRINT_SP_GET_USER_UPLOAD_FAILED -3080 //failed to get_user_upload +#define BAMBU_NETWORK_ERR_PRINT_SP_GET_USER_UPLOAD_FAILED -3080 //failed to get_user_upload #define BAMBU_NETWORK_ERR_PRINT_SP_FILE_OVER_SIZE -3090 //the size of the uploaded file cannot exceed 1 GB #define BAMBU_NETWORK_ERR_PRINT_SP_UPLOAD_3MF_TO_OSS_FAILED -3100 //failed to upload 3mf to oss #define BAMBU_NETWORK_ERR_PRINT_SP_PATCH_PROJECT_FAILED -3110 //failed to patch project @@ -90,7 +94,7 @@ namespace BBL { #define BAMBU_NETWORK_LIBRARY "bambu_networking" #define BAMBU_NETWORK_AGENT_NAME "bambu_network_agent" -#define BAMBU_NETWORK_AGENT_VERSION "01.07.06.01" +#define BAMBU_NETWORK_AGENT_VERSION "01.07.09.02" //iot preset type strings #define IOT_PRINTER_TYPE_STRING "printer" @@ -106,6 +110,20 @@ namespace BBL { #define IOT_JSON_KEY_FILAMENT_ID "filament_id" #define IOT_JSON_KEY_USER_ID "user_id" +#define IOT_JSON_KEY_SIGN_DATE "sign_date" +#define IOT_JSON_KEY_CERT_START_DATE "cert_start_date" +#define IOT_JSON_KEY_CERT_END_DATE "cert_end_date" +#define IOT_JSON_KEY_CERT_ISSUE_NAME "issue_name" +#define IOT_JSON_KEY_CERT_SUBJECT_NAME "subject_name" +#define IOT_JSON_KEY_CERT_SERIAL_NUMBER "serial_number" +#define IOT_JSON_KEY_CERT_HASH_VALUE "hash_value" +#define IOT_JSON_KEY_CERT_VERIFY_RESULT "verify_result" + +#define EMBEDDED_ISSUER_NAME "GlobalSign GCC R45 EV CodeSigning CA 2020" +#define EMBEDDED_SUBJECT_NAME "Shenzhen Tuozhu Technology Co., Ltd." +#define EMBEDDED_SERIAL_NAME "0b209295a54b188466ad7478" +#define EMBEDDED_HASH_NAME "9690647085f910ffe2098129bc1229956a51e250" + // user callbacks typedef std::function OnUserLoginFn; @@ -117,6 +135,7 @@ typedef std::function OnMessageFn; // http callbacks typedef std::function OnHttpErrorFn; typedef std::function GetCountryCodeFn; +typedef std::function GetSubscribeFailureFn; // print callbacks typedef std::function OnUpdateStatusFn; typedef std::function WasCancelledFn; @@ -137,17 +156,17 @@ enum SendingPrintJobStage { PrintingStageUpload = 1, PrintingStageWaiting = 2, PrintingStageSending = 3, - PrintingStageRecord = 4, + PrintingStageRecord = 4, PrintingStageWaitPrinter = 5, PrintingStageFinished = 6, PrintingStageERROR = 7, }; enum PublishingStage { - PublishingCreate = 0, - PublishingUpload = 1, - PublishingWaiting = 2, - PublishingJumpUrl = 3, + PublishingCreate = 0, + PublishingUpload = 1, + PublishingWaiting = 2, + PublishingJumpUrl = 3, }; enum BindJobStage { @@ -183,6 +202,7 @@ struct PrintParams { std::string connection_type; std::string comments; int origin_profile_id = 0; + int stl_design_id = 0; std::string origin_model_id; std::string print_type; std::string dst_file; diff --git a/src/slic3r/Utils/json_diff.cpp b/src/slic3r/Utils/json_diff.cpp index da3cc1a1f9f..d82ef213420 100644 --- a/src/slic3r/Utils/json_diff.cpp +++ b/src/slic3r/Utils/json_diff.cpp @@ -9,10 +9,13 @@ #include #include "nlohmann/json.hpp" + +#include + using namespace std; using json = nlohmann::json; -int json_diff::diff_objects(json in, json &out, json &base) +int json_diff::diff_objects(json const &in, json &out, json const &base) { for (auto& el: in.items()) { if (el.value().empty()) { @@ -63,14 +66,49 @@ int json_diff::diff_objects(json in, json &out, json &base) return 0; } -int json_diff::all2diff_base_reset(json &base) +int json_diff::all2diff_base_reset(json const &base) { BOOST_LOG_TRIVIAL(trace) << "all2diff_base_reset"; all2diff_base = base; return 0; } -int json_diff::all2diff(json& in, json& out) +bool json_diff::load_compatible_settings(std::string const &type, std::string const &version) +{ + // Reload on empty type and version + if (!type.empty() || !version.empty()) { + std::string type2 = type.empty() ? printer_type : type; + std::string version2 = version.empty() ? printer_version : version; + if (type2 == printer_type && version2 == printer_version) + return false; + printer_type = type2; + printer_version = version2; + } + settings_base.clear(); + std::string config_file = Slic3r::data_dir() + "/printers/" + printer_type + ".json"; + boost::nowide::ifstream json_file(config_file.c_str()); + try { + json versions; + if (json_file.is_open()) { + json_file >> versions; + for (auto iter = versions.begin(); iter != versions.end(); ++iter) { + if (iter.key() > printer_version) + break; + merge_objects(*iter, settings_base); + } + if (!full_message.empty()) + diff2all_base_reset(full_message); + return true; + } else { + BOOST_LOG_TRIVIAL(error) << "load_compatible_settings failed, file = " << config_file; + } + } catch (...) { + BOOST_LOG_TRIVIAL(error) << "load_compatible_settings failed, file = " << config_file; + } + return false; +} + +int json_diff::all2diff(json const &in, json &out) { int ret = 0; if (all2diff_base.empty()) { @@ -88,7 +126,7 @@ int json_diff::all2diff(json& in, json& out) return 0; } -int json_diff::restore_objects(json in, json &out, json &base) +int json_diff::restore_objects(json const &in, json &out, json const &base) { json jout; @@ -145,7 +183,7 @@ int json_diff::restore_objects(json in, json &out, json &base) return 0; } -int json_diff::restore_append_objects(json in, json &out) +int json_diff::restore_append_objects(json const &in, json &out) { /*a new element comming, but be recoreded in base need be added to output*/ @@ -173,7 +211,22 @@ int json_diff::restore_append_objects(json in, json &out) return 0; } -int json_diff::diff2all(json &in, json &out) +void json_diff::merge_objects(json const &in, json &out) +{ + for (auto &el : in.items()) { + if (!out.contains(el.key())) { + out[el.key()] = el.value(); + continue; + } + if (el.value().is_object()) { + merge_objects(el.value(), out[el.key()]); + continue; + } + out[el.key()] = el.value(); + } +} + +int json_diff::diff2all(json const &in, json &out) { if (!diff2all_base.empty()) { int ret = restore_objects(in, out, diff2all_base); @@ -218,8 +271,13 @@ bool json_diff::is_need_request() return false; } -int json_diff::diff2all_base_reset(json &base){ +int json_diff::diff2all_base_reset(json &base) +{ BOOST_LOG_TRIVIAL(trace) << "diff2all_base_reset"; + full_message = base; + if (!settings_base.empty()) { + merge_objects(settings_base, base); + } diff2all_base = base; return 0; } diff --git a/src/slic3r/Utils/json_diff.hpp b/src/slic3r/Utils/json_diff.hpp index a72fa1de411..6ba5a1b8e4c 100644 --- a/src/slic3r/Utils/json_diff.hpp +++ b/src/slic3r/Utils/json_diff.hpp @@ -14,19 +14,26 @@ using namespace std; class json_diff { private: + std::string printer_type; + std::string printer_version = "00.00.00.00"; + json settings_base; + json full_message; + json diff2all_base; json all2diff_base; int decode_error_count = 0; - int diff_objects(json in, json &out, json &base); - int restore_objects(json in, json &out, json &base); - int restore_append_objects(json in, json &out); + int diff_objects(json const &in, json &out, json const &base); + int restore_objects(json const &in, json &out, json const &base); + int restore_append_objects(json const &in, json &out); + void merge_objects(json const &in, json &out); public: - int all2diff(json &in, json &out); - int diff2all(json &in, json &out); - int all2diff_base_reset(json &base); - int diff2all_base_reset(json &base); + bool load_compatible_settings(std::string const &type, std::string const &version); + int all2diff(json const &in, json &out); + int diff2all(json const &in, json &out); + int all2diff_base_reset(json const &base); + int diff2all_base_reset(json &base); void compare_print(json &a, json &b); bool is_need_request(); diff --git a/version.inc b/version.inc index 7e062b19c95..fe58ae74069 100644 --- a/version.inc +++ b/version.inc @@ -16,4 +16,6 @@ string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" set(ORCA_VERSION_MAJOR ${CMAKE_MATCH_1}) set(ORCA_VERSION_MINOR ${CMAKE_MATCH_2}) set(ORCA_VERSION_PATCH ${CMAKE_MATCH_3}) -set(SLIC3R_VERSION "01.07.07.89") \ No newline at end of file + +# The build_version should start from 50 in master branch +set(SLIC3R_VERSION "01.08.01.53")